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