Whamcloud - gitweb
landing b_cmobd_merge on HEAD
[fs/lustre-release.git] / lnet / utils / l_ioctl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Portals, http://www.sf.net/projects/lustre/
7  *
8  *   Portals is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Portals is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Portals; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define __USE_FILE_OFFSET64
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <sys/mman.h>
32 #include <sys/ioctl.h>
33 #include <errno.h>
34 #include <unistd.h>
35
36 #include <portals/api-support.h>
37 #include <portals/ptlctl.h>
38
39 #ifndef __CYGWIN__
40  #include <syscall.h>
41 #else
42  #include <windows.h>
43  #include <windef.h>
44 #endif
45
46 static ioc_handler_t  do_ioctl;                 /* forward ref */
47 static ioc_handler_t *current_ioc_handler = &do_ioctl;
48
49 struct ioc_dev {
50         const char * dev_name;
51         int dev_fd;
52 };
53
54 static struct ioc_dev ioc_dev_list[10];
55
56 struct dump_hdr {
57         int magic;
58         int dev_id;
59         unsigned int opc;
60 };
61
62 char *dump_filename;
63
64 void
65 set_ioc_handler (ioc_handler_t *handler)
66 {
67         if (handler == NULL)
68                 current_ioc_handler = do_ioctl;
69         else
70                 current_ioc_handler = handler;
71 }
72
73 static int
74 open_ioc_dev(int dev_id) 
75 {
76         const char * dev_name;
77
78         if (dev_id < 0 || dev_id >= sizeof(ioc_dev_list))
79                 return -EINVAL;
80
81         dev_name = ioc_dev_list[dev_id].dev_name;
82         if (dev_name == NULL) {
83                 fprintf(stderr, "unknown device id: %d\n", dev_id);
84                 return -EINVAL;
85         }
86
87         if (ioc_dev_list[dev_id].dev_fd < 0) {
88                 int fd = open(dev_name, O_RDWR);
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         return rc;
114         
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 portal_ioctl_hdr * ioc_hdr = (struct  portal_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) 
171 {
172
173         if (dev_id < 0 || dev_id >= sizeof(ioc_dev_list))
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
181         return dev_id;
182 }
183
184 void
185 unregister_ioc_dev(int dev_id) 
186 {
187
188         if (dev_id < 0 || dev_id >= sizeof(ioc_dev_list))
189                 return;
190         if (ioc_dev_list[dev_id].dev_name != NULL &&
191             ioc_dev_list[dev_id].dev_fd >= 0) 
192                 close(ioc_dev_list[dev_id].dev_fd);
193
194         ioc_dev_list[dev_id].dev_name = NULL;
195         ioc_dev_list[dev_id].dev_fd = -1;
196 }
197
198 /* If this file is set, then all ioctl buffers will be 
199    appended to the file. */
200 int
201 set_ioctl_dump(char * file)
202 {
203         if (dump_filename)
204                 free(dump_filename);
205         
206         dump_filename = strdup(file);
207         if (dump_filename == NULL)
208                 abort();
209
210         set_ioc_handler(&dump);
211         return 0;
212 }
213
214 int
215 l_ioctl(int dev_id, unsigned int opc, void *buf)
216 {
217         return current_ioc_handler(dev_id, opc, buf);
218 }
219
220 /* Read an ioctl dump file, and call the ioc_func for each ioctl buffer
221  * in the file.  For example:
222  *
223  * parse_dump("lctl.dump", l_ioctl);
224  *
225  * Note: if using l_ioctl, then you also need to register_ioc_dev() for 
226  * each device used in the dump.
227  */
228 int 
229 parse_dump(char * dump_file, ioc_handler_t ioc_func)
230 {
231         int line =0;
232         struct stat st;
233         char *start, *buf, *end;
234 #ifndef __CYGWIN__
235         int fd;
236 #else
237         HANDLE fd, hmap;
238         DWORD size;
239 #endif
240         
241 #ifndef __CYGWIN__
242         fd = syscall(SYS_open, dump_file, O_RDONLY);
243         if (fd < 0) {
244                 fprintf(stderr, "couldn't open %s: %s\n", dump_file, 
245                         strerror(errno));
246                 exit(1);
247         }
248
249         if (fstat(fd, &st)) { 
250                 perror("stat fails");
251                 exit(1);
252         }
253
254         if (st.st_size < 1) {
255                 fprintf(stderr, "KML is empty\n");
256                 exit(1);
257         }
258
259         start = buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE , fd, 0);
260         end = start + st.st_size;
261         close(fd);
262         if (start == MAP_FAILED) {
263                 fprintf(stderr, "can't create file mapping\n");
264                 exit(1);
265         }
266 #else
267         fd = CreateFile(dump_file, GENERIC_READ, FILE_SHARE_READ, NULL,
268                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
269         size = GetFileSize(fd, NULL);
270         if (size < 1) {
271                 fprintf(stderr, "KML is empty\n");
272                 exit(1);
273         }
274
275         hmap = CreateFileMapping(fd, NULL, PAGE_READONLY, 0,0, NULL);
276         start = buf = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
277         end = buf + size;
278         CloseHandle(fd);
279         if (start == NULL) {
280                 fprintf(stderr, "can't create file mapping\n");
281                 exit(1);
282         }
283 #endif /* __CYGWIN__ */
284
285         while (buf < end) {
286                 struct dump_hdr *dump_hdr = (struct dump_hdr *) buf;
287                 struct portal_ioctl_hdr * data;
288                 char tmp[8096];
289                 int rc;
290
291                 line++;
292
293                 data = (struct portal_ioctl_hdr *) (buf + sizeof(*dump_hdr));
294                 if (buf + data->ioc_len > end ) {
295                         fprintf(stderr, "dump file overflow, %p + %d > %p\n", buf,
296                                 data->ioc_len, end);
297                         return -1;
298                 }
299 #if 0
300                 printf ("dump_hdr: %lx data: %lx\n",
301                         (unsigned long)dump_hdr - (unsigned long)buf, (unsigned long)data - (unsigned long)buf);
302
303                 printf("%d: opcode %x len: %d  ver: %x ", line, dump_hdr->opc,
304                        data->ioc_len, data->ioc_version);
305 #endif
306
307                 memcpy(tmp, data, data->ioc_len);
308
309                 rc = ioc_func(dump_hdr->dev_id, dump_hdr->opc, tmp);
310                 if (rc) {
311                         printf("failed: %d\n", rc);
312                         exit(1);
313                 }
314
315                 buf += data->ioc_len + sizeof(*dump_hdr);
316         }
317
318 #ifndef __CYGWIN__
319         munmap(start, end - start);
320 #else
321         UnmapViewOfFile(start);
322         CloseHandle(hmap);
323 #endif
324
325         return 0;
326 }
327
328 int 
329 jt_ioc_dump(int argc, char **argv)
330 {
331         if (argc > 2) {
332                 fprintf(stderr, "usage: %s [hostname]\n", argv[0]);
333                 return 0;
334         }
335         printf("setting dumpfile to: %s\n", argv[1]);
336         
337         set_ioctl_dump(argv[1]);
338         return 0;
339 }