2 * nfsstat.c Output NFS statistics
4 * Copyright (C) 1995-2005 Olaf Kirch <okir@suse.de>
11 #define NFSSRVSTAT "/proc/net/rpc/nfsd"
12 #define NFSCLTSTAT "/proc/net/rpc/nfs"
14 #define MOUNTSFILE "/proc/mounts"
38 static unsigned int srvproc2info[SRVPROC2_SZ+2],
39 srvproc2info_old[SRVPROC2_SZ+2]; /* NFSv2 call counts ([0] == 18) */
40 static unsigned int cltproc2info[CLTPROC2_SZ+2],
41 cltproc2info_old[CLTPROC2_SZ+2]; /* NFSv2 call counts ([0] == 18) */
42 static unsigned int srvproc3info[SRVPROC3_SZ+2],
43 srvproc3info_old[SRVPROC3_SZ+2]; /* NFSv3 call counts ([0] == 22) */
44 static unsigned int cltproc3info[CLTPROC3_SZ+2],
45 cltproc3info_old[CLTPROC3_SZ+2]; /* NFSv3 call counts ([0] == 22) */
46 static unsigned int srvproc4info[SRVPROC4_SZ+2],
47 srvproc4info_old[SRVPROC4_SZ+2]; /* NFSv4 call counts ([0] == 2) */
48 static unsigned int cltproc4info[CLTPROC4_SZ+2],
49 cltproc4info_old[CLTPROC4_SZ+2]; /* NFSv4 call counts ([0] == 49) */
50 static unsigned int srvproc4opsinfo[SRVPROC4OPS_SZ+2],
51 srvproc4opsinfo_old[SRVPROC4OPS_SZ+2]; /* NFSv4 call counts ([0] == 59) */
52 static unsigned int srvnetinfo[5], srvnetinfo_old[5]; /* 0 # of received packets
57 static unsigned int cltnetinfo[5], cltnetinfo_old[5]; /* 0 # of received packets
63 static unsigned int srvrpcinfo[6], srvrpcinfo_old[6]; /* 0 total # of RPC calls
64 * 1 total # of bad calls
66 * 3 authentication failed
69 static unsigned int cltrpcinfo[4], cltrpcinfo_old[4]; /* 0 total # of RPC calls
70 * 1 retransmitted calls
74 static unsigned int srvrcinfo[9], srvrcinfo_old[9]; /* 0 repcache hits
77 * (for pre-2.4 kernels:)
80 * 5 noncached non-directories
81 * 6 noncached directories
85 static unsigned int srvfhinfo[7], srvfhinfo_old[7]; /* (for kernels >= 2.4.0)
89 * 3 noncached directories
90 * 4 noncached non-directories
91 * leave hole to relocate stale for order
95 static const char * nfsv2name[SRVPROC2_SZ] = {
96 "null", "getattr", "setattr", "root", "lookup", "readlink",
97 "read", "wrcache", "write", "create", "remove", "rename",
98 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
101 static const char * nfsv3name[SRVPROC3_SZ] = {
102 "null", "getattr", "setattr", "lookup", "access", "readlink",
103 "read", "write", "create", "mkdir", "symlink", "mknod",
104 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
105 "fsstat", "fsinfo", "pathconf", "commit"
108 static const char * nfssrvproc4name[SRVPROC4_SZ] = {
113 static const char * nfscltproc4name[CLTPROC4_SZ] = {
114 "null", "read", "write", "commit", "open", "open_conf",
115 "open_noat", "open_dgrd", "close", "setattr", "fsinfo", "renew",
116 "setclntid", "confirm", "lock",
117 "lockt", "locku", "access", "getattr", "lookup", "lookup_root",
118 "remove", "rename", "link", "symlink", "create", "pathconf",
119 "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl",
120 "setacl", "fs_locations",
121 "rel_lkowner", "secinfo",
122 /* nfsv4.1 client ops */
136 static const char * nfssrvproc4opname[SRVPROC4OPS_SZ] = {
137 "op0-unused", "op1-unused", "op2-future", "access", "close", "commit",
138 "create", "delegpurge", "delegreturn", "getattr", "getfh", "link",
139 "lock", "lockt", "locku", "lookup", "lookup_root", "nverify",
140 "open", "openattr", "open_conf", "open_dgrd", "putfh", "putpubfh",
141 "putrootfh", "read", "readdir", "readlink", "remove", "rename",
142 "renew", "restorefh", "savefh", "secinfo", "setattr", "setcltid",
143 "setcltidconf", "verify", "write", "rellockowner",
144 /* nfsv4.1 server ops */
166 #define LABEL_srvnet "Server packet stats:\n"
167 #define LABEL_srvrpc "Server rpc stats:\n"
168 #define LABEL_srvrc "Server reply cache:\n"
169 #define LABEL_srvfh "Server file handle cache:\n"
170 #define LABEL_srvproc2 "Server nfs v2:\n"
171 #define LABEL_srvproc3 "Server nfs v3:\n"
172 #define LABEL_srvproc4 "Server nfs v4:\n"
173 #define LABEL_srvproc4ops "Server nfs v4 operations:\n"
174 #define LABEL_cltnet "Client packet stats:\n"
175 #define LABEL_cltrpc "Client rpc stats:\n"
176 #define LABEL_cltproc2 "Client nfs v2:\n"
177 #define LABEL_cltproc3 "Client nfs v3:\n"
178 #define LABEL_cltproc4 "Client nfs v4:\n"
180 typedef struct statinfo {
184 unsigned int * valptr;
188 * We now build the arrays of statinfos using macros, which will make it easier
189 * to add new variables for --sleep. e.g., SRV(net) expands into the struct
190 * statinfo: { "net", "Server packet stats:\n", 5, srvnetinfo }
192 #define ARRAYSIZE(x) sizeof(x)/sizeof(*x)
193 #define STATINFO(k, t, s...) { #t, LABEL_##k##t, ARRAYSIZE(k##t##info##s), k##t##info##s }
194 #define SRV(t, s...) STATINFO(srv, t, s)
195 #define CLT(t, s...) STATINFO(clt, t, s)
196 #define DECLARE_SRV(n, s...) static statinfo n##s[] = { \
205 { NULL, NULL, 0, NULL }\
207 #define DECLARE_CLT(n, s...) static statinfo n##s[] = { \
213 { NULL, NULL, 0, NULL }\
215 DECLARE_SRV(srvinfo);
216 DECLARE_SRV(srvinfo, _old);
217 DECLARE_CLT(cltinfo);
218 DECLARE_CLT(cltinfo, _old);
220 static void print_all_stats(int, int, int);
221 static void print_server_stats(int);
222 static void print_client_stats(int);
223 static void print_stats_list(int, int, int);
224 static void print_numbers(const char *, unsigned int *,
226 static void print_callstats(const char *, const char **,
227 unsigned int *, unsigned int);
228 static void print_callstats_list(const char *, const char **,
229 unsigned int *, unsigned int);
230 static int parse_raw_statfile(const char *, struct statinfo *);
231 static int parse_pretty_statfile(const char *, struct statinfo *);
233 static statinfo *get_stat_info(const char *, struct statinfo *);
235 static int mounts(const char *);
237 static void get_stats(const char *, struct statinfo *, int *, int,
239 static int has_stats(const unsigned int *, int);
240 static int has_rpcstats(const unsigned int *, int);
241 static void diff_stats(struct statinfo *, struct statinfo *, int);
242 static void unpause(int);
243 static void update_old_counters(struct statinfo *, struct statinfo *);
245 static time_t starttime;
247 #define PRNT_CALLS 0x0001
248 #define PRNT_RPC 0x0002
249 #define PRNT_NET 0x0004
250 #define PRNT_FH 0x0008
251 #define PRNT_RC 0x0010
252 #define PRNT_AUTO 0x1000
253 #define PRNT_V2 0x2000
254 #define PRNT_V3 0x4000
255 #define PRNT_V4 0x8000
256 #define PRNT_ALL 0x0fff
264 void usage(char *name)
266 printf("Usage: %s [OPTION]...\n\
268 -m, --mounts Show statistics on mounted NFS filesystems\n\
269 -c, --client Show NFS client statistics\n\
270 -s, --server Show NFS server statistics\n\
271 -2 Show NFS version 2 statistics\n\
272 -3 Show NFS version 3 statistics\n\
273 -4 Show NFS version 4 statistics\n\
274 -o [facility] Show statistics on particular facilities.\n\
275 nfs NFS protocol information\n\
276 rpc General RPC information\n\
277 net Network layer statistics\n\
278 fh Usage information on the server's file handle cache\n\
279 rc Usage information on the server's request reply cache\n\
280 all Select all of the above\n\
281 -v, --verbose, --all Same as '-o all'\n\
282 -r, --rpc Show RPC statistics\n\
283 -n, --nfs Show NFS statistics\n\
284 -Z[#], --sleep[=#] Collects stats until interrupted.\n\
285 Cumulative stats are then printed\n\
286 If # is provided, stats will be output every\n\
288 -S, --since file Shows difference between current stats and those in 'file'\n\
289 -l, --list Prints stats in list format\n\
290 --version Show program version\n\
291 --help What you just did\n\
296 static struct option longopts[] =
298 { "acl", 0, 0, 'a' },
299 { "all", 0, 0, 'v' },
300 { "auto", 0, 0, '\3' },
301 { "client", 0, 0, 'c' },
302 { "mounted", 0, 0, 'm' },
303 { "nfs", 0, 0, 'n' },
304 { "rpc", 0, 0, 'r' },
305 { "server", 0, 0, 's' },
306 { "verbose", 0, 0, 'v' },
307 { "zero", 0, 0, 'z' },
308 { "help", 0, 0, '\1' },
309 { "version", 0, 0, '\2' },
310 { "sleep", 2, 0, 'Z' },
311 { "since", 1, 0, 'S' },
312 { "list", 0, 0, 'l' },
318 main(int argc, char **argv)
329 *serverfile = NFSSRVSTAT,
330 *clientfile = NFSCLTSTAT;
332 struct statinfo *serverinfo = srvinfo,
333 *serverinfo_tmp = srvinfo_old,
334 *clientinfo = cltinfo,
335 *clientinfo_tmp = cltinfo_old;
337 struct sigaction act = {
338 .sa_handler = unpause,
339 .sa_flags = SA_ONESHOT,
342 if ((progname = strrchr(argv[0], '/')))
347 while ((c = getopt_long(argc, argv, "234acmno:Z::S:vrslz\1\2", longopts, NULL)) != EOF) {
350 fprintf(stderr, "nfsstat: nfs acls are not yet supported.\n");
356 opt_prt |= PRNT_CALLS;
359 if (!strcmp(optarg, "nfs"))
360 opt_prt |= PRNT_CALLS;
361 else if (!strcmp(optarg, "rpc"))
363 else if (!strcmp(optarg, "net"))
365 else if (!strcmp(optarg, "rc"))
367 else if (!strcmp(optarg, "fh"))
369 else if (!strcmp(optarg, "all"))
370 opt_prt |= PRNT_CALLS | PRNT_RPC | PRNT_NET | PRNT_RC | PRNT_FH;
372 fprintf(stderr, "nfsstat: unknown category: "
380 sleep_time = atoi(optarg);
391 opt_prt |= versions[c - '2'];
397 opt_prt |= PRNT_AUTO;
409 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
410 "not yet supported\n");
413 return mounts(MOUNTSFILE);
418 fprintf(stdout, "nfsstat: " VERSION "\n");
421 printf("Try `%s --help' for more information.\n", progname);
427 opt_srv = opt_clt = 1;
430 if (!(opt_srv + opt_clt))
431 opt_srv = opt_clt = 1;
432 if (!(opt_prt & 0xfff)) {
433 opt_prt |= PRNT_CALLS + PRNT_RPC;
435 if (!(opt_prt & 0xe000)) {
436 opt_prt |= PRNT_AUTO;
438 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
440 "You requested file handle or request cache "
441 "statistics while using the -c option.\n"
442 "This information is available only for the NFS "
446 if (opt_since || opt_sleep) {
447 serverinfo = srvinfo_old;
448 serverinfo_tmp = srvinfo;
449 clientinfo = cltinfo_old;
450 clientinfo_tmp = cltinfo;
454 get_stats(serverfile, serverinfo, &opt_srv, opt_clt, 1);
456 get_stats(clientfile, clientinfo, &opt_clt, opt_srv, 0);
458 if (opt_sleep && !sleep_time) {
459 starttime = time(NULL);
460 printf("Collecting statistics; press CTRL-C to view results from interval (i.e., from pause to CTRL-C).\n");
461 if (sigaction(SIGINT, &act, NULL) != 0) {
462 fprintf(stderr, "Error: couldn't register for signal and pause.\n");
468 if (opt_since || (opt_sleep && !sleep_time)) {
470 get_stats(NFSSRVSTAT, serverinfo_tmp, &opt_srv, opt_clt, 1);
471 diff_stats(serverinfo_tmp, serverinfo, 1);
474 get_stats(NFSCLTSTAT, clientinfo_tmp, &opt_clt, opt_srv, 0);
475 diff_stats(clientinfo_tmp, clientinfo, 0);
481 get_stats(NFSSRVSTAT, serverinfo_tmp , &opt_srv, opt_clt, 1);
482 diff_stats(serverinfo_tmp, serverinfo, 1);
485 get_stats(NFSCLTSTAT, clientinfo_tmp, &opt_clt, opt_srv, 0);
486 diff_stats(clientinfo_tmp, clientinfo, 0);
489 print_stats_list(opt_srv, opt_clt, opt_prt);
491 print_all_stats(opt_srv, opt_clt, opt_prt);
496 update_old_counters(serverinfo_tmp, serverinfo);
498 update_old_counters(clientinfo_tmp, clientinfo);
504 print_stats_list(opt_srv, opt_clt, opt_prt);
506 print_all_stats(opt_srv, opt_clt, opt_prt);
514 print_all_stats (int opt_srv, int opt_clt, int opt_prt)
517 print_server_stats(opt_prt);
520 print_client_stats(opt_prt);
524 print_server_stats(int opt_prt)
526 if (opt_prt & PRNT_NET) {
527 if (opt_sleep && !has_rpcstats(srvnetinfo, 4)) {
529 print_numbers( LABEL_srvnet
530 "packets udp tcp tcpconn\n",
535 if (opt_prt & PRNT_RPC) {
536 if (opt_sleep && !has_rpcstats(srvrpcinfo, 5)) {
539 print_numbers(LABEL_srvrpc
540 "calls badcalls badclnt badauth xdrcall\n",
545 if (opt_prt & PRNT_RC) {
546 if (opt_sleep && !has_rpcstats(srvrcinfo, 3)) {
549 print_numbers(LABEL_srvrc
550 "hits misses nocache\n",
557 * 2.2 puts all fh-related info after the 'rc' header
558 * 2.4 puts all fh-related info after the 'fh' header, but relocates
559 * 'stale' to the start and swaps dir and nondir :-(
560 * We preseve the 2.2 order
562 if (opt_prt & PRNT_FH) {
563 if (get_stat_info("fh", srvinfo)) { /* >= 2.4 */
564 int t = srvfhinfo[3];
565 srvfhinfo[3]=srvfhinfo[4];
568 srvfhinfo[5]=srvfhinfo[0]; /* relocate 'stale' */
572 "lookup anon ncachedir ncachedir stale\n",
577 "lookup anon ncachedir ncachedir stale\n",
581 if (opt_prt & PRNT_CALLS) {
582 int has_v2_stats = has_stats(srvproc2info, SRVPROC2_SZ+2);
583 int has_v3_stats = has_stats(srvproc3info, SRVPROC3_SZ+2);
584 int has_v4_stats = has_stats(srvproc4info, SRVPROC4_SZ+2);
586 if ((opt_prt & PRNT_V2) ||
587 ((opt_prt & PRNT_AUTO) && has_v2_stats)) {
588 if (!opt_sleep || has_v2_stats) {
589 print_callstats(LABEL_srvproc2,
590 nfsv2name, srvproc2info + 1,
591 sizeof(nfsv2name)/sizeof(char *));
594 if ((opt_prt & PRNT_V3) ||
595 ((opt_prt & PRNT_AUTO) && has_v3_stats)) {
596 if (!opt_sleep || has_v3_stats) {
597 print_callstats(LABEL_srvproc3,
598 nfsv3name, srvproc3info + 1,
599 sizeof(nfsv3name)/sizeof(char *));
602 if ((opt_prt & PRNT_V4) ||
603 ((opt_prt & PRNT_AUTO) && has_v4_stats)) {
604 if (!opt_sleep || has_v4_stats) {
605 print_callstats( LABEL_srvproc4,
606 nfssrvproc4name, srvproc4info + 1,
607 sizeof(nfssrvproc4name)/sizeof(char *));
608 print_callstats(LABEL_srvproc4ops,
609 nfssrvproc4opname, srvproc4opsinfo + 1,
610 sizeof(nfssrvproc4opname)/sizeof(char *));
616 print_client_stats(int opt_prt)
618 if (opt_prt & PRNT_NET) {
619 if (opt_sleep && !has_rpcstats(cltnetinfo, 4)) {
622 print_numbers(LABEL_cltnet
623 "packets udp tcp tcpconn\n",
628 if (opt_prt & PRNT_RPC) {
629 if (opt_sleep && !has_rpcstats(cltrpcinfo, 3)) {
632 print_numbers(LABEL_cltrpc
633 "calls retrans authrefrsh\n",
638 if (opt_prt & PRNT_CALLS) {
639 int has_v2_stats = has_stats(cltproc2info, CLTPROC2_SZ+2);
640 int has_v3_stats = has_stats(cltproc3info, CLTPROC3_SZ+2);
641 int has_v4_stats = has_stats(cltproc4info, CLTPROC4_SZ+2);
642 if ((opt_prt & PRNT_V2) ||
643 ((opt_prt & PRNT_AUTO) && has_v2_stats)) {
644 if (!opt_sleep || has_v2_stats) {
645 print_callstats(LABEL_cltproc2,
646 nfsv2name, cltproc2info + 1,
647 sizeof(nfsv2name)/sizeof(char *));
650 if ((opt_prt & PRNT_V3) ||
651 ((opt_prt & PRNT_AUTO) && has_v3_stats)) {
652 if (!opt_sleep || has_v3_stats) {
653 print_callstats(LABEL_cltproc3,
654 nfsv3name, cltproc3info + 1,
655 sizeof(nfsv3name)/sizeof(char *));
658 if ((opt_prt & PRNT_V4) ||
659 ((opt_prt & PRNT_AUTO) && has_v4_stats)) {
660 if (!opt_sleep || has_v4_stats) {
661 print_callstats(LABEL_cltproc4,
662 nfscltproc4name, cltproc4info + 1,
663 sizeof(nfscltproc4name)/sizeof(char *));
670 print_clnt_list(int opt_prt)
672 if (opt_prt & PRNT_CALLS) {
673 int has_v2_stats = has_stats(cltproc2info, CLTPROC2_SZ+2);
674 int has_v3_stats = has_stats(cltproc3info, CLTPROC3_SZ+2);
675 int has_v4_stats = has_stats(cltproc4info, CLTPROC4_SZ+2);
676 if ((opt_prt & PRNT_V2) ||
677 ((opt_prt & PRNT_AUTO) && has_v2_stats)) {
678 if (!opt_sleep || has_v2_stats) {
679 print_callstats_list("nfs v2 client",
680 nfsv2name, cltproc2info + 1,
681 sizeof(nfsv2name)/sizeof(char *));
684 if ((opt_prt & PRNT_V3) ||
685 ((opt_prt & PRNT_AUTO) && has_v3_stats)) {
686 if (!opt_sleep || has_v3_stats) {
687 print_callstats_list("nfs v3 client",
688 nfsv3name, cltproc3info + 1,
689 sizeof(nfsv3name)/sizeof(char *));
692 if ((opt_prt & PRNT_V4) ||
693 ((opt_prt & PRNT_AUTO) && has_v4_stats)) {
694 if (!opt_sleep || has_v4_stats) {
695 print_callstats_list("nfs v4 client",
696 nfscltproc4name, cltproc4info + 1,
697 sizeof(nfscltproc4name)/sizeof(char *));
703 print_serv_list(int opt_prt)
705 if (opt_prt & PRNT_CALLS) {
706 int has_v2_stats = has_stats(srvproc2info, SRVPROC2_SZ+2);
707 int has_v3_stats = has_stats(srvproc3info, SRVPROC3_SZ+2);
708 int has_v4_stats = has_stats(srvproc4info, SRVPROC4_SZ+2);
709 if ((opt_prt & PRNT_V2) ||
710 ((opt_prt & PRNT_AUTO) && has_v2_stats)) {
711 if (!opt_sleep || has_v2_stats) {
712 print_callstats_list("nfs v2 server",
713 nfsv2name, srvproc2info + 1,
714 sizeof(nfsv2name)/sizeof(char *));
717 if ((opt_prt & PRNT_V3) ||
718 ((opt_prt & PRNT_AUTO) && has_v3_stats)) {
719 if (!opt_sleep || has_v3_stats) {
720 print_callstats_list("nfs v3 server",
721 nfsv3name, srvproc3info + 1,
722 sizeof(nfsv3name)/sizeof(char *));
725 if ((opt_prt & PRNT_V4) ||
726 ((opt_prt & PRNT_AUTO) && has_v4_stats)) {
727 if (!opt_sleep || has_v4_stats) {
728 print_callstats_list("nfs v4 server",
729 nfssrvproc4name, srvproc4info + 1,
730 sizeof(nfssrvproc4name)/sizeof(char *));
731 print_callstats_list("nfs v4 servop",
732 nfssrvproc4opname, srvproc4opsinfo + 1,
733 sizeof(nfssrvproc4opname)/sizeof(char *));
739 print_stats_list(int opt_srv, int opt_clt, int opt_prt)
742 print_serv_list(opt_prt);
745 print_clnt_list(opt_prt);
749 get_stat_info(const char *sp, struct statinfo *statp)
753 for (ip = statp; ip->tag; ip++) {
754 if (!strcmp(sp, ip->tag))
762 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
767 for (i = 0; i < nr; i++)
768 printf("%s%-8u", i? " " : "", info[i]);
773 print_callstats(const char *hdr, const char **names,
774 unsigned int *info, unsigned int nr)
776 unsigned long long total;
777 unsigned long long pct;
781 for (i = 0, total = 0; i < nr; i++)
785 for (i = 0; i < nr; i += 6) {
786 for (j = 0; j < 6 && i + j < nr; j++)
787 printf("%-13s", names[i+j]);
789 for (j = 0; j < 6 && i + j < nr; j++) {
790 pct = ((unsigned long long) info[i+j]*100)/total;
791 printf("%-8u%3llu%% ", info[i+j], pct);
799 print_callstats_list(const char *hdr, const char **names,
800 unsigned int *callinfo, unsigned int nr)
802 unsigned long long calltotal;
805 for (i = 0, calltotal = 0; i < nr; i++) {
806 calltotal += callinfo[i];
810 printf("%13s %13s %8llu \n", hdr, "total:", calltotal);
811 printf("------------- ------------- --------\n");
812 for (i = 0; i < nr; i++) {
814 printf("%13s %12s: %8u \n", hdr, names[i], callinfo[i]);
821 /* returns 0 on success, 1 otherwise */
823 parse_raw_statfile(const char *name, struct statinfo *statp)
825 char buffer[4096], *next;
828 /* Being unable to read e.g. the nfsd stats file shouldn't
829 * be a fatal error -- it usually means the module isn't loaded.
831 if ((fp = fopen(name, "r")) == NULL) {
832 // fprintf(stderr, "Warning: %s: %m\n", name);
836 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
838 char *sp, *line = buffer;
840 unsigned int total = 0;
842 if ((next = strchr(line, '\n')) != NULL)
844 if (!(sp = strtok(line, " \t")))
847 ip = get_stat_info(sp, statp);
853 for (i = 0; i < cnt; i++) {
854 if (!(sp = strtok(NULL, " \t")))
856 ip->valptr[i] = (unsigned int) strtoul(sp, NULL, 0);
857 total += ip->valptr[i];
859 ip->valptr[cnt - 1] = total;
866 /* returns 0 on success, 1 otherwise */
868 parse_pretty_statfile(const char *filename, struct statinfo *info)
870 int numvals, curindex, numconsumed, n, err = 1;
872 char buf[4096], *bufp, *fmt, is_proc;
876 if ((fp = fopen(filename, "r")) == NULL)
877 //err(2, "Unable to open statfile '%s'.\n", filename);
880 while (fgets(buf, sizeof(buf), fp) != NULL) {
881 for (ip = info; ip->tag; ip++) {
882 if (strcmp(buf, ip->label))
886 numvals = ip->nrvals - 1;
887 is_proc = strncmp("proc", ip->tag, 4) ? 0 : 1;
889 fmt = " %u %*u%% %n";
897 /* get (and skip) header */
898 if (fgets(buf, sizeof(buf), fp) == NULL) {
899 fprintf(stderr, "Failed to locate header after "
900 "label for '%s' in %s.\n",
904 /* no header -- done with this "tag" */
906 ip->valptr[numvals] = sum;
910 if (fgets(buf, sizeof(buf), fp) == NULL) {
911 fprintf(stderr, "Failed to locate stats after "
912 "header for '%s' in %s.\n",
917 for (; curindex < numvals; curindex++) {
918 n = sscanf(bufp, fmt, &ip->valptr[curindex],
926 sum += ip->valptr[curindex];
940 mounts(const char *name)
942 char buffer[4096], *next;
945 /* Being unable to read e.g. the nfsd stats file shouldn't
946 * be a fatal error -- it usually means the module isn't loaded.
948 if ((fp = fopen(name, "r")) == NULL) {
949 fprintf(stderr, "Warning: %s: %m\n", name);
953 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
955 char *device, *mount, *type, *flags;
957 if ((next = strchr(line, '\n')) != NULL)
960 if (!(device = strtok(line, " \t")))
963 if (!(mount = strtok(NULL, " \t")))
966 if (!(type = strtok(NULL, " \t")))
969 if (strcmp(type, "nfs") && strcmp(type,"nfs4")) {
973 if (!(flags = strtok(NULL, " \t")))
976 printf("%s from %s\n", mount, device);
977 printf(" Flags:\t%s\n", flags);
988 get_stats(const char *file, struct statinfo *info, int *opt, int other_opt,
994 char *label = is_srv ? "Server" : "Client";
996 /* try to guess what type of stat file we're dealing with */
997 if ((fp = fopen(file, "r")) == NULL)
999 if (fgets(buf, 10, fp) == NULL)
1001 if (!strncmp(buf, "net ", 4)) {
1002 /* looks like raw client stats */
1004 fprintf(stderr, "Warning: no server info present in "
1005 "raw client stats file.\n");
1008 err = parse_raw_statfile(file, info);
1009 } else if (!strncmp(buf, "rc ", 3)) {
1010 /* looks like raw server stats */
1012 fprintf(stderr, "Warning: no client info present in "
1013 "raw server stats file.\n");
1016 err = parse_raw_statfile(file, info);
1018 /* looks like pretty client and server stats */
1019 err = parse_pretty_statfile(file, info);
1025 fprintf(stderr, "Error: No %s Stats (%s: %m). \n",
1034 * This is for proc2/3/4-type stats, where, in the /proc files, the first entry's value
1035 * denotes the number of subsequent entries. statinfo value arrays contain an additional
1036 * field at the end which contains the sum of all previous elements in the array -- so,
1037 * there are stats if the sum's greater than the entry-count.
1040 has_stats(const unsigned int *info, int nr)
1042 return (info[0] && info[nr-1] > info[0]);
1045 has_rpcstats(const unsigned int *info, int size)
1049 for (i=0, cnt=0; i < size; i++)
1055 * take the difference of each individual stat value in 'new' and 'old'
1056 * and store the results back into 'new'
1059 diff_stats(struct statinfo *new, struct statinfo *old, int is_srv)
1061 int i, j, nodiff_first_index, should_diff;
1064 * Different stat types have different formats in the /proc
1065 * files: for the proc2/3/4-type stats, the first entry has
1066 * the total number of subsequent entries; one does not want
1067 * to diff that first entry. The other stat types aren't like
1068 * this. So, we diff a given entry if it's not of one of the
1069 * procX types ("i" < 2 for clt, < 4 for srv), or if it's not
1070 * the first entry ("j" > 0).
1072 nodiff_first_index = 2 + (2 * is_srv);
1074 for (i = 0; old[i].tag; i++) {
1075 for (j = 0; j < new[i].nrvals; j++) {
1076 should_diff = (i < nodiff_first_index || j > 0);
1078 new[i].valptr[j] -= old[i].valptr[j];
1082 * Make sure that the "totals" entry (last value in
1083 * each stat array) for the procX-type stats has the
1084 * "numentries" entry's (first value in procX-type
1085 * stat arrays) constant value added-back after the
1086 * diff -- i.e., it should always be included in the
1089 if (!strncmp("proc", new[i].tag, 4) && old[i].valptr[0])
1090 new[i].valptr[new[i].nrvals - 1] += new[i].valptr[0];
1098 int minutes, seconds;
1101 endtime = time(NULL);
1102 time_diff = difftime(endtime, starttime);
1103 minutes = time_diff / 60;
1104 seconds = (int)time_diff % 60;
1105 printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds);
1109 update_old_counters(struct statinfo *new, struct statinfo *old)
1112 for (z = 0; old[z].tag; z++)
1113 for (i = 0; i <= old[z].nrvals; i++)
1114 old[z].valptr[i] += new[z].valptr[i];