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