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