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 /* 225a59a8b3Srsb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 235a59a8b3Srsb * Use is subject to license terms. 245a59a8b3Srsb */ 255a59a8b3Srsb 265a59a8b3Srsb #pragma ident "%Z%%M% %I% %E% SMI" 275a59a8b3Srsb 285a59a8b3Srsb #include <stdio.h> 295a59a8b3Srsb #include <kstat.h> 305a59a8b3Srsb #include <stdlib.h> 315a59a8b3Srsb #include <string.h> 325a59a8b3Srsb #include <strings.h> 335a59a8b3Srsb #include <errno.h> 345a59a8b3Srsb #include <limits.h> 355a59a8b3Srsb #include <sys/types.h> 365a59a8b3Srsb #include <time.h> 3713c7b6acSrsb #include <langinfo.h> 385a59a8b3Srsb #include <sys/time.h> 395a59a8b3Srsb #include <sys/uio.h> 405a59a8b3Srsb #include <sys/vnode.h> 415a59a8b3Srsb #include <sys/vfs.h> 425a59a8b3Srsb #include <sys/statvfs.h> 435a59a8b3Srsb #include <sys/fstyp.h> 445a59a8b3Srsb #include <sys/fsid.h> 455a59a8b3Srsb #include <sys/mnttab.h> 465a59a8b3Srsb #include <values.h> 475a59a8b3Srsb #include <poll.h> 485a59a8b3Srsb #include <ctype.h> 495a59a8b3Srsb #include <libintl.h> 5013c7b6acSrsb #include <locale.h> 515a59a8b3Srsb 523a401a6bSrsb /* 533a401a6bSrsb * For now, parsable output is turned off. Once we gather feedback and 543a401a6bSrsb * stablize the output format, we'll turn it back on. This prevents 553a401a6bSrsb * the situation where users build tools which depend on a specific 563a401a6bSrsb * format before we declare the output stable. 573a401a6bSrsb */ 583a401a6bSrsb #define PARSABLE_OUTPUT 0 593a401a6bSrsb 603a401a6bSrsb #if PARSABLE_OUTPUT 613a401a6bSrsb #define OPTIONS "FPT:afginv" 623a401a6bSrsb #else 633a401a6bSrsb #define OPTIONS "FT:afginv" 643a401a6bSrsb #endif 655a59a8b3Srsb 665a59a8b3Srsb /* Time stamp values */ 675a59a8b3Srsb #define NODATE 0 /* Default: No time stamp */ 685a59a8b3Srsb #define DDATE 1 /* Standard date format */ 695a59a8b3Srsb #define UDATE 2 /* Internal representation of Unix time */ 705a59a8b3Srsb 715a59a8b3Srsb #define RETRY_DELAY 250 /* Timeout for poll() */ 723a401a6bSrsb #define HEADERLINES 12 /* Number of lines between display headers */ 735a59a8b3Srsb 745a59a8b3Srsb #define LBUFSZ 64 /* Generic size for local buffer */ 755a59a8b3Srsb 765a59a8b3Srsb /* 775a59a8b3Srsb * The following are used for the nicenum() function 785a59a8b3Srsb */ 795a59a8b3Srsb #define KILO_VAL 1024 805a59a8b3Srsb #define ONE_INDEX 3 815a59a8b3Srsb 825a59a8b3Srsb #define NENTITY_INIT 1 /* Initial number of entities to allocate */ 835a59a8b3Srsb 845a59a8b3Srsb /* 855a59a8b3Srsb * We need to have a mechanism for an old/previous and new/current vopstat 865a59a8b3Srsb * structure. We only need two per entity and we can swap between them. 875a59a8b3Srsb */ 885a59a8b3Srsb #define VS_SIZE 2 /* Size of vopstat array */ 895a59a8b3Srsb #define CUR_INDEX (vs_i) 905a59a8b3Srsb #define PREV_INDEX ((vs_i == 0) ? 1 : 0) /* Opposite of CUR_INDEX */ 915a59a8b3Srsb #define BUMP_INDEX() vs_i = ((vs_i == 0) ? 1 : 0) 925a59a8b3Srsb 935a59a8b3Srsb /* 945a59a8b3Srsb * An "entity" is anything we're collecting statistics on, it could 955a59a8b3Srsb * be a mountpoint or an FS-type. 965a59a8b3Srsb * e_name is the name of the entity (e.g. mount point or FS-type) 975a59a8b3Srsb * e_ksname is the name of the associated kstat 985a59a8b3Srsb * e_vs is an array of vopstats. This is used to keep track of "previous" 995a59a8b3Srsb * and "current" vopstats. 1005a59a8b3Srsb */ 1015a59a8b3Srsb typedef struct entity { 1025a59a8b3Srsb char *e_name; /* name of entity */ 1035a59a8b3Srsb vopstats_t *e_vs; /* Array of vopstats */ 1045a59a8b3Srsb ulong_t e_fsid; /* fsid for ENTYPE_MNTPT only */ 1055a59a8b3Srsb int e_type; /* type of entity */ 1065a59a8b3Srsb char e_ksname[KSTAT_STRLEN]; /* kstat name */ 1075a59a8b3Srsb } entity_t; 1085a59a8b3Srsb 1095a59a8b3Srsb /* Types of entities (e_type) */ 1105a59a8b3Srsb #define ENTYPE_UNKNOWN 0 /* UNKNOWN must be zero since we calloc() */ 1115a59a8b3Srsb #define ENTYPE_FSTYPE 1 1125a59a8b3Srsb #define ENTYPE_MNTPT 2 1135a59a8b3Srsb 1145a59a8b3Srsb /* If more sub-one units are added, make sure to adjust ONE_INDEX above */ 1155a59a8b3Srsb static char units[] = "num KMGTPE"; 1165a59a8b3Srsb 1175a59a8b3Srsb static char *cmdname; /* name of this command */ 1185a59a8b3Srsb 1195a59a8b3Srsb static int vs_i = 0; /* Index of current vs[] slot */ 1205a59a8b3Srsb 1215a59a8b3Srsb static void 1225a59a8b3Srsb usage() 1235a59a8b3Srsb { 1243a401a6bSrsb (void) fprintf(stderr, gettext( 1253a401a6bSrsb "Usage: %s [-a|f|i|n|v] [-T d|u] {-F | {fstype | fspath}...} " 1265a59a8b3Srsb "[interval [count]]\n"), cmdname); 1275a59a8b3Srsb exit(2); 1285a59a8b3Srsb } 1295a59a8b3Srsb 1305a59a8b3Srsb /* 1315a59a8b3Srsb * Given a 64-bit number and a starting unit (e.g., n - nanoseconds), 1325a59a8b3Srsb * convert the number to a 5-character representation including any 1335a59a8b3Srsb * decimal point and single-character unit. Put that representation 1345a59a8b3Srsb * into the array "buf" (which had better be big enough). 1355a59a8b3Srsb */ 1365a59a8b3Srsb char * 1375a59a8b3Srsb nicenum(uint64_t num, char unit, char *buf) 1385a59a8b3Srsb { 1395a59a8b3Srsb uint64_t n = num; 1405a59a8b3Srsb int unit_index; 1415a59a8b3Srsb int index; 1425a59a8b3Srsb char u; 1435a59a8b3Srsb 1445a59a8b3Srsb /* If the user passed in a NUL/zero unit, use the blank value for 1 */ 1455a59a8b3Srsb if (unit == '\0') 1465a59a8b3Srsb unit = ' '; 1475a59a8b3Srsb 1485a59a8b3Srsb unit_index = 0; 1495a59a8b3Srsb while (units[unit_index] != unit) { 1505a59a8b3Srsb unit_index++; 1515a59a8b3Srsb if (unit_index > sizeof (units) - 1) { 1525a59a8b3Srsb (void) sprintf(buf, "??"); 1535a59a8b3Srsb return (buf); 1545a59a8b3Srsb } 1555a59a8b3Srsb } 1565a59a8b3Srsb 1575a59a8b3Srsb index = 0; 1585a59a8b3Srsb while (n >= KILO_VAL) { 1595a59a8b3Srsb n = (n + (KILO_VAL / 2)) / KILO_VAL; /* Round up or down */ 1605a59a8b3Srsb index++; 1615a59a8b3Srsb unit_index++; 1625a59a8b3Srsb } 1635a59a8b3Srsb 1645a59a8b3Srsb if (unit_index >= sizeof (units) - 1) { 1655a59a8b3Srsb (void) sprintf(buf, "??"); 1665a59a8b3Srsb return (buf); 1675a59a8b3Srsb } 1685a59a8b3Srsb 1695a59a8b3Srsb u = units[unit_index]; 1705a59a8b3Srsb 1715a59a8b3Srsb if (unit_index == ONE_INDEX) { 1725a59a8b3Srsb (void) sprintf(buf, "%llu", (u_longlong_t)n); 1735a59a8b3Srsb } else if (n < 10 && (num & (num - 1)) != 0) { 1745a59a8b3Srsb (void) sprintf(buf, "%.2f%c", 1755a59a8b3Srsb (double)num / (1ULL << 10 * index), u); 1765a59a8b3Srsb } else if (n < 100 && (num & (num - 1)) != 0) { 1775a59a8b3Srsb (void) sprintf(buf, "%.1f%c", 1785a59a8b3Srsb (double)num / (1ULL << 10 * index), u); 1795a59a8b3Srsb } else { 1805a59a8b3Srsb (void) sprintf(buf, "%llu%c", (u_longlong_t)n, u); 1815a59a8b3Srsb } 1825a59a8b3Srsb 1835a59a8b3Srsb return (buf); 1845a59a8b3Srsb } 1855a59a8b3Srsb 1865a59a8b3Srsb 1875a59a8b3Srsb #define RAWVAL(ptr, member) ((ptr)->member.value.ui64) 1885a59a8b3Srsb #define DELTA(member) \ 1895a59a8b3Srsb (newvsp->member.value.ui64 - (oldvsp ? oldvsp->member.value.ui64 : 0)) 1903a401a6bSrsb 1915a59a8b3Srsb #define PRINTSTAT(isnice, nicestring, rawstring, rawval, unit, buf) \ 1925a59a8b3Srsb (isnice) ? \ 1935a59a8b3Srsb (void) printf((nicestring), nicenum(rawval, unit, buf)) \ 1945a59a8b3Srsb : \ 1955a59a8b3Srsb (void) printf((rawstring), (rawval)) 1965a59a8b3Srsb 1975a59a8b3Srsb /* Values for display flag */ 1985a59a8b3Srsb #define DISP_HEADER 0x1 1995a59a8b3Srsb #define DISP_RAW 0x2 2005a59a8b3Srsb 2015a59a8b3Srsb /* 2025a59a8b3Srsb * The policy for dealing with multiple flags is dealt with here. 2035a59a8b3Srsb * Currently, if we are displaying raw output, then don't allow 2045a59a8b3Srsb * headers to be printed. 2055a59a8b3Srsb */ 2065a59a8b3Srsb int 2075a59a8b3Srsb dispflag_policy(int printhdr, int dispflag) 2085a59a8b3Srsb { 2095a59a8b3Srsb /* If we're not displaying raw output, then allow headers to print */ 2105a59a8b3Srsb if ((dispflag & DISP_RAW) == 0) { 2115a59a8b3Srsb if (printhdr) { 2125a59a8b3Srsb dispflag |= DISP_HEADER; 2135a59a8b3Srsb } 2145a59a8b3Srsb } 2155a59a8b3Srsb 2165a59a8b3Srsb return (dispflag); 2175a59a8b3Srsb } 2185a59a8b3Srsb 2195a59a8b3Srsb static void 2205a59a8b3Srsb dflt_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag) 2215a59a8b3Srsb { 2225a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0); 2235a59a8b3Srsb longlong_t nnewfile; 2245a59a8b3Srsb longlong_t nnamerm; 2255a59a8b3Srsb longlong_t nnamechg; 2265a59a8b3Srsb longlong_t nattrret; 2275a59a8b3Srsb longlong_t nattrchg; 2285a59a8b3Srsb longlong_t nlookup; 2295a59a8b3Srsb longlong_t nreaddir; 2305a59a8b3Srsb longlong_t ndataread; 2315a59a8b3Srsb longlong_t ndatawrite; 2325a59a8b3Srsb longlong_t readthruput; 2335a59a8b3Srsb longlong_t writethruput; 2345a59a8b3Srsb char buf[LBUFSZ]; 2355a59a8b3Srsb 2365a59a8b3Srsb nnewfile = DELTA(ncreate) + DELTA(nmkdir) + DELTA(nsymlink); 2375a59a8b3Srsb nnamerm = DELTA(nremove) + DELTA(nrmdir); 2385a59a8b3Srsb nnamechg = DELTA(nrename) + DELTA(nlink) + DELTA(nsymlink); 2395a59a8b3Srsb nattrret = DELTA(ngetattr) + DELTA(naccess) + 2405a59a8b3Srsb DELTA(ngetsecattr) + DELTA(nfid); 2415a59a8b3Srsb nattrchg = DELTA(nsetattr) + DELTA(nsetsecattr) + DELTA(nspace); 2425a59a8b3Srsb nlookup = DELTA(nlookup); 2435a59a8b3Srsb nreaddir = DELTA(nreaddir); 2445a59a8b3Srsb ndataread = DELTA(nread); 2455a59a8b3Srsb ndatawrite = DELTA(nwrite); 2465a59a8b3Srsb readthruput = DELTA(read_bytes); 2475a59a8b3Srsb writethruput = DELTA(write_bytes); 2485a59a8b3Srsb 2495a59a8b3Srsb if (dispflag & DISP_HEADER) { 250757bea67Srsb (void) printf( 2515a59a8b3Srsb " new name name attr attr lookup rddir read read write write\n" 252757bea67Srsb " file remov chng get set ops ops ops bytes ops bytes\n"); 2535a59a8b3Srsb } 2545a59a8b3Srsb 2555a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nnewfile, ' ', buf); 2565a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nnamerm, ' ', buf); 2575a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nnamechg, ' ', buf); 2585a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nattrret, ' ', buf); 2595a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nattrchg, ' ', buf); 2605a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", nlookup, ' ', buf); 2615a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", nreaddir, ' ', buf); 2625a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", ndataread, ' ', buf); 2635a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", readthruput, ' ', buf); 2645a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", ndatawrite, ' ', buf); 2655a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", writethruput, ' ', buf); 2665a59a8b3Srsb (void) printf("%s\n", name); 2675a59a8b3Srsb } 2685a59a8b3Srsb 2695a59a8b3Srsb static void 2705a59a8b3Srsb io_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag) 2715a59a8b3Srsb { 2725a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0); 2735a59a8b3Srsb char buf[LBUFSZ]; 2745a59a8b3Srsb 2755a59a8b3Srsb if (dispflag & DISP_HEADER) { 276757bea67Srsb (void) printf( 2775a59a8b3Srsb " read read write write rddir rddir rwlock rwulock\n" 278757bea67Srsb " ops bytes ops bytes ops bytes ops ops\n"); 2795a59a8b3Srsb } 2805a59a8b3Srsb 2815a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nread), ' ', buf); 2825a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(read_bytes), ' ', buf); 2835a59a8b3Srsb 2845a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nwrite), ' ', buf); 2855a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(write_bytes), ' ', buf); 2865a59a8b3Srsb 2875a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreaddir), ' ', buf); 2885a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(readdir_bytes), ' ', buf); 2895a59a8b3Srsb 2905a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nrwlock), ' ', buf); 2915a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrwunlock), ' ', buf); 2925a59a8b3Srsb 2935a59a8b3Srsb (void) printf("%s\n", name); 2945a59a8b3Srsb } 2955a59a8b3Srsb 2965a59a8b3Srsb static void 2975a59a8b3Srsb vm_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag) 2985a59a8b3Srsb { 2995a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0); 3005a59a8b3Srsb char buf[LBUFSZ]; 3015a59a8b3Srsb 3025a59a8b3Srsb if (dispflag & DISP_HEADER) { 303757bea67Srsb (void) printf(" map addmap delmap getpag putpag pagio\n"); 3045a59a8b3Srsb } 3055a59a8b3Srsb 3065a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nmap), ' ', buf); 3075a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(naddmap), ' ', buf); 3085a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ndelmap), ' ', buf); 3095a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetpage), ' ', buf); 3105a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nputpage), ' ', buf); 3115a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(npageio), ' ', buf); 3125a59a8b3Srsb (void) printf("%s\n", name); 3135a59a8b3Srsb } 3145a59a8b3Srsb 3155a59a8b3Srsb static void 3165a59a8b3Srsb attr_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 (dispflag & DISP_HEADER) { 322757bea67Srsb (void) printf("getattr setattr getsec setsec\n"); 3235a59a8b3Srsb } 3245a59a8b3Srsb 3255a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetattr), ' ', buf); 3265a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsetattr), ' ', buf); 3275a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(ngetsecattr), ' ', buf); 3285a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsetsecattr), ' ', buf); 3295a59a8b3Srsb 3305a59a8b3Srsb (void) printf("%s\n", name); 3315a59a8b3Srsb } 3325a59a8b3Srsb 3335a59a8b3Srsb static void 3345a59a8b3Srsb naming_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag) 3355a59a8b3Srsb { 3365a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0); 3375a59a8b3Srsb char buf[LBUFSZ]; 3385a59a8b3Srsb 3395a59a8b3Srsb if (dispflag & DISP_HEADER) { 340757bea67Srsb (void) printf( 341757bea67Srsb "lookup creat remov link renam mkdir rmdir rddir symlnk rdlnk\n"); 3425a59a8b3Srsb } 3435a59a8b3Srsb 3445a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nlookup), ' ', buf); 3455a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(ncreate), ' ', buf); 3465a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nremove), ' ', buf); 3475a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nlink), ' ', buf); 3485a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrename), ' ', buf); 3495a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nmkdir), ' ', buf); 3505a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nrmdir), ' ', buf); 3515a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreaddir), ' ', buf); 3525a59a8b3Srsb PRINTSTAT(niceflag, " %5s ", "%lld:", DELTA(nsymlink), ' ', buf); 3535a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(nreadlink), ' ', buf); 3545a59a8b3Srsb (void) printf("%s\n", name); 3555a59a8b3Srsb } 3565a59a8b3Srsb 3575a59a8b3Srsb 3585a59a8b3Srsb #define PRINT_VOPSTAT_CMN(niceflag, vop) \ 3595a59a8b3Srsb if (niceflag) \ 3605a59a8b3Srsb (void) printf("%10s ", #vop); \ 3615a59a8b3Srsb PRINTSTAT(niceflag, "%5s ", "%lld:", DELTA(n##vop), ' ', buf); 3625a59a8b3Srsb 3635a59a8b3Srsb #define PRINT_VOPSTAT(niceflag, vop) \ 3645a59a8b3Srsb PRINT_VOPSTAT_CMN(niceflag, vop); \ 3655a59a8b3Srsb if (niceflag) \ 3665a59a8b3Srsb (void) printf("\n"); 3675a59a8b3Srsb 3685a59a8b3Srsb #define PRINT_VOPSTAT_IO(niceflag, vop) \ 3695a59a8b3Srsb PRINT_VOPSTAT_CMN(niceflag, vop); \ 3705a59a8b3Srsb PRINTSTAT(niceflag, " %5s\n", "%lld:", \ 3715a59a8b3Srsb DELTA(vop##_bytes), ' ', buf); 3725a59a8b3Srsb 3735a59a8b3Srsb static void 3745a59a8b3Srsb vop_display(char *name, vopstats_t *oldvsp, vopstats_t *newvsp, int dispflag) 3755a59a8b3Srsb { 3765a59a8b3Srsb int niceflag = ((dispflag & DISP_RAW) == 0); 3775a59a8b3Srsb char buf[LBUFSZ]; 3785a59a8b3Srsb 3795a59a8b3Srsb if (niceflag) { 3805a59a8b3Srsb (void) printf("%s\n", name); 381757bea67Srsb (void) printf(" operation #ops bytes\n"); 3825a59a8b3Srsb } 3835a59a8b3Srsb 3845a59a8b3Srsb PRINT_VOPSTAT(niceflag, open); 3855a59a8b3Srsb PRINT_VOPSTAT(niceflag, close); 3865a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, read); 3875a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, write); 3885a59a8b3Srsb PRINT_VOPSTAT(niceflag, ioctl); 3895a59a8b3Srsb PRINT_VOPSTAT(niceflag, setfl); 3905a59a8b3Srsb PRINT_VOPSTAT(niceflag, getattr); 3915a59a8b3Srsb PRINT_VOPSTAT(niceflag, setattr); 3925a59a8b3Srsb PRINT_VOPSTAT(niceflag, access); 3935a59a8b3Srsb PRINT_VOPSTAT(niceflag, lookup); 3945a59a8b3Srsb PRINT_VOPSTAT(niceflag, create); 3955a59a8b3Srsb PRINT_VOPSTAT(niceflag, remove); 3965a59a8b3Srsb PRINT_VOPSTAT(niceflag, link); 3975a59a8b3Srsb PRINT_VOPSTAT(niceflag, rename); 3985a59a8b3Srsb PRINT_VOPSTAT(niceflag, mkdir); 3995a59a8b3Srsb PRINT_VOPSTAT(niceflag, rmdir); 4005a59a8b3Srsb PRINT_VOPSTAT_IO(niceflag, readdir); 4015a59a8b3Srsb PRINT_VOPSTAT(niceflag, symlink); 4025a59a8b3Srsb PRINT_VOPSTAT(niceflag, readlink); 4035a59a8b3Srsb PRINT_VOPSTAT(niceflag, fsync); 4045a59a8b3Srsb PRINT_VOPSTAT(niceflag, inactive); 4055a59a8b3Srsb PRINT_VOPSTAT(niceflag, fid); 4065a59a8b3Srsb PRINT_VOPSTAT(niceflag, rwlock); 4075a59a8b3Srsb PRINT_VOPSTAT(niceflag, rwunlock); 4085a59a8b3Srsb PRINT_VOPSTAT(niceflag, seek); 4095a59a8b3Srsb PRINT_VOPSTAT(niceflag, cmp); 4105a59a8b3Srsb PRINT_VOPSTAT(niceflag, frlock); 4115a59a8b3Srsb PRINT_VOPSTAT(niceflag, space); 4125a59a8b3Srsb PRINT_VOPSTAT(niceflag, realvp); 4135a59a8b3Srsb PRINT_VOPSTAT(niceflag, getpage); 4145a59a8b3Srsb PRINT_VOPSTAT(niceflag, putpage); 4155a59a8b3Srsb PRINT_VOPSTAT(niceflag, map); 4165a59a8b3Srsb PRINT_VOPSTAT(niceflag, addmap); 4175a59a8b3Srsb PRINT_VOPSTAT(niceflag, delmap); 4185a59a8b3Srsb PRINT_VOPSTAT(niceflag, poll); 4195a59a8b3Srsb PRINT_VOPSTAT(niceflag, dump); 4205a59a8b3Srsb PRINT_VOPSTAT(niceflag, pathconf); 4215a59a8b3Srsb PRINT_VOPSTAT(niceflag, pageio); 4225a59a8b3Srsb PRINT_VOPSTAT(niceflag, dumpctl); 4235a59a8b3Srsb PRINT_VOPSTAT(niceflag, dispose); 4245a59a8b3Srsb PRINT_VOPSTAT(niceflag, getsecattr); 4255a59a8b3Srsb PRINT_VOPSTAT(niceflag, setsecattr); 4265a59a8b3Srsb PRINT_VOPSTAT(niceflag, shrlock); 4275a59a8b3Srsb PRINT_VOPSTAT(niceflag, vnevent); 4285a59a8b3Srsb 4295a59a8b3Srsb if (niceflag) { 4305a59a8b3Srsb /* Make it easier on the eyes */ 4315a59a8b3Srsb (void) printf("\n"); 4325a59a8b3Srsb } else { 4335a59a8b3Srsb (void) printf("%s\n", name); 4345a59a8b3Srsb } 4355a59a8b3Srsb } 4365a59a8b3Srsb 4375a59a8b3Srsb 4385a59a8b3Srsb /* 4395a59a8b3Srsb * Retrieve the vopstats. If kspp (pointer to kstat_t pointer) is non-NULL, 4405a59a8b3Srsb * then pass it back to the caller. 4415a59a8b3Srsb * 4425a59a8b3Srsb * Returns 0 on success, non-zero on failure. 4435a59a8b3Srsb */ 4445a59a8b3Srsb int 4455a59a8b3Srsb get_vopstats(kstat_ctl_t *kc, char *ksname, vopstats_t *vsp, kstat_t **kspp) 4465a59a8b3Srsb { 4475a59a8b3Srsb kstat_t *ksp; 4485a59a8b3Srsb 4495a59a8b3Srsb if (ksname == NULL || *ksname == 0) 4505a59a8b3Srsb return (1); 4515a59a8b3Srsb 4525a59a8b3Srsb errno = 0; 4535a59a8b3Srsb /* wait for a possibly up-to-date chain */ 4545a59a8b3Srsb while (kstat_chain_update(kc) == -1) { 4555a59a8b3Srsb if (errno == EAGAIN) { 4565a59a8b3Srsb errno = 0; 4575a59a8b3Srsb (void) poll(NULL, 0, RETRY_DELAY); 4585a59a8b3Srsb continue; 4595a59a8b3Srsb } 460757bea67Srsb perror("kstat_chain_update"); 4615a59a8b3Srsb exit(1); 4625a59a8b3Srsb } 4635a59a8b3Srsb 4645a59a8b3Srsb if ((ksp = kstat_lookup(kc, NULL, -1, ksname)) == NULL) { 4655a59a8b3Srsb return (1); 4665a59a8b3Srsb } 4675a59a8b3Srsb 4685a59a8b3Srsb if (kstat_read(kc, ksp, vsp) == -1) { 4695a59a8b3Srsb return (1); 4705a59a8b3Srsb } 4715a59a8b3Srsb 4725a59a8b3Srsb if (kspp) 4735a59a8b3Srsb *kspp = ksp; 4745a59a8b3Srsb 4755a59a8b3Srsb return (0); 4765a59a8b3Srsb } 4775a59a8b3Srsb 4785a59a8b3Srsb /* 4795a59a8b3Srsb * Given a file system type name, determine if it's part of the 4805a59a8b3Srsb * exception list of file systems that are not to be displayed. 4815a59a8b3Srsb */ 4825a59a8b3Srsb int 4835a59a8b3Srsb is_exception(char *fsname) 4845a59a8b3Srsb { 4855a59a8b3Srsb char **xlp; /* Pointer into the exception list */ 4865a59a8b3Srsb 4875a59a8b3Srsb static char *exception_list[] = { 4885a59a8b3Srsb "specfs", 4895a59a8b3Srsb "fifofs", 4905a59a8b3Srsb "fd", 4915a59a8b3Srsb "swapfs", 4925a59a8b3Srsb "ctfs", 4935a59a8b3Srsb "objfs", 4945a59a8b3Srsb "nfsdyn", 4955a59a8b3Srsb NULL 4965a59a8b3Srsb }; 4975a59a8b3Srsb 4985a59a8b3Srsb for (xlp = &exception_list[0]; *xlp != NULL; xlp++) { 4995a59a8b3Srsb if (strcmp(fsname, *xlp) == 0) 5005a59a8b3Srsb return (1); 5015a59a8b3Srsb } 5025a59a8b3Srsb 5035a59a8b3Srsb return (0); 5045a59a8b3Srsb } 5055a59a8b3Srsb 5065a59a8b3Srsb /* 5075a59a8b3Srsb * Plain and simple, build an array of names for fstypes 5085a59a8b3Srsb * Returns 0, if it encounters a problem. 5095a59a8b3Srsb */ 5105a59a8b3Srsb int 5115a59a8b3Srsb build_fstype_list(char ***fstypep) 5125a59a8b3Srsb { 5135a59a8b3Srsb int i; 5145a59a8b3Srsb int nfstype; 5155a59a8b3Srsb char buf[FSTYPSZ + 1]; 5165a59a8b3Srsb 5175a59a8b3Srsb if ((nfstype = sysfs(GETNFSTYP)) < 0) { 518757bea67Srsb perror("sysfs(GETNFSTYP)"); 5195a59a8b3Srsb return (0); 5205a59a8b3Srsb } 5215a59a8b3Srsb 5225a59a8b3Srsb if ((*fstypep = calloc(nfstype, sizeof (char *))) == NULL) { 523757bea67Srsb perror("calloc() fstypes"); 5245a59a8b3Srsb return (0); 5255a59a8b3Srsb } 5265a59a8b3Srsb 5275a59a8b3Srsb for (i = 1; i < nfstype; i++) { 5285a59a8b3Srsb if (sysfs(GETFSTYP, i, buf) < 0) { 529757bea67Srsb perror("sysfs(GETFSTYP)"); 5305a59a8b3Srsb return (0); 5315a59a8b3Srsb } 5325a59a8b3Srsb 5335a59a8b3Srsb if (buf[0] == 0) 5345a59a8b3Srsb continue; 5355a59a8b3Srsb 5365a59a8b3Srsb /* If this is part of the exception list, move on */ 5375a59a8b3Srsb if (is_exception(buf)) 5385a59a8b3Srsb continue; 5395a59a8b3Srsb 5405a59a8b3Srsb if (((*fstypep)[i] = strdup(buf)) == NULL) { 541757bea67Srsb perror("strdup() fstype name"); 5425a59a8b3Srsb return (0); 5435a59a8b3Srsb } 5445a59a8b3Srsb } 5455a59a8b3Srsb 5465a59a8b3Srsb return (i); 5475a59a8b3Srsb } 5485a59a8b3Srsb 5495a59a8b3Srsb /* 5505a59a8b3Srsb * After we're done with getopts(), process the rest of the 5515a59a8b3Srsb * operands. We have three cases and this is the priority: 5525a59a8b3Srsb * 5535a59a8b3Srsb * 1) [ operand... ] interval count 5545a59a8b3Srsb * 2) [ operand... ] interval 5555a59a8b3Srsb * 3) [ operand... ] 5565a59a8b3Srsb * 5575a59a8b3Srsb * The trick is that any of the operands might start with a number or even 5585a59a8b3Srsb * be made up exclusively of numbers (and we have to handle negative numbers 5595a59a8b3Srsb * in case a user/script gets out of line). If we find two operands at the 5605a59a8b3Srsb * end of the list then we claim case 1. If we find only one operand at the 5615a59a8b3Srsb * end made up only of number, then we claim case 2. Otherwise, case 3. 5625a59a8b3Srsb * BTW, argc, argv don't change. 5635a59a8b3Srsb */ 5645a59a8b3Srsb int 5655a59a8b3Srsb parse_operands( 5665a59a8b3Srsb int argc, 5675a59a8b3Srsb char **argv, 5685a59a8b3Srsb int optind, 5695a59a8b3Srsb long *interval, 5705a59a8b3Srsb long *count, 5715a59a8b3Srsb entity_t **entityp) /* Array of stat-able entities */ 5725a59a8b3Srsb { 5735a59a8b3Srsb int nentities = 0; /* Number of entities found */ 5745a59a8b3Srsb int out_of_range; /* Set if 2nd-to-last operand out-of-range */ 5755a59a8b3Srsb 5765a59a8b3Srsb if (argc == optind) 5775a59a8b3Srsb return (nentities); /* None found, returns 0 */ 5785a59a8b3Srsb /* 5795a59a8b3Srsb * We know exactly what the maximum number of entities is going 5805a59a8b3Srsb * to be: argc - optind 5815a59a8b3Srsb */ 5825a59a8b3Srsb if ((*entityp = calloc((argc - optind), sizeof (entity_t))) == NULL) { 583757bea67Srsb perror("calloc() entities"); 5845a59a8b3Srsb return (-1); 5855a59a8b3Srsb } 5865a59a8b3Srsb 5875a59a8b3Srsb for (/* void */; argc > optind; optind++) { 5885a59a8b3Srsb char *endptr; 5895a59a8b3Srsb 5905a59a8b3Srsb /* If we have more than two operands left to process */ 5915a59a8b3Srsb if ((argc - optind) > 2) { 5925a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind]); 5935a59a8b3Srsb continue; 5945a59a8b3Srsb } 5955a59a8b3Srsb 5965a59a8b3Srsb /* If we're here, then we only have one or two operands left */ 5975a59a8b3Srsb errno = 0; 5985a59a8b3Srsb out_of_range = 0; 5995a59a8b3Srsb *interval = strtol(argv[optind], &endptr, 10); 6005a59a8b3Srsb if (*endptr && !isdigit((int)*endptr)) { 6015a59a8b3Srsb /* Operand was not a number */ 6025a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind]); 6035a59a8b3Srsb continue; 6045a59a8b3Srsb } else if (errno == ERANGE || *interval <= 0 || 6055a59a8b3Srsb *interval > MAXLONG) { 6065a59a8b3Srsb /* Operand was a number, just out of range */ 6075a59a8b3Srsb out_of_range++; 6085a59a8b3Srsb } 6095a59a8b3Srsb 6105a59a8b3Srsb /* 6115a59a8b3Srsb * The last operand we saw was a number. If it happened to 6125a59a8b3Srsb * be the last operand, then it is the interval... 6135a59a8b3Srsb */ 6145a59a8b3Srsb if ((argc - optind) == 1) { 6155a59a8b3Srsb /* ...but we need to check the range. */ 6165a59a8b3Srsb if (out_of_range) { 6175a59a8b3Srsb (void) fprintf(stderr, gettext( 6185a59a8b3Srsb "interval must be between 1 and " 6195a59a8b3Srsb "%ld (inclusive)\n"), MAXLONG); 6205a59a8b3Srsb return (-1); 6215a59a8b3Srsb } else { 6225a59a8b3Srsb /* 6235a59a8b3Srsb * The value of the interval is valid. Set 6245a59a8b3Srsb * count to something really big so it goes 6255a59a8b3Srsb * virtually forever. 6265a59a8b3Srsb */ 6275a59a8b3Srsb *count = MAXLONG; 6285a59a8b3Srsb break; 6295a59a8b3Srsb } 6305a59a8b3Srsb } 6315a59a8b3Srsb 6325a59a8b3Srsb /* 6335a59a8b3Srsb * At this point, we *might* have the interval, but if the 6345a59a8b3Srsb * next operand isn't a number, then we don't have either 6355a59a8b3Srsb * the interval nor the count. Both must be set to the 6365a59a8b3Srsb * defaults. In that case, both the current and the previous 6375a59a8b3Srsb * operands are stat-able entities. 6385a59a8b3Srsb */ 6395a59a8b3Srsb errno = 0; 6405a59a8b3Srsb *count = strtol(argv[optind + 1], &endptr, 10); 6415a59a8b3Srsb if (*endptr && !isdigit((int)*endptr)) { 6425a59a8b3Srsb /* 6435a59a8b3Srsb * Faked out! The last operand wasn't a number so 6445a59a8b3Srsb * the current and previous operands should be 6455a59a8b3Srsb * stat-able entities. We also need to reset interval. 6465a59a8b3Srsb */ 6475a59a8b3Srsb *interval = 0; 6485a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind++]); 6495a59a8b3Srsb (*entityp)[nentities++].e_name = strdup(argv[optind++]); 6505a59a8b3Srsb } else if (out_of_range || errno == ERANGE || *count <= 0) { 6515a59a8b3Srsb (void) fprintf(stderr, gettext( 6525a59a8b3Srsb "Both interval and count must be between 1 " 6535a59a8b3Srsb "and %ld (inclusive)\n"), MAXLONG); 6545a59a8b3Srsb return (-1); 6555a59a8b3Srsb } 6565a59a8b3Srsb break; /* Done! */ 6575a59a8b3Srsb } 6585a59a8b3Srsb return (nentities); 6595a59a8b3Srsb } 6605a59a8b3Srsb 6615a59a8b3Srsb /* 6625a59a8b3Srsb * set_mntpt() looks at the entity's name (e_name) and finds its 6635a59a8b3Srsb * mountpoint. To do this, we need to build a list of mountpoints 6645a59a8b3Srsb * from /etc/mnttab. We only need to do this once and we don't do it 6655a59a8b3Srsb * if we don't need to look at any mountpoints. 6665a59a8b3Srsb * Returns 0 on success, non-zero if it couldn't find a mount-point. 6675a59a8b3Srsb */ 6685a59a8b3Srsb int 6695a59a8b3Srsb set_mntpt(entity_t *ep) 6705a59a8b3Srsb { 6715a59a8b3Srsb static struct mnt { 6725a59a8b3Srsb struct mnt *m_next; 6735a59a8b3Srsb char *m_mntpt; 6745a59a8b3Srsb ulong_t m_fsid; /* From statvfs(), set only as needed */ 6755a59a8b3Srsb } *mnt_list = NULL; /* Linked list of mount-points */ 6765a59a8b3Srsb struct mnt *mntp; 677*06f33e8dSrsb struct statvfs64 statvfsbuf; 6785a59a8b3Srsb char *original_name = ep->e_name; 6795a59a8b3Srsb char path[PATH_MAX]; 6805a59a8b3Srsb 6815a59a8b3Srsb if (original_name == NULL) /* Shouldn't happen */ 6825a59a8b3Srsb return (1); 6835a59a8b3Srsb 6845a59a8b3Srsb /* We only set up mnt_list the first time this is called */ 6855a59a8b3Srsb if (mnt_list == NULL) { 6865a59a8b3Srsb FILE *fp; 6875a59a8b3Srsb struct mnttab mnttab; 6885a59a8b3Srsb 6895a59a8b3Srsb if ((fp = fopen(MNTTAB, "r")) == NULL) { 6905a59a8b3Srsb perror(MNTTAB); 6915a59a8b3Srsb return (1); 6925a59a8b3Srsb } 6935a59a8b3Srsb resetmnttab(fp); 6945a59a8b3Srsb /* 6955a59a8b3Srsb * We insert at the front of the list so that when we 6965a59a8b3Srsb * search entries we'll have the last mounted entries 6975a59a8b3Srsb * first in the list so that we can match the longest 6985a59a8b3Srsb * mountpoint. 6995a59a8b3Srsb */ 7005a59a8b3Srsb while (getmntent(fp, &mnttab) == 0) { 7015a59a8b3Srsb if ((mntp = malloc(sizeof (*mntp))) == NULL) { 702757bea67Srsb perror("malloc() mount list"); 7035a59a8b3Srsb return (1); 7045a59a8b3Srsb } 7055a59a8b3Srsb mntp->m_mntpt = strdup(mnttab.mnt_mountp); 7065a59a8b3Srsb mntp->m_next = mnt_list; 7075a59a8b3Srsb mnt_list = mntp; 7085a59a8b3Srsb } 7095a59a8b3Srsb (void) fclose(fp); 7105a59a8b3Srsb } 7115a59a8b3Srsb 7125a59a8b3Srsb if (realpath(original_name, path) == NULL) { 7135a59a8b3Srsb perror(original_name); 7145a59a8b3Srsb return (1); 7155a59a8b3Srsb } 7165a59a8b3Srsb 7175a59a8b3Srsb /* 7185a59a8b3Srsb * Now that we have the path, walk through the mnt_list and 7195a59a8b3Srsb * look for the first (best) match. 7205a59a8b3Srsb */ 7215a59a8b3Srsb for (mntp = mnt_list; mntp; mntp = mntp->m_next) { 7225a59a8b3Srsb if (strncmp(path, mntp->m_mntpt, strlen(mntp->m_mntpt)) == 0) { 7235a59a8b3Srsb if (mntp->m_fsid == 0) { 724*06f33e8dSrsb if (statvfs64(mntp->m_mntpt, &statvfsbuf)) { 7255a59a8b3Srsb /* Can't statvfs so no match */ 7265a59a8b3Srsb continue; 7275a59a8b3Srsb } else { 7285a59a8b3Srsb mntp->m_fsid = statvfsbuf.f_fsid; 7295a59a8b3Srsb } 7305a59a8b3Srsb } 7315a59a8b3Srsb 7325a59a8b3Srsb if (ep->e_fsid != mntp->m_fsid) { 7335a59a8b3Srsb /* No match - Move on */ 7345a59a8b3Srsb continue; 7355a59a8b3Srsb } 7365a59a8b3Srsb 7375a59a8b3Srsb break; 7385a59a8b3Srsb } 7395a59a8b3Srsb } 7405a59a8b3Srsb 7415a59a8b3Srsb if (mntp == NULL) { 7425a59a8b3Srsb (void) fprintf(stderr, gettext( 7435a59a8b3Srsb "Can't find mount point for %s\n"), path); 7445a59a8b3Srsb return (1); 7455a59a8b3Srsb } 7465a59a8b3Srsb 7475a59a8b3Srsb ep->e_name = strdup(mntp->m_mntpt); 7485a59a8b3Srsb free(original_name); 7495a59a8b3Srsb return (0); 7505a59a8b3Srsb } 7515a59a8b3Srsb 7525a59a8b3Srsb /* 7535a59a8b3Srsb * We have an array of entities that are potentially stat-able. Using 7545a59a8b3Srsb * the name (e_name) of the entity, attempt to construct a ksname suitable 7555a59a8b3Srsb * for use by kstat_lookup(3kstat) and fill it into the e_ksname member. 7565a59a8b3Srsb * 7575a59a8b3Srsb * We check the e_name against the list of file system types. If there is 7585a59a8b3Srsb * no match then test to see if the path is valid. If the path is valid, 7595a59a8b3Srsb * then determine the mountpoint. 7605a59a8b3Srsb */ 7615a59a8b3Srsb void 7625a59a8b3Srsb set_ksnames(entity_t *entities, int nentities, char **fstypes, int nfstypes) 7635a59a8b3Srsb { 7645a59a8b3Srsb int i, j; 765*06f33e8dSrsb struct statvfs64 statvfsbuf; 7665a59a8b3Srsb 7675a59a8b3Srsb for (i = 0; i < nentities; i++) { 7685a59a8b3Srsb entity_t *ep = &entities[i]; 7695a59a8b3Srsb 7705a59a8b3Srsb /* Check the name against the list of fstypes */ 7715a59a8b3Srsb for (j = 1; j < nfstypes; j++) { 7725a59a8b3Srsb if (fstypes[j] && ep->e_name && 7735a59a8b3Srsb strcmp(ep->e_name, fstypes[j]) == 0) { 7745a59a8b3Srsb /* It's a file system type */ 7755a59a8b3Srsb ep->e_type = ENTYPE_FSTYPE; 7765a59a8b3Srsb (void) snprintf(ep->e_ksname, 7775a59a8b3Srsb KSTAT_STRLEN, "%s%s", 7785a59a8b3Srsb VOPSTATS_STR, ep->e_name); 7795a59a8b3Srsb /* Now allocate the vopstats array */ 7805a59a8b3Srsb ep->e_vs = calloc(VS_SIZE, sizeof (vopstats_t)); 7815a59a8b3Srsb if (entities[i].e_vs == NULL) { 782757bea67Srsb perror("calloc() fstype vopstats"); 7835a59a8b3Srsb exit(1); 7845a59a8b3Srsb } 7855a59a8b3Srsb break; 7865a59a8b3Srsb } 7875a59a8b3Srsb } 7885a59a8b3Srsb if (j < nfstypes) /* Found it! */ 7895a59a8b3Srsb continue; 7905a59a8b3Srsb 7915a59a8b3Srsb /* 7925a59a8b3Srsb * If the entity in the exception list of fstypes, then 7935a59a8b3Srsb * null out the entry so it isn't displayed and move along. 7945a59a8b3Srsb */ 7955a59a8b3Srsb if (is_exception(ep->e_name)) { 7965a59a8b3Srsb ep->e_ksname[0] = 0; 7975a59a8b3Srsb continue; 7985a59a8b3Srsb } 7995a59a8b3Srsb 8005a59a8b3Srsb /* If we didn't find it, see if it's a path */ 801*06f33e8dSrsb if (ep->e_name == NULL || statvfs64(ep->e_name, &statvfsbuf)) { 8025a59a8b3Srsb /* Error - Make sure the entry is nulled out */ 8035a59a8b3Srsb ep->e_ksname[0] = 0; 8045a59a8b3Srsb continue; 8055a59a8b3Srsb } 8065a59a8b3Srsb (void) snprintf(ep->e_ksname, KSTAT_STRLEN, "%s%lx", 8075a59a8b3Srsb VOPSTATS_STR, statvfsbuf.f_fsid); 8085a59a8b3Srsb ep->e_fsid = statvfsbuf.f_fsid; 8095a59a8b3Srsb if (set_mntpt(ep)) { 8105a59a8b3Srsb (void) fprintf(stderr, 8115a59a8b3Srsb gettext("Can't determine type of \"%s\"\n"), 8125a59a8b3Srsb ep->e_name ? ep->e_name : gettext("<NULL>")); 8135a59a8b3Srsb } else { 8145a59a8b3Srsb ep->e_type = ENTYPE_MNTPT; 8155a59a8b3Srsb } 8165a59a8b3Srsb 8175a59a8b3Srsb /* Now allocate the vopstats array */ 8185a59a8b3Srsb ep->e_vs = calloc(VS_SIZE, sizeof (vopstats_t)); 8195a59a8b3Srsb if (entities[i].e_vs == NULL) { 820757bea67Srsb perror("calloc() vopstats array"); 8215a59a8b3Srsb exit(1); 8225a59a8b3Srsb } 8235a59a8b3Srsb } 8245a59a8b3Srsb } 8255a59a8b3Srsb 8265a59a8b3Srsb void 8275a59a8b3Srsb print_time(int type) 8285a59a8b3Srsb { 8295a59a8b3Srsb time_t t; 83013c7b6acSrsb static char *fmt = NULL; /* Time format */ 83113c7b6acSrsb 83213c7b6acSrsb /* We only need to retrieve this once per invocation */ 83313c7b6acSrsb if (fmt == NULL) { 83413c7b6acSrsb fmt = nl_langinfo(_DATE_FMT); 83513c7b6acSrsb } 8365a59a8b3Srsb 8375a59a8b3Srsb if (time(&t) != -1) { 8385a59a8b3Srsb if (type == UDATE) { 8395a59a8b3Srsb (void) printf("%ld\n", t); 8405a59a8b3Srsb } else if (type == DDATE) { 84113c7b6acSrsb char dstr[64]; 84213c7b6acSrsb int len; 8435a59a8b3Srsb 84413c7b6acSrsb len = strftime(dstr, sizeof (dstr), fmt, localtime(&t)); 84513c7b6acSrsb if (len > 0) { 84613c7b6acSrsb (void) printf("%s\n", dstr); 8475a59a8b3Srsb } 8485a59a8b3Srsb } 8495a59a8b3Srsb } 8505a59a8b3Srsb } 8515a59a8b3Srsb 8525a59a8b3Srsb /* 8535a59a8b3Srsb * The idea is that 'dspfunc' should only be modified from the default 8545a59a8b3Srsb * once since the display options are mutually exclusive. If 'dspfunc' 8555a59a8b3Srsb * only contains the default display function, then all is good and we 8565a59a8b3Srsb * can set it to the new display function. Otherwise, bail. 8575a59a8b3Srsb */ 8585a59a8b3Srsb void 8595a59a8b3Srsb set_dispfunc( 8605a59a8b3Srsb void (**dspfunc)(char *, vopstats_t *, vopstats_t *, int), 8615a59a8b3Srsb void (*newfunc)(char *, vopstats_t *, vopstats_t *, int)) 8625a59a8b3Srsb { 8635a59a8b3Srsb if (*dspfunc != dflt_display) { 8645a59a8b3Srsb (void) fprintf(stderr, gettext( 8655a59a8b3Srsb "%s: Display options -{a|f|i|n|v} are mutually exclusive\n"), 8665a59a8b3Srsb cmdname); 8675a59a8b3Srsb usage(); 8685a59a8b3Srsb } 8695a59a8b3Srsb *dspfunc = newfunc; 8705a59a8b3Srsb } 8715a59a8b3Srsb 8725a59a8b3Srsb int 8735a59a8b3Srsb main(int argc, char *argv[]) 8745a59a8b3Srsb { 8755a59a8b3Srsb int c; 8765a59a8b3Srsb int i, j; /* Generic counters */ 8775a59a8b3Srsb int nentities_found; 8785a59a8b3Srsb int linesout; /* Keeps track of lines printed */ 8795a59a8b3Srsb int printhdr = 0; /* Print a header? 0 = no, 1 = yes */ 8805a59a8b3Srsb int nfstypes; /* Number of fstypes */ 8815a59a8b3Srsb int dispflag = 0; /* Flags for display control */ 8825a59a8b3Srsb int timestamp = NODATE; /* Default: no time stamp */ 8835a59a8b3Srsb long count = 0; /* Number of iterations for display */ 8845a59a8b3Srsb long interval = 0; 8855a59a8b3Srsb boolean_t fstypes_only = B_FALSE; /* Display fstypes only */ 8865a59a8b3Srsb char **fstypes; /* Array of names of all fstypes */ 8875a59a8b3Srsb int nentities; /* Number of stat-able entities */ 8885a59a8b3Srsb entity_t *entities; /* Array of stat-able entities */ 8895a59a8b3Srsb kstat_ctl_t *kc; 8905a59a8b3Srsb void (*dfunc)(char *, vopstats_t *, vopstats_t *, int) = dflt_display; 8915a59a8b3Srsb 8925a59a8b3Srsb extern int optind; 8935a59a8b3Srsb 89413c7b6acSrsb (void) setlocale(LC_ALL, ""); 89513c7b6acSrsb #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 89613c7b6acSrsb #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 89713c7b6acSrsb #endif 89813c7b6acSrsb (void) textdomain(TEXT_DOMAIN); 89913c7b6acSrsb 9005a59a8b3Srsb cmdname = argv[0]; 9015a59a8b3Srsb while ((c = getopt(argc, argv, OPTIONS)) != EOF) { 9025a59a8b3Srsb switch (c) { 9035a59a8b3Srsb 9045a59a8b3Srsb default: 9055a59a8b3Srsb usage(); 9065a59a8b3Srsb break; 9075a59a8b3Srsb 9083a401a6bSrsb case 'F': /* Only display available FStypes */ 9093a401a6bSrsb fstypes_only = B_TRUE; 9103a401a6bSrsb break; 9113a401a6bSrsb 9123a401a6bSrsb #if PARSABLE_OUTPUT 9135a59a8b3Srsb case 'P': /* Parsable output */ 9145a59a8b3Srsb dispflag |= DISP_RAW; 9155a59a8b3Srsb break; 9163a401a6bSrsb #endif /* PARSABLE_OUTPUT */ 9175a59a8b3Srsb 9185a59a8b3Srsb case 'T': /* Timestamp */ 9195a59a8b3Srsb if (optarg) { 9205a59a8b3Srsb if (strcmp(optarg, "u") == 0) { 9215a59a8b3Srsb timestamp = UDATE; 9225a59a8b3Srsb } else if (strcmp(optarg, "d") == 0) { 9235a59a8b3Srsb timestamp = DDATE; 9245a59a8b3Srsb } 9255a59a8b3Srsb } 9265a59a8b3Srsb 9275a59a8b3Srsb /* If it was never set properly... */ 9285a59a8b3Srsb if (timestamp == NODATE) { 9295a59a8b3Srsb (void) fprintf(stderr, gettext( 9305a59a8b3Srsb "%s: -T option requires either 'u' or 'd'\n"), 9315a59a8b3Srsb cmdname); 9325a59a8b3Srsb usage(); 9335a59a8b3Srsb } 9345a59a8b3Srsb break; 9355a59a8b3Srsb 9365a59a8b3Srsb case 'a': 9375a59a8b3Srsb set_dispfunc(&dfunc, attr_display); 9385a59a8b3Srsb break; 9395a59a8b3Srsb 9405a59a8b3Srsb case 'f': 9415a59a8b3Srsb set_dispfunc(&dfunc, vop_display); 9425a59a8b3Srsb break; 9435a59a8b3Srsb 9445a59a8b3Srsb case 'i': 9455a59a8b3Srsb set_dispfunc(&dfunc, io_display); 9465a59a8b3Srsb break; 9475a59a8b3Srsb 9485a59a8b3Srsb case 'n': 9495a59a8b3Srsb set_dispfunc(&dfunc, naming_display); 9505a59a8b3Srsb break; 9515a59a8b3Srsb 9525a59a8b3Srsb case 'v': 9535a59a8b3Srsb set_dispfunc(&dfunc, vm_display); 9545a59a8b3Srsb break; 9555a59a8b3Srsb } 9565a59a8b3Srsb } 9575a59a8b3Srsb 9583a401a6bSrsb #if PARSABLE_OUTPUT 9595a59a8b3Srsb if ((dispflag & DISP_RAW) && (timestamp != NODATE)) { 9605a59a8b3Srsb (void) fprintf(stderr, gettext( 9615a59a8b3Srsb "-P and -T options are mutually exclusive\n")); 9625a59a8b3Srsb usage(); 9635a59a8b3Srsb } 9643a401a6bSrsb #endif /* PARSABLE_OUTPUT */ 9655a59a8b3Srsb 9665a59a8b3Srsb /* Gather the list of filesystem types */ 9675a59a8b3Srsb if ((nfstypes = build_fstype_list(&fstypes)) == 0) { 9685a59a8b3Srsb (void) fprintf(stderr, 9695a59a8b3Srsb gettext("Can't build list of fstypes\n")); 9705a59a8b3Srsb exit(1); 9715a59a8b3Srsb } 9725a59a8b3Srsb 9735a59a8b3Srsb nentities = parse_operands( 9745a59a8b3Srsb argc, argv, optind, &interval, &count, &entities); 9755a59a8b3Srsb 9765a59a8b3Srsb if (nentities == -1) /* Set of operands didn't parse properly */ 9775a59a8b3Srsb usage(); 9785a59a8b3Srsb 9793a401a6bSrsb if ((nentities == 0) && (fstypes_only == B_FALSE)) { 9803a401a6bSrsb (void) fprintf(stderr, gettext( 9813a401a6bSrsb "Must specify -F or at least one fstype or mount point\n")); 9823a401a6bSrsb usage(); 9833a401a6bSrsb } 9845a59a8b3Srsb 9853a401a6bSrsb if ((nentities > 0) && (fstypes_only == B_TRUE)) { 9863a401a6bSrsb (void) fprintf(stderr, gettext( 9873a401a6bSrsb "Cannot use -F with fstypes or mount points\n")); 9883a401a6bSrsb usage(); 9893a401a6bSrsb } 9903a401a6bSrsb 9913a401a6bSrsb /* 9923a401a6bSrsb * If we had no operands (except for interval/count) and we 9933a401a6bSrsb * requested FStypes only (-F), then fill in the entities[] 9943a401a6bSrsb * array with all available fstypes. 9953a401a6bSrsb */ 9963a401a6bSrsb if ((nentities == 0) && (fstypes_only == B_TRUE)) { 9975a59a8b3Srsb if ((entities = calloc(nfstypes, sizeof (entity_t))) == NULL) { 998757bea67Srsb perror("calloc() fstype stats"); 9995a59a8b3Srsb exit(1); 10005a59a8b3Srsb } 10015a59a8b3Srsb 10025a59a8b3Srsb for (i = 1; i < nfstypes; i++) { 10035a59a8b3Srsb if (fstypes[i]) { 10045a59a8b3Srsb entities[nentities].e_name = strdup(fstypes[i]); 10055a59a8b3Srsb nentities++; 10065a59a8b3Srsb } 10075a59a8b3Srsb } 10085a59a8b3Srsb } 10095a59a8b3Srsb 10105a59a8b3Srsb set_ksnames(entities, nentities, fstypes, nfstypes); 10115a59a8b3Srsb 10125a59a8b3Srsb if ((kc = kstat_open()) == NULL) { 1013757bea67Srsb perror("kstat_open"); 10145a59a8b3Srsb exit(1); 10155a59a8b3Srsb } 10165a59a8b3Srsb 10175a59a8b3Srsb /* 10185a59a8b3Srsb * The following loop walks through the entities[] list to "prime 10195a59a8b3Srsb * the pump" 10205a59a8b3Srsb */ 10215a59a8b3Srsb for (j = 0, linesout = 0; j < nentities; j++) { 10225a59a8b3Srsb entity_t *ent = &entities[j]; 10235a59a8b3Srsb vopstats_t *vsp = &ent->e_vs[CUR_INDEX]; 10245a59a8b3Srsb kstat_t *ksp = NULL; 10255a59a8b3Srsb 10265a59a8b3Srsb if (get_vopstats(kc, ent->e_ksname, vsp, &ksp) == 0) { 10275a59a8b3Srsb (*dfunc)(ent->e_name, NULL, vsp, 10285a59a8b3Srsb dispflag_policy(linesout == 0, dispflag)); 10295a59a8b3Srsb linesout++; 10305a59a8b3Srsb } else { 10315a59a8b3Srsb /* 10325a59a8b3Srsb * If we can't find it the first time through, then 10335a59a8b3Srsb * get rid of it. 10345a59a8b3Srsb */ 10355a59a8b3Srsb entities[j].e_ksname[0] = 0; 10365a59a8b3Srsb 10375a59a8b3Srsb /* 10383a401a6bSrsb * If we're only displaying FStypes (-F) then don't 10395a59a8b3Srsb * complain about any file systems that might not 10405a59a8b3Srsb * be loaded. Otherwise, let the user know that 10415a59a8b3Srsb * he chose poorly. 10425a59a8b3Srsb */ 10435a59a8b3Srsb if (fstypes_only == B_FALSE) { 10445a59a8b3Srsb (void) fprintf(stderr, gettext( 10455a59a8b3Srsb "No statistics available for %s\n"), 10465a59a8b3Srsb entities[j].e_name); 10475a59a8b3Srsb } 10485a59a8b3Srsb } 10495a59a8b3Srsb } 10505a59a8b3Srsb 10515a59a8b3Srsb BUMP_INDEX(); /* Swap the previous/current indices */ 10525a59a8b3Srsb for (i = 1; i <= count; i++) { 10535a59a8b3Srsb /* 10545a59a8b3Srsb * No telling how many lines will be printed in any interval. 10555a59a8b3Srsb * There should be a minimum of HEADERLINES between any 10565a59a8b3Srsb * header. If we exceed that, no big deal. 10575a59a8b3Srsb */ 10585a59a8b3Srsb if (linesout > HEADERLINES) { 10595a59a8b3Srsb linesout = 0; 10605a59a8b3Srsb printhdr = 1; 10615a59a8b3Srsb } 10625a59a8b3Srsb (void) poll(NULL, 0, interval*1000); 10635a59a8b3Srsb 10645a59a8b3Srsb if (timestamp) { 10655a59a8b3Srsb print_time(timestamp); 10665a59a8b3Srsb linesout++; 10675a59a8b3Srsb } 10685a59a8b3Srsb 10695a59a8b3Srsb for (j = 0, nentities_found = 0; j < nentities; j++) { 10705a59a8b3Srsb entity_t *ent = &entities[j]; 10715a59a8b3Srsb 10725a59a8b3Srsb /* 10735a59a8b3Srsb * If this entry has been cleared, don't attempt 10745a59a8b3Srsb * to process it. 10755a59a8b3Srsb */ 10765a59a8b3Srsb if (ent->e_ksname[0] == 0) { 10775a59a8b3Srsb continue; 10785a59a8b3Srsb } 10795a59a8b3Srsb 10805a59a8b3Srsb if (get_vopstats(kc, ent->e_ksname, 10815a59a8b3Srsb &ent->e_vs[CUR_INDEX], NULL) == 0) { 10825a59a8b3Srsb (*dfunc)(ent->e_name, &ent->e_vs[PREV_INDEX], 10835a59a8b3Srsb &ent->e_vs[CUR_INDEX], 10845a59a8b3Srsb dispflag_policy(printhdr, dispflag)); 10855a59a8b3Srsb linesout++; 10865a59a8b3Srsb nentities_found++; 10875a59a8b3Srsb } else { 10885a59a8b3Srsb if (ent->e_type == ENTYPE_MNTPT) { 10895a59a8b3Srsb (void) printf(gettext( 10905a59a8b3Srsb "<<mount point no longer " 10915a59a8b3Srsb "available: %s>>\n"), ent->e_name); 10925a59a8b3Srsb } else if (ent->e_type == ENTYPE_FSTYPE) { 10935a59a8b3Srsb (void) printf(gettext( 10945a59a8b3Srsb "<<file system module no longer " 10955a59a8b3Srsb "loaded: %s>>\n"), ent->e_name); 10965a59a8b3Srsb } else { 10975a59a8b3Srsb (void) printf(gettext( 10985a59a8b3Srsb "<<%s no longer available>>\n"), 10995a59a8b3Srsb ent->e_name); 11005a59a8b3Srsb } 11015a59a8b3Srsb /* Disable this so it doesn't print again */ 11025a59a8b3Srsb ent->e_ksname[0] = 0; 11035a59a8b3Srsb } 11045a59a8b3Srsb printhdr = 0; /* Always shut this off */ 11055a59a8b3Srsb } 11065a59a8b3Srsb BUMP_INDEX(); /* Bump the previous/current indices */ 11075a59a8b3Srsb 11085a59a8b3Srsb /* 11095a59a8b3Srsb * If the entities we were observing are no longer there 11105a59a8b3Srsb * (file system modules unloaded, file systems unmounted) 11115a59a8b3Srsb * then we're done. 11125a59a8b3Srsb */ 11135a59a8b3Srsb if (nentities_found == 0) 11145a59a8b3Srsb break; 11155a59a8b3Srsb } 11165a59a8b3Srsb 11175a59a8b3Srsb return (0); 11185a59a8b3Srsb } 1119