summaryrefslogtreecommitdiffstats
path: root/tools/rpcdebug/rpcdebug.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/rpcdebug/rpcdebug.c')
-rw-r--r--tools/rpcdebug/rpcdebug.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c
new file mode 100644
index 0000000..ec05179
--- /dev/null
+++ b/tools/rpcdebug/rpcdebug.c
@@ -0,0 +1,364 @@
+/*
+ * 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>
+#include <libgen.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); /* usage does not return */
+ break;
+ 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, FSCACHE),
+ FLAG(NFS, PNFS),
+ FLAG(NFS, PNFS_LD),
+ FLAG(NFS, STATE),
+ 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);
+}
+