Imported Upstream version 1.0.8+1.0.9pre1
[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,       PMAP),
150         FLAG(RPC,       SCHED),
151         FLAG(RPC,       SVCSOCK),
152         FLAG(RPC,       SVCDSP),
153         FLAG(RPC,       MISC),
154         FLAG(RPC,       ALL),
155
156         /* nfs */
157         FLAG(NFS,       VFS),
158         FLAG(NFS,       DIRCACHE),
159         FLAG(NFS,       LOOKUPCACHE),
160         FLAG(NFS,       PAGECACHE),
161         FLAG(NFS,       PROC),
162         FLAG(NFS,       XDR),
163         FLAG(NFS,       FILE),
164         FLAG(NFS,       ROOT),
165         //      FLAG(NFS,       CALLBACK),
166         FLAG(NFS,       ALL),
167
168         /* nfsd */
169         FLAG(NFSD,      SOCK),
170         FLAG(NFSD,      FH),
171         FLAG(NFSD,      EXPORT),
172         FLAG(NFSD,      SVC),
173         FLAG(NFSD,      PROC),
174         FLAG(NFSD,      FILEOP),
175         FLAG(NFSD,      AUTH),
176         FLAG(NFSD,      REPCACHE),
177         FLAG(NFSD,      XDR),
178         FLAG(NFSD,      LOCKD),
179         FLAG(NFSD,      ALL),
180
181         /* lockd */
182         FLAG(NLM,       SVC),
183         FLAG(NLM,       CLIENT),
184         FLAG(NLM,       CLNTLOCK),
185         FLAG(NLM,       SVCLOCK),
186         FLAG(NLM,       MONITOR),
187         FLAG(NLM,       CLNTSUBS),
188         FLAG(NLM,       SVCSUBS),
189         FLAG(NLM,       HOSTCACHE),
190         FLAG(NLM,       ALL),
191
192       { NULL,           NULL,           0 }
193 };
194
195 static unsigned int
196 find_flag(char **module, char *name)
197 {
198         char            *mod = *module;
199         unsigned int    value = 0;
200         int             i;
201
202         for (i = 0; flagmap[i].module; i++) {
203                 if ((mod && strcasecmp(mod, flagmap[i].module))
204                  || strcasecmp(name, flagmap[i].name))
205                         continue;
206                 if (value) {
207                         fprintf(stderr,
208                                 "%s: ambiguous symbol name %s.\n"
209                                 "This name is used by more than one module, "
210                                 "please specify the module name using\n"
211                                 "the -m option.\n",
212                                 cdename, name);
213                         exit(1);
214                 }
215                 value = flagmap[i].value;
216                 if (*module)
217                         return value;
218                 mod = flagmap[i].module;
219         }
220
221         if (!value) {
222                 if (*module)
223                         fprintf(stderr,
224                                 "%s: unknown module or flag %s/%s\n",
225                                 cdename, *module, name);
226                 else
227                         fprintf(stderr,
228                                 "%s: unknown flag %s\n",
229                                 cdename, name);
230                 exit(1);
231         }
232
233         *module = mod;
234         return value;
235 }
236
237 static unsigned int
238 get_flags(char *module)
239 {
240         char    buffer[256], filename[256];
241         int     sysfd, len;
242
243         snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module);
244
245         if ((sysfd = open(filename, O_RDONLY)) < 0) {
246                 perror(filename);
247                 exit(1);
248         }
249         if ((len = read(sysfd, buffer, sizeof(buffer))) < 0) {
250                 perror("read");
251                 exit(1);
252         }
253         close(sysfd);
254         buffer[len - 1] = '\0';
255
256         return strtoul(buffer, NULL, 0);
257 }
258
259 static unsigned int
260 set_flags(char *module, unsigned int value)
261 {
262         char    buffer[64], filename[256];
263         int     sysfd, len, ret;
264
265         snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module);
266
267         len = sprintf(buffer, "%d", value);
268         if ((sysfd = open(filename, O_WRONLY)) < 0) {
269                 perror(filename);
270                 exit(1);
271         }
272         if ((ret = write(sysfd, buffer, len)) < 0) {
273                 perror("write");
274                 exit(1);
275         }
276         if (ret < len) {
277                 fprintf(stderr, "error: short write in set_flags!\n");
278                 exit(1);
279         }
280         close(sysfd);
281         return value;
282 }
283
284
285 static char *
286 strtolower(char *str)
287 {
288         static char     temp[64];
289         char            *sp;
290
291         strcpy(temp, str);
292         for (sp = temp; *sp; sp++)
293                 *sp = tolower(*sp);
294         return temp;
295 }
296
297 static void
298 print_flags(FILE *ofp, char *module, unsigned int flags, int show_all)
299 {
300         char            *lastmod = NULL;
301         unsigned int    shown = 0;
302         int             i;
303
304         if (module) {
305                 fprintf(ofp, "%-10s", strtolower(module));
306                 if (!flags) {
307                         fprintf(ofp, "<no flags set>\n");
308                         return;
309                 }
310         }
311
312         for (i = 0, shown = 0; flagmap[i].module; i++) {
313                 if (module) {
314                         if (strcasecmp(flagmap[i].module, module))
315                                 continue;
316                 } else if (!lastmod || strcmp(lastmod, flagmap[i].module)) {
317                         if (lastmod) {
318                                 fprintf(ofp, "\n");
319                                 shown = 0;
320                         }
321                         fprintf(ofp, "%-10s", strtolower(flagmap[i].module));
322                         lastmod = flagmap[i].module;
323                 }
324                 if (!(flags & flagmap[i].value)
325                  || (!show_all && (shown & flagmap[i].value))
326                  || (module && !strcasecmp(flagmap[i].name, "all")))
327                         continue;
328                 fprintf(ofp, " %s", strtolower(flagmap[i].name));
329                 shown |= flagmap[i].value;
330         }
331         fprintf(ofp, "\n");
332 }
333
334 static void
335 usage(int excode, char *module)
336 {
337         if (module)
338           fprintf(stderr, "usage: %s [-v] [-h] [-s flags...|-c flags...]\n", cdename);
339         else
340           fprintf(stderr, "usage: %s [-v] [-h] [-m module] [-s flags...|-c flags...]\n", cdename);
341         fprintf(stderr, "       set or cancel debug flags.\n");
342         if (verbose) {
343           fprintf(stderr, "\nModule     Valid flags\n");
344           print_flags(stderr, module, ~(unsigned int) 0, 1);
345         } else {
346           if (module)
347             fprintf(stderr, "       (use %s -vh to get a list of valid flags)\n", cdename);
348           else
349             fprintf(stderr, "       (use %s -vh to get a list of modules and valid flags)\n", cdename);
350         }
351         exit (excode);
352 }
353