Initial revision
[nfs-utils.git] / tools / rpcdebug / neat_idea.c
1 /*
2  * Get or set RPC debug flags.
3  *
4  * I would have loved to write this without recourse to the sysctl
5  * interface, but the only plausible approach (reading and writing
6  * /dev/kmem at the offsets indicated by the *_debug symbols from
7  * /proc/ksyms) didn't work, because /dev/kmem doesn't translate virtual
8  * addresses on write. Unfortunately, modules are stuffed into memory
9  * allocated via vmalloc.
10  *
11  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
12  */
13
14 #include "config.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <getopt.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <nfs/debug.h>
24 #include "nfslib.h"
25
26 static int              verbose = 0;
27 static int              memfd;
28 static off_t            flagpos;
29
30 static void             find_offset(char *module);
31 static unsigned int     find_flag(char **module, char *name);
32 static unsigned int     get_flags(void);
33 static void             set_flags(unsigned int value);
34 static void             print_flags(char *module, unsigned int flags);
35 static void             usage(int excode);
36
37 int
38 main(int argc, char **argv)
39 {
40         int             opt_s = 0,
41                         opt_c = 0;
42         unsigned int    flags = 0, oflags;
43         char *          module = NULL;
44         int             c;
45
46         while ((c = getopt(argc, argv, "chm:sv")) != EOF) {
47                 switch (c) {
48                 case 'c':
49                         opt_c = 1;
50                         break;
51                 case 'h':
52                         usage(0);
53                 case 'm':
54                         module = optarg;
55                         break;
56                 case 's':
57                         opt_s = 1;
58                         break;
59                 case 'v':
60                         verbose++;
61                         break;
62                 default:
63                         fprintf(stderr, "rpcdebug: unknown option -%c\n",
64                                                 optopt);
65                         usage(1);
66                 }
67         }
68
69         if (opt_c + opt_s > 1) {
70                 fprintf(stderr, "You can use at most one of -c and -s\n");
71                 usage(1);
72         }
73
74         if (argc == optind) {
75                 flags = ~(unsigned int) 0;
76         } else {
77                 for (; optind < argc; optind++) {
78                         unsigned int    temp;
79
80                         if (!(temp = find_flag(&module, argv[optind]))) {
81                                 fprintf(stderr, "rpcdebug: unknown flag %s\n",
82                                                         argv[optind]);
83                                 exit(1);
84                         }
85                         flags |= temp;
86                 }
87         }
88
89         if (!module) {
90                 fprintf(stderr, "rpcdebug: no module name specified, and "
91                                 "could not be inferred.\n");
92                 usage(1);
93         }
94
95         if ((memfd = open("/dev/kmem", O_RDWR)) < 0) {
96                 perror("can't open /dev/mem");
97                 exit(1);
98         }
99
100         find_offset(module);
101
102         oflags = get_flags();
103
104         if (opt_c) {
105                 set_flags(oflags & ~flags);
106         } else if (opt_s) {
107                 set_flags(oflags | flags);
108         } else {
109                 print_flags(module, oflags);
110         }
111
112         close(memfd);
113         return 0;
114 }
115
116 #define FLAG(mname, fname)      \
117       { #mname, #fname, mname##DBG_##fname }
118
119 static struct flagmap {
120         char *          module;
121         char *          name;
122         unsigned int    value;
123 }                       flagmap[] = {
124         /* rpc */
125         FLAG(RPC,       XPRT),
126         FLAG(RPC,       CALL),
127         FLAG(RPC,       TYPES),
128         FLAG(RPC,       NFS),
129         FLAG(RPC,       AUTH),
130         FLAG(RPC,       PMAP),
131         FLAG(RPC,       SCHED),
132         FLAG(RPC,       SVCSOCK),
133         FLAG(RPC,       SVCDSP),
134         FLAG(RPC,       MISC),
135         FLAG(RPC,       ALL),
136
137         /* nfs */
138         /* currently handled by RPCDBG_NFS */
139
140         /* nfsd */
141         FLAG(NFSD,      SOCK),
142         FLAG(NFSD,      FH),
143         FLAG(NFSD,      EXPORT),
144         FLAG(NFSD,      SVC),
145         FLAG(NFSD,      PROC),
146         FLAG(NFSD,      FILEOP),
147         FLAG(NFSD,      AUTH),
148         FLAG(NFSD,      REPCACHE),
149         FLAG(NFSD,      XDR),
150         FLAG(NFSD,      LOCKD),
151         FLAG(NFSD,      ALL),
152
153         /* lockd */
154         FLAG(NLM,       SVC),
155         FLAG(NLM,       CLIENT),
156         FLAG(NLM,       CLNTLOCK),
157         FLAG(NLM,       SVCLOCK),
158         FLAG(NLM,       MONITOR),
159         FLAG(NLM,       CLNTSUBS),
160         FLAG(NLM,       SVCSUBS),
161         FLAG(NLM,       ALL),
162
163       { NULL,           NULL,           0 }
164 };
165
166 static unsigned int
167 find_flag(char **module, char *name)
168 {
169         char            *mod = *module;
170         unsigned int    value = 0;
171         int             i;
172
173         for (i = 0; flagmap[i].module; i++) {
174                 if ((mod && strcasecmp(mod, flagmap[i].module))
175                  || strcasecmp(name, flagmap[i].name))
176                         continue;
177                 if (value) {
178                         fprintf(stderr,
179                                 "rpcdebug: ambiguous symbol name %s.\n"
180                                 "This name is used by more than one module, "
181                                 "please specify the module name using\n"
182                                 "the -m option.\n",
183                                 name);
184                         usage(1);
185                 }
186                 value = flagmap[i].value;
187                 if (*module)
188                         return value;
189                 mod = flagmap[i].module;
190         }
191
192         *module = mod;
193         return value;
194 }
195
196 static unsigned int
197 get_flags(void)
198 {
199         unsigned int    value;
200         int             count;
201
202         if (lseek(memfd, flagpos, SEEK_SET) < 0) {
203                 perror("lseek");
204                 exit(1);
205         }
206         if ((count = read(memfd, &value, sizeof(value))) < 0) {
207                 perror("read");
208                 exit(1);
209         }
210         if (count != sizeof(value)) {
211                 fprintf(stderr, "read failed (only %d bytes read)\n",
212                                 count);
213                 exit(1);
214         }
215         if (verbose)
216                 printf("getting flags 0x%x\n", value);
217         return value;
218 }
219
220 static void
221 set_flags(unsigned int value)
222 {
223         int     count;
224
225         if (verbose)
226                 printf("setting flags 0x%x\n", value);
227         if (lseek(memfd, flagpos, SEEK_SET) < 0) {
228                 perror("lseek");
229                 exit(1);
230         }
231         if ((count = write(memfd, &value, sizeof(value))) < 0) {
232                 perror("write");
233                 exit(1);
234         }
235         if (count != sizeof(value)) {
236                 fprintf(stderr, "write failed (only %d bytes written)\n",
237                                 count);
238                 exit(1);
239         }
240 }
241
242 static void
243 find_offset(char *module)
244 {
245         char    buffer[512], *sp;
246         char    symbol[64];
247         FILE    *fp;
248         int     len;
249
250         len = sprintf(symbol, "%s_debug", module);
251
252         if ((fp = fopen("/proc/ksyms", "r")) < 0) {
253                 perror("rpcdebug: can't open /proc/ksyms");
254                 exit(1);
255         }
256
257         while (fgets(buffer, sizeof(buffer), fp) != NULL) {
258                 if (!(sp = strchr(buffer, ' ')))
259                         continue;
260                 if (strncmp(++sp, symbol, len))
261                         continue;
262                 if (sp[len] != '\n' && sp[len] != '\t'
263                  && strncmp(sp+len, "_R", 2))
264                         continue;
265                 flagpos = (unsigned long) strtol(buffer, &sp, 16);
266                 /* printf("position is %lx\n", flagpos); */
267                 if (sp && *sp == ' ')
268                         return;
269                 fprintf(stderr, "rpcdebug: weird line in /proc/ksyms: %s\n",
270                                 buffer);
271                 exit(1);
272         }
273
274         fprintf(stderr, "rpcdebug: debug symbol for module %s not found.\n",
275                         module);
276         exit(1);
277 }
278
279 static char *
280 strtolower(char *str)
281 {
282         static char     temp[64];
283         char            *sp;
284
285         strcpy(temp, str);
286         for (sp = temp; *sp; sp++)
287                 *sp = tolower(*sp);
288         return temp;
289 }
290
291 static void
292 print_flags(char *module, unsigned int flags)
293 {
294         char    *lastmod = NULL;
295         int     i;
296
297         if (module) {
298                 printf("%-10s", strtolower(module));
299                 if (!flags) {
300                         printf("<no flags set>\n");
301                         return;
302                 }
303                 /* printf(" <%x>", flags); */
304         }
305
306         for (i = 0; flagmap[i].module; i++) {
307                 if (module) {
308                         if (strcasecmp(flagmap[i].module, module))
309                                 continue;
310                 } else if (!lastmod || strcmp(lastmod, flagmap[i].module)) {
311                         if (lastmod)
312                                 printf("\n");
313                         printf("%-10s", strtolower(flagmap[i].module));
314                         lastmod = flagmap[i].module;
315                 }
316                 if (!(flags & flagmap[i].value)
317                  || (module && !strcasecmp(flagmap[i].name, "all")))
318                         continue;
319                 printf(" %s", strtolower(flagmap[i].name));
320         }
321         printf("\n");
322 }
323
324 static void
325 usage(int excode)
326 {
327         fprintf(stderr, "usage: rpcdebug [-m module] [-cs] flags ...\n");
328         if (verbose) {
329                 printf("\nModule     Valid flags\n");
330                 print_flags(NULL, ~(unsigned int) 0);
331         }
332         exit (excode);
333 }
334