2 * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
4 * This file is part of Portals, http://www.sf.net/projects/lustre/
6 * Portals is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
10 * Portals is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Portals; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #define __USE_FILE_OFFSET64
23 #include <libcfs/libcfsutil.h>
24 #include <lnet/lnetctl.h>
26 static ioc_handler_t do_ioctl; /* forward ref */
27 static ioc_handler_t *current_ioc_handler = &do_ioctl;
30 const char * dev_name;
36 static struct ioc_dev ioc_dev_list[10];
47 set_ioc_handler (ioc_handler_t *handler)
50 current_ioc_handler = do_ioctl;
52 current_ioc_handler = handler;
55 /* Catamount has no <linux/kdev_t.h>, so just define it here */
57 # define MKDEV(a,b) (((a) << 8) | (b))
61 open_ioc_dev(int dev_id)
63 const char * dev_name;
66 dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
69 dev_name = ioc_dev_list[dev_id].dev_name;
70 if (dev_name == NULL) {
71 fprintf(stderr, "unknown device id: %d\n", dev_id);
75 if (ioc_dev_list[dev_id].dev_fd < 0) {
76 int fd = open(dev_name, O_RDWR);
78 /* Make the /dev/ node if we need to */
79 if (fd < 0 && errno == ENOENT) {
80 if (mknod(dev_name, S_IFCHR|S_IWUSR|S_IRUSR,
81 MKDEV(ioc_dev_list[dev_id].dev_major,
82 ioc_dev_list[dev_id].dev_minor)) == 0)
83 fd = open(dev_name, O_RDWR);
85 fprintf(stderr, "mknod %s failed: %s\n",
86 dev_name, strerror(errno));
90 fprintf(stderr, "opening %s failed: %s\n"
91 "hint: the kernel modules may not be loaded\n",
92 dev_name, strerror(errno));
95 ioc_dev_list[dev_id].dev_fd = fd;
98 return ioc_dev_list[dev_id].dev_fd;
103 do_ioctl(int dev_id, unsigned int opc, void *buf)
107 fd = open_ioc_dev(dev_id);
111 rc = ioctl(fd, opc, buf);
121 if (!dump_filename) {
122 fprintf(stderr, "no dump filename\n");
124 fp = fopen(dump_filename, "a");
129 * The dump file should start with a description of which devices are
130 * used, but for now it will assumed whatever app reads the file will
131 * know what to do. */
133 dump(int dev_id, unsigned int opc, void *buf)
136 struct dump_hdr dump_hdr;
137 struct libcfs_ioctl_hdr * ioc_hdr = (struct libcfs_ioctl_hdr *) buf;
140 printf("dumping opc %x to %s\n", opc, dump_filename);
143 dump_hdr.magic = 0xdeadbeef;
144 dump_hdr.dev_id = dev_id;
147 fp = get_dump_file();
149 fprintf(stderr, "%s: %s\n", dump_filename,
154 rc = fwrite(&dump_hdr, sizeof(dump_hdr), 1, fp);
156 rc = fwrite(buf, ioc_hdr->ioc_len, 1, fp);
159 fprintf(stderr, "%s: %s\n", dump_filename,
167 /* register a device to send ioctls to. */
169 register_ioc_dev(int dev_id, const char * dev_name, int major, int minor)
173 dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
176 unregister_ioc_dev(dev_id);
178 ioc_dev_list[dev_id].dev_name = dev_name;
179 ioc_dev_list[dev_id].dev_fd = -1;
180 ioc_dev_list[dev_id].dev_major = major;
181 ioc_dev_list[dev_id].dev_minor = minor;
187 unregister_ioc_dev(int dev_id)
190 dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
193 if (ioc_dev_list[dev_id].dev_name != NULL &&
194 ioc_dev_list[dev_id].dev_fd >= 0)
195 close(ioc_dev_list[dev_id].dev_fd);
197 ioc_dev_list[dev_id].dev_name = NULL;
198 ioc_dev_list[dev_id].dev_fd = -1;
201 /* If this file is set, then all ioctl buffers will be
202 appended to the file. */
204 set_ioctl_dump(char * file)
209 dump_filename = strdup(file);
210 if (dump_filename == NULL)
213 set_ioc_handler(&dump);
218 l_ioctl(int dev_id, unsigned int opc, void *buf)
220 return current_ioc_handler(dev_id, opc, buf);
223 /* Read an ioctl dump file, and call the ioc_func for each ioctl buffer
224 * in the file. For example:
226 * parse_dump("lctl.dump", l_ioctl);
228 * Note: if using l_ioctl, then you also need to register_ioc_dev() for
229 * each device used in the dump.
232 parse_dump(char * dump_file, ioc_handler_t ioc_func)
235 char *start, *buf, *end;
239 fd = open(dump_file, O_RDONLY);
241 fprintf(stderr, "couldn't open %s: %s\n", dump_file,
246 if (fstat(fd, &st)) {
247 perror("stat fails");
251 if (st.st_size < 1) {
252 fprintf(stderr, "KML is empty\n");
256 start = buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE , fd, 0);
257 end = start + st.st_size;
259 if (start == MAP_FAILED) {
260 fprintf(stderr, "can't create file mapping\n");
265 struct dump_hdr *dump_hdr = (struct dump_hdr *) buf;
266 struct libcfs_ioctl_hdr * data;
272 data = (struct libcfs_ioctl_hdr *) (buf + sizeof(*dump_hdr));
273 if (buf + data->ioc_len > end ) {
274 fprintf(stderr, "dump file overflow, %p + %d > %p\n", buf,
279 printf ("dump_hdr: %lx data: %lx\n",
280 (unsigned long)dump_hdr - (unsigned long)buf, (unsigned long)data - (unsigned long)buf);
282 printf("%d: opcode %x len: %d ver: %x ", line, dump_hdr->opc,
283 data->ioc_len, data->ioc_version);
286 memcpy(tmp, data, data->ioc_len);
288 rc = ioc_func(dump_hdr->dev_id, dump_hdr->opc, tmp);
290 printf("failed: %d\n", rc);
294 buf += data->ioc_len + sizeof(*dump_hdr);
297 munmap(start, end - start);
303 jt_ioc_dump(int argc, char **argv)
306 fprintf(stderr, "usage: %s [hostname]\n", argv[0]);
309 printf("setting dumpfile to: %s\n", argv[1]);
311 set_ioctl_dump(argv[1]);
315 int libcfs_ioctl_pack(struct libcfs_ioctl_data *data, char **pbuf,
319 struct libcfs_ioctl_data *overlay;
320 data->ioc_hdr.ioc_len = libcfs_ioctl_packlen(data);
321 data->ioc_hdr.ioc_version = LIBCFS_IOCTL_VERSION;
323 if (*pbuf != NULL && libcfs_ioctl_packlen(data) > max)
326 *pbuf = malloc(data->ioc_hdr.ioc_len);
329 overlay = (struct libcfs_ioctl_data *)*pbuf;
330 memcpy(*pbuf, data, sizeof(*data));
332 ptr = overlay->ioc_bulk;
333 if (data->ioc_inlbuf1 != NULL)
334 LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
335 if (data->ioc_inlbuf2 != NULL)
336 LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
337 if (libcfs_ioctl_is_invalid(overlay))
344 libcfs_ioctl_unpack(struct libcfs_ioctl_data *data, char *pbuf)
346 struct libcfs_ioctl_data *overlay = (struct libcfs_ioctl_data *)pbuf;
349 /* Preserve the caller's buffer pointers */
350 overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
351 overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
353 memcpy(data, pbuf, sizeof(*data));
354 ptr = &overlay->ioc_bulk[0];
356 if (data->ioc_inlbuf1 != NULL)
357 LOGU(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
358 if (data->ioc_inlbuf2 != NULL)
359 LOGU(data->ioc_inlbuf2, data->ioc_inllen2, ptr);