1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /* LINTLIBRARY */
23 /* PROTOLIB1 */
24
25 /*
26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
29 */
30
31 /*
32 * nfsstat: Network File System statistics
33 *
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <kvm.h>
44 #include <kstat.h>
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/t_lock.h>
48 #include <sys/tiuser.h>
49 #include <sys/statvfs.h>
50 #include <sys/mntent.h>
51 #include <sys/mnttab.h>
52 #include <sys/sysmacros.h>
53 #include <sys/mkdev.h>
54 #include <rpc/types.h>
55 #include <rpc/xdr.h>
56 #include <rpc/auth.h>
57 #include <rpc/clnt.h>
58 #include <nfs/nfs.h>
59 #include <nfs/nfs_clnt.h>
60 #include <nfs/nfs_sec.h>
61 #include <inttypes.h>
62 #include <signal.h>
63 #include <time.h>
64 #include <sys/time.h>
65 #include <strings.h>
66 #include <ctype.h>
67 #include <locale.h>
68
69 #include "statcommon.h"
70
71 static kstat_ctl_t *kc = NULL; /* libkstat cookie */
72 static kstat_t *rpc_clts_client_kstat, *rpc_clts_server_kstat;
73 static kstat_t *rpc_cots_client_kstat, *rpc_cots_server_kstat;
74 static kstat_t *rpc_rdma_client_kstat, *rpc_rdma_server_kstat;
75 static kstat_t *nfs_client_kstat, *nfs_server_v2_kstat, *nfs_server_v3_kstat;
76 static kstat_t *nfs4_client_kstat, *nfs_server_v4_kstat;
77 static kstat_t *rfsproccnt_v2_kstat, *rfsproccnt_v3_kstat, *rfsproccnt_v4_kstat;
78 static kstat_t *rfsreqcnt_v2_kstat, *rfsreqcnt_v3_kstat, *rfsreqcnt_v4_kstat;
79 static kstat_t *aclproccnt_v2_kstat, *aclproccnt_v3_kstat;
80 static kstat_t *aclreqcnt_v2_kstat, *aclreqcnt_v3_kstat;
81 static kstat_t *ksum_kstat;
82
83 static void handle_sig(int);
84 static int getstats_rpc(void);
85 static int getstats_nfs(void);
86 static int getstats_rfsproc(int);
87 static int getstats_rfsreq(int);
88 static int getstats_aclproc(void);
89 static int getstats_aclreq(void);
90 static void putstats(void);
91 static void setup(void);
92 static void cr_print(int);
93 static void sr_print(int);
94 static void cn_print(int, int);
95 static void sn_print(int, int);
96 static void ca_print(int, int);
97 static void sa_print(int, int);
98 static void req_print(kstat_t *, kstat_t *, int, int, int);
99 static void req_print_v4(kstat_t *, kstat_t *, int, int);
100 static void stat_print(const char *, kstat_t *, kstat_t *, int, int);
101 static void nfsstat_kstat_sum(kstat_t *, kstat_t *, kstat_t *);
102 static void stats_timer(int);
103 static void safe_zalloc(void **, uint_t, int);
104 static int safe_strtoi(char const *, char *);
105
106
107 static void nfsstat_kstat_copy(kstat_t *, kstat_t *, int);
108 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
109 static kid_t safe_kstat_write(kstat_ctl_t *, kstat_t *, void *);
110
111 static void usage(void);
112 static void mi_print(void);
113 static int ignore(char *);
114 static int interval; /* interval between stats */
115 static int count; /* number of iterations the stat is printed */
116 #define MAX_COLUMNS 80
117 #define MAX_PATHS 50 /* max paths that can be taken by -m */
118
119 /*
120 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot
121 * include that file here. Same with MI4_REFERRAL.
122 */
123 #define MI4_MIRRORMOUNT 0x4000
124 #define MI4_REFERRAL 0x8000
125 #define NFS_V4 4
126
127 static int req_width(kstat_t *, int);
128 static int stat_width(kstat_t *, int);
129 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */
130
131 /*
132 * Struct holds the previous kstat values so
133 * we can compute deltas when using the -i flag
134 */
135 typedef struct old_kstat
136 {
137 kstat_t kst;
138 int tot;
139 } old_kstat_t;
140
141 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat;
142 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat;
143 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat;
144 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat;
145 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat;
146 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat;
147 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat;
148 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat;
149 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat;
150 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat;
151 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat;
152
153 static uint_t timestamp_fmt = NODATE;
154
155 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
156 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't */
157 #endif
158
159 int
main(int argc,char * argv[])160 main(int argc, char *argv[])
161 {
162 int c, go_forever, j;
163 int cflag = 0; /* client stats */
164 int sflag = 0; /* server stats */
165 int nflag = 0; /* nfs stats */
166 int rflag = 0; /* rpc stats */
167 int mflag = 0; /* mount table stats */
168 int aflag = 0; /* print acl statistics */
169 int vflag = 0; /* version specified, 0 specifies all */
170 int zflag = 0; /* zero stats after printing */
171 char *split_line = "*******************************************"
172 "*************************************";
173
174 interval = 0;
175 count = 0;
176 go_forever = 0;
177
178 (void) setlocale(LC_ALL, "");
179 (void) textdomain(TEXT_DOMAIN);
180
181 while ((c = getopt(argc, argv, "cnrsmzav:T:")) != EOF) {
182 switch (c) {
183 case 'c':
184 cflag++;
185 break;
186 case 'n':
187 nflag++;
188 break;
189 case 'r':
190 rflag++;
191 break;
192 case 's':
193 sflag++;
194 break;
195 case 'm':
196 mflag++;
197 break;
198 case 'z':
199 if (geteuid())
200 fail(0, "Must be root for z flag\n");
201 zflag++;
202 break;
203 case 'a':
204 aflag++;
205 break;
206 case 'v':
207 vflag = atoi(optarg);
208 if ((vflag < 2) || (vflag > 4))
209 fail(0, "Invalid version number\n");
210 break;
211 case 'T':
212 if (optarg) {
213 if (*optarg == 'u')
214 timestamp_fmt = UDATE;
215 else if (*optarg == 'd')
216 timestamp_fmt = DDATE;
217 else
218 usage();
219 } else {
220 usage();
221 }
222 break;
223 case '?':
224 default:
225 usage();
226 }
227 }
228
229 if (((argc - optind) > 0) && !mflag) {
230
231 interval = safe_strtoi(argv[optind], "invalid interval");
232 if (interval < 1)
233 fail(0, "invalid interval\n");
234 optind++;
235
236 if ((argc - optind) > 0) {
237 count = safe_strtoi(argv[optind], "invalid count");
238 if (count <= 0)
239 fail(0, "invalid count\n");
240 }
241 optind++;
242
243 if ((argc - optind) > 0)
244 usage();
245
246 /*
247 * no count number was set, so we will loop infinitely
248 * at interval specified
249 */
250 if (!count)
251 go_forever = 1;
252 stats_timer(interval);
253 } else if (mflag) {
254
255 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag)
256 fail(0,
257 "The -m flag may not be used with any other flags");
258
259 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) {
260 path[j] = argv[optind];
261 if (*path[j] != '/')
262 fail(0, "Please fully qualify your pathname "
263 "with a leading '/'");
264 optind++;
265 }
266 path[j] = NULL;
267 if (argc - optind > 0)
268 fprintf(stderr, "Only the first 50 paths "
269 "will be searched for\n");
270 }
271
272 setup();
273
274 do {
275 if (mflag) {
276 mi_print();
277 } else {
278 if (timestamp_fmt != NODATE)
279 print_timestamp(timestamp_fmt);
280
281 if (sflag &&
282 (rpc_clts_server_kstat == NULL ||
283 nfs_server_v4_kstat == NULL)) {
284 fprintf(stderr,
285 "nfsstat: kernel is not configured with "
286 "the server nfs and rpc code.\n");
287 }
288
289 /* if s and nothing else, all 3 prints are called */
290 if (sflag || (!sflag && !cflag)) {
291 if (rflag || (!rflag && !nflag && !aflag))
292 sr_print(zflag);
293 if (nflag || (!rflag && !nflag && !aflag))
294 sn_print(zflag, vflag);
295 if (aflag || (!rflag && !nflag && !aflag))
296 sa_print(zflag, vflag);
297 }
298 if (cflag &&
299 (rpc_clts_client_kstat == NULL ||
300 nfs_client_kstat == NULL)) {
301 fprintf(stderr,
302 "nfsstat: kernel is not configured with"
303 " the client nfs and rpc code.\n");
304 }
305 if (cflag || (!sflag && !cflag)) {
306 if (rflag || (!rflag && !nflag && !aflag))
307 cr_print(zflag);
308 if (nflag || (!rflag && !nflag && !aflag))
309 cn_print(zflag, vflag);
310 if (aflag || (!rflag && !nflag && !aflag))
311 ca_print(zflag, vflag);
312 }
313 }
314
315 if (zflag)
316 putstats();
317 if (interval)
318 printf("%s\n", split_line);
319
320 if (interval > 0)
321 (void) pause();
322 } while ((--count > 0) || go_forever);
323
324 kstat_close(kc);
325 free(ksum_kstat);
326 return (0);
327 }
328
329
330 static int
getstats_rpc(void)331 getstats_rpc(void)
332 {
333 int field_width = 0;
334
335 if (rpc_clts_client_kstat != NULL) {
336 safe_kstat_read(kc, rpc_clts_client_kstat, NULL);
337 field_width = stat_width(rpc_clts_client_kstat, field_width);
338 }
339
340 if (rpc_cots_client_kstat != NULL) {
341 safe_kstat_read(kc, rpc_cots_client_kstat, NULL);
342 field_width = stat_width(rpc_cots_client_kstat, field_width);
343 }
344
345 if (rpc_rdma_client_kstat != NULL) {
346 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL);
347 field_width = stat_width(rpc_rdma_client_kstat, field_width);
348 }
349
350 if (rpc_clts_server_kstat != NULL) {
351 safe_kstat_read(kc, rpc_clts_server_kstat, NULL);
352 field_width = stat_width(rpc_clts_server_kstat, field_width);
353 }
354 if (rpc_cots_server_kstat != NULL) {
355 safe_kstat_read(kc, rpc_cots_server_kstat, NULL);
356 field_width = stat_width(rpc_cots_server_kstat, field_width);
357 }
358 if (rpc_rdma_server_kstat != NULL) {
359 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL);
360 field_width = stat_width(rpc_rdma_server_kstat, field_width);
361 }
362 return (field_width);
363 }
364
365 static int
getstats_nfs(void)366 getstats_nfs(void)
367 {
368 int field_width = 0;
369
370 if (nfs_client_kstat != NULL) {
371 safe_kstat_read(kc, nfs_client_kstat, NULL);
372 field_width = stat_width(nfs_client_kstat, field_width);
373 }
374 if (nfs4_client_kstat != NULL) {
375 safe_kstat_read(kc, nfs4_client_kstat, NULL);
376 field_width = stat_width(nfs4_client_kstat, field_width);
377 }
378 if (nfs_server_v2_kstat != NULL) {
379 safe_kstat_read(kc, nfs_server_v2_kstat, NULL);
380 field_width = stat_width(nfs_server_v2_kstat, field_width);
381 }
382 if (nfs_server_v3_kstat != NULL) {
383 safe_kstat_read(kc, nfs_server_v3_kstat, NULL);
384 field_width = stat_width(nfs_server_v3_kstat, field_width);
385 }
386 if (nfs_server_v4_kstat != NULL) {
387 safe_kstat_read(kc, nfs_server_v4_kstat, NULL);
388 field_width = stat_width(nfs_server_v4_kstat, field_width);
389 }
390 return (field_width);
391 }
392
393 static int
getstats_rfsproc(int ver)394 getstats_rfsproc(int ver)
395 {
396 int field_width = 0;
397
398 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) {
399 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL);
400 field_width = req_width(rfsproccnt_v2_kstat, field_width);
401 }
402 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) {
403 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL);
404 field_width = req_width(rfsproccnt_v3_kstat, field_width);
405 }
406 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) {
407 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL);
408 field_width = req_width(rfsproccnt_v4_kstat, field_width);
409 }
410 return (field_width);
411 }
412
413 static int
getstats_rfsreq(int ver)414 getstats_rfsreq(int ver)
415 {
416 int field_width = 0;
417 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) {
418 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL);
419 field_width = req_width(rfsreqcnt_v2_kstat, field_width);
420 }
421 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) {
422 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL);
423 field_width = req_width(rfsreqcnt_v3_kstat, field_width);
424 }
425 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) {
426 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL);
427 field_width = req_width(rfsreqcnt_v4_kstat, field_width);
428 }
429 return (field_width);
430 }
431
432 static int
getstats_aclproc(void)433 getstats_aclproc(void)
434 {
435 int field_width = 0;
436 if (aclproccnt_v2_kstat != NULL) {
437 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL);
438 field_width = req_width(aclproccnt_v2_kstat, field_width);
439 }
440 if (aclproccnt_v3_kstat != NULL) {
441 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL);
442 field_width = req_width(aclproccnt_v3_kstat, field_width);
443 }
444 return (field_width);
445 }
446
447 static int
getstats_aclreq(void)448 getstats_aclreq(void)
449 {
450 int field_width = 0;
451 if (aclreqcnt_v2_kstat != NULL) {
452 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL);
453 field_width = req_width(aclreqcnt_v2_kstat, field_width);
454 }
455 if (aclreqcnt_v3_kstat != NULL) {
456 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL);
457 field_width = req_width(aclreqcnt_v3_kstat, field_width);
458 }
459 return (field_width);
460 }
461
462 static void
putstats(void)463 putstats(void)
464 {
465 if (rpc_clts_client_kstat != NULL)
466 safe_kstat_write(kc, rpc_clts_client_kstat, NULL);
467 if (rpc_cots_client_kstat != NULL)
468 safe_kstat_write(kc, rpc_cots_client_kstat, NULL);
469 if (rpc_rdma_client_kstat != NULL)
470 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL);
471 if (nfs_client_kstat != NULL)
472 safe_kstat_write(kc, nfs_client_kstat, NULL);
473 if (nfs4_client_kstat != NULL)
474 safe_kstat_write(kc, nfs4_client_kstat, NULL);
475 if (rpc_clts_server_kstat != NULL)
476 safe_kstat_write(kc, rpc_clts_server_kstat, NULL);
477 if (rpc_cots_server_kstat != NULL)
478 safe_kstat_write(kc, rpc_cots_server_kstat, NULL);
479 if (rpc_rdma_server_kstat != NULL)
480 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL);
481 if (nfs_server_v2_kstat != NULL)
482 safe_kstat_write(kc, nfs_server_v2_kstat, NULL);
483 if (nfs_server_v3_kstat != NULL)
484 safe_kstat_write(kc, nfs_server_v3_kstat, NULL);
485 if (nfs_server_v4_kstat != NULL)
486 safe_kstat_write(kc, nfs_server_v4_kstat, NULL);
487 if (rfsproccnt_v2_kstat != NULL)
488 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL);
489 if (rfsproccnt_v3_kstat != NULL)
490 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL);
491 if (rfsproccnt_v4_kstat != NULL)
492 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL);
493 if (rfsreqcnt_v2_kstat != NULL)
494 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL);
495 if (rfsreqcnt_v3_kstat != NULL)
496 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL);
497 if (rfsreqcnt_v4_kstat != NULL)
498 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL);
499 if (aclproccnt_v2_kstat != NULL)
500 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL);
501 if (aclproccnt_v3_kstat != NULL)
502 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL);
503 if (aclreqcnt_v2_kstat != NULL)
504 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL);
505 if (aclreqcnt_v3_kstat != NULL)
506 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL);
507 }
508
509 static void
setup(void)510 setup(void)
511 {
512 if ((kc = kstat_open()) == NULL)
513 fail(1, "kstat_open(): can't open /dev/kstat");
514
515 /* alloc space for our temporary kstat */
516 safe_zalloc((void **)&ksum_kstat, sizeof (kstat_t), 0);
517 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client");
518 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server");
519 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client");
520 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server");
521 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client");
522 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server");
523 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client");
524 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client");
525 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server");
526 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server");
527 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server");
528 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2");
529 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3");
530 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4");
531 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2");
532 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3");
533 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4");
534 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2");
535 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3");
536 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2");
537 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3");
538 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL &&
539 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL)
540 fail(0, "Multiple kstat lookups failed."
541 "Your kernel module may not be loaded\n");
542 }
543
544 static int
req_width(kstat_t * req,int field_width)545 req_width(kstat_t *req, int field_width)
546 {
547 int i, nreq, per, len;
548 char fixlen[128];
549 kstat_named_t *knp;
550 uint64_t tot;
551
552 tot = 0;
553 knp = KSTAT_NAMED_PTR(req);
554 for (i = 0; i < req->ks_ndata; i++)
555 tot += knp[i].value.ui64;
556
557 knp = kstat_data_lookup(req, "null");
558 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
559
560 for (i = 0; i < nreq; i++) {
561 len = strlen(knp[i].name) + 1;
562 if (field_width < len)
563 field_width = len;
564 if (tot)
565 per = (int)(knp[i].value.ui64 * 100 / tot);
566 else
567 per = 0;
568 (void) sprintf(fixlen, "%" PRIu64 " %d%%",
569 knp[i].value.ui64, per);
570 len = strlen(fixlen) + 1;
571 if (field_width < len)
572 field_width = len;
573 }
574 return (field_width);
575 }
576
577 static int
stat_width(kstat_t * req,int field_width)578 stat_width(kstat_t *req, int field_width)
579 {
580 int i, nreq, len;
581 char fixlen[128];
582 kstat_named_t *knp;
583
584 knp = KSTAT_NAMED_PTR(req);
585 nreq = req->ks_ndata;
586
587 for (i = 0; i < nreq; i++) {
588 len = strlen(knp[i].name) + 1;
589 if (field_width < len)
590 field_width = len;
591 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64);
592 len = strlen(fixlen) + 1;
593 if (field_width < len)
594 field_width = len;
595 }
596 return (field_width);
597 }
598
599 static void
cr_print(int zflag)600 cr_print(int zflag)
601 {
602 int field_width;
603
604 field_width = getstats_rpc();
605 if (field_width == 0)
606 return;
607
608 stat_print("\nClient rpc:\nConnection oriented:",
609 rpc_cots_client_kstat,
610 &old_rpc_cots_client_kstat.kst, field_width, zflag);
611 stat_print("Connectionless:", rpc_clts_client_kstat,
612 &old_rpc_clts_client_kstat.kst, field_width, zflag);
613 stat_print("RDMA based:", rpc_rdma_client_kstat,
614 &old_rpc_rdma_client_kstat.kst, field_width, zflag);
615 }
616
617 static void
sr_print(int zflag)618 sr_print(int zflag)
619 {
620 int field_width;
621
622 field_width = getstats_rpc();
623 if (field_width == 0)
624 return;
625
626 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat,
627 &old_rpc_cots_server_kstat.kst, field_width, zflag);
628 stat_print("Connectionless:", rpc_clts_server_kstat,
629 &old_rpc_clts_server_kstat.kst, field_width, zflag);
630 stat_print("RDMA based:", rpc_rdma_server_kstat,
631 &old_rpc_rdma_server_kstat.kst, field_width, zflag);
632 }
633
634 static void
cn_print(int zflag,int vflag)635 cn_print(int zflag, int vflag)
636 {
637 int field_width;
638
639 field_width = getstats_nfs();
640 if (field_width == 0)
641 return;
642
643 if (vflag == 0) {
644 nfsstat_kstat_sum(nfs_client_kstat, nfs4_client_kstat,
645 ksum_kstat);
646 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst,
647 field_width, zflag);
648 }
649
650 if (vflag == 2 || vflag == 3) {
651 stat_print("\nClient nfs:", nfs_client_kstat,
652 &old_nfs_client_kstat.kst, field_width, zflag);
653 }
654
655 if (vflag == 4) {
656 stat_print("\nClient nfs:", nfs4_client_kstat,
657 &old_nfs4_client_kstat.kst, field_width, zflag);
658 }
659
660 if (vflag == 2 || vflag == 0) {
661 field_width = getstats_rfsreq(2);
662 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst,
663 2, field_width, zflag);
664 }
665
666 if (vflag == 3 || vflag == 0) {
667 field_width = getstats_rfsreq(3);
668 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3,
669 field_width, zflag);
670 }
671
672 if (vflag == 4 || vflag == 0) {
673 field_width = getstats_rfsreq(4);
674 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst,
675 field_width, zflag);
676 }
677 }
678
679 static void
sn_print(int zflag,int vflag)680 sn_print(int zflag, int vflag)
681 {
682 int field_width;
683
684 field_width = getstats_nfs();
685 if (field_width == 0)
686 return;
687
688 if (vflag == 2 || vflag == 0) {
689 stat_print("\nServer NFSv2:", nfs_server_v2_kstat,
690 &old_nfs_server_v2_kstat.kst, field_width, zflag);
691 }
692
693 if (vflag == 3 || vflag == 0) {
694 stat_print("\nServer NFSv3:", nfs_server_v3_kstat,
695 &old_nfs_server_v3_kstat.kst, field_width, zflag);
696 }
697
698 if (vflag == 4 || vflag == 0) {
699 stat_print("\nServer NFSv4:", nfs_server_v4_kstat,
700 &old_nfs_server_v4_kstat.kst, field_width, zflag);
701 }
702
703 if (vflag == 2 || vflag == 0) {
704 field_width = getstats_rfsproc(2);
705 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst,
706 2, field_width, zflag);
707 }
708
709 if (vflag == 3 || vflag == 0) {
710 field_width = getstats_rfsproc(3);
711 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst,
712 3, field_width, zflag);
713 }
714
715 if (vflag == 4 || vflag == 0) {
716 field_width = getstats_rfsproc(4);
717 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst,
718 field_width, zflag);
719 }
720 }
721
722 static void
ca_print(int zflag,int vflag)723 ca_print(int zflag, int vflag)
724 {
725 int field_width;
726
727 field_width = getstats_aclreq();
728 if (field_width == 0)
729 return;
730
731 printf("\nClient nfs_acl:\n");
732
733 if (vflag == 2 || vflag == 0) {
734 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2,
735 field_width, zflag);
736 }
737
738 if (vflag == 3 || vflag == 0) {
739 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst,
740 3, field_width, zflag);
741 }
742 }
743
744 static void
sa_print(int zflag,int vflag)745 sa_print(int zflag, int vflag)
746 {
747 int field_width;
748
749 field_width = getstats_aclproc();
750 if (field_width == 0)
751 return;
752
753 printf("\nServer nfs_acl:\n");
754
755 if (vflag == 2 || vflag == 0) {
756 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst,
757 2, field_width, zflag);
758 }
759
760 if (vflag == 3 || vflag == 0) {
761 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst,
762 3, field_width, zflag);
763 }
764 }
765
766 #define MIN(a, b) ((a) < (b) ? (a) : (b))
767
768 static void
req_print(kstat_t * req,kstat_t * req_old,int ver,int field_width,int zflag)769 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width,
770 int zflag)
771 {
772 int i, j, nreq, per, ncolumns;
773 uint64_t tot, old_tot;
774 char fixlen[128];
775 kstat_named_t *knp;
776 kstat_named_t *kptr;
777 kstat_named_t *knp_old;
778
779 if (req == NULL)
780 return;
781
782 if (field_width == 0)
783 return;
784
785 ncolumns = (MAX_COLUMNS -1)/field_width;
786 knp = kstat_data_lookup(req, "null");
787 knp_old = KSTAT_NAMED_PTR(req_old);
788
789 kptr = KSTAT_NAMED_PTR(req);
790 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
791
792 tot = 0;
793 old_tot = 0;
794
795 if (knp_old == NULL) {
796 old_tot = 0;
797 }
798
799 for (i = 0; i < req->ks_ndata; i++)
800 tot += kptr[i].value.ui64;
801
802 if (interval && knp_old != NULL) {
803 for (i = 0; i < req_old->ks_ndata; i++)
804 old_tot += knp_old[i].value.ui64;
805 tot -= old_tot;
806 }
807
808 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot);
809
810 for (i = 0; i < nreq; i += ncolumns) {
811 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
812 printf("%-*s", field_width, knp[j].name);
813 }
814 printf("\n");
815 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
816 if (tot && interval && knp_old != NULL)
817 per = (int)((knp[j].value.ui64 -
818 knp_old[j].value.ui64) * 100 / tot);
819 else if (tot)
820 per = (int)(knp[j].value.ui64 * 100 / tot);
821 else
822 per = 0;
823 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
824 ((interval && knp_old != NULL) ?
825 (knp[j].value.ui64 - knp_old[j].value.ui64)
826 : knp[j].value.ui64), per);
827 printf("%-*s", field_width, fixlen);
828 }
829 printf("\n");
830 }
831 if (zflag) {
832 for (i = 0; i < req->ks_ndata; i++)
833 knp[i].value.ui64 = 0;
834 }
835 if (knp_old != NULL)
836 nfsstat_kstat_copy(req, req_old, 1);
837 else
838 nfsstat_kstat_copy(req, req_old, 0);
839 }
840
841 /*
842 * Separate version of the req_print() to deal with V4 and its use of
843 * procedures and operations. It looks odd to have the counts for
844 * both of those lumped into the same set of statistics so this
845 * function (copy of req_print() does the separation and titles).
846 */
847
848 #define COUNT 2
849
850 static void
req_print_v4(kstat_t * req,kstat_t * req_old,int field_width,int zflag)851 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag)
852 {
853 int i, j, nreq, per, ncolumns;
854 uint64_t tot, tot_ops, old_tot, old_tot_ops;
855 char fixlen[128];
856 kstat_named_t *kptr;
857 kstat_named_t *knp;
858 kstat_named_t *kptr_old;
859
860 if (req == NULL)
861 return;
862
863 if (field_width == 0)
864 return;
865
866 ncolumns = (MAX_COLUMNS)/field_width;
867 kptr = KSTAT_NAMED_PTR(req);
868 kptr_old = KSTAT_NAMED_PTR(req_old);
869
870 if (kptr_old == NULL) {
871 old_tot_ops = 0;
872 old_tot = 0;
873 } else {
874 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64;
875 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++)
876 old_tot_ops += kptr_old[i].value.ui64;
877 }
878
879 /* Count the number of operations sent */
880 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++)
881 tot_ops += kptr[i].value.ui64;
882 /* For v4 NULL/COMPOUND are the only procedures */
883 tot = kptr[0].value.ui64 + kptr[1].value.ui64;
884
885 if (interval) {
886 tot -= old_tot;
887 tot_ops -= old_tot_ops;
888 }
889
890 printf("Version 4: (%" PRIu64 " calls)\n", tot);
891
892 knp = kstat_data_lookup(req, "null");
893 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
894
895 for (i = 0; i < COUNT; i += ncolumns) {
896 for (j = i; j < MIN(i + ncolumns, 2); j++) {
897 printf("%-*s", field_width, knp[j].name);
898 }
899 printf("\n");
900 for (j = i; j < MIN(i + ncolumns, 2); j++) {
901 if (tot && interval && kptr_old != NULL)
902 per = (int)((knp[j].value.ui64 -
903 kptr_old[j].value.ui64) * 100 / tot);
904 else if (tot)
905 per = (int)(knp[j].value.ui64 * 100 / tot);
906 else
907 per = 0;
908 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
909 ((interval && kptr_old != NULL) ?
910 (knp[j].value.ui64 - kptr_old[j].value.ui64)
911 : knp[j].value.ui64), per);
912 printf("%-*s", field_width, fixlen);
913 }
914 printf("\n");
915 }
916
917 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops);
918 for (i = 2; i < nreq; i += ncolumns) {
919 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
920 printf("%-*s", field_width, knp[j].name);
921 }
922 printf("\n");
923 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
924 if (tot_ops && interval && kptr_old != NULL)
925 per = (int)((knp[j].value.ui64 -
926 kptr_old[j].value.ui64) * 100 / tot_ops);
927 else if (tot_ops)
928 per = (int)(knp[j].value.ui64 * 100 / tot_ops);
929 else
930 per = 0;
931 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
932 ((interval && kptr_old != NULL) ?
933 (knp[j].value.ui64 - kptr_old[j].value.ui64)
934 : knp[j].value.ui64), per);
935 printf("%-*s", field_width, fixlen);
936 }
937 printf("\n");
938 }
939 if (zflag) {
940 for (i = 0; i < req->ks_ndata; i++)
941 kptr[i].value.ui64 = 0;
942 }
943 if (kptr_old != NULL)
944 nfsstat_kstat_copy(req, req_old, 1);
945 else
946 nfsstat_kstat_copy(req, req_old, 0);
947 }
948
949 static void
stat_print(const char * title_string,kstat_t * req,kstat_t * req_old,int field_width,int zflag)950 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old,
951 int field_width, int zflag)
952 {
953 int i, j, nreq, ncolumns;
954 char fixlen[128];
955 kstat_named_t *knp;
956 kstat_named_t *knp_old;
957
958 if (req == NULL)
959 return;
960
961 if (field_width == 0)
962 return;
963
964 printf("%s\n", title_string);
965 ncolumns = (MAX_COLUMNS -1)/field_width;
966
967 /* MEANS knp = (kstat_named_t *)req->ks_data */
968 knp = KSTAT_NAMED_PTR(req);
969 nreq = req->ks_ndata;
970 knp_old = KSTAT_NAMED_PTR(req_old);
971
972 for (i = 0; i < nreq; i += ncolumns) {
973 /* prints out the titles of the columns */
974 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
975 printf("%-*s", field_width, knp[j].name);
976 }
977 printf("\n");
978 /* prints out the stat numbers */
979 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
980 (void) sprintf(fixlen, "%" PRIu64 " ",
981 (interval && knp_old != NULL) ?
982 (knp[j].value.ui64 - knp_old[j].value.ui64)
983 : knp[j].value.ui64);
984 printf("%-*s", field_width, fixlen);
985 }
986 printf("\n");
987
988 }
989 if (zflag) {
990 for (i = 0; i < req->ks_ndata; i++)
991 knp[i].value.ui64 = 0;
992 }
993
994 if (knp_old != NULL)
995 nfsstat_kstat_copy(req, req_old, 1);
996 else
997 nfsstat_kstat_copy(req, req_old, 0);
998 }
999
1000 static void
nfsstat_kstat_sum(kstat_t * kstat1,kstat_t * kstat2,kstat_t * sum)1001 nfsstat_kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum)
1002 {
1003 int i;
1004 kstat_named_t *knp1, *knp2, *knpsum;
1005 if (kstat1 == NULL || kstat2 == NULL)
1006 return;
1007
1008 knp1 = KSTAT_NAMED_PTR(kstat1);
1009 knp2 = KSTAT_NAMED_PTR(kstat2);
1010 if (sum->ks_data == NULL)
1011 nfsstat_kstat_copy(kstat1, sum, 0);
1012 knpsum = KSTAT_NAMED_PTR(sum);
1013
1014 for (i = 0; i < (kstat1->ks_ndata); i++)
1015 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64;
1016 }
1017
1018 /*
1019 * my_dir and my_path could be pointers
1020 */
1021 struct myrec {
1022 ulong_t my_fsid;
1023 char my_dir[MAXPATHLEN];
1024 char *my_path;
1025 char *ig_path;
1026 struct myrec *next;
1027 };
1028
1029 /*
1030 * Print the mount table info
1031 */
1032 static void
mi_print(void)1033 mi_print(void)
1034 {
1035 FILE *mt;
1036 struct extmnttab m;
1037 struct myrec *list, *mrp, *pmrp;
1038 char *flavor;
1039 int ignored = 0;
1040 seconfig_t nfs_sec;
1041 kstat_t *ksp;
1042 struct mntinfo_kstat mik;
1043 int transport_flag = 0;
1044 int path_count;
1045 int found;
1046 char *timer_name[] = {
1047 "Lookups",
1048 "Reads",
1049 "Writes",
1050 "All"
1051 };
1052
1053 mt = fopen(MNTTAB, "r");
1054 if (mt == NULL) {
1055 perror(MNTTAB);
1056 exit(0);
1057 }
1058
1059 list = NULL;
1060 resetmnttab(mt);
1061
1062 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {
1063 /* ignore non "nfs" and save the "ignore" entries */
1064 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0)
1065 continue;
1066 /*
1067 * Check to see here if user gave a path(s) to
1068 * only show the mount point they wanted
1069 * Iterate through the list of paths the user gave and see
1070 * if any of them match our current nfs mount
1071 */
1072 if (path[0] != NULL) {
1073 found = 0;
1074 for (path_count = 0; path[path_count] != NULL;
1075 path_count++) {
1076 if (strcmp(path[path_count], m.mnt_mountp)
1077 == 0) {
1078 found = 1;
1079 break;
1080 }
1081 }
1082 if (!found)
1083 continue;
1084 }
1085
1086 if ((mrp = malloc(sizeof (struct myrec))) == 0) {
1087 fprintf(stderr, "nfsstat: not enough memory\n");
1088 exit(1);
1089 }
1090 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor);
1091 if (ignore(m.mnt_mntopts)) {
1092 /*
1093 * ignored entries cannot be ignored for this
1094 * option. We have to display the info for this
1095 * nfs mount. The ignore is an indication
1096 * that the actual mount point is different and
1097 * something is in between the nfs mount.
1098 * So save the mount point now
1099 */
1100 if ((mrp->ig_path = malloc(
1101 strlen(m.mnt_mountp) + 1)) == 0) {
1102 fprintf(stderr, "nfsstat: not enough memory\n");
1103 exit(1);
1104 }
1105 (void) strcpy(mrp->ig_path, m.mnt_mountp);
1106 ignored++;
1107 } else {
1108 mrp->ig_path = 0;
1109 (void) strcpy(mrp->my_dir, m.mnt_mountp);
1110 }
1111 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) {
1112 fprintf(stderr, "nfsstat: not enough memory\n");
1113 exit(1);
1114 }
1115 mrp->next = list;
1116 list = mrp;
1117 }
1118
1119 (void) fclose(mt);
1120
1121 if (ignored) {
1122 /*
1123 * Now ignored entries which do not have
1124 * the my_dir initialized are really ignored; This never
1125 * happens unless the mnttab is corrupted.
1126 */
1127 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) {
1128 if (mrp->ig_path == 0)
1129 pmrp = mrp;
1130 else if (pmrp)
1131 pmrp->next = mrp->next;
1132 else
1133 list = mrp->next;
1134 }
1135 }
1136
1137 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1138 int i;
1139
1140 if (ksp->ks_type != KSTAT_TYPE_RAW)
1141 continue;
1142 if (strcmp(ksp->ks_module, "nfs") != 0)
1143 continue;
1144 if (strcmp(ksp->ks_name, "mntinfo") != 0)
1145 continue;
1146
1147 for (mrp = list; mrp; mrp = mrp->next) {
1148 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance)
1149 break;
1150 }
1151 if (mrp == 0)
1152 continue;
1153
1154 if (safe_kstat_read(kc, ksp, &mik) == -1)
1155 continue;
1156
1157 printf("%s from %s\n", mrp->my_dir, mrp->my_path);
1158
1159 /*
1160 * for printing rdma transport and provider string.
1161 * This way we avoid modifying the kernel mntinfo_kstat
1162 * struct for protofmly.
1163 */
1164 if (strcmp(mik.mik_proto, "ibtf") == 0) {
1165 printf(" Flags: vers=%u,proto=rdma",
1166 mik.mik_vers);
1167 transport_flag = 1;
1168 } else {
1169 printf(" Flags: vers=%u,proto=%s",
1170 mik.mik_vers, mik.mik_proto);
1171 transport_flag = 0;
1172 }
1173
1174 /*
1175 * get the secmode name from /etc/nfssec.conf.
1176 */
1177 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
1178 flavor = nfs_sec.sc_name;
1179 } else
1180 flavor = NULL;
1181
1182 if (flavor != NULL)
1183 printf(",sec=%s", flavor);
1184 else
1185 printf(",sec#=%d", mik.mik_secmod);
1186
1187 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft");
1188 if (mik.mik_flags & MI_PRINTED)
1189 printf(",printed");
1190 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr");
1191 if (mik.mik_flags & MI_DOWN)
1192 printf(",down");
1193 if (mik.mik_flags & MI_NOAC)
1194 printf(",noac");
1195 if (mik.mik_flags & MI_NOCTO)
1196 printf(",nocto");
1197 if (mik.mik_flags & MI_DYNAMIC)
1198 printf(",dynamic");
1199 if (mik.mik_flags & MI_LLOCK)
1200 printf(",llock");
1201 if (mik.mik_flags & MI_GRPID)
1202 printf(",grpid");
1203 if (mik.mik_flags & MI_RPCTIMESYNC)
1204 printf(",rpctimesync");
1205 if (mik.mik_flags & MI_LINK)
1206 printf(",link");
1207 if (mik.mik_flags & MI_SYMLINK)
1208 printf(",symlink");
1209 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY)
1210 printf(",readdironly");
1211 if (mik.mik_flags & MI_ACL)
1212 printf(",acl");
1213 if (mik.mik_flags & MI_DIRECTIO)
1214 printf(",forcedirectio");
1215
1216 if (mik.mik_vers >= NFS_V4) {
1217 if (mik.mik_flags & MI4_MIRRORMOUNT)
1218 printf(",mirrormount");
1219 if (mik.mik_flags & MI4_REFERRAL)
1220 printf(",referral");
1221 }
1222
1223 printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d",
1224 mik.mik_curread, mik.mik_curwrite, mik.mik_retrans,
1225 mik.mik_timeo);
1226 printf("\n");
1227 printf(" Attr cache: acregmin=%d,acregmax=%d"
1228 ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin,
1229 mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax);
1230
1231 if (transport_flag) {
1232 printf(" Transport: proto=rdma, plugin=%s\n",
1233 mik.mik_proto);
1234 }
1235
1236 #define srtt_to_ms(x) x, (x * 2 + x / 2)
1237 #define dev_to_ms(x) x, (x * 5)
1238
1239 for (i = 0; i < NFS_CALLTYPES + 1; i++) {
1240 int j;
1241
1242 j = (i == NFS_CALLTYPES ? i - 1 : i);
1243 if (mik.mik_timers[j].srtt ||
1244 mik.mik_timers[j].rtxcur) {
1245 printf(" %s: srtt=%d (%dms), "
1246 "dev=%d (%dms), cur=%u (%ums)\n",
1247 timer_name[i],
1248 srtt_to_ms(mik.mik_timers[i].srtt),
1249 dev_to_ms(mik.mik_timers[i].deviate),
1250 mik.mik_timers[i].rtxcur,
1251 mik.mik_timers[i].rtxcur * 20);
1252 }
1253 }
1254
1255 if (strchr(mrp->my_path, ','))
1256 printf(
1257 " Failover: noresponse=%d,failover=%d,"
1258 "remap=%d,currserver=%s\n",
1259 mik.mik_noresponse, mik.mik_failover,
1260 mik.mik_remap, mik.mik_curserver);
1261 printf("\n");
1262 }
1263 }
1264
1265 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };
1266 #define IGNORE 0
1267 #define DEV 1
1268
1269 /*
1270 * Return 1 if "ignore" appears in the options string
1271 */
1272 static int
ignore(char * opts)1273 ignore(char *opts)
1274 {
1275 char *value;
1276 char *s;
1277
1278 if (opts == NULL)
1279 return (0);
1280 s = strdup(opts);
1281 if (s == NULL)
1282 return (0);
1283 opts = s;
1284
1285 while (*opts != '\0') {
1286 if (getsubopt(&opts, mntopts, &value) == IGNORE) {
1287 free(s);
1288 return (1);
1289 }
1290 }
1291
1292 free(s);
1293 return (0);
1294 }
1295
1296 void
usage(void)1297 usage(void)
1298 {
1299 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] "
1300 "[-T d|u] [interval [count]]\n");
1301 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n");
1302 exit(1);
1303 }
1304
1305 void
fail(int do_perror,char * message,...)1306 fail(int do_perror, char *message, ...)
1307 {
1308 va_list args;
1309
1310 va_start(args, message);
1311 fprintf(stderr, "nfsstat: ");
1312 vfprintf(stderr, message, args);
1313 va_end(args);
1314 if (do_perror)
1315 fprintf(stderr, ": %s", strerror(errno));
1316 fprintf(stderr, "\n");
1317 exit(1);
1318 }
1319
1320 kid_t
safe_kstat_read(kstat_ctl_t * kc,kstat_t * ksp,void * data)1321 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1322 {
1323 kid_t kstat_chain_id = kstat_read(kc, ksp, data);
1324
1325 if (kstat_chain_id == -1)
1326 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name);
1327 return (kstat_chain_id);
1328 }
1329
1330 kid_t
safe_kstat_write(kstat_ctl_t * kc,kstat_t * ksp,void * data)1331 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1332 {
1333 kid_t kstat_chain_id = 0;
1334
1335 if (ksp->ks_data != NULL) {
1336 kstat_chain_id = kstat_write(kc, ksp, data);
1337
1338 if (kstat_chain_id == -1)
1339 fail(1, "kstat_write(%x, '%s') failed", kc,
1340 ksp->ks_name);
1341 }
1342 return (kstat_chain_id);
1343 }
1344
1345 void
stats_timer(int interval)1346 stats_timer(int interval)
1347 {
1348 timer_t t_id;
1349 itimerspec_t time_struct;
1350 struct sigevent sig_struct;
1351 struct sigaction act;
1352
1353 bzero(&sig_struct, sizeof (struct sigevent));
1354 bzero(&act, sizeof (struct sigaction));
1355
1356 /* Create timer */
1357 sig_struct.sigev_notify = SIGEV_SIGNAL;
1358 sig_struct.sigev_signo = SIGUSR1;
1359 sig_struct.sigev_value.sival_int = 0;
1360
1361 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
1362 fail(1, "Timer creation failed");
1363 }
1364
1365 act.sa_handler = handle_sig;
1366
1367 if (sigaction(SIGUSR1, &act, NULL) != 0) {
1368 fail(1, "Could not set up signal handler");
1369 }
1370
1371 time_struct.it_value.tv_sec = interval;
1372 time_struct.it_value.tv_nsec = 0;
1373 time_struct.it_interval.tv_sec = interval;
1374 time_struct.it_interval.tv_nsec = 0;
1375
1376 /* Arm timer */
1377 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
1378 fail(1, "Setting timer failed");
1379 }
1380 }
1381
1382 void
handle_sig(int x)1383 handle_sig(int x)
1384 {
1385 }
1386
1387 static void
nfsstat_kstat_copy(kstat_t * src,kstat_t * dst,int fr)1388 nfsstat_kstat_copy(kstat_t *src, kstat_t *dst, int fr)
1389 {
1390
1391 if (fr)
1392 free(dst->ks_data);
1393
1394 *dst = *src;
1395
1396 if (src->ks_data != NULL) {
1397 safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
1398 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
1399 } else {
1400 dst->ks_data = NULL;
1401 dst->ks_data_size = 0;
1402 }
1403 }
1404
1405 /*
1406 * "Safe" allocators - if we return we're guaranteed to have the desired space
1407 * allocated and zero-filled. We exit via fail if we can't get the space.
1408 */
1409 void
safe_zalloc(void ** ptr,uint_t size,int free_first)1410 safe_zalloc(void **ptr, uint_t size, int free_first)
1411 {
1412 if (ptr == NULL)
1413 fail(1, "invalid pointer");
1414 if (free_first && *ptr != NULL)
1415 free(*ptr);
1416 if ((*ptr = (void *)malloc(size)) == NULL)
1417 fail(1, "malloc failed");
1418 (void) memset(*ptr, 0, size);
1419 }
1420
1421 static int
safe_strtoi(char const * val,char * errmsg)1422 safe_strtoi(char const *val, char *errmsg)
1423 {
1424 char *end;
1425 long tmp;
1426 errno = 0;
1427 tmp = strtol(val, &end, 10);
1428 if (*end != '\0' || errno)
1429 fail(0, "%s %s", errmsg, val);
1430 return ((int)tmp);
1431 }
1432