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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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