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