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