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