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