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