| /* |
| * Get or set RPC debug flags. |
| * |
| * I would have loved to write this without recourse to the sysctl |
| * interface, but the only plausible approach (reading and writing |
| * /dev/kmem at the offsets indicated by the _debug symbols from |
| * /proc/ksyms) didn't work, because /dev/kmem doesn't translate virtual |
| * addresses on write. Unfortunately, modules are stuffed into memory |
| * allocated via vmalloc. |
| * |
| * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> |
| * (C) 2004 <frederic.jolly@bull.ext.net> |
| * |
| * 06/15/2004: updated for NFSv4 |
| * |
| */ |
| |
| /* #include "config.h" */ |
| |
| #include <sys/types.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <malloc.h> |
| #include <fcntl.h> |
| #include <ctype.h> |
| /* RPC debug flags |
| #include <sunrpc/debug.h> */ |
| /* NFS debug flags |
| #include <nfs_fs.h> */ |
| /* NFSD and NLM debug flags |
| #include <nfsd/debug.h> */ |
| #include <nfs/debug.h> |
| |
| static int verbose = 0; |
| static char* cdename; |
| |
| static unsigned int find_flag(char **module, char *name); |
| static unsigned int get_flags(char *); |
| static unsigned int set_flags(char *, unsigned int value); |
| static void print_flags(FILE *, char *, unsigned int, int); |
| static char * strtolower(char *str); |
| static void usage(int excode, char *module); |
| |
| int |
| main(int argc, char **argv) |
| { |
| int opt_s = 0, |
| opt_c = 0; |
| unsigned int flags = 0, oflags; |
| char * module = NULL; |
| int c; |
| |
| cdename = malloc(strlen(basename(argv[0]))); |
| if (cdename == NULL) { |
| fprintf(stderr, "failed in malloc\n"); |
| exit(1); |
| } |
| strcpy(cdename, basename(argv[0])); |
| |
| if (!strcmp(cdename, "nfsdebug")) { |
| module = "nfs"; |
| } |
| else if (!strcmp(cdename, "nfsddebug")) { |
| module = "nfsd"; |
| } |
| |
| while ((c = getopt(argc, argv, "chm:sv")) != EOF) { |
| switch (c) { |
| case 'c': |
| opt_c = 1; |
| break; |
| case 'h': |
| usage(0, module); |
| case 'm': |
| module = optarg; |
| break; |
| case 's': |
| opt_s = 1; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| default: |
| fprintf(stderr, "%s: unknown option -%c\n", cdename, optopt); |
| usage(1, module); |
| } |
| } |
| |
| if (opt_c + opt_s > 1) { |
| fprintf(stderr, "You can use at most one of -c and -s\n"); |
| usage(1, module); |
| } |
| |
| if (!module) { |
| fprintf(stderr, "%s: no module name specified.\n", cdename); |
| usage(1, module); |
| } |
| |
| if (strcmp(module, "nfsd") && |
| strcmp(module, "nfs") && |
| strcmp(module, "nlm") && |
| strcmp(module, "rpc")) { |
| fprintf(stderr, "%s: unknown module: %s\n", cdename, module); |
| usage(1, module); |
| } |
| |
| if (argc == optind) { |
| flags = ~(unsigned int) 0; |
| } else { |
| for (; optind < argc; optind++) |
| flags |= find_flag(&module, argv[optind]); |
| if (flags && !opt_c) |
| opt_s = 1; |
| } |
| |
| oflags = get_flags(module); |
| |
| if (opt_c) { |
| oflags = set_flags(module, oflags & ~flags); |
| } else if (opt_s) { |
| oflags = set_flags(module, oflags | flags); |
| } |
| print_flags(stdout, module, oflags, 0); |
| if (verbose) { |
| fprintf(stdout, "\nModule Valid flags\n"); |
| print_flags(stdout, module, ~(unsigned int) 0, 1); |
| } |
| |
| return 0; |
| } |
| |
| #define FLAG(mname, fname) \ |
| { #mname, #fname, mname##DBG_##fname } |
| |
| static struct flagmap { |
| char * module; |
| char * name; |
| unsigned int value; |
| } flagmap[] = { |
| /* rpc */ |
| FLAG(RPC, XPRT), |
| FLAG(RPC, CALL), |
| FLAG(RPC, DEBUG), |
| FLAG(RPC, NFS), |
| FLAG(RPC, AUTH), |
| FLAG(RPC, BIND), |
| FLAG(RPC, SCHED), |
| FLAG(RPC, TRANS), |
| FLAG(RPC, SVCSOCK), |
| FLAG(RPC, SVCDSP), |
| FLAG(RPC, MISC), |
| FLAG(RPC, CACHE), |
| FLAG(RPC, ALL), |
| |
| /* nfs */ |
| FLAG(NFS, VFS), |
| FLAG(NFS, DIRCACHE), |
| FLAG(NFS, LOOKUPCACHE), |
| FLAG(NFS, PAGECACHE), |
| FLAG(NFS, PROC), |
| FLAG(NFS, XDR), |
| FLAG(NFS, FILE), |
| FLAG(NFS, ROOT), |
| FLAG(NFS, CALLBACK), |
| FLAG(NFS, CLIENT), |
| FLAG(NFS, MOUNT), |
| FLAG(NFS, ALL), |
| |
| /* nfsd */ |
| FLAG(NFSD, SOCK), |
| FLAG(NFSD, FH), |
| FLAG(NFSD, EXPORT), |
| FLAG(NFSD, SVC), |
| FLAG(NFSD, PROC), |
| FLAG(NFSD, FILEOP), |
| FLAG(NFSD, AUTH), |
| FLAG(NFSD, REPCACHE), |
| FLAG(NFSD, XDR), |
| FLAG(NFSD, LOCKD), |
| FLAG(NFSD, ALL), |
| |
| /* lockd */ |
| FLAG(NLM, SVC), |
| FLAG(NLM, CLIENT), |
| FLAG(NLM, CLNTLOCK), |
| FLAG(NLM, SVCLOCK), |
| FLAG(NLM, MONITOR), |
| FLAG(NLM, CLNTSUBS), |
| FLAG(NLM, SVCSUBS), |
| FLAG(NLM, HOSTCACHE), |
| FLAG(NLM, XDR), |
| FLAG(NLM, ALL), |
| |
| { NULL, NULL, 0 } |
| }; |
| |
| static unsigned int |
| find_flag(char **module, char *name) |
| { |
| char *mod = *module; |
| unsigned int value = 0; |
| int i; |
| |
| for (i = 0; flagmap[i].module; i++) { |
| if ((mod && strcasecmp(mod, flagmap[i].module)) |
| || strcasecmp(name, flagmap[i].name)) |
| continue; |
| if (value) { |
| fprintf(stderr, |
| "%s: ambiguous symbol name %s.\n" |
| "This name is used by more than one module, " |
| "please specify the module name using\n" |
| "the -m option.\n", |
| cdename, name); |
| exit(1); |
| } |
| value = flagmap[i].value; |
| if (*module) |
| return value; |
| mod = flagmap[i].module; |
| } |
| |
| if (!value) { |
| if (*module) |
| fprintf(stderr, |
| "%s: unknown module or flag %s/%s\n", |
| cdename, *module, name); |
| else |
| fprintf(stderr, |
| "%s: unknown flag %s\n", |
| cdename, name); |
| exit(1); |
| } |
| |
| *module = mod; |
| return value; |
| } |
| |
| static unsigned int |
| get_flags(char *module) |
| { |
| char buffer[256], filename[256]; |
| int sysfd, len; |
| |
| snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module); |
| |
| if ((sysfd = open(filename, O_RDONLY)) < 0) { |
| perror(filename); |
| exit(1); |
| } |
| if ((len = read(sysfd, buffer, sizeof(buffer))) < 0) { |
| perror("read"); |
| exit(1); |
| } |
| close(sysfd); |
| buffer[len - 1] = '\0'; |
| |
| return strtoul(buffer, NULL, 0); |
| } |
| |
| static unsigned int |
| set_flags(char *module, unsigned int value) |
| { |
| char buffer[64], filename[256]; |
| int sysfd, len, ret; |
| |
| snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module); |
| |
| len = sprintf(buffer, "%d", value); |
| if ((sysfd = open(filename, O_WRONLY)) < 0) { |
| perror(filename); |
| exit(1); |
| } |
| if ((ret = write(sysfd, buffer, len)) < 0) { |
| perror("write"); |
| exit(1); |
| } |
| if (ret < len) { |
| fprintf(stderr, "error: short write in set_flags!\n"); |
| exit(1); |
| } |
| close(sysfd); |
| return value; |
| } |
| |
| |
| static char * |
| strtolower(char *str) |
| { |
| static char temp[64]; |
| char *sp; |
| |
| strcpy(temp, str); |
| for (sp = temp; *sp; sp++) |
| *sp = tolower(*sp); |
| return temp; |
| } |
| |
| static void |
| print_flags(FILE *ofp, char *module, unsigned int flags, int show_all) |
| { |
| char *lastmod = NULL; |
| unsigned int shown = 0; |
| int i; |
| |
| if (module) { |
| fprintf(ofp, "%-10s", strtolower(module)); |
| if (!flags) { |
| fprintf(ofp, "<no flags set>\n"); |
| return; |
| } |
| } |
| |
| for (i = 0, shown = 0; flagmap[i].module; i++) { |
| if (module) { |
| if (strcasecmp(flagmap[i].module, module)) |
| continue; |
| } else if (!lastmod || strcmp(lastmod, flagmap[i].module)) { |
| if (lastmod) { |
| fprintf(ofp, "\n"); |
| shown = 0; |
| } |
| fprintf(ofp, "%-10s", strtolower(flagmap[i].module)); |
| lastmod = flagmap[i].module; |
| } |
| if (!(flags & flagmap[i].value) |
| || (!show_all && (shown & flagmap[i].value)) |
| || (module && !strcasecmp(flagmap[i].name, "all"))) |
| continue; |
| fprintf(ofp, " %s", strtolower(flagmap[i].name)); |
| shown |= flagmap[i].value; |
| } |
| fprintf(ofp, "\n"); |
| } |
| |
| static void |
| usage(int excode, char *module) |
| { |
| if (module) |
| fprintf(stderr, "usage: %s [-v] [-h] [-s flags...|-c flags...]\n", cdename); |
| else |
| fprintf(stderr, "usage: %s [-v] [-h] [-m module] [-s flags...|-c flags...]\n", cdename); |
| fprintf(stderr, " set or cancel debug flags.\n"); |
| if (verbose) { |
| fprintf(stderr, "\nModule Valid flags\n"); |
| print_flags(stderr, module, ~(unsigned int) 0, 1); |
| } else { |
| if (module) |
| fprintf(stderr, " (use %s -vh to get a list of valid flags)\n", cdename); |
| else |
| fprintf(stderr, " (use %s -vh to get a list of modules and valid flags)\n", cdename); |
| } |
| exit (excode); |
| } |
| |