Whamcloud - gitweb
LU-2675 lnet: add lnet/nidstr.h
[fs/lustre-release.git] / libcfs / libcfs / util / l_ioctl.c
1 /*
2  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
3  *
4  *   This file is part of Portals, http://www.sf.net/projects/lustre/
5  *
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.
9  *
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.
14  *
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.
18  *
19  */
20
21 #define __USE_FILE_OFFSET64
22
23 #include <libcfs/libcfsutil.h>
24 #include <lnet/lnetctl.h>
25
26 static ioc_handler_t  do_ioctl;                 /* forward ref */
27 static ioc_handler_t *current_ioc_handler = &do_ioctl;
28
29 struct ioc_dev {
30         const char * dev_name;
31         int dev_fd;
32         int dev_major;
33         int dev_minor;
34 };
35
36 static struct ioc_dev ioc_dev_list[10];
37
38 struct dump_hdr {
39         int magic;
40         int dev_id;
41         unsigned int opc;
42 };
43
44 char *dump_filename;
45
46 void
47 set_ioc_handler (ioc_handler_t *handler)
48 {
49         if (handler == NULL)
50                 current_ioc_handler = do_ioctl;
51         else
52                 current_ioc_handler = handler;
53 }
54
55 /* Catamount has no <linux/kdev_t.h>, so just define it here */
56 #ifndef MKDEV
57 # define MKDEV(a,b) (((a) << 8) | (b))
58 #endif
59
60 static int
61 open_ioc_dev(int dev_id) 
62 {
63         const char * dev_name;
64
65         if (dev_id < 0 || 
66             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
67                 return -EINVAL;
68
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);
72                 return -EINVAL;
73         }
74
75         if (ioc_dev_list[dev_id].dev_fd < 0) {
76                 int fd = open(dev_name, O_RDWR);
77
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);
84                         else
85                                 fprintf(stderr, "mknod %s failed: %s\n",
86                                         dev_name, strerror(errno));
87                 }
88
89                 if (fd < 0) {
90                         fprintf(stderr, "opening %s failed: %s\n"
91                                 "hint: the kernel modules may not be loaded\n",
92                                 dev_name, strerror(errno));
93                         return fd;
94                 }
95                 ioc_dev_list[dev_id].dev_fd = fd;
96         }
97
98         return ioc_dev_list[dev_id].dev_fd;
99 }
100
101
102 static int 
103 do_ioctl(int dev_id, unsigned int opc, void *buf)
104 {
105         int fd, rc;
106         
107         fd = open_ioc_dev(dev_id);
108         if (fd < 0) 
109                 return fd;
110
111         rc = ioctl(fd, opc, buf);
112
113         return rc;
114 }
115
116 static FILE *
117 get_dump_file() 
118 {
119         FILE *fp = NULL;
120         
121         if (!dump_filename) {
122                 fprintf(stderr, "no dump filename\n");
123         } else 
124                 fp = fopen(dump_filename, "a");
125         return fp;
126 }
127
128 /*
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. */
132 int 
133 dump(int dev_id, unsigned int opc, void *buf)
134 {
135         FILE *fp;
136         struct dump_hdr dump_hdr;
137         struct libcfs_ioctl_hdr * ioc_hdr = (struct  libcfs_ioctl_hdr *) buf;
138         int rc;
139         
140         printf("dumping opc %x to %s\n", opc, dump_filename);
141         
142
143         dump_hdr.magic = 0xdeadbeef;
144         dump_hdr.dev_id = dev_id;
145         dump_hdr.opc = opc;
146
147         fp = get_dump_file();
148         if (fp == NULL) {
149                 fprintf(stderr, "%s: %s\n", dump_filename, 
150                         strerror(errno));
151                 return -EINVAL;
152         }
153         
154         rc = fwrite(&dump_hdr, sizeof(dump_hdr), 1, fp);
155         if (rc == 1)
156                 rc = fwrite(buf, ioc_hdr->ioc_len, 1, fp);
157         fclose(fp);
158         if (rc != 1) {
159                 fprintf(stderr, "%s: %s\n", dump_filename,
160                         strerror(errno));
161                 return -EINVAL;
162         }
163
164         return 0;
165 }
166
167 /* register a device to send ioctls to.  */
168 int 
169 register_ioc_dev(int dev_id, const char * dev_name, int major, int minor) 
170 {
171
172         if (dev_id < 0 || 
173             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
174                 return -EINVAL;
175
176         unregister_ioc_dev(dev_id);
177
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;
182  
183         return dev_id;
184 }
185
186 void
187 unregister_ioc_dev(int dev_id) 
188 {
189         if (dev_id < 0 ||
190             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
191                 return;
192
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);
196
197         ioc_dev_list[dev_id].dev_name = NULL;
198         ioc_dev_list[dev_id].dev_fd = -1;
199 }
200
201 /* If this file is set, then all ioctl buffers will be 
202    appended to the file. */
203 int
204 set_ioctl_dump(char * file)
205 {
206         if (dump_filename)
207                 free(dump_filename);
208         
209         dump_filename = strdup(file);
210         if (dump_filename == NULL)
211                 abort();
212
213         set_ioc_handler(&dump);
214         return 0;
215 }
216
217 int
218 l_ioctl(int dev_id, unsigned int opc, void *buf)
219 {
220         return current_ioc_handler(dev_id, opc, buf);
221 }
222
223 /* Read an ioctl dump file, and call the ioc_func for each ioctl buffer
224  * in the file.  For example:
225  *
226  * parse_dump("lctl.dump", l_ioctl);
227  *
228  * Note: if using l_ioctl, then you also need to register_ioc_dev() for 
229  * each device used in the dump.
230  */
231 int 
232 parse_dump(char * dump_file, ioc_handler_t ioc_func)
233 {
234         int line =0;
235         char *start, *buf, *end;
236         struct stat st;
237         int fd;
238
239         fd = open(dump_file, O_RDONLY);
240         if (fd < 0) {
241                 fprintf(stderr, "couldn't open %s: %s\n", dump_file, 
242                         strerror(errno));
243                 exit(1);
244         }
245
246         if (fstat(fd, &st)) { 
247                 perror("stat fails");
248                 exit(1);
249         }
250
251         if (st.st_size < 1) {
252                 fprintf(stderr, "KML is empty\n");
253                 exit(1);
254         }
255
256         start = buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE , fd, 0);
257         end = start + st.st_size;
258         close(fd);
259         if (start == MAP_FAILED) {
260                 fprintf(stderr, "can't create file mapping\n");
261                 exit(1);
262         }
263
264         while (buf < end) {
265                 struct dump_hdr *dump_hdr = (struct dump_hdr *) buf;
266                 struct libcfs_ioctl_hdr * data;
267                 char tmp[8096];
268                 int rc;
269
270                 line++;
271
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,
275                                 data->ioc_len, end);
276                         return -1;
277                 }
278 #if 0
279                 printf ("dump_hdr: %lx data: %lx\n",
280                         (unsigned long)dump_hdr - (unsigned long)buf, (unsigned long)data - (unsigned long)buf);
281
282                 printf("%d: opcode %x len: %d  ver: %x ", line, dump_hdr->opc,
283                        data->ioc_len, data->ioc_version);
284 #endif
285
286                 memcpy(tmp, data, data->ioc_len);
287
288                 rc = ioc_func(dump_hdr->dev_id, dump_hdr->opc, tmp);
289                 if (rc) {
290                         printf("failed: %d\n", rc);
291                         exit(1);
292                 }
293
294                 buf += data->ioc_len + sizeof(*dump_hdr);
295         }
296
297         munmap(start, end - start);
298
299         return 0;
300 }
301
302 int 
303 jt_ioc_dump(int argc, char **argv)
304 {
305         if (argc > 2) {
306                 fprintf(stderr, "usage: %s [hostname]\n", argv[0]);
307                 return 0;
308         }
309         printf("setting dumpfile to: %s\n", argv[1]);
310         
311         set_ioctl_dump(argv[1]);
312         return 0;
313 }
314
315 int libcfs_ioctl_pack(struct libcfs_ioctl_data *data, char **pbuf,
316                                     int max)
317 {
318         char *ptr;
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;
322
323         if (*pbuf != NULL && libcfs_ioctl_packlen(data) > max)
324                 return 1;
325         if (*pbuf == NULL)
326                 *pbuf = malloc(data->ioc_hdr.ioc_len);
327         if (*pbuf == NULL)
328                 return 1;
329         overlay = (struct libcfs_ioctl_data *)*pbuf;
330         memcpy(*pbuf, data, sizeof(*data));
331
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))
338                 return 1;
339
340         return 0;
341 }
342