15a59a8b3Srsb /*
25a59a8b3Srsb * CDDL HEADER START
35a59a8b3Srsb *
45a59a8b3Srsb * The contents of this file are subject to the terms of the
55a59a8b3Srsb * Common Development and Distribution License (the "License").
65a59a8b3Srsb * You may not use this file except in compliance with the License.
75a59a8b3Srsb *
85a59a8b3Srsb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95a59a8b3Srsb * or http://www.opensolaris.org/os/licensing.
105a59a8b3Srsb * See the License for the specific language governing permissions
115a59a8b3Srsb * and limitations under the License.
125a59a8b3Srsb *
135a59a8b3Srsb * When distributing Covered Code, include this CDDL HEADER in each
145a59a8b3Srsb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155a59a8b3Srsb * If applicable, add the following below this CDDL HEADER, with the
165a59a8b3Srsb * fields enclosed by brackets "[]" replaced with your own identifying
175a59a8b3Srsb * information: Portions Copyright [yyyy] [name of copyright owner]
185a59a8b3Srsb *
195a59a8b3Srsb * CDDL HEADER END
205a59a8b3Srsb */
215a59a8b3Srsb /*
22c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
235a59a8b3Srsb * Use is subject to license terms.
24*fc30d466SJason King * Copyright 2017 Jason King
255a59a8b3Srsb */
265a59a8b3Srsb
275a59a8b3Srsb #include <stdio.h>
285a59a8b3Srsb #include <kstat.h>
295a59a8b3Srsb #include <stdlib.h>
305a59a8b3Srsb #include <string.h>
315a59a8b3Srsb #include <strings.h>
325a59a8b3Srsb #include <errno.h>
335a59a8b3Srsb #include <limits.h>
345a59a8b3Srsb #include <sys/types.h>
355a59a8b3Srsb #include <time.h>
365a59a8b3Srsb #include <sys/time.h>
375a59a8b3Srsb #include <sys/uio.h>
385a59a8b3Srsb #include <sys/vnode.h>
395a59a8b3Srsb #include <sys/vfs.h>
405a59a8b3Srsb #include <sys/statvfs.h>
415a59a8b3Srsb #include <sys/fstyp.h>
425a59a8b3Srsb #include <sys/fsid.h>
435a59a8b3Srsb #include <sys/mnttab.h>
44*fc30d466SJason King #include <sys/debug.h>
455a59a8b3Srsb #include <values.h>
465a59a8b3Srsb #include <poll.h>
475a59a8b3Srsb #include <ctype.h>
485a59a8b3Srsb #include <libintl.h>
4913c7b6acSrsb #include <locale.h>
5000c76d6fStc35445 #include <signal.h>
51*fc30d466SJason King #include <libcmdutils.h>
5200c76d6fStc35445
5300c76d6fStc35445 #include "statcommon.h"
545a59a8b3Srsb
553a401a6bSrsb /*
563a401a6bSrsb * For now, parsable output is turned off. Once we gather feedback and
573a401a6bSrsb * stablize the output format, we'll turn it back on. This prevents
583a401a6bSrsb * the situation where users build tools which depend on a specific
593a401a6bSrsb * format before we declare the output stable.
603a401a6bSrsb */
613a401a6bSrsb #define PARSABLE_OUTPUT 0
623a401a6bSrsb
633a401a6bSrsb #if PARSABLE_OUTPUT
643a401a6bSrsb #define OPTIONS "FPT:afginv"
653a401a6bSrsb #else
663a401a6bSrsb #define OPTIONS "FT:afginv"
673a401a6bSrsb #endif
685a59a8b3Srsb
695a59a8b3Srsb /* Time stamp values */
705a59a8b3Srsb #define NODATE 0 /* Default: No time stamp */
715a59a8b3Srsb #define DDATE 1 /* Standard date format */
725a59a8b3Srsb #define UDATE 2 /* Internal representation of Unix time */
735a59a8b3Srsb
745a59a8b3Srsb #define RETRY_DELAY 250 /* Timeout for poll() */
753a401a6bSrsb #define HEADERLINES 12 /* Number of lines between display headers */
765a59a8b3Srsb
775a59a8b3Srsb #define LBUFSZ 64 /* Generic size for local buffer */
78*fc30d466SJason King CTASSERT(LBUFSZ >= NN_NUMBUF_SZ);
795a59a8b3Srsb
805a59a8b3Srsb #define NENTITY_INIT 1 /* Initial number of entities to allocate */
815a59a8b3Srsb
825a59a8b3Srsb /*
835a59a8b3Srsb * We need to have a mechanism for an old/previous and new/current vopstat
845a59a8b3Srsb * structure. We only need two per entity and we can swap between them.
855a59a8b3Srsb */
865a59a8b3Srsb #define VS_SIZE 2 /* Size of vopstat array */
875a59a8b3Srsb #define CUR_INDEX (vs_i)
885a59a8b3Srsb #define PREV_INDEX ((vs_i == 0) ? 1 : 0) /* Opposite of CUR_INDEX */
895a59a8b3Srsb #define BUMP_INDEX() vs_i = ((vs_i == 0) ? 1 : 0)
905a59a8b3Srsb
915a59a8b3Srsb /*
925a59a8b3Srsb * An "entity" is anything we're collecting statistics on, it could
935a59a8b3Srsb * be a mountpoint or an FS-type.
945a59a8b3Srsb * e_name is the name of the entity (e.g. mount point or FS-type)
955a59a8b3Srsb * e_ksname is the name of the associated kstat
965a59a8b3Srsb * e_vs is an array of vopstats. This is used to keep track of "previous"
975a59a8b3Srsb * and "current" vopstats.
985a59a8b3Srsb */
995a59a8b3Srsb typedef struct entity {
1005a59a8b3Srsb char *e_name; /* name of entity */
1015a59a8b3Srsb vopstats_t *e_vs; /* Array of vopstats */
1025a59a8b3Srsb ulong_t e_fsid; /* fsid for ENTYPE_MNTPT only */
1035a59a8b3Srsb int e_type; /* type of entity */
1045a59a8b3Srsb char e_ksname[KSTAT_STRLEN]; /* kstat name */
1055a59a8b3Srsb } entity_t;
1065a59a8b3Srsb
1075a59a8b3Srsb /* Types of entities (e_type) */
1085a59a8b3Srsb #define ENTYPE_UNKNOWN 0 /* UNKNOWN must be zero since we calloc() */
1095a59a8b3Srsb #define ENTYPE_FSTYPE 1
1105a59a8b3Srsb #define ENTYPE_MNTPT 2
1115a59a8b3Srsb
11200c76d6fStc35445 char *cmdname; /* name of this command */
11300c76d6fStc35445 int caught_cont = 0; /* have caught a SIGCONT */
1145a59a8b3Srsb
11526fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE; /* print timestamp with stats */
1164944376cSJohn Levon
1175a59a8b3Srsb static int vs_i = 0; /* Index of current vs[] slot */
1185a59a8b3Srsb
1195a59a8b3Srsb static void
usage()1205a59a8b3Srsb usage()
1215a59a8b3Srsb {
1223a401a6bSrsb (void) fprintf(stderr, gettext(
1233a401a6bSrsb "Usage: %s [-a|f|i|n|v] [-T d|u] {-F | {fstype | fspath}...} "
1245a59a8b3Srsb "[interval [count]]\n"), cmdname);
1255a59a8b3Srsb exit(2);
1265a59a8b3Srsb }
1275a59a8b3Srsb
1285a59a8b3Srsb #define RAWVAL(ptr, member) ((ptr)->member.value.ui64)
1295a59a8b3Srsb #define DELTA(member) \
1305a59a8b3Srsb (newvsp->member.value.ui64 - (oldvsp ? oldvsp->member.value.ui64 : 0))
1313a401a6bSrsb
132*fc30d466SJason King #define PRINTSTAT(isnice, nicestring, rawstring, rawval, buf) \
1335a59a8b3Srsb (isnice) ? \
134*fc30d466SJason King nicenum(rawval, buf, sizeof (buf)), \
135*fc30d466SJason King (void) printf((nicestring), (buf)) \
1365a59a8b3Srsb : \
1375a59a8b3Srsb (void) printf((rawstring), (rawval))
1385a59a8b3Srsb
1395a59a8b3Srsb /* Values for display flag */
1405a59a8b3Srsb #define DISP_HEADER 0x1
1415a59a8b3Srsb #define DISP_RAW 0x2
1425a59a8b3Srsb
1435a59a8b3Srsb /*
1445a59a8b3Srsb * The policy for dealing with multiple flags is dealt with here.
1455a59a8b3Srsb * Currently, if we are displaying raw output, then don't allow
1465a59a8b3Srsb * headers to be printed.
1475a59a8b3Srsb */
1485a59a8b3Srsb int
dispflag_policy(int printhdr,int dispflag)1495a59a8b3Srsb dispflag_policy(int printhdr, int dispflag)
1505a59a8b3Srsb {
1515a59a8b3Srsb /* If we're not displaying raw output, then allow headers to print */
1525a59a8b3Srsb if ((dispflag & DISP_RAW) == 0) {
1535a59a8b3Srsb if (printhdr) {
1545a59a8b3Srsb dispflag |= DISP_HEADER;
1555a59a8b3Srsb }
1565a59a8b3Srsb }
1575a59a8b3Srsb
1585a59a8b3Srsb return (dispflag);
1595a59a8b3Srsb }
1605a59a8b3Srsb
1615a59a8b3Srsb static void
dflt_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)1625a59a8b3Srsb dflt_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
1635a59a8b3Srsb {
1645a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
1655a59a8b3Srsb longlong_t nnewfile;
1665a59a8b3Srsb longlong_t nnamerm;
1675a59a8b3Srsb longlong_t nnamechg;
1685a59a8b3Srsb longlong_t nattrret;
1695a59a8b3Srsb longlong_t nattrchg;
1705a59a8b3Srsb longlong_t nlookup;
1715a59a8b3Srsb longlong_t nreaddir;
1725a59a8b3Srsb longlong_t ndataread;
1735a59a8b3Srsb longlong_t ndatawrite;
1745a59a8b3Srsb longlong_t readthruput;
1755a59a8b3Srsb longlong_t writethruput;
1765a59a8b3Srsb char buf[LBUFSZ];
1775a59a8b3Srsb
1785a59a8b3Srsb nnewfile = DELTA(ncreate) + DELTA(nmkdir) + DELTA(nsymlink);
1795a59a8b3Srsb nnamerm = DELTA(nremove) + DELTA(nrmdir);
1805a59a8b3Srsb nnamechg = DELTA(nrename) + DELTA(nlink) + DELTA(nsymlink);
1815a59a8b3Srsb nattrret = DELTA(ngetattr) + DELTA(naccess) +
1825a59a8b3Srsb DELTA(ngetsecattr) + DELTA(nfid);
1835a59a8b3Srsb nattrchg = DELTA(nsetattr) + DELTA(nsetsecattr) + DELTA(nspace);
1845a59a8b3Srsb nlookup = DELTA(nlookup);
1855a59a8b3Srsb nreaddir = DELTA(nreaddir);
1865a59a8b3Srsb ndataread = DELTA(nread);
1875a59a8b3Srsb ndatawrite = DELTA(nwrite);
1885a59a8b3Srsb readthruput = DELTA(read_bytes);
1895a59a8b3Srsb writethruput = DELTA(write_bytes);
1905a59a8b3Srsb
1915a59a8b3Srsb if (dispflag & DISP_HEADER) {
192757bea67Srsb (void) printf(
1935a59a8b3Srsb " new name name attr attr lookup rddir read read write write\n"
194757bea67Srsb " file remov chng get set ops ops ops bytes ops bytes\n");
1955a59a8b3Srsb }
1965a59a8b3Srsb
197*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nnewfile, buf);
198*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nnamerm, buf);
199*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nnamechg, buf);
200*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nattrret, buf);
201*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nattrchg, buf);
202*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", nlookup, buf);
203*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", nreaddir, buf);
204*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", ndataread, buf);
205*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", readthruput, buf);
206*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", ndatawrite, buf);
207*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", writethruput, buf);
2085a59a8b3Srsb (void) printf("%s\n", name);
2095a59a8b3Srsb }
2105a59a8b3Srsb
2115a59a8b3Srsb static void
io_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)2125a59a8b3Srsb io_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
2135a59a8b3Srsb {
2145a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
2155a59a8b3Srsb char buf[LBUFSZ];
2165a59a8b3Srsb
2175a59a8b3Srsb if (dispflag & DISP_HEADER) {
218757bea67Srsb (void) printf(
2195a59a8b3Srsb " read read write write rddir rddir rwlock rwulock\n"
220757bea67Srsb " ops bytes ops bytes ops bytes ops ops\n");
2215a59a8b3Srsb }
2225a59a8b3Srsb
223*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nread), buf);
224*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(read_bytes), buf);
2255a59a8b3Srsb
226*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nwrite), buf);
227*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(write_bytes), buf);
2285a59a8b3Srsb
229*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreaddir), buf);
230*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(readdir_bytes), buf);
2315a59a8b3Srsb
232*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nrwlock), buf);
233*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrwunlock), buf);
2345a59a8b3Srsb
2355a59a8b3Srsb (void) printf("%s\n", name);
2365a59a8b3Srsb }
2375a59a8b3Srsb
2385a59a8b3Srsb static void
vm_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)2395a59a8b3Srsb vm_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
2405a59a8b3Srsb {
2415a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
2425a59a8b3Srsb char buf[LBUFSZ];
2435a59a8b3Srsb
2445a59a8b3Srsb if (dispflag & DISP_HEADER) {
245757bea67Srsb (void) printf(" map addmap delmap getpag putpag pagio\n");
2465a59a8b3Srsb }
2475a59a8b3Srsb
248*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nmap), buf);
249*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(naddmap), buf);
250*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ndelmap), buf);
251*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetpage), buf);
252*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nputpage), buf);
253*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(npageio), buf);
2545a59a8b3Srsb (void) printf("%s\n", name);
2555a59a8b3Srsb }
2565a59a8b3Srsb
2575a59a8b3Srsb static void
attr_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)2585a59a8b3Srsb attr_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
2595a59a8b3Srsb {
2605a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
2615a59a8b3Srsb char buf[LBUFSZ];
2625a59a8b3Srsb
2635a59a8b3Srsb if (dispflag & DISP_HEADER) {
264757bea67Srsb (void) printf("getattr setattr getsec setsec\n");
2655a59a8b3Srsb }
2665a59a8b3Srsb
267*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetattr), buf);
268*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsetattr), buf);
269*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetsecattr), buf);
270*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsetsecattr), buf);
2715a59a8b3Srsb
2725a59a8b3Srsb (void) printf("%s\n", name);
2735a59a8b3Srsb }
2745a59a8b3Srsb
2755a59a8b3Srsb static void
naming_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)2765a59a8b3Srsb naming_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
2775a59a8b3Srsb {
2785a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
2795a59a8b3Srsb char buf[LBUFSZ];
2805a59a8b3Srsb
2815a59a8b3Srsb if (dispflag & DISP_HEADER) {
282757bea67Srsb (void) printf(
283757bea67Srsb "lookup creat remov link renam mkdir rmdir rddir symlnk rdlnk\n");
2845a59a8b3Srsb }
2855a59a8b3Srsb
286*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nlookup), buf);
287*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(ncreate), buf);
288*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nremove), buf);
289*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nlink), buf);
290*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrename), buf);
291*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nmkdir), buf);
292*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrmdir), buf);
293*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreaddir), buf);
294*fc30d466SJason King PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsymlink), buf);
295*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreadlink), buf);
2965a59a8b3Srsb (void) printf("%s\n", name);
2975a59a8b3Srsb }
2985a59a8b3Srsb
2995a59a8b3Srsb
3005a59a8b3Srsb #define PRINT_VOPSTAT_CMN(niceflag, vop) \
3015a59a8b3Srsb if (niceflag) \
3025a59a8b3Srsb (void) printf("%10s ", #vop); \
303*fc30d466SJason King PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(n##vop), buf);
3045a59a8b3Srsb
3055a59a8b3Srsb #define PRINT_VOPSTAT(niceflag, vop) \
3065a59a8b3Srsb PRINT_VOPSTAT_CMN(niceflag, vop); \
3075a59a8b3Srsb if (niceflag) \
3085a59a8b3Srsb (void) printf("\n");
3095a59a8b3Srsb
3105a59a8b3Srsb #define PRINT_VOPSTAT_IO(niceflag, vop) \
3115a59a8b3Srsb PRINT_VOPSTAT_CMN(niceflag, vop); \
3125a59a8b3Srsb PRINTSTAT(niceflag, " %5s\n", "%lld:", \
313*fc30d466SJason King DELTA(vop##_bytes), buf);
3145a59a8b3Srsb
3155a59a8b3Srsb static void
vop_display(char * name,vopstats_t * oldvsp,vopstats_t * newvsp,int dispflag)3165a59a8b3Srsb vop_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag)
3175a59a8b3Srsb {
3185a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0);
3195a59a8b3Srsb char buf[LBUFSZ];
3205a59a8b3Srsb
3215a59a8b3Srsb if (niceflag) {
3225a59a8b3Srsb (void) printf("%s\n", name);
323757bea67Srsb (void) printf(" operation #ops bytes\n");
3245a59a8b3Srsb }
3255a59a8b3Srsb
3265a59a8b3Srsb PRINT_VOPSTAT(niceflag, open);
3275a59a8b3Srsb PRINT_VOPSTAT(niceflag, close);
3285a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, read);
3295a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, write);
3305a59a8b3Srsb PRINT_VOPSTAT(niceflag, ioctl);
3315a59a8b3Srsb PRINT_VOPSTAT(niceflag, setfl);
3325a59a8b3Srsb PRINT_VOPSTAT(niceflag, getattr);
3335a59a8b3Srsb PRINT_VOPSTAT(niceflag, setattr);
3345a59a8b3Srsb PRINT_VOPSTAT(niceflag, access);
3355a59a8b3Srsb PRINT_VOPSTAT(niceflag, lookup);
3365a59a8b3Srsb PRINT_VOPSTAT(niceflag, create);
3375a59a8b3Srsb PRINT_VOPSTAT(niceflag, remove);
3385a59a8b3Srsb PRINT_VOPSTAT(niceflag, link);
3395a59a8b3Srsb PRINT_VOPSTAT(niceflag, rename);
3405a59a8b3Srsb PRINT_VOPSTAT(niceflag, mkdir);
3415a59a8b3Srsb PRINT_VOPSTAT(niceflag, rmdir);
3425a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, readdir);
3435a59a8b3Srsb PRINT_VOPSTAT(niceflag, symlink);
3445a59a8b3Srsb PRINT_VOPSTAT(niceflag, readlink);
3455a59a8b3Srsb PRINT_VOPSTAT(niceflag, fsync);
3465a59a8b3Srsb PRINT_VOPSTAT(niceflag, inactive);
3475a59a8b3Srsb PRINT_VOPSTAT(niceflag, fid);
3485a59a8b3Srsb PRINT_VOPSTAT(niceflag, rwlock);
3495a59a8b3Srsb PRINT_VOPSTAT(niceflag, rwunlock);
3505a59a8b3Srsb PRINT_VOPSTAT(niceflag, seek);
3515a59a8b3Srsb PRINT_VOPSTAT(niceflag, cmp);
3525a59a8b3Srsb PRINT_VOPSTAT(niceflag, frlock);
3535a59a8b3Srsb PRINT_VOPSTAT(niceflag, space);
3545a59a8b3Srsb PRINT_VOPSTAT(niceflag, realvp);
3555a59a8b3Srsb PRINT_VOPSTAT(niceflag, getpage);
3565a59a8b3Srsb PRINT_VOPSTAT(niceflag, putpage);
3575a59a8b3Srsb PRINT_VOPSTAT(niceflag, map);
3585a59a8b3Srsb PRINT_VOPSTAT(niceflag, addmap);
3595a59a8b3Srsb PRINT_VOPSTAT(niceflag, delmap);
3605a59a8b3Srsb PRINT_VOPSTAT(niceflag, poll);
3615a59a8b3Srsb PRINT_VOPSTAT(niceflag, dump);
3625a59a8b3Srsb PRINT_VOPSTAT(niceflag, pathconf);
3635a59a8b3Srsb PRINT_VOPSTAT(niceflag, pageio);
3645a59a8b3Srsb PRINT_VOPSTAT(niceflag, dumpctl);
3655a59a8b3Srsb PRINT_VOPSTAT(niceflag, dispose);
3665a59a8b3Srsb PRINT_VOPSTAT(niceflag, getsecattr);
3675a59a8b3Srsb PRINT_VOPSTAT(niceflag, setsecattr);
3685a59a8b3Srsb PRINT_VOPSTAT(niceflag, shrlock);
3695a59a8b3Srsb PRINT_VOPSTAT(niceflag, vnevent);
370c242f9a0Schunli zhang - Sun Microsystems - Irvine United States PRINT_VOPSTAT(niceflag, reqzcbuf);
371c242f9a0Schunli zhang - Sun Microsystems - Irvine United States PRINT_VOPSTAT(niceflag, retzcbuf);
3725a59a8b3Srsb
3735a59a8b3Srsb if (niceflag) {
3745a59a8b3Srsb /* Make it easier on the eyes */
3755a59a8b3Srsb (void) printf("\n");
3765a59a8b3Srsb } else {
3775a59a8b3Srsb (void) printf("%s\n", name);
3785a59a8b3Srsb }
3795a59a8b3Srsb }
3805a59a8b3Srsb
3815a59a8b3Srsb
3825a59a8b3Srsb /*
3835a59a8b3Srsb * Retrieve the vopstats. If kspp (pointer to kstat_t pointer) is non-NULL,
3845a59a8b3Srsb * then pass it back to the caller.
3855a59a8b3Srsb *
3865a59a8b3Srsb * Returns 0 on success, non-zero on failure.
3875a59a8b3Srsb */
3885a59a8b3Srsb int
get_vopstats(kstat_ctl_t * kc,char * ksname,vopstats_t * vsp,kstat_t ** kspp)3895a59a8b3Srsb get_vopstats(kstat_ctl_t *kc, char *ksname, vopstats_t *vsp, kstat_t **kspp)
3905a59a8b3Srsb {
3915a59a8b3Srsb kstat_t *ksp;
3925a59a8b3Srsb
3935a59a8b3Srsb if (ksname == NULL || *ksname == 0)
3945a59a8b3Srsb return (1);
3955a59a8b3Srsb
3965a59a8b3Srsb errno = 0;
3975a59a8b3Srsb /* wait for a possibly up-to-date chain */
3985a59a8b3Srsb while (kstat_chain_update(kc) == -1) {
3995a59a8b3Srsb if (errno == EAGAIN) {
4005a59a8b3Srsb errno = 0;
4015a59a8b3Srsb (void) poll(NULL, 0, RETRY_DELAY);
4025a59a8b3Srsb continue;
4035a59a8b3Srsb }
404757bea67Srsb perror("kstat_chain_update");
4055a59a8b3Srsb exit(1);
4065a59a8b3Srsb }
4075a59a8b3Srsb
4085a59a8b3Srsb if ((ksp = kstat_lookup(kc, NULL, -1, ksname)) == NULL) {
4095a59a8b3Srsb return (1);
4105a59a8b3Srsb }
4115a59a8b3Srsb
4125a59a8b3Srsb if (kstat_read(kc, ksp, vsp) == -1) {
4135a59a8b3Srsb return (1);
4145a59a8b3Srsb }
4155a59a8b3Srsb
4165a59a8b3Srsb if (kspp)
4175a59a8b3Srsb *kspp = ksp;
4185a59a8b3Srsb
4195a59a8b3Srsb return (0);
4205a59a8b3Srsb }
4215a59a8b3Srsb
4225a59a8b3Srsb /*
4235a59a8b3Srsb * Given a file system type name, determine if it's part of the
4245a59a8b3Srsb * exception list of file systems that are not to be displayed.
4255a59a8b3Srsb */
4265a59a8b3Srsb int
is_exception(char * fsname)4275a59a8b3Srsb is_exception(char *fsname)
4285a59a8b3Srsb {
4295a59a8b3Srsb char **xlp; /* Pointer into the exception list */
4305a59a8b3Srsb
4315a59a8b3Srsb static char *exception_list[] = {
4325a59a8b3Srsb "specfs",
4335a59a8b3Srsb "fifofs",
4345a59a8b3Srsb "fd",
4355a59a8b3Srsb "swapfs",
4365a59a8b3Srsb "ctfs",
4375a59a8b3Srsb "objfs",
4385a59a8b3Srsb "nfsdyn",
4395a59a8b3Srsb NULL
4405a59a8b3Srsb };
4415a59a8b3Srsb
4425a59a8b3Srsb for (xlp = &exception_list[0]; *xlp != NULL; xlp++) {
4435a59a8b3Srsb if (strcmp(fsname, *xlp) == 0)
4445a59a8b3Srsb return (1);
4455a59a8b3Srsb }
4465a59a8b3Srsb
4475a59a8b3Srsb return (0);
4485a59a8b3Srsb }
4495a59a8b3Srsb
4505a59a8b3Srsb /*
4515a59a8b3Srsb * Plain and simple, build an array of names for fstypes
4525a59a8b3Srsb * Returns 0, if it encounters a problem.
4535a59a8b3Srsb */
4545a59a8b3Srsb int
build_fstype_list(char *** fstypep)4555a59a8b3Srsb build_fstype_list(char ***fstypep)
4565a59a8b3Srsb {
4575a59a8b3Srsb int i;
4585a59a8b3Srsb int nfstype;
4595a59a8b3Srsb char buf[FSTYPSZ + 1];
4605a59a8b3Srsb
4615a59a8b3Srsb if ((nfstype = sysfs(GETNFSTYP)) < 0) {
462757bea67Srsb perror("sysfs(GETNFSTYP)");
4635a59a8b3Srsb return (0);
4645a59a8b3Srsb }
4655a59a8b3Srsb
4665a59a8b3Srsb if ((*fstypep = calloc(nfstype, sizeof (char *))) == NULL) {
467757bea67Srsb perror("calloc() fstypes");
4685a59a8b3Srsb return (0);
4695a59a8b3Srsb }
4705a59a8b3Srsb
4715a59a8b3Srsb for (i = 1; i < nfstype; i++) {
4725a59a8b3Srsb if (sysfs(GETFSTYP, i, buf) < 0) {
473757bea67Srsb perror("sysfs(GETFSTYP)");
4745a59a8b3Srsb return (0);
4755a59a8b3Srsb }
4765a59a8b3Srsb
4775a59a8b3Srsb if (buf[0] == 0)
4785a59a8b3Srsb continue;
4795a59a8b3Srsb
4805a59a8b3Srsb /* If this is part of the exception list, move on */
4815a59a8b3Srsb if (is_exception(buf))
4825a59a8b3Srsb continue;
4835a59a8b3Srsb
4845a59a8b3Srsb if (((*fstypep)[i] = strdup(buf)) == NULL) {
485757bea67Srsb perror("strdup() fstype name");
4865a59a8b3Srsb return (0);
4875a59a8b3Srsb }
4885a59a8b3Srsb }
4895a59a8b3Srsb
4905a59a8b3Srsb return (i);
4915a59a8b3Srsb }
4925a59a8b3Srsb
4935a59a8b3Srsb /*
4945a59a8b3Srsb * After we're done with getopts(), process the rest of the
4955a59a8b3Srsb * operands. We have three cases and this is the priority:
4965a59a8b3Srsb *
4975a59a8b3Srsb * 1) [ operand... ] interval count
4985a59a8b3Srsb * 2) [ operand... ] interval
4995a59a8b3Srsb * 3) [ operand... ]
5005a59a8b3Srsb *
5015a59a8b3Srsb * The trick is that any of the operands might start with a number or even
5025a59a8b3Srsb * be made up exclusively of numbers (and we have to handle negative numbers
5035a59a8b3Srsb * in case a user/script gets out of line). If we find two operands at the
5045a59a8b3Srsb * end of the list then we claim case 1. If we find only one operand at the
5055a59a8b3Srsb * end made up only of number, then we claim case 2. Otherwise, case 3.
5065a59a8b3Srsb * BTW, argc, argv don't change.
5075a59a8b3Srsb */
5085a59a8b3Srsb int
parse_operands(int argc,char ** argv,int optind,long * interval,long * count,entity_t ** entityp)5095a59a8b3Srsb parse_operands(
5105a59a8b3Srsb int argc,
5115a59a8b3Srsb char **argv,
5125a59a8b3Srsb int optind,
5135a59a8b3Srsb long *interval,
5145a59a8b3Srsb long *count,
5155a59a8b3Srsb entity_t **entityp) /* Array of stat-able entities */
5165a59a8b3Srsb {
5175a59a8b3Srsb int nentities = 0; /* Number of entities found */
5185a59a8b3Srsb int out_of_range; /* Set if 2nd-to-last operand out-of-range */
5195a59a8b3Srsb
5205a59a8b3Srsb if (argc == optind)
5215a59a8b3Srsb return (nentities); /* None found, returns 0 */
5225a59a8b3Srsb /*
5235a59a8b3Srsb * We know exactly what the maximum number of entities is going
5245a59a8b3Srsb * to be: argc - optind
5255a59a8b3Srsb */
5265a59a8b3Srsb if ((*entityp = calloc((argc - optind), sizeof (entity_t))) == NULL) {
527757bea67Srsb perror("calloc() entities");
5285a59a8b3Srsb return (-1);
5295a59a8b3Srsb }
5305a59a8b3Srsb
5315a59a8b3Srsb for (/* void */; argc > optind; optind++) {
5325a59a8b3Srsb char *endptr;
5335a59a8b3Srsb
5345a59a8b3Srsb /* If we have more than two operands left to process */
5355a59a8b3Srsb if ((argc - optind) > 2) {
5365a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind]);
5375a59a8b3Srsb continue;
5385a59a8b3Srsb }
5395a59a8b3Srsb
5405a59a8b3Srsb /* If we're here, then we only have one or two operands left */
5415a59a8b3Srsb errno = 0;
5425a59a8b3Srsb out_of_range = 0;
5435a59a8b3Srsb *interval = strtol(argv[optind], &endptr, 10);
5445a59a8b3Srsb if (*endptr && !isdigit((int)*endptr)) {
5455a59a8b3Srsb /* Operand was not a number */
5465a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind]);
5475a59a8b3Srsb continue;
5485a59a8b3Srsb } else if (errno == ERANGE || *interval <= 0 ||
5495a59a8b3Srsb *interval > MAXLONG) {
5505a59a8b3Srsb /* Operand was a number, just out of range */
5515a59a8b3Srsb out_of_range++;
5525a59a8b3Srsb }
5535a59a8b3Srsb
5545a59a8b3Srsb /*
5555a59a8b3Srsb * The last operand we saw was a number. If it happened to
5565a59a8b3Srsb * be the last operand, then it is the interval...
5575a59a8b3Srsb */
5585a59a8b3Srsb if ((argc - optind) == 1) {
5595a59a8b3Srsb /* ...but we need to check the range. */
5605a59a8b3Srsb if (out_of_range) {
5615a59a8b3Srsb (void) fprintf(stderr, gettext(
5625a59a8b3Srsb "interval must be between 1 and "
5635a59a8b3Srsb "%ld (inclusive)\n"), MAXLONG);
5645a59a8b3Srsb return (-1);
5655a59a8b3Srsb } else {
5665a59a8b3Srsb /*
5675a59a8b3Srsb * The value of the interval is valid. Set
5685a59a8b3Srsb * count to something really big so it goes
5695a59a8b3Srsb * virtually forever.
5705a59a8b3Srsb */
5715a59a8b3Srsb *count = MAXLONG;
5725a59a8b3Srsb break;
5735a59a8b3Srsb }
5745a59a8b3Srsb }
5755a59a8b3Srsb
5765a59a8b3Srsb /*
5775a59a8b3Srsb * At this point, we *might* have the interval, but if the
5785a59a8b3Srsb * next operand isn't a number, then we don't have either
5795a59a8b3Srsb * the interval nor the count. Both must be set to the
5805a59a8b3Srsb * defaults. In that case, both the current and the previous
5815a59a8b3Srsb * operands are stat-able entities.
5825a59a8b3Srsb */
5835a59a8b3Srsb errno = 0;
5845a59a8b3Srsb *count = strtol(argv[optind + 1], &endptr, 10);
5855a59a8b3Srsb if (*endptr && !isdigit((int)*endptr)) {
5865a59a8b3Srsb /*
5875a59a8b3Srsb * Faked out! The last operand wasn't a number so
5885a59a8b3Srsb * the current and previous operands should be
5895a59a8b3Srsb * stat-able entities. We also need to reset interval.
5905a59a8b3Srsb */
5915a59a8b3Srsb *interval = 0;
5925a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind++]);
5935a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind++]);
5945a59a8b3Srsb } else if (out_of_range || errno == ERANGE || *count <= 0) {
5955a59a8b3Srsb (void) fprintf(stderr, gettext(
5965a59a8b3Srsb "Both interval and count must be between 1 "
5975a59a8b3Srsb "and %ld (inclusive)\n"), MAXLONG);
5985a59a8b3Srsb return (-1);
5995a59a8b3Srsb }
6005a59a8b3Srsb break; /* Done! */
6015a59a8b3Srsb }
6025a59a8b3Srsb return (nentities);
6035a59a8b3Srsb }
6045a59a8b3Srsb
6055a59a8b3Srsb /*
6065a59a8b3Srsb * set_mntpt() looks at the entity's name (e_name) and finds its
6075a59a8b3Srsb * mountpoint. To do this, we need to build a list of mountpoints
6085a59a8b3Srsb * from /etc/mnttab. We only need to do this once and we don't do it
6095a59a8b3Srsb * if we don't need to look at any mountpoints.
6105a59a8b3Srsb * Returns 0 on success, non-zero if it couldn't find a mount-point.
6115a59a8b3Srsb */
6125a59a8b3Srsb int
set_mntpt(entity_t * ep)6135a59a8b3Srsb set_mntpt(entity_t *ep)
6145a59a8b3Srsb {
6155a59a8b3Srsb static struct mnt {
6165a59a8b3Srsb struct mnt *m_next;
6175a59a8b3Srsb char *m_mntpt;
6185a59a8b3Srsb ulong_t m_fsid; /* From statvfs(), set only as needed */
6195a59a8b3Srsb } *mnt_list = NULL; /* Linked list of mount-points */
6205a59a8b3Srsb struct mnt *mntp;
62106f33e8dSrsb struct statvfs64 statvfsbuf;
6225a59a8b3Srsb char *original_name = ep->e_name;
6235a59a8b3Srsb char path[PATH_MAX];
6245a59a8b3Srsb
6255a59a8b3Srsb if (original_name == NULL) /* Shouldn't happen */
6265a59a8b3Srsb return (1);
6275a59a8b3Srsb
6285a59a8b3Srsb /* We only set up mnt_list the first time this is called */
6295a59a8b3Srsb if (mnt_list == NULL) {
6305a59a8b3Srsb FILE *fp;
6315a59a8b3Srsb struct mnttab mnttab;
6325a59a8b3Srsb
6335a59a8b3Srsb if ((fp = fopen(MNTTAB, "r")) == NULL) {
6345a59a8b3Srsb perror(MNTTAB);
6355a59a8b3Srsb return (1);
6365a59a8b3Srsb }
6375a59a8b3Srsb resetmnttab(fp);
6385a59a8b3Srsb /*
6395a59a8b3Srsb * We insert at the front of the list so that when we
6405a59a8b3Srsb * search entries we'll have the last mounted entries
6415a59a8b3Srsb * first in the list so that we can match the longest
6425a59a8b3Srsb * mountpoint.
6435a59a8b3Srsb */
6445a59a8b3Srsb while (getmntent(fp, &mnttab) == 0) {
6455a59a8b3Srsb if ((mntp = malloc(sizeof (*mntp))) == NULL) {
646757bea67Srsb perror("malloc() mount list");
6475a59a8b3Srsb return (1);
6485a59a8b3Srsb }
6495a59a8b3Srsb mntp->m_mntpt = strdup(mnttab.mnt_mountp);
6505a59a8b3Srsb mntp->m_next = mnt_list;
6515a59a8b3Srsb mnt_list = mntp;
6525a59a8b3Srsb }
6535a59a8b3Srsb (void) fclose(fp);
6545a59a8b3Srsb }
6555a59a8b3Srsb
6565a59a8b3Srsb if (realpath(original_name, path) == NULL) {
6575a59a8b3Srsb perror(original_name);
6585a59a8b3Srsb return (1);
6595a59a8b3Srsb }
6605a59a8b3Srsb
6615a59a8b3Srsb /*
6625a59a8b3Srsb * Now that we have the path, walk through the mnt_list and
6635a59a8b3Srsb * look for the first (best) match.
6645a59a8b3Srsb */
6655a59a8b3Srsb for (mntp = mnt_list; mntp; mntp = mntp->m_next) {
6665a59a8b3Srsb if (strncmp(path, mntp->m_mntpt, strlen(mntp->m_mntpt)) == 0) {
6675a59a8b3Srsb if (mntp->m_fsid == 0) {
66806f33e8dSrsb if (statvfs64(mntp->m_mntpt, &statvfsbuf)) {
6695a59a8b3Srsb /* Can't statvfs so no match */
6705a59a8b3Srsb continue;
6715a59a8b3Srsb } else {
6725a59a8b3Srsb mntp->m_fsid = statvfsbuf.f_fsid;
6735a59a8b3Srsb }
6745a59a8b3Srsb }
6755a59a8b3Srsb
6765a59a8b3Srsb if (ep->e_fsid != mntp->m_fsid) {
6775a59a8b3Srsb /* No match - Move on */
6785a59a8b3Srsb continue;
6795a59a8b3Srsb }
6805a59a8b3Srsb
6815a59a8b3Srsb break;
6825a59a8b3Srsb }
6835a59a8b3Srsb }
6845a59a8b3Srsb
6855a59a8b3Srsb if (mntp == NULL) {
6865a59a8b3Srsb (void) fprintf(stderr, gettext(
6875a59a8b3Srsb "Can't find mount point for %s\n"), path);
6885a59a8b3Srsb return (1);
6895a59a8b3Srsb }
6905a59a8b3Srsb
6915a59a8b3Srsb ep->e_name = strdup(mntp->m_mntpt);
6925a59a8b3Srsb free(original_name);
6935a59a8b3Srsb return (0);
6945a59a8b3Srsb }
6955a59a8b3Srsb
6965a59a8b3Srsb /*
6975a59a8b3Srsb * We have an array of entities that are potentially stat-able. Using
6985a59a8b3Srsb * the name (e_name) of the entity, attempt to construct a ksname suitable
6995a59a8b3Srsb * for use by kstat_lookup(3kstat) and fill it into the e_ksname member.
7005a59a8b3Srsb *
7015a59a8b3Srsb * We check the e_name against the list of file system types. If there is
7025a59a8b3Srsb * no match then test to see if the path is valid. If the path is valid,
7035a59a8b3Srsb * then determine the mountpoint.
7045a59a8b3Srsb */
7055a59a8b3Srsb void
set_ksnames(entity_t * entities,int nentities,char ** fstypes,int nfstypes)7065a59a8b3Srsb set_ksnames(entity_t *entities, int nentities, char **fstypes, int nfstypes)
7075a59a8b3Srsb {
7085a59a8b3Srsb int i, j;
70906f33e8dSrsb struct statvfs64 statvfsbuf;
7105a59a8b3Srsb
7115a59a8b3Srsb for (i = 0; i < nentities; i++) {
7125a59a8b3Srsb entity_t *ep = &entities[i];
7135a59a8b3Srsb
7145a59a8b3Srsb /* Check the name against the list of fstypes */
7155a59a8b3Srsb for (j = 1; j < nfstypes; j++) {
7165a59a8b3Srsb if (fstypes[j] && ep->e_name &&
7175a59a8b3Srsb strcmp(ep->e_name, fstypes[j]) == 0) {
7185a59a8b3Srsb /* It's a file system type */
7195a59a8b3Srsb ep->e_type = ENTYPE_FSTYPE;
720f5cd957fSRobert Harris (void) snprintf(ep->e_ksname, KSTAT_STRLEN,
721f5cd957fSRobert Harris "%s%s", VOPSTATS_STR, ep->e_name);
7225a59a8b3Srsb /* Now allocate the vopstats array */
7235a59a8b3Srsb ep->e_vs = calloc(VS_SIZE, sizeof (vopstats_t));
7245a59a8b3Srsb if (entities[i].e_vs == NULL) {
725757bea67Srsb perror("calloc() fstype vopstats");
7265a59a8b3Srsb exit(1);
7275a59a8b3Srsb }
7285a59a8b3Srsb break;
7295a59a8b3Srsb }
7305a59a8b3Srsb }
7315a59a8b3Srsb if (j < nfstypes) /* Found it! */
7325a59a8b3Srsb continue;
7335a59a8b3Srsb
7345a59a8b3Srsb /*
7355a59a8b3Srsb * If the entity in the exception list of fstypes, then
7365a59a8b3Srsb * null out the entry so it isn't displayed and move along.
7375a59a8b3Srsb */
7385a59a8b3Srsb if (is_exception(ep->e_name)) {
7395a59a8b3Srsb ep->e_ksname[0] = 0;
7405a59a8b3Srsb continue;
7415a59a8b3Srsb }
7425a59a8b3Srsb
7435a59a8b3Srsb /* If we didn't find it, see if it's a path */
74406f33e8dSrsb if (ep->e_name == NULL || statvfs64(ep->e_name, &statvfsbuf)) {
7455a59a8b3Srsb /* Error - Make sure the entry is nulled out */
7465a59a8b3Srsb ep->e_ksname[0] = 0;
7475a59a8b3Srsb continue;
7485a59a8b3Srsb }
7495a59a8b3Srsb (void) snprintf(ep->e_ksname, KSTAT_STRLEN, "%s%lx",
7505a59a8b3Srsb VOPSTATS_STR, statvfsbuf.f_fsid);
7515a59a8b3Srsb ep->e_fsid = statvfsbuf.f_fsid;
7525a59a8b3Srsb if (set_mntpt(ep)) {
7535a59a8b3Srsb (void) fprintf(stderr,
7545a59a8b3Srsb gettext("Can't determine type of \"%s\"\n"),
7555a59a8b3Srsb ep->e_name ? ep->e_name : gettext("<NULL>"));
7565a59a8b3Srsb } else {
7575a59a8b3Srsb ep->e_type = ENTYPE_MNTPT;
7585a59a8b3Srsb }
7595a59a8b3Srsb
7605a59a8b3Srsb /* Now allocate the vopstats array */
7615a59a8b3Srsb ep->e_vs = calloc(VS_SIZE, sizeof (vopstats_t));
7625a59a8b3Srsb if (entities[i].e_vs == NULL) {
763757bea67Srsb perror("calloc() vopstats array");
7645a59a8b3Srsb exit(1);
7655a59a8b3Srsb }
7665a59a8b3Srsb }
7675a59a8b3Srsb }
7685a59a8b3Srsb
7695a59a8b3Srsb /*
7705a59a8b3Srsb * The idea is that 'dspfunc' should only be modified from the default
7715a59a8b3Srsb * once since the display options are mutually exclusive. If 'dspfunc'
7725a59a8b3Srsb * only contains the default display function, then all is good and we
7735a59a8b3Srsb * can set it to the new display function. Otherwise, bail.
7745a59a8b3Srsb */
7755a59a8b3Srsb void
set_dispfunc(void (** dspfunc)(char *,vopstats_t *,vopstats_t *,int),void (* newfunc)(char *,vopstats_t *,vopstats_t *,int))7765a59a8b3Srsb set_dispfunc(
7775a59a8b3Srsb void (**dspfunc)(char *, vopstats_t *, vopstats_t *, int),
7785a59a8b3Srsb void (*newfunc)(char *, vopstats_t *, vopstats_t *, int))
7795a59a8b3Srsb {
7805a59a8b3Srsb if (*dspfunc != dflt_display) {
7815a59a8b3Srsb (void) fprintf(stderr, gettext(
7825a59a8b3Srsb "%s: Display options -{a|f|i|n|v} are mutually exclusive\n"),
7835a59a8b3Srsb cmdname);
7845a59a8b3Srsb usage();
7855a59a8b3Srsb }
7865a59a8b3Srsb *dspfunc = newfunc;
7875a59a8b3Srsb }
7885a59a8b3Srsb
7895a59a8b3Srsb int
main(int argc,char * argv[])7905a59a8b3Srsb main(int argc, char *argv[])
7915a59a8b3Srsb {
7925a59a8b3Srsb int c;
7935a59a8b3Srsb int i, j; /* Generic counters */
7945a59a8b3Srsb int nentities_found;
7954944376cSJohn Levon int linesout = 0; /* Keeps track of lines printed */
7965a59a8b3Srsb int printhdr = 0; /* Print a header? 0 = no, 1 = yes */
7975a59a8b3Srsb int nfstypes; /* Number of fstypes */
7985a59a8b3Srsb int dispflag = 0; /* Flags for display control */
7995a59a8b3Srsb long count = 0; /* Number of iterations for display */
80000c76d6fStc35445 int forever; /* Run forever */
8015a59a8b3Srsb long interval = 0;
8025a59a8b3Srsb boolean_t fstypes_only = B_FALSE; /* Display fstypes only */
8035a59a8b3Srsb char **fstypes; /* Array of names of all fstypes */
8045a59a8b3Srsb int nentities; /* Number of stat-able entities */
8055a59a8b3Srsb entity_t *entities; /* Array of stat-able entities */
8065a59a8b3Srsb kstat_ctl_t *kc;
8075a59a8b3Srsb void (*dfunc)(char *, vopstats_t *, vopstats_t *, int) = dflt_display;
80800c76d6fStc35445 hrtime_t start_n; /* Start time */
80900c76d6fStc35445 hrtime_t period_n; /* Interval in nanoseconds */
8105a59a8b3Srsb
8115a59a8b3Srsb extern int optind;
8125a59a8b3Srsb
81313c7b6acSrsb (void) setlocale(LC_ALL, "");
81413c7b6acSrsb #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
81513c7b6acSrsb #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
81613c7b6acSrsb #endif
81713c7b6acSrsb (void) textdomain(TEXT_DOMAIN);
81813c7b6acSrsb
819f5cd957fSRobert Harris /* Don't let buffering interfere with piped output. */
820f5cd957fSRobert Harris (void) setvbuf(stdout, NULL, _IOLBF, 0);
821f5cd957fSRobert Harris
8225a59a8b3Srsb cmdname = argv[0];
8235a59a8b3Srsb while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
8245a59a8b3Srsb switch (c) {
8255a59a8b3Srsb
8265a59a8b3Srsb default:
8275a59a8b3Srsb usage();
8285a59a8b3Srsb break;
8295a59a8b3Srsb
8303a401a6bSrsb case 'F': /* Only display available FStypes */
8313a401a6bSrsb fstypes_only = B_TRUE;
8323a401a6bSrsb break;
8333a401a6bSrsb
8343a401a6bSrsb #if PARSABLE_OUTPUT
8355a59a8b3Srsb case 'P': /* Parsable output */
8365a59a8b3Srsb dispflag |= DISP_RAW;
8375a59a8b3Srsb break;
8383a401a6bSrsb #endif /* PARSABLE_OUTPUT */
8395a59a8b3Srsb
8405a59a8b3Srsb case 'T': /* Timestamp */
8415a59a8b3Srsb if (optarg) {
8425a59a8b3Srsb if (strcmp(optarg, "u") == 0) {
8434944376cSJohn Levon timestamp_fmt = UDATE;
8445a59a8b3Srsb } else if (strcmp(optarg, "d") == 0) {
8454944376cSJohn Levon timestamp_fmt = DDATE;
8465a59a8b3Srsb }
8475a59a8b3Srsb }
8485a59a8b3Srsb
8495a59a8b3Srsb /* If it was never set properly... */
8504944376cSJohn Levon if (timestamp_fmt == NODATE) {
851f5cd957fSRobert Harris (void) fprintf(stderr, gettext("%s: -T option "
852f5cd957fSRobert Harris "requires either 'u' or 'd'\n"), cmdname);
8535a59a8b3Srsb usage();
8545a59a8b3Srsb }
8555a59a8b3Srsb break;
8565a59a8b3Srsb
8575a59a8b3Srsb case 'a':
8585a59a8b3Srsb set_dispfunc(&dfunc, attr_display);
8595a59a8b3Srsb break;
8605a59a8b3Srsb
8615a59a8b3Srsb case 'f':
8625a59a8b3Srsb set_dispfunc(&dfunc, vop_display);
8635a59a8b3Srsb break;
8645a59a8b3Srsb
8655a59a8b3Srsb case 'i':
8665a59a8b3Srsb set_dispfunc(&dfunc, io_display);
8675a59a8b3Srsb break;
8685a59a8b3Srsb
8695a59a8b3Srsb case 'n':
8705a59a8b3Srsb set_dispfunc(&dfunc, naming_display);
8715a59a8b3Srsb break;
8725a59a8b3Srsb
8735a59a8b3Srsb case 'v':
8745a59a8b3Srsb set_dispfunc(&dfunc, vm_display);
8755a59a8b3Srsb break;
8765a59a8b3Srsb }
8775a59a8b3Srsb }
8785a59a8b3Srsb
8793a401a6bSrsb #if PARSABLE_OUTPUT
8804944376cSJohn Levon if ((dispflag & DISP_RAW) && (timestamp_fmt != NODATE)) {
8815a59a8b3Srsb (void) fprintf(stderr, gettext(
8825a59a8b3Srsb "-P and -T options are mutually exclusive\n"));
8835a59a8b3Srsb usage();
8845a59a8b3Srsb }
8853a401a6bSrsb #endif /* PARSABLE_OUTPUT */
8865a59a8b3Srsb
8875a59a8b3Srsb /* Gather the list of filesystem types */
8885a59a8b3Srsb if ((nfstypes = build_fstype_list(&fstypes)) == 0) {
8895a59a8b3Srsb (void) fprintf(stderr,
8905a59a8b3Srsb gettext("Can't build list of fstypes\n"));
8915a59a8b3Srsb exit(1);
8925a59a8b3Srsb }
8935a59a8b3Srsb
8945a59a8b3Srsb nentities = parse_operands(
8955a59a8b3Srsb argc, argv, optind, &interval, &count, &entities);
89600c76d6fStc35445 forever = count == MAXLONG;
89700c76d6fStc35445 period_n = (hrtime_t)interval * NANOSEC;
8985a59a8b3Srsb
8995a59a8b3Srsb if (nentities == -1) /* Set of operands didn't parse properly */
9005a59a8b3Srsb usage();
9015a59a8b3Srsb
9023a401a6bSrsb if ((nentities == 0) && (fstypes_only == B_FALSE)) {
9033a401a6bSrsb (void) fprintf(stderr, gettext(
9043a401a6bSrsb "Must specify -F or at least one fstype or mount point\n"));
9053a401a6bSrsb usage();
9063a401a6bSrsb }
9075a59a8b3Srsb
9083a401a6bSrsb if ((nentities > 0) && (fstypes_only == B_TRUE)) {
9093a401a6bSrsb (void) fprintf(stderr, gettext(
9103a401a6bSrsb "Cannot use -F with fstypes or mount points\n"));
9113a401a6bSrsb usage();
9123a401a6bSrsb }
9133a401a6bSrsb
9143a401a6bSrsb /*
9153a401a6bSrsb * If we had no operands (except for interval/count) and we
9163a401a6bSrsb * requested FStypes only (-F), then fill in the entities[]
9173a401a6bSrsb * array with all available fstypes.
9183a401a6bSrsb */
9193a401a6bSrsb if ((nentities == 0) && (fstypes_only == B_TRUE)) {
9205a59a8b3Srsb if ((entities = calloc(nfstypes, sizeof (entity_t))) == NULL) {
921757bea67Srsb perror("calloc() fstype stats");
9225a59a8b3Srsb exit(1);
9235a59a8b3Srsb }
9245a59a8b3Srsb
9255a59a8b3Srsb for (i = 1; i < nfstypes; i++) {
9265a59a8b3Srsb if (fstypes[i]) {
9275a59a8b3Srsb entities[nentities].e_name = strdup(fstypes[i]);
9285a59a8b3Srsb nentities++;
9295a59a8b3Srsb }
9305a59a8b3Srsb }
9315a59a8b3Srsb }
9325a59a8b3Srsb
9335a59a8b3Srsb set_ksnames(entities, nentities, fstypes, nfstypes);
9345a59a8b3Srsb
9355a59a8b3Srsb if ((kc = kstat_open()) == NULL) {
936757bea67Srsb perror("kstat_open");
9375a59a8b3Srsb exit(1);
9385a59a8b3Srsb }
9395a59a8b3Srsb
94000c76d6fStc35445 /* Set start time */
94100c76d6fStc35445 start_n = gethrtime();
94200c76d6fStc35445
9434944376cSJohn Levon /* Initial timestamp */
9444944376cSJohn Levon if (timestamp_fmt != NODATE) {
94526fd7700SKrishnendu Sadhukhan - Sun Microsystems print_timestamp(timestamp_fmt);
9464944376cSJohn Levon linesout++;
9474944376cSJohn Levon }
9484944376cSJohn Levon
9495a59a8b3Srsb /*
9505a59a8b3Srsb * The following loop walks through the entities[] list to "prime
9515a59a8b3Srsb * the pump"
9525a59a8b3Srsb */
9534944376cSJohn Levon for (j = 0, printhdr = 1; j < nentities; j++) {
9545a59a8b3Srsb entity_t *ent = &entities[j];
9555a59a8b3Srsb vopstats_t *vsp = &ent->e_vs[CUR_INDEX];
9565a59a8b3Srsb kstat_t *ksp = NULL;
9575a59a8b3Srsb
9585a59a8b3Srsb if (get_vopstats(kc, ent->e_ksname, vsp, &ksp) == 0) {
9595a59a8b3Srsb (*dfunc)(ent->e_name, NULL, vsp,
9604944376cSJohn Levon dispflag_policy(printhdr, dispflag));
9615a59a8b3Srsb linesout++;
9625a59a8b3Srsb } else {
9635a59a8b3Srsb /*
9645a59a8b3Srsb * If we can't find it the first time through, then
9655a59a8b3Srsb * get rid of it.
9665a59a8b3Srsb */
9675a59a8b3Srsb entities[j].e_ksname[0] = 0;
9685a59a8b3Srsb
9695a59a8b3Srsb /*
9703a401a6bSrsb * If we're only displaying FStypes (-F) then don't
9715a59a8b3Srsb * complain about any file systems that might not
9725a59a8b3Srsb * be loaded. Otherwise, let the user know that
9735a59a8b3Srsb * he chose poorly.
9745a59a8b3Srsb */
9755a59a8b3Srsb if (fstypes_only == B_FALSE) {
9765a59a8b3Srsb (void) fprintf(stderr, gettext(
9775a59a8b3Srsb "No statistics available for %s\n"),
9785a59a8b3Srsb entities[j].e_name);
9795a59a8b3Srsb }
9805a59a8b3Srsb }
9814944376cSJohn Levon printhdr = 0;
9825a59a8b3Srsb }
9835a59a8b3Srsb
98400c76d6fStc35445 if (count > 1)
98500c76d6fStc35445 /* Set up signal handler for SIGCONT */
98600c76d6fStc35445 if (signal(SIGCONT, cont_handler) == SIG_ERR)
98700c76d6fStc35445 fail(1, "signal failed");
98800c76d6fStc35445
98900c76d6fStc35445
9905a59a8b3Srsb BUMP_INDEX(); /* Swap the previous/current indices */
99100c76d6fStc35445 i = 1;
99200c76d6fStc35445 while (forever || i++ <= count) {
9935a59a8b3Srsb /*
9945a59a8b3Srsb * No telling how many lines will be printed in any interval.
9955a59a8b3Srsb * There should be a minimum of HEADERLINES between any
9965a59a8b3Srsb * header. If we exceed that, no big deal.
9975a59a8b3Srsb */
9985a59a8b3Srsb if (linesout > HEADERLINES) {
9995a59a8b3Srsb linesout = 0;
10005a59a8b3Srsb printhdr = 1;
10015a59a8b3Srsb }
100200c76d6fStc35445 /* Have a kip */
100300c76d6fStc35445 sleep_until(&start_n, period_n, forever, &caught_cont);
10045a59a8b3Srsb
10054944376cSJohn Levon if (timestamp_fmt != NODATE) {
100626fd7700SKrishnendu Sadhukhan - Sun Microsystems print_timestamp(timestamp_fmt);
10075a59a8b3Srsb linesout++;
10085a59a8b3Srsb }
10095a59a8b3Srsb
10105a59a8b3Srsb for (j = 0, nentities_found = 0; j < nentities; j++) {
10115a59a8b3Srsb entity_t *ent = &entities[j];
10125a59a8b3Srsb
10135a59a8b3Srsb /*
10145a59a8b3Srsb * If this entry has been cleared, don't attempt
10155a59a8b3Srsb * to process it.
10165a59a8b3Srsb */
10175a59a8b3Srsb if (ent->e_ksname[0] == 0) {
10185a59a8b3Srsb continue;
10195a59a8b3Srsb }
10205a59a8b3Srsb
10215a59a8b3Srsb if (get_vopstats(kc, ent->e_ksname,
10225a59a8b3Srsb &ent->e_vs[CUR_INDEX], NULL) == 0) {
10235a59a8b3Srsb (*dfunc)(ent->e_name, &ent->e_vs[PREV_INDEX],
10245a59a8b3Srsb &ent->e_vs[CUR_INDEX],
10255a59a8b3Srsb dispflag_policy(printhdr, dispflag));
10265a59a8b3Srsb linesout++;
10275a59a8b3Srsb nentities_found++;
10285a59a8b3Srsb } else {
10295a59a8b3Srsb if (ent->e_type == ENTYPE_MNTPT) {
10305a59a8b3Srsb (void) printf(gettext(
10315a59a8b3Srsb "<<mount point no longer "
10325a59a8b3Srsb "available: %s>>\n"), ent->e_name);
10335a59a8b3Srsb } else if (ent->e_type == ENTYPE_FSTYPE) {
10345a59a8b3Srsb (void) printf(gettext(
10355a59a8b3Srsb "<<file system module no longer "
10365a59a8b3Srsb "loaded: %s>>\n"), ent->e_name);
10375a59a8b3Srsb } else {
10385a59a8b3Srsb (void) printf(gettext(
10395a59a8b3Srsb "<<%s no longer available>>\n"),
10405a59a8b3Srsb ent->e_name);
10415a59a8b3Srsb }
10425a59a8b3Srsb /* Disable this so it doesn't print again */
10435a59a8b3Srsb ent->e_ksname[0] = 0;
10445a59a8b3Srsb }
10455a59a8b3Srsb printhdr = 0; /* Always shut this off */
10465a59a8b3Srsb }
10475a59a8b3Srsb BUMP_INDEX(); /* Bump the previous/current indices */
10485a59a8b3Srsb
10495a59a8b3Srsb /*
10505a59a8b3Srsb * If the entities we were observing are no longer there
10515a59a8b3Srsb * (file system modules unloaded, file systems unmounted)
10525a59a8b3Srsb * then we're done.
10535a59a8b3Srsb */
10545a59a8b3Srsb if (nentities_found == 0)
10555a59a8b3Srsb break;
10565a59a8b3Srsb }
10575a59a8b3Srsb
10585a59a8b3Srsb return (0);
10595a59a8b3Srsb }
1060