1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*0Sstevel@tonic-gate /* All Rights Reserved */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate /* 27*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28*0Sstevel@tonic-gate * Use is subject to license terms. 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <stdio.h> 35*0Sstevel@tonic-gate #include <stdarg.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <locale.h> 38*0Sstevel@tonic-gate #include <libintl.h> 39*0Sstevel@tonic-gate #include <stdlib.h> 40*0Sstevel@tonic-gate #include <ftw.h> 41*0Sstevel@tonic-gate #include <errno.h> 42*0Sstevel@tonic-gate #include <sys/types.h> 43*0Sstevel@tonic-gate #include <unistd.h> 44*0Sstevel@tonic-gate #include <sys/statvfs.h> 45*0Sstevel@tonic-gate #include <sys/stat.h> 46*0Sstevel@tonic-gate #include <sys/param.h> 47*0Sstevel@tonic-gate #include <sys/mnttab.h> 48*0Sstevel@tonic-gate #include <sys/mntent.h> 49*0Sstevel@tonic-gate #include <sys/vfstab.h> 50*0Sstevel@tonic-gate #include <sys/wait.h> 51*0Sstevel@tonic-gate #include <sys/mkdev.h> 52*0Sstevel@tonic-gate #include <sys/int_limits.h> 53*0Sstevel@tonic-gate #include <sys/zone.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #include "fslib.h" 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate extern char *default_fstype(char *); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate /* 60*0Sstevel@tonic-gate * General notice: 61*0Sstevel@tonic-gate * String pointers in this code may point to statically allocated memory 62*0Sstevel@tonic-gate * or dynamically allocated memory. Furthermore, a dynamically allocated 63*0Sstevel@tonic-gate * string may be pointed to by more than one pointer. This does not pose 64*0Sstevel@tonic-gate * a problem because malloc'ed memory is never free'd (so we don't need 65*0Sstevel@tonic-gate * to remember which pointers point to malloc'ed memory). 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * TRANSLATION_NOTE 70*0Sstevel@tonic-gate * Only strings passed as arguments to the TRANSLATE macro need to 71*0Sstevel@tonic-gate * be translated. 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #ifndef MNTTYPE_LOFS 75*0Sstevel@tonic-gate #define MNTTYPE_LOFS "lofs" 76*0Sstevel@tonic-gate #endif 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate #define EQ(s1, s2) (strcmp(s1, s2) == 0) 79*0Sstevel@tonic-gate #define NEW(type) xmalloc(sizeof (type)) 80*0Sstevel@tonic-gate #define CLEAR(var) (void) memset(&(var), 0, sizeof (var)) 81*0Sstevel@tonic-gate #define MAX(a, b) ((a) > (b) ? (a) : (b)) 82*0Sstevel@tonic-gate #define MAX3(a, b, c) MAX(a, MAX(b, c)) 83*0Sstevel@tonic-gate #define TRANSLATE(s) new_string(gettext(s)) 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate #define MAX_OPTIONS 36 86*0Sstevel@tonic-gate #define N_FSTYPES 20 87*0Sstevel@tonic-gate #define MOUNT_TABLE_ENTRIES 40 /* initial allocation */ 88*0Sstevel@tonic-gate #define MSGBUF_SIZE 1024 89*0Sstevel@tonic-gate #define LINEBUF_SIZE 256 /* either input or output lines */ 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate #define BLOCK_SIZE 512 /* when reporting in terms of blocks */ 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate #define DEVNM_CMD "devnm" 94*0Sstevel@tonic-gate #define FS_LIBPATH "/usr/lib/fs/" 95*0Sstevel@tonic-gate #define MOUNT_TAB "/etc/mnttab" 96*0Sstevel@tonic-gate #define VFS_TAB "/etc/vfstab" 97*0Sstevel@tonic-gate #define REMOTE_FS "/etc/dfs/fstypes" 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate #define NUL '\0' 100*0Sstevel@tonic-gate #define FALSE 0 101*0Sstevel@tonic-gate #define TRUE 1 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* 104*0Sstevel@tonic-gate * Formatting constants 105*0Sstevel@tonic-gate */ 106*0Sstevel@tonic-gate #define IBCS2_FILESYSTEM_WIDTH 15 /* Truncate to match ISC/SCO */ 107*0Sstevel@tonic-gate #define IBCS2_MOUNT_POINT_WIDTH 10 /* Truncate to match ISC/SCO */ 108*0Sstevel@tonic-gate #define FILESYSTEM_WIDTH 20 109*0Sstevel@tonic-gate #define MOUNT_POINT_WIDTH 19 110*0Sstevel@tonic-gate #define SPECIAL_DEVICE_WIDTH 18 111*0Sstevel@tonic-gate #define FSTYPE_WIDTH 8 112*0Sstevel@tonic-gate #define BLOCK_WIDTH 8 113*0Sstevel@tonic-gate #define NFILES_WIDTH 8 114*0Sstevel@tonic-gate #ifdef XPG4 115*0Sstevel@tonic-gate #define KBYTE_WIDTH 11 116*0Sstevel@tonic-gate #define AVAILABLE_WIDTH 10 117*0Sstevel@tonic-gate #else 118*0Sstevel@tonic-gate #define KBYTE_WIDTH 7 119*0Sstevel@tonic-gate #define AVAILABLE_WIDTH 6 120*0Sstevel@tonic-gate #endif 121*0Sstevel@tonic-gate #define SCALED_WIDTH 6 122*0Sstevel@tonic-gate #define CAPACITY_WIDTH 9 123*0Sstevel@tonic-gate #define BSIZE_WIDTH 6 124*0Sstevel@tonic-gate #define FRAGSIZE_WIDTH 7 125*0Sstevel@tonic-gate #define FSID_WIDTH 7 126*0Sstevel@tonic-gate #define FLAG_WIDTH 8 127*0Sstevel@tonic-gate #define NAMELEN_WIDTH 7 128*0Sstevel@tonic-gate #define MNT_SPEC_WIDTH MOUNT_POINT_WIDTH + SPECIAL_DEVICE_WIDTH + 2 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * Flags for the errmsg() function 132*0Sstevel@tonic-gate */ 133*0Sstevel@tonic-gate #define ERR_NOFLAGS 0x0 134*0Sstevel@tonic-gate #define ERR_NONAME 0x1 /* don't include the program name */ 135*0Sstevel@tonic-gate /* as a prefix */ 136*0Sstevel@tonic-gate #define ERR_FATAL 0x2 /* call exit after printing the */ 137*0Sstevel@tonic-gate /* message */ 138*0Sstevel@tonic-gate #define ERR_PERROR 0x4 /* append an errno explanation to */ 139*0Sstevel@tonic-gate /* the message */ 140*0Sstevel@tonic-gate #define ERR_USAGE 0x8 /* print the usage line after the */ 141*0Sstevel@tonic-gate /* message */ 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #define NUMBER_WIDTH 40 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate typedef char numbuf_t[ NUMBER_WIDTH ]; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* 151*0Sstevel@tonic-gate * We use bool_int instead of int to make clear which variables are 152*0Sstevel@tonic-gate * supposed to be boolean 153*0Sstevel@tonic-gate */ 154*0Sstevel@tonic-gate typedef int bool_int; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate struct mtab_entry { 157*0Sstevel@tonic-gate bool_int mte_dev_is_valid; 158*0Sstevel@tonic-gate dev_t mte_dev; 159*0Sstevel@tonic-gate bool_int mte_ignore; /* the "ignore" option was set */ 160*0Sstevel@tonic-gate struct extmnttab *mte_mount; 161*0Sstevel@tonic-gate }; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate struct df_request { 165*0Sstevel@tonic-gate bool_int dfr_valid; 166*0Sstevel@tonic-gate char *dfr_cmd_arg; /* what the user specified */ 167*0Sstevel@tonic-gate struct mtab_entry *dfr_mte; 168*0Sstevel@tonic-gate char *dfr_fstype; 169*0Sstevel@tonic-gate int dfr_index; /* to make qsort stable */ 170*0Sstevel@tonic-gate }; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate #define DFR_MOUNT_POINT(dfrp) (dfrp)->dfr_mte->mte_mount->mnt_mountp 173*0Sstevel@tonic-gate #define DFR_SPECIAL(dfrp) (dfrp)->dfr_mte->mte_mount->mnt_special 174*0Sstevel@tonic-gate #define DFR_ISMOUNTEDFS(dfrp) ((dfrp)->dfr_mte != NULL) 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate #define DFRP(p) ((struct df_request *)(p)) 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate typedef void (*output_func)(struct df_request *, struct statvfs64 *); 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate struct df_output { 181*0Sstevel@tonic-gate output_func dfo_func; /* function that will do the output */ 182*0Sstevel@tonic-gate int dfo_flags; 183*0Sstevel@tonic-gate }; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Output flags 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate #define DFO_NOFLAGS 0x0 189*0Sstevel@tonic-gate #define DFO_HEADER 0x1 /* output preceded by header */ 190*0Sstevel@tonic-gate #define DFO_STATVFS 0x2 /* must do a statvfs64(2) */ 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate static char *program_name; 194*0Sstevel@tonic-gate static char df_options[MAX_OPTIONS] = "-"; 195*0Sstevel@tonic-gate static size_t df_options_len = 1; 196*0Sstevel@tonic-gate static char *o_option_arg; /* arg to the -o option */ 197*0Sstevel@tonic-gate static char *FSType; 198*0Sstevel@tonic-gate static char *remote_fstypes[N_FSTYPES+1]; /* allocate an extra one */ 199*0Sstevel@tonic-gate /* to use as a terminator */ 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate /* 202*0Sstevel@tonic-gate * The following three variables support an in-memory copy of the mount table 203*0Sstevel@tonic-gate * to speedup searches. 204*0Sstevel@tonic-gate */ 205*0Sstevel@tonic-gate static struct mtab_entry *mount_table; /* array of mtab_entry's */ 206*0Sstevel@tonic-gate static size_t mount_table_entries; 207*0Sstevel@tonic-gate static size_t mount_table_allocated_entries; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate static bool_int F_option; 210*0Sstevel@tonic-gate static bool_int V_option; 211*0Sstevel@tonic-gate static bool_int P_option; /* Added for XCU4 compliance */ 212*0Sstevel@tonic-gate static bool_int Z_option; 213*0Sstevel@tonic-gate static bool_int v_option; 214*0Sstevel@tonic-gate #ifdef _iBCS2 215*0Sstevel@tonic-gate char *sysv3_set; 216*0Sstevel@tonic-gate #endif /* _iBCS2 */ 217*0Sstevel@tonic-gate static bool_int a_option; 218*0Sstevel@tonic-gate static bool_int b_option; 219*0Sstevel@tonic-gate static bool_int e_option; 220*0Sstevel@tonic-gate static bool_int g_option; 221*0Sstevel@tonic-gate static bool_int h_option; 222*0Sstevel@tonic-gate static bool_int k_option; 223*0Sstevel@tonic-gate static bool_int l_option; 224*0Sstevel@tonic-gate static bool_int n_option; 225*0Sstevel@tonic-gate static bool_int t_option; 226*0Sstevel@tonic-gate static bool_int o_option; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate static bool_int tty_output; 229*0Sstevel@tonic-gate static bool_int use_scaling; 230*0Sstevel@tonic-gate static int scale; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate static void usage(void); 233*0Sstevel@tonic-gate static void do_devnm(int, char **); 234*0Sstevel@tonic-gate static void do_df(int, char **); 235*0Sstevel@tonic-gate static void parse_options(int, char **); 236*0Sstevel@tonic-gate static char *basename(char *); 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate void 240*0Sstevel@tonic-gate main(int argc, char *argv[]) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 245*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 246*0Sstevel@tonic-gate #endif 247*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate program_name = basename(argv[0]); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate #ifdef _iBCS2 252*0Sstevel@tonic-gate sysv3_set = getenv("SYSV3"); 253*0Sstevel@tonic-gate #endif /* _iBCS2 */ 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate if (EQ(program_name, DEVNM_CMD)) 256*0Sstevel@tonic-gate do_devnm(argc, argv); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate parse_options(argc, argv); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * The k_option implies SunOS 4.x compatibility: when the special 262*0Sstevel@tonic-gate * device name is too long the line will be split except when the 263*0Sstevel@tonic-gate * output has been redirected. 264*0Sstevel@tonic-gate * This is also valid for the -h option. 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate if (use_scaling || k_option || P_option || v_option) 268*0Sstevel@tonic-gate tty_output = isatty(1); 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate do_df(argc - optind, &argv[optind]); 271*0Sstevel@tonic-gate /* NOTREACHED */ 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * Prints an error message to stderr. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate /* VARARGS2 */ 279*0Sstevel@tonic-gate static void 280*0Sstevel@tonic-gate errmsg(int flags, char *fmt, ...) 281*0Sstevel@tonic-gate { 282*0Sstevel@tonic-gate char buf[MSGBUF_SIZE]; 283*0Sstevel@tonic-gate va_list ap; 284*0Sstevel@tonic-gate int cc; 285*0Sstevel@tonic-gate int offset; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if (flags & ERR_NONAME) 288*0Sstevel@tonic-gate offset = 0; 289*0Sstevel@tonic-gate else 290*0Sstevel@tonic-gate offset = sprintf(buf, "%s: ", program_name); 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate va_start(ap, fmt); 293*0Sstevel@tonic-gate cc = vsprintf(&buf[offset], gettext(fmt), ap); 294*0Sstevel@tonic-gate offset += cc; 295*0Sstevel@tonic-gate va_end(ap); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate if (flags & ERR_PERROR) { 298*0Sstevel@tonic-gate if (buf[offset-1] != ' ') 299*0Sstevel@tonic-gate (void) strcat(buf, " "); 300*0Sstevel@tonic-gate (void) strcat(buf, strerror(errno)); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", buf); 303*0Sstevel@tonic-gate if (flags & ERR_USAGE) 304*0Sstevel@tonic-gate usage(); 305*0Sstevel@tonic-gate if (flags & ERR_FATAL) 306*0Sstevel@tonic-gate exit(1); 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate static void 311*0Sstevel@tonic-gate usage() 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate #ifdef XPG4 314*0Sstevel@tonic-gate errmsg(ERR_NONAME, 315*0Sstevel@tonic-gate "Usage: %s [-F FSType] [-abeghklntPVZ] [-o FSType-specific_options]" 316*0Sstevel@tonic-gate " [directory | block_device | resource]", program_name); 317*0Sstevel@tonic-gate #else 318*0Sstevel@tonic-gate errmsg(ERR_NONAME, 319*0Sstevel@tonic-gate "Usage: %s [-F FSType] [-abeghklntVvZ] [-o FSType-specific_options]" 320*0Sstevel@tonic-gate " [directory | block_device | resource]", program_name); 321*0Sstevel@tonic-gate #endif 322*0Sstevel@tonic-gate exit(1); 323*0Sstevel@tonic-gate /* NOTREACHED */ 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate static char * 328*0Sstevel@tonic-gate new_string(char *s) 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate char *p = NULL; 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if (s) { 333*0Sstevel@tonic-gate p = strdup(s); 334*0Sstevel@tonic-gate if (p) 335*0Sstevel@tonic-gate return (p); 336*0Sstevel@tonic-gate errmsg(ERR_FATAL, "out of memory"); 337*0Sstevel@tonic-gate /* NOTREACHED */ 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate return (p); 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * Allocate memory using malloc but terminate if the allocation fails 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate static void * 347*0Sstevel@tonic-gate xmalloc(size_t size) 348*0Sstevel@tonic-gate { 349*0Sstevel@tonic-gate void *p = malloc(size); 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate if (p) 352*0Sstevel@tonic-gate return (p); 353*0Sstevel@tonic-gate errmsg(ERR_FATAL, "out of memory"); 354*0Sstevel@tonic-gate /* NOTREACHED */ 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate /* 359*0Sstevel@tonic-gate * Allocate memory using realloc but terminate if the allocation fails 360*0Sstevel@tonic-gate */ 361*0Sstevel@tonic-gate static void * 362*0Sstevel@tonic-gate xrealloc(void *ptr, size_t size) 363*0Sstevel@tonic-gate { 364*0Sstevel@tonic-gate void *p = realloc(ptr, size); 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate if (p) 367*0Sstevel@tonic-gate return (p); 368*0Sstevel@tonic-gate errmsg(ERR_FATAL, "out of memory"); 369*0Sstevel@tonic-gate /* NOTREACHED */ 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate /* 374*0Sstevel@tonic-gate * fopen the specified file for reading but terminate if the fopen fails 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate static FILE * 377*0Sstevel@tonic-gate xfopen(char *file) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate FILE *fp = fopen(file, "r"); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if (fp == NULL) 382*0Sstevel@tonic-gate errmsg(ERR_FATAL + ERR_PERROR, "failed to open %s:", file); 383*0Sstevel@tonic-gate return (fp); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate * Read remote file system types from REMOTE_FS into the 389*0Sstevel@tonic-gate * remote_fstypes array. 390*0Sstevel@tonic-gate */ 391*0Sstevel@tonic-gate static void 392*0Sstevel@tonic-gate init_remote_fs() 393*0Sstevel@tonic-gate { 394*0Sstevel@tonic-gate FILE *fp; 395*0Sstevel@tonic-gate char line_buf[LINEBUF_SIZE]; 396*0Sstevel@tonic-gate size_t fstype_index = 0; 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate if ((fp = fopen(REMOTE_FS, "r")) == NULL) { 399*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 400*0Sstevel@tonic-gate "Warning: can't open %s, ignored", REMOTE_FS); 401*0Sstevel@tonic-gate return; 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate while (fgets(line_buf, sizeof (line_buf), fp) != NULL) { 405*0Sstevel@tonic-gate char buf[LINEBUF_SIZE]; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate (void) sscanf(line_buf, "%s", buf); 408*0Sstevel@tonic-gate remote_fstypes[fstype_index++] = new_string(buf); 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (fstype_index == N_FSTYPES) 411*0Sstevel@tonic-gate break; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate (void) fclose(fp); 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * Returns TRUE if fstype is a remote file system type; 419*0Sstevel@tonic-gate * otherwise, returns FALSE. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate static int 422*0Sstevel@tonic-gate is_remote_fs(char *fstype) 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate char **p; 425*0Sstevel@tonic-gate static bool_int remote_fs_initialized; 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate if (! remote_fs_initialized) { 428*0Sstevel@tonic-gate init_remote_fs(); 429*0Sstevel@tonic-gate remote_fs_initialized = TRUE; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate for (p = remote_fstypes; *p; p++) 433*0Sstevel@tonic-gate if (EQ(fstype, *p)) 434*0Sstevel@tonic-gate return (TRUE); 435*0Sstevel@tonic-gate return (FALSE); 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate static char * 440*0Sstevel@tonic-gate basename(char *s) 441*0Sstevel@tonic-gate { 442*0Sstevel@tonic-gate char *p = strrchr(s, '/'); 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate return (p ? p+1 : s); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate /* 449*0Sstevel@tonic-gate * Create a new "struct extmnttab" and make sure that its fields point 450*0Sstevel@tonic-gate * to malloc'ed memory 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate static struct extmnttab * 453*0Sstevel@tonic-gate mntdup(struct extmnttab *old) 454*0Sstevel@tonic-gate { 455*0Sstevel@tonic-gate struct extmnttab *new = NEW(struct extmnttab); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate new->mnt_special = new_string(old->mnt_special); 458*0Sstevel@tonic-gate new->mnt_mountp = new_string(old->mnt_mountp); 459*0Sstevel@tonic-gate new->mnt_fstype = new_string(old->mnt_fstype); 460*0Sstevel@tonic-gate new->mnt_mntopts = new_string(old->mnt_mntopts); 461*0Sstevel@tonic-gate new->mnt_time = new_string(old->mnt_time); 462*0Sstevel@tonic-gate new->mnt_major = old->mnt_major; 463*0Sstevel@tonic-gate new->mnt_minor = old->mnt_minor; 464*0Sstevel@tonic-gate return (new); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate static void 469*0Sstevel@tonic-gate mtab_error(char *mtab_file, int status) 470*0Sstevel@tonic-gate { 471*0Sstevel@tonic-gate if (status == MNT_TOOLONG) 472*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, "a line in %s exceeds %d characters", 473*0Sstevel@tonic-gate mtab_file, MNT_LINE_MAX); 474*0Sstevel@tonic-gate else if (status == MNT_TOOMANY) 475*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 476*0Sstevel@tonic-gate "a line in %s has too many fields", mtab_file); 477*0Sstevel@tonic-gate else if (status == MNT_TOOFEW) 478*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 479*0Sstevel@tonic-gate "a line in %s has too few fields", mtab_file); 480*0Sstevel@tonic-gate else 481*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 482*0Sstevel@tonic-gate "error while reading %s: %d", mtab_file, status); 483*0Sstevel@tonic-gate exit(1); 484*0Sstevel@tonic-gate /* NOTREACHED */ 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* 489*0Sstevel@tonic-gate * Read the mount table from the specified file. 490*0Sstevel@tonic-gate * We keep the table in memory for faster lookups. 491*0Sstevel@tonic-gate */ 492*0Sstevel@tonic-gate static void 493*0Sstevel@tonic-gate mtab_read_file() 494*0Sstevel@tonic-gate { 495*0Sstevel@tonic-gate char *mtab_file = MOUNT_TAB; 496*0Sstevel@tonic-gate FILE *fp; 497*0Sstevel@tonic-gate struct extmnttab mtab; 498*0Sstevel@tonic-gate int status; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate fp = xfopen(mtab_file); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate resetmnttab(fp); 503*0Sstevel@tonic-gate mount_table_allocated_entries = MOUNT_TABLE_ENTRIES; 504*0Sstevel@tonic-gate mount_table_entries = 0; 505*0Sstevel@tonic-gate mount_table = xmalloc( 506*0Sstevel@tonic-gate mount_table_allocated_entries * sizeof (struct mtab_entry)); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) 509*0Sstevel@tonic-gate == 0) { 510*0Sstevel@tonic-gate struct mtab_entry *mtep; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if (mount_table_entries == mount_table_allocated_entries) { 513*0Sstevel@tonic-gate mount_table_allocated_entries += MOUNT_TABLE_ENTRIES; 514*0Sstevel@tonic-gate mount_table = xrealloc(mount_table, 515*0Sstevel@tonic-gate mount_table_allocated_entries * 516*0Sstevel@tonic-gate sizeof (struct mtab_entry)); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate mtep = &mount_table[mount_table_entries++]; 519*0Sstevel@tonic-gate mtep->mte_mount = mntdup(&mtab); 520*0Sstevel@tonic-gate mtep->mte_dev_is_valid = FALSE; 521*0Sstevel@tonic-gate mtep->mte_ignore = (hasmntopt((struct mnttab *)&mtab, 522*0Sstevel@tonic-gate MNTOPT_IGNORE) != NULL); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate (void) fclose(fp); 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate if (status == -1) /* reached EOF */ 528*0Sstevel@tonic-gate return; 529*0Sstevel@tonic-gate mtab_error(mtab_file, status); 530*0Sstevel@tonic-gate /* NOTREACHED */ 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * We use this macro when we want to record the option for the purpose of 536*0Sstevel@tonic-gate * passing it to the FS-specific df 537*0Sstevel@tonic-gate */ 538*0Sstevel@tonic-gate #define SET_OPTION(opt) opt##_option = TRUE, \ 539*0Sstevel@tonic-gate df_options[df_options_len++] = arg 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate static void 542*0Sstevel@tonic-gate parse_options(int argc, char *argv[]) 543*0Sstevel@tonic-gate { 544*0Sstevel@tonic-gate int arg; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate opterr = 0; /* getopt shouldn't complain about unknown options */ 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate #ifdef XPG4 549*0Sstevel@tonic-gate while ((arg = getopt(argc, argv, "F:o:abehkVtgnlPZ")) != EOF) { 550*0Sstevel@tonic-gate #else 551*0Sstevel@tonic-gate while ((arg = getopt(argc, argv, "F:o:abehkVtgnlvZ")) != EOF) { 552*0Sstevel@tonic-gate #endif 553*0Sstevel@tonic-gate if (arg == 'F') { 554*0Sstevel@tonic-gate if (F_option) 555*0Sstevel@tonic-gate errmsg(ERR_FATAL + ERR_USAGE, 556*0Sstevel@tonic-gate "more than one FSType specified"); 557*0Sstevel@tonic-gate F_option = 1; 558*0Sstevel@tonic-gate FSType = optarg; 559*0Sstevel@tonic-gate } else if (arg == 'V' && ! V_option) { 560*0Sstevel@tonic-gate V_option = TRUE; 561*0Sstevel@tonic-gate } else if (arg == 'v' && ! v_option) { 562*0Sstevel@tonic-gate v_option = TRUE; 563*0Sstevel@tonic-gate #ifdef XPG4 564*0Sstevel@tonic-gate } else if (arg == 'P' && ! P_option) { 565*0Sstevel@tonic-gate SET_OPTION(P); 566*0Sstevel@tonic-gate #endif 567*0Sstevel@tonic-gate } else if (arg == 'a' && ! a_option) { 568*0Sstevel@tonic-gate SET_OPTION(a); 569*0Sstevel@tonic-gate } else if (arg == 'b' && ! b_option) { 570*0Sstevel@tonic-gate SET_OPTION(b); 571*0Sstevel@tonic-gate } else if (arg == 'e' && ! e_option) { 572*0Sstevel@tonic-gate SET_OPTION(e); 573*0Sstevel@tonic-gate } else if (arg == 'g' && ! g_option) { 574*0Sstevel@tonic-gate SET_OPTION(g); 575*0Sstevel@tonic-gate } else if (arg == 'h') { 576*0Sstevel@tonic-gate use_scaling = TRUE; 577*0Sstevel@tonic-gate scale = 1024; 578*0Sstevel@tonic-gate } else if (arg == 'k' && ! k_option) { 579*0Sstevel@tonic-gate SET_OPTION(k); 580*0Sstevel@tonic-gate } else if (arg == 'l' && ! l_option) { 581*0Sstevel@tonic-gate SET_OPTION(l); 582*0Sstevel@tonic-gate } else if (arg == 'n' && ! n_option) { 583*0Sstevel@tonic-gate SET_OPTION(n); 584*0Sstevel@tonic-gate } else if (arg == 't' && ! t_option) { 585*0Sstevel@tonic-gate SET_OPTION(t); 586*0Sstevel@tonic-gate } else if (arg == 'o') { 587*0Sstevel@tonic-gate if (o_option) 588*0Sstevel@tonic-gate errmsg(ERR_FATAL + ERR_USAGE, 589*0Sstevel@tonic-gate "the -o option can only be specified once"); 590*0Sstevel@tonic-gate o_option = TRUE; 591*0Sstevel@tonic-gate o_option_arg = optarg; 592*0Sstevel@tonic-gate } else if (arg == 'Z') { 593*0Sstevel@tonic-gate SET_OPTION(Z); 594*0Sstevel@tonic-gate } else if (arg == '?') { 595*0Sstevel@tonic-gate errmsg(ERR_USAGE, "unknown option: %c", optopt); 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Option sanity checks 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate if (g_option && o_option) 603*0Sstevel@tonic-gate errmsg(ERR_FATAL, "-o and -g options are incompatible"); 604*0Sstevel@tonic-gate if (l_option && o_option) 605*0Sstevel@tonic-gate errmsg(ERR_FATAL, "-o and -l options are incompatible"); 606*0Sstevel@tonic-gate if (n_option && o_option) 607*0Sstevel@tonic-gate errmsg(ERR_FATAL, "-o and -n options are incompatible"); 608*0Sstevel@tonic-gate if (use_scaling && o_option) 609*0Sstevel@tonic-gate errmsg(ERR_FATAL, "-o and -h options are incompatible"); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate /* 615*0Sstevel@tonic-gate * Check if the user-specified argument is a resource name. 616*0Sstevel@tonic-gate * A resource name is whatever is placed in the mnt_special field of 617*0Sstevel@tonic-gate * struct mnttab. In the case of NFS, a resource name has the form 618*0Sstevel@tonic-gate * hostname:pathname 619*0Sstevel@tonic-gate * We try to find an exact match between the user-specified argument 620*0Sstevel@tonic-gate * and the mnt_special field of a mount table entry. 621*0Sstevel@tonic-gate * We also use the heuristic of removing the basename from the user-specified 622*0Sstevel@tonic-gate * argument and repeating the test until we get a match. This works 623*0Sstevel@tonic-gate * fine for NFS but may fail for other remote file system types. However, 624*0Sstevel@tonic-gate * it is guaranteed that the function will not fail if the user specifies 625*0Sstevel@tonic-gate * the exact resource name. 626*0Sstevel@tonic-gate * If successful, this function sets the 'dfr_mte' field of '*dfrp' 627*0Sstevel@tonic-gate */ 628*0Sstevel@tonic-gate static void 629*0Sstevel@tonic-gate resource_mount_entry(struct df_request *dfrp) 630*0Sstevel@tonic-gate { 631*0Sstevel@tonic-gate char *name; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * We need our own copy since we will modify the string 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate name = new_string(dfrp->dfr_cmd_arg); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate for (;;) { 639*0Sstevel@tonic-gate char *p; 640*0Sstevel@tonic-gate int i; 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * Compare against all known mount points. 644*0Sstevel@tonic-gate * We start from the most recent mount, which is at the 645*0Sstevel@tonic-gate * end of the array. 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate for (i = mount_table_entries - 1; i >= 0; i--) { 648*0Sstevel@tonic-gate struct mtab_entry *mtep = &mount_table[i]; 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate if (EQ(name, mtep->mte_mount->mnt_special)) { 651*0Sstevel@tonic-gate dfrp->dfr_mte = mtep; 652*0Sstevel@tonic-gate break; 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate /* 657*0Sstevel@tonic-gate * Remove the last component of the pathname. 658*0Sstevel@tonic-gate * If there is no such component, this is not a resource name. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate p = strrchr(name, '/'); 661*0Sstevel@tonic-gate if (p == NULL) 662*0Sstevel@tonic-gate break; 663*0Sstevel@tonic-gate *p = NUL; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate } 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate /* 670*0Sstevel@tonic-gate * Try to match the command line argument which is a block special device 671*0Sstevel@tonic-gate * with the special device of one of the mounted file systems. 672*0Sstevel@tonic-gate * If one is found, set the appropriate field of 'dfrp' to the mount 673*0Sstevel@tonic-gate * table entry. 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate static void 676*0Sstevel@tonic-gate bdev_mount_entry(struct df_request *dfrp) 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate int i; 679*0Sstevel@tonic-gate char *special = dfrp->dfr_cmd_arg; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate /* 682*0Sstevel@tonic-gate * Compare against all known mount points. 683*0Sstevel@tonic-gate * We start from the most recent mount, which is at the 684*0Sstevel@tonic-gate * end of the array. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate for (i = mount_table_entries - 1; i >= 0; i--) { 687*0Sstevel@tonic-gate struct mtab_entry *mtep = &mount_table[i]; 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate if (EQ(special, mtep->mte_mount->mnt_special)) { 690*0Sstevel@tonic-gate dfrp->dfr_mte = mtep; 691*0Sstevel@tonic-gate break; 692*0Sstevel@tonic-gate } 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate static struct mtab_entry * 697*0Sstevel@tonic-gate devid_matches(int i, dev_t devno) 698*0Sstevel@tonic-gate { 699*0Sstevel@tonic-gate struct mtab_entry *mtep = &mount_table[i]; 700*0Sstevel@tonic-gate struct extmnttab *mtp = mtep->mte_mount; 701*0Sstevel@tonic-gate /* int len = strlen(mtp->mnt_mountp); */ 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate if (EQ(mtp->mnt_fstype, MNTTYPE_SWAP)) 704*0Sstevel@tonic-gate return (NULL); 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * check if device numbers match. If there is a cached device number 707*0Sstevel@tonic-gate * in the mtab_entry, use it, otherwise get the device number 708*0Sstevel@tonic-gate * either from the mnttab entry or by stat'ing the mount point. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate if (! mtep->mte_dev_is_valid) { 711*0Sstevel@tonic-gate struct stat64 st; 712*0Sstevel@tonic-gate dev_t dev = NODEV; 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate dev = makedev(mtp->mnt_major, mtp->mnt_minor); 715*0Sstevel@tonic-gate if (dev == 0) 716*0Sstevel@tonic-gate dev = NODEV; 717*0Sstevel@tonic-gate if (dev == NODEV) { 718*0Sstevel@tonic-gate if (stat64(mtp->mnt_mountp, &st) == -1) { 719*0Sstevel@tonic-gate return (NULL); 720*0Sstevel@tonic-gate } else { 721*0Sstevel@tonic-gate dev = st.st_dev; 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate mtep->mte_dev = dev; 725*0Sstevel@tonic-gate mtep->mte_dev_is_valid = TRUE; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate if (mtep->mte_dev == devno) { 728*0Sstevel@tonic-gate return (mtep); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate return (NULL); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate /* 734*0Sstevel@tonic-gate * Find the mount point under which the user-specified path resides 735*0Sstevel@tonic-gate * and set the 'dfr_mte' field of '*dfrp' to point to the mount table entry. 736*0Sstevel@tonic-gate */ 737*0Sstevel@tonic-gate static void 738*0Sstevel@tonic-gate path_mount_entry(struct df_request *dfrp, dev_t devno) 739*0Sstevel@tonic-gate { 740*0Sstevel@tonic-gate char dirpath[MAXPATHLEN]; 741*0Sstevel@tonic-gate char *dir = dfrp->dfr_cmd_arg; 742*0Sstevel@tonic-gate struct mtab_entry *match, *tmatch; 743*0Sstevel@tonic-gate int i; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* 746*0Sstevel@tonic-gate * Expand the given path to get a canonical version (i.e. an absolute 747*0Sstevel@tonic-gate * path without symbolic links). 748*0Sstevel@tonic-gate */ 749*0Sstevel@tonic-gate if (realpath(dir, dirpath) == NULL) { 750*0Sstevel@tonic-gate errmsg(ERR_PERROR, "cannot canonicalize %s:", dir); 751*0Sstevel@tonic-gate return; 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate /* 754*0Sstevel@tonic-gate * If the mnt point is lofs, search from the top of entries from 755*0Sstevel@tonic-gate * /etc/mnttab and return the first entry that matches the devid 756*0Sstevel@tonic-gate * For non-lofs mount points, return the first entry from the bottom 757*0Sstevel@tonic-gate * of the entries in /etc/mnttab that matches on the devid field 758*0Sstevel@tonic-gate */ 759*0Sstevel@tonic-gate match = NULL; 760*0Sstevel@tonic-gate if (dfrp->dfr_fstype && EQ(dfrp->dfr_fstype, MNTTYPE_LOFS)) { 761*0Sstevel@tonic-gate for (i = 0; i < mount_table_entries; i++) { 762*0Sstevel@tonic-gate if (match = devid_matches(i, devno)) 763*0Sstevel@tonic-gate break; 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate } else { 766*0Sstevel@tonic-gate for (i = mount_table_entries - 1; i >= 0; i--) { 767*0Sstevel@tonic-gate if (tmatch = devid_matches(i, devno)) { 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * If executing in a zone, there might be lofs 770*0Sstevel@tonic-gate * mounts for which the real mount point is 771*0Sstevel@tonic-gate * invisible; accept the "best fit" for this 772*0Sstevel@tonic-gate * devid. 773*0Sstevel@tonic-gate */ 774*0Sstevel@tonic-gate match = tmatch; 775*0Sstevel@tonic-gate if (!EQ(match->mte_mount->mnt_fstype, 776*0Sstevel@tonic-gate MNTTYPE_LOFS)) { 777*0Sstevel@tonic-gate break; 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate if (! match) { 783*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 784*0Sstevel@tonic-gate "Could not find mount point for %s", dir); 785*0Sstevel@tonic-gate return; 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate dfrp->dfr_mte = match; 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate /* 791*0Sstevel@tonic-gate * Execute a single FS-specific df command for all given requests 792*0Sstevel@tonic-gate * Return 0 if successful, 1 otherwise. 793*0Sstevel@tonic-gate */ 794*0Sstevel@tonic-gate static int 795*0Sstevel@tonic-gate run_fs_specific_df(struct df_request request_list[], int entries) 796*0Sstevel@tonic-gate { 797*0Sstevel@tonic-gate int i; 798*0Sstevel@tonic-gate int argv_index; 799*0Sstevel@tonic-gate char **argv; 800*0Sstevel@tonic-gate size_t size; 801*0Sstevel@tonic-gate pid_t pid; 802*0Sstevel@tonic-gate int status; 803*0Sstevel@tonic-gate char cmd_path[MAXPATHLEN]; 804*0Sstevel@tonic-gate char *fstype; 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate if (entries == 0) 807*0Sstevel@tonic-gate return (0); 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate fstype = request_list[0].dfr_fstype; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate if (F_option && ! EQ(FSType, fstype)) 812*0Sstevel@tonic-gate return (0); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate (void) sprintf(cmd_path, "%s%s/df", FS_LIBPATH, fstype); 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * Argv entries: 817*0Sstevel@tonic-gate * 1 for the path 818*0Sstevel@tonic-gate * 2 for -o <options> 819*0Sstevel@tonic-gate * 1 for the generic options that we propagate 820*0Sstevel@tonic-gate * 1 for the terminating NULL pointer 821*0Sstevel@tonic-gate * n for the number of user-specified arguments 822*0Sstevel@tonic-gate */ 823*0Sstevel@tonic-gate size = (5 + entries) * sizeof (char *); 824*0Sstevel@tonic-gate argv = xmalloc(size); 825*0Sstevel@tonic-gate (void) memset(argv, 0, size); 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate argv[0] = cmd_path; 828*0Sstevel@tonic-gate argv_index = 1; 829*0Sstevel@tonic-gate if (o_option) { 830*0Sstevel@tonic-gate argv[argv_index++] = "-o"; 831*0Sstevel@tonic-gate argv[argv_index++] = o_option_arg; 832*0Sstevel@tonic-gate } 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate /* 835*0Sstevel@tonic-gate * Check if we need to propagate any generic options 836*0Sstevel@tonic-gate */ 837*0Sstevel@tonic-gate if (df_options_len > 1) 838*0Sstevel@tonic-gate argv[argv_index++] = df_options; 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate /* 841*0Sstevel@tonic-gate * If there is a user-specified path, we pass that to the 842*0Sstevel@tonic-gate * FS-specific df. Otherwise, we are guaranteed to have a mount 843*0Sstevel@tonic-gate * point, since a request without a user path implies that 844*0Sstevel@tonic-gate * we are reporting only on mounted file systems. 845*0Sstevel@tonic-gate */ 846*0Sstevel@tonic-gate for (i = 0; i < entries; i++) { 847*0Sstevel@tonic-gate struct df_request *dfrp = &request_list[i]; 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate argv[argv_index++] = (dfrp->dfr_cmd_arg == NULL) 850*0Sstevel@tonic-gate ? DFR_MOUNT_POINT(dfrp) 851*0Sstevel@tonic-gate : dfrp->dfr_cmd_arg; 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate if (V_option) { 855*0Sstevel@tonic-gate for (i = 0; i < argv_index-1; i++) 856*0Sstevel@tonic-gate (void) printf("%s ", argv[i]); 857*0Sstevel@tonic-gate (void) printf("%s\n", argv[i]); 858*0Sstevel@tonic-gate return (0); 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate pid = fork(); 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate if (pid == -1) { 864*0Sstevel@tonic-gate errmsg(ERR_PERROR, "cannot fork process:"); 865*0Sstevel@tonic-gate return (1); 866*0Sstevel@tonic-gate } else if (pid == 0) { 867*0Sstevel@tonic-gate (void) execv(cmd_path, argv); 868*0Sstevel@tonic-gate if (errno == ENOENT) 869*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 870*0Sstevel@tonic-gate "operation not applicable for FSType %s", 871*0Sstevel@tonic-gate fstype); 872*0Sstevel@tonic-gate else 873*0Sstevel@tonic-gate errmsg(ERR_PERROR, "cannot execute %s:", cmd_path); 874*0Sstevel@tonic-gate exit(2); 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate /* 878*0Sstevel@tonic-gate * Reap the child 879*0Sstevel@tonic-gate */ 880*0Sstevel@tonic-gate for (;;) { 881*0Sstevel@tonic-gate pid_t wpid = waitpid(pid, &status, 0); 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate if (wpid == -1) 884*0Sstevel@tonic-gate if (errno == EINTR) 885*0Sstevel@tonic-gate continue; 886*0Sstevel@tonic-gate else { 887*0Sstevel@tonic-gate errmsg(ERR_PERROR, "waitpid error:"); 888*0Sstevel@tonic-gate return (1); 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate else 891*0Sstevel@tonic-gate break; 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate return ((WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : 1); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate /* 900*0Sstevel@tonic-gate * Remove from the request list all requests that do not apply. 901*0Sstevel@tonic-gate * Notice that the subsequent processing of the requests depends on 902*0Sstevel@tonic-gate * the sanity checking performed by this function. 903*0Sstevel@tonic-gate */ 904*0Sstevel@tonic-gate static int 905*0Sstevel@tonic-gate prune_list(struct df_request request_list[], 906*0Sstevel@tonic-gate size_t n_requests, 907*0Sstevel@tonic-gate size_t *valid_requests) 908*0Sstevel@tonic-gate { 909*0Sstevel@tonic-gate size_t i; 910*0Sstevel@tonic-gate size_t n_valid = 0; 911*0Sstevel@tonic-gate int errors = 0; 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate for (i = 0; i < n_requests; i++) { 914*0Sstevel@tonic-gate struct df_request *dfrp = &request_list[i]; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate /* 917*0Sstevel@tonic-gate * Skip file systems that are not mounted if either the 918*0Sstevel@tonic-gate * -l or -n options were specified. If none of these options 919*0Sstevel@tonic-gate * are present, the appropriate FS-specific df will be invoked. 920*0Sstevel@tonic-gate */ 921*0Sstevel@tonic-gate if (! DFR_ISMOUNTEDFS(dfrp)) { 922*0Sstevel@tonic-gate if (l_option || n_option) { 923*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 924*0Sstevel@tonic-gate "%s option incompatible with unmounted special device (%s)", 925*0Sstevel@tonic-gate l_option ? "-l" : "-n", dfrp->dfr_cmd_arg); 926*0Sstevel@tonic-gate dfrp->dfr_valid = FALSE; 927*0Sstevel@tonic-gate errors++; 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate else 930*0Sstevel@tonic-gate n_valid++; 931*0Sstevel@tonic-gate continue; 932*0Sstevel@tonic-gate } 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate /* 935*0Sstevel@tonic-gate * Check for inconsistency between the argument of -F and 936*0Sstevel@tonic-gate * the actual file system type. 937*0Sstevel@tonic-gate * If there is an inconsistency and the user specified a 938*0Sstevel@tonic-gate * path, this is an error since we are asked to interpret 939*0Sstevel@tonic-gate * the path using the wrong file system type. If there is 940*0Sstevel@tonic-gate * no path associated with this request, we quietly ignore it. 941*0Sstevel@tonic-gate */ 942*0Sstevel@tonic-gate if (F_option && ! EQ(dfrp->dfr_fstype, FSType)) { 943*0Sstevel@tonic-gate dfrp->dfr_valid = FALSE; 944*0Sstevel@tonic-gate if (dfrp->dfr_cmd_arg != NULL) { 945*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 946*0Sstevel@tonic-gate "Warning: %s mounted as a %s file system", 947*0Sstevel@tonic-gate dfrp->dfr_cmd_arg, dfrp->dfr_fstype); 948*0Sstevel@tonic-gate errors++; 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate continue; 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate /* 954*0Sstevel@tonic-gate * Skip remote file systems if the -l option is present 955*0Sstevel@tonic-gate */ 956*0Sstevel@tonic-gate if (l_option && is_remote_fs(dfrp->dfr_fstype)) { 957*0Sstevel@tonic-gate if (dfrp->dfr_cmd_arg != NULL) { 958*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 959*0Sstevel@tonic-gate "Warning: %s is not a local file system", 960*0Sstevel@tonic-gate dfrp->dfr_cmd_arg); 961*0Sstevel@tonic-gate errors++; 962*0Sstevel@tonic-gate } 963*0Sstevel@tonic-gate dfrp->dfr_valid = FALSE; 964*0Sstevel@tonic-gate continue; 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate /* 968*0Sstevel@tonic-gate * Skip file systems mounted as "ignore" unless the -a option 969*0Sstevel@tonic-gate * is present, or the user explicitly specified them on 970*0Sstevel@tonic-gate * the command line. 971*0Sstevel@tonic-gate */ 972*0Sstevel@tonic-gate if (dfrp->dfr_mte->mte_ignore && 973*0Sstevel@tonic-gate ! (a_option || dfrp->dfr_cmd_arg)) { 974*0Sstevel@tonic-gate dfrp->dfr_valid = FALSE; 975*0Sstevel@tonic-gate continue; 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate n_valid++; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate *valid_requests = n_valid; 981*0Sstevel@tonic-gate return (errors); 982*0Sstevel@tonic-gate } 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate /* 986*0Sstevel@tonic-gate * Print the appropriate header for the requested output format. 987*0Sstevel@tonic-gate * Options are checked in order of their precedence. 988*0Sstevel@tonic-gate */ 989*0Sstevel@tonic-gate static void 990*0Sstevel@tonic-gate print_header() 991*0Sstevel@tonic-gate { 992*0Sstevel@tonic-gate if (use_scaling) { /* this comes from the -h option */ 993*0Sstevel@tonic-gate int arg = 'h'; 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate (void) printf("%-*s %*s %*s %*s %-*s %s\n", 996*0Sstevel@tonic-gate FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 997*0Sstevel@tonic-gate #ifdef XPG4 998*0Sstevel@tonic-gate SCALED_WIDTH, TRANSLATE("Size"), 999*0Sstevel@tonic-gate SCALED_WIDTH, TRANSLATE("Used"), 1000*0Sstevel@tonic-gate AVAILABLE_WIDTH, TRANSLATE("Available"), 1001*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE("Capacity"), 1002*0Sstevel@tonic-gate #else 1003*0Sstevel@tonic-gate SCALED_WIDTH, TRANSLATE("size"), 1004*0Sstevel@tonic-gate SCALED_WIDTH, TRANSLATE("used"), 1005*0Sstevel@tonic-gate AVAILABLE_WIDTH, TRANSLATE("avail"), 1006*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE("capacity"), 1007*0Sstevel@tonic-gate #endif 1008*0Sstevel@tonic-gate TRANSLATE("Mounted on")); 1009*0Sstevel@tonic-gate SET_OPTION(h); 1010*0Sstevel@tonic-gate return; 1011*0Sstevel@tonic-gate } 1012*0Sstevel@tonic-gate if (k_option) { 1013*0Sstevel@tonic-gate int arg = 'h'; 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate (void) printf(gettext("%-*s %*s %*s %*s %-*s %s\n"), 1016*0Sstevel@tonic-gate FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 1017*0Sstevel@tonic-gate #ifdef XPG4 1018*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("1024-blocks"), 1019*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("Used"), 1020*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("Available"), 1021*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE("Capacity"), 1022*0Sstevel@tonic-gate #else 1023*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("kbytes"), 1024*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("used"), 1025*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("avail"), 1026*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE("capacity"), 1027*0Sstevel@tonic-gate #endif 1028*0Sstevel@tonic-gate TRANSLATE("Mounted on")); 1029*0Sstevel@tonic-gate SET_OPTION(h); 1030*0Sstevel@tonic-gate return; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate /* Added for XCU4 compliance */ 1033*0Sstevel@tonic-gate if (P_option) { 1034*0Sstevel@tonic-gate int arg = 'h'; 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate (void) printf(gettext("%-*s %*s %*s %*s %-*s %s\n"), 1037*0Sstevel@tonic-gate FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 1038*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("512-blocks"), 1039*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("Used"), 1040*0Sstevel@tonic-gate KBYTE_WIDTH, TRANSLATE("Available"), 1041*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE("Capacity"), 1042*0Sstevel@tonic-gate TRANSLATE("Mounted on")); 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate SET_OPTION(h); 1045*0Sstevel@tonic-gate return; 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate /* End XCU4 */ 1048*0Sstevel@tonic-gate if (v_option) { 1049*0Sstevel@tonic-gate (void) printf("%-*s %-*s %*s %*s %*s %-*s\n", 1050*0Sstevel@tonic-gate IBCS2_MOUNT_POINT_WIDTH, TRANSLATE("Mount Dir"), 1051*0Sstevel@tonic-gate IBCS2_FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 1052*0Sstevel@tonic-gate BLOCK_WIDTH, TRANSLATE("blocks"), 1053*0Sstevel@tonic-gate BLOCK_WIDTH, TRANSLATE("used"), 1054*0Sstevel@tonic-gate BLOCK_WIDTH, TRANSLATE("free"), 1055*0Sstevel@tonic-gate CAPACITY_WIDTH, TRANSLATE(" %used")); 1056*0Sstevel@tonic-gate return; 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate if (e_option) { 1059*0Sstevel@tonic-gate (void) printf(gettext("%-*s %*s\n"), 1060*0Sstevel@tonic-gate FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 1061*0Sstevel@tonic-gate BLOCK_WIDTH, TRANSLATE("ifree")); 1062*0Sstevel@tonic-gate return; 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate if (b_option) { 1065*0Sstevel@tonic-gate (void) printf(gettext("%-*s %*s\n"), 1066*0Sstevel@tonic-gate FILESYSTEM_WIDTH, TRANSLATE("Filesystem"), 1067*0Sstevel@tonic-gate BLOCK_WIDTH, TRANSLATE("avail")); 1068*0Sstevel@tonic-gate return; 1069*0Sstevel@tonic-gate } 1070*0Sstevel@tonic-gate } 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 1075*0Sstevel@tonic-gate * result in the caller-supplied buffer. 1076*0Sstevel@tonic-gate * The given number is in units of "unit_from" size, but the 1077*0Sstevel@tonic-gate * converted number will be in units of "unit_to" size. The unit sizes 1078*0Sstevel@tonic-gate * must be powers of 2. 1079*0Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 1080*0Sstevel@tonic-gate * converted to "-1". 1081*0Sstevel@tonic-gate * Returns a pointer to the caller-supplied buffer. 1082*0Sstevel@tonic-gate */ 1083*0Sstevel@tonic-gate static char * 1084*0Sstevel@tonic-gate number_to_string( 1085*0Sstevel@tonic-gate char *buf, /* put the result here */ 1086*0Sstevel@tonic-gate unsigned long long number, /* convert this number */ 1087*0Sstevel@tonic-gate int unit_from, /* from units of this size */ 1088*0Sstevel@tonic-gate int unit_to) /* to units of this size */ 1089*0Sstevel@tonic-gate { 1090*0Sstevel@tonic-gate if ((long long)number == (long long)-1) 1091*0Sstevel@tonic-gate (void) strcpy(buf, "-1"); 1092*0Sstevel@tonic-gate else { 1093*0Sstevel@tonic-gate if (unit_from == unit_to) 1094*0Sstevel@tonic-gate (void) sprintf(buf, "%llu", number); 1095*0Sstevel@tonic-gate else if (unit_from < unit_to) 1096*0Sstevel@tonic-gate (void) sprintf(buf, "%llu", 1097*0Sstevel@tonic-gate number / (unsigned long long)(unit_to / unit_from)); 1098*0Sstevel@tonic-gate else 1099*0Sstevel@tonic-gate (void) sprintf(buf, "%llu", 1100*0Sstevel@tonic-gate number * (unsigned long long)(unit_from / unit_to)); 1101*0Sstevel@tonic-gate } 1102*0Sstevel@tonic-gate return (buf); 1103*0Sstevel@tonic-gate } 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate /* 1106*0Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 1107*0Sstevel@tonic-gate * result in the caller-supplied buffer. 1108*0Sstevel@tonic-gate * The given number is in units of "unit_from" size, 1109*0Sstevel@tonic-gate * this will first be converted to a number in 1024 or 1000 byte size, 1110*0Sstevel@tonic-gate * depending on the scaling factor. 1111*0Sstevel@tonic-gate * Then the number is scaled down until it is small enough to be in a good 1112*0Sstevel@tonic-gate * human readable format i.e. in the range 0 thru scale-1. 1113*0Sstevel@tonic-gate * If it's smaller than 10 there's room enough to provide one decimal place. 1114*0Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 1115*0Sstevel@tonic-gate * converted to "-1". 1116*0Sstevel@tonic-gate * Returns a pointer to the caller-supplied buffer. 1117*0Sstevel@tonic-gate */ 1118*0Sstevel@tonic-gate static char * 1119*0Sstevel@tonic-gate number_to_scaled_string( 1120*0Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 1121*0Sstevel@tonic-gate unsigned long long number, /* convert this number */ 1122*0Sstevel@tonic-gate int unit_from, 1123*0Sstevel@tonic-gate int scale) 1124*0Sstevel@tonic-gate { 1125*0Sstevel@tonic-gate unsigned long long save = 0; 1126*0Sstevel@tonic-gate char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */ 1127*0Sstevel@tonic-gate char *uom = M; /* unit of measurement, initially 'K' (=M[0]) */ 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate if ((long long)number == (long long)-1) { 1130*0Sstevel@tonic-gate (void) strcpy(buf, "-1"); 1131*0Sstevel@tonic-gate return (buf); 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate /* 1135*0Sstevel@tonic-gate * Convert number from unit_from to given scale (1024 or 1000). 1136*0Sstevel@tonic-gate * This means multiply number by unit_from and divide by scale. 1137*0Sstevel@tonic-gate * 1138*0Sstevel@tonic-gate * Would like to multiply by unit_from and then divide by scale, 1139*0Sstevel@tonic-gate * but if the first multiplication would overflow, then need to 1140*0Sstevel@tonic-gate * divide by scale and then multiply by unit_from. 1141*0Sstevel@tonic-gate */ 1142*0Sstevel@tonic-gate if (number > (UINT64_MAX / (unsigned long long)unit_from)) { 1143*0Sstevel@tonic-gate number = (number / (unsigned long long)scale) * 1144*0Sstevel@tonic-gate (unsigned long long)unit_from; 1145*0Sstevel@tonic-gate } else { 1146*0Sstevel@tonic-gate number = (number * (unsigned long long)unit_from) / 1147*0Sstevel@tonic-gate (unsigned long long)scale; 1148*0Sstevel@tonic-gate } 1149*0Sstevel@tonic-gate 1150*0Sstevel@tonic-gate /* 1151*0Sstevel@tonic-gate * Now we have number as a count of scale units. 1152*0Sstevel@tonic-gate * Stop scaling when we reached exa bytes, then something is 1153*0Sstevel@tonic-gate * probably wrong with our number. 1154*0Sstevel@tonic-gate */ 1155*0Sstevel@tonic-gate 1156*0Sstevel@tonic-gate while ((number >= scale) && (*uom != 'E')) { 1157*0Sstevel@tonic-gate uom++; /* next unit of measurement */ 1158*0Sstevel@tonic-gate save = number; 1159*0Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 1162*0Sstevel@tonic-gate if (save && ((save / scale) < 10)) { 1163*0Sstevel@tonic-gate /* sprintf() will round for us */ 1164*0Sstevel@tonic-gate float fnum = (float)save / scale; 1165*0Sstevel@tonic-gate (void) sprintf(buf, "%2.1f%c", fnum, *uom); 1166*0Sstevel@tonic-gate } else { 1167*0Sstevel@tonic-gate (void) sprintf(buf, "%4llu%c", number, *uom); 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate return (buf); 1170*0Sstevel@tonic-gate } 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate /* 1174*0Sstevel@tonic-gate * The output will appear properly columnized regardless of the names of 1175*0Sstevel@tonic-gate * the various fields 1176*0Sstevel@tonic-gate */ 1177*0Sstevel@tonic-gate static void 1178*0Sstevel@tonic-gate g_output(struct df_request *dfrp, struct statvfs64 *fsp) 1179*0Sstevel@tonic-gate { 1180*0Sstevel@tonic-gate fsblkcnt64_t available_blocks = fsp->f_bavail; 1181*0Sstevel@tonic-gate numbuf_t total_blocks_buf; 1182*0Sstevel@tonic-gate numbuf_t total_files_buf; 1183*0Sstevel@tonic-gate numbuf_t free_blocks_buf; 1184*0Sstevel@tonic-gate numbuf_t available_blocks_buf; 1185*0Sstevel@tonic-gate numbuf_t free_files_buf; 1186*0Sstevel@tonic-gate numbuf_t fname_buf; 1187*0Sstevel@tonic-gate char *temp_buf; 1188*0Sstevel@tonic-gate 1189*0Sstevel@tonic-gate #define DEFINE_STR_LEN(var) \ 1190*0Sstevel@tonic-gate static char *var##_str; \ 1191*0Sstevel@tonic-gate static size_t var##_len 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate #define SET_STR_LEN(name, var)\ 1194*0Sstevel@tonic-gate if (! var##_str) {\ 1195*0Sstevel@tonic-gate var##_str = TRANSLATE(name); \ 1196*0Sstevel@tonic-gate var##_len = strlen(var##_str); \ 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate DEFINE_STR_LEN(block_size); 1200*0Sstevel@tonic-gate DEFINE_STR_LEN(frag_size); 1201*0Sstevel@tonic-gate DEFINE_STR_LEN(total_blocks); 1202*0Sstevel@tonic-gate DEFINE_STR_LEN(free_blocks); 1203*0Sstevel@tonic-gate DEFINE_STR_LEN(available); 1204*0Sstevel@tonic-gate DEFINE_STR_LEN(total_files); 1205*0Sstevel@tonic-gate DEFINE_STR_LEN(free_files); 1206*0Sstevel@tonic-gate DEFINE_STR_LEN(fstype); 1207*0Sstevel@tonic-gate DEFINE_STR_LEN(fsys_id); 1208*0Sstevel@tonic-gate DEFINE_STR_LEN(fname); 1209*0Sstevel@tonic-gate DEFINE_STR_LEN(flag); 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate /* 1212*0Sstevel@tonic-gate * TRANSLATION_NOTE 1213*0Sstevel@tonic-gate * The first argument of each of the following macro invocations is a 1214*0Sstevel@tonic-gate * string that needs to be translated. 1215*0Sstevel@tonic-gate */ 1216*0Sstevel@tonic-gate SET_STR_LEN("block size", block_size); 1217*0Sstevel@tonic-gate SET_STR_LEN("frag size", frag_size); 1218*0Sstevel@tonic-gate SET_STR_LEN("total blocks", total_blocks); 1219*0Sstevel@tonic-gate SET_STR_LEN("free blocks", free_blocks); 1220*0Sstevel@tonic-gate SET_STR_LEN("available", available); 1221*0Sstevel@tonic-gate SET_STR_LEN("total files", total_files); 1222*0Sstevel@tonic-gate SET_STR_LEN("free files", free_files); 1223*0Sstevel@tonic-gate SET_STR_LEN("fstype", fstype); 1224*0Sstevel@tonic-gate SET_STR_LEN("filesys id", fsys_id); 1225*0Sstevel@tonic-gate SET_STR_LEN("filename length", fname); 1226*0Sstevel@tonic-gate SET_STR_LEN("flag", flag); 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate #define NCOL1_WIDTH (int)MAX3(BLOCK_WIDTH, NFILES_WIDTH, FSTYPE_WIDTH) 1229*0Sstevel@tonic-gate #define NCOL2_WIDTH (int)MAX3(BLOCK_WIDTH, FSID_WIDTH, FLAG_WIDTH) + 2 1230*0Sstevel@tonic-gate #define NCOL3_WIDTH (int)MAX3(BSIZE_WIDTH, BLOCK_WIDTH, NAMELEN_WIDTH) 1231*0Sstevel@tonic-gate #define NCOL4_WIDTH (int)MAX(FRAGSIZE_WIDTH, NFILES_WIDTH) 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate #define SCOL1_WIDTH (int)MAX3(total_blocks_len, free_files_len, fstype_len) 1234*0Sstevel@tonic-gate #define SCOL2_WIDTH (int)MAX3(free_blocks_len, fsys_id_len, flag_len) 1235*0Sstevel@tonic-gate #define SCOL3_WIDTH (int)MAX3(block_size_len, available_len, fname_len) 1236*0Sstevel@tonic-gate #define SCOL4_WIDTH (int)MAX(frag_size_len, total_files_len) 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate temp_buf = xmalloc( 1239*0Sstevel@tonic-gate MAX(MOUNT_POINT_WIDTH, strlen(DFR_MOUNT_POINT(dfrp))) 1240*0Sstevel@tonic-gate + MAX(SPECIAL_DEVICE_WIDTH, strlen(DFR_SPECIAL(dfrp))) 1241*0Sstevel@tonic-gate + 20); /* plus slop - nulls & formatting */ 1242*0Sstevel@tonic-gate (void) sprintf(temp_buf, "%-*s(%-*s):", 1243*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1244*0Sstevel@tonic-gate SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp)); 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate (void) printf("%-*s %*lu %-*s %*lu %-*s\n", 1247*0Sstevel@tonic-gate NCOL1_WIDTH + 1 + SCOL1_WIDTH + 1 + NCOL2_WIDTH + 1 + SCOL2_WIDTH, 1248*0Sstevel@tonic-gate temp_buf, 1249*0Sstevel@tonic-gate NCOL3_WIDTH, fsp->f_bsize, SCOL3_WIDTH, block_size_str, 1250*0Sstevel@tonic-gate NCOL4_WIDTH, fsp->f_frsize, SCOL4_WIDTH, frag_size_str); 1251*0Sstevel@tonic-gate free(temp_buf); 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate /* 1254*0Sstevel@tonic-gate * Adjust available_blocks value - it can be less than 0 on 1255*0Sstevel@tonic-gate * a 4.x file system. Reset it to 0 in order to avoid printing 1256*0Sstevel@tonic-gate * negative numbers. 1257*0Sstevel@tonic-gate */ 1258*0Sstevel@tonic-gate if ((long long)available_blocks < (long long)0) 1259*0Sstevel@tonic-gate available_blocks = (fsblkcnt64_t)0; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate (void) printf("%*s %-*s %*s %-*s %*s %-*s %*s %-*s\n", 1262*0Sstevel@tonic-gate NCOL1_WIDTH, number_to_string(total_blocks_buf, 1263*0Sstevel@tonic-gate fsp->f_blocks, fsp->f_frsize, 512), 1264*0Sstevel@tonic-gate SCOL1_WIDTH, total_blocks_str, 1265*0Sstevel@tonic-gate NCOL2_WIDTH, number_to_string(free_blocks_buf, 1266*0Sstevel@tonic-gate fsp->f_bfree, fsp->f_frsize, 512), 1267*0Sstevel@tonic-gate SCOL2_WIDTH, free_blocks_str, 1268*0Sstevel@tonic-gate NCOL3_WIDTH, number_to_string(available_blocks_buf, 1269*0Sstevel@tonic-gate available_blocks, fsp->f_frsize, 512), 1270*0Sstevel@tonic-gate SCOL3_WIDTH, available_str, 1271*0Sstevel@tonic-gate NCOL4_WIDTH, number_to_string(total_files_buf, 1272*0Sstevel@tonic-gate fsp->f_files, 1, 1), 1273*0Sstevel@tonic-gate SCOL4_WIDTH, total_files_str); 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate (void) printf("%*s %-*s %*lu %-*s %s\n", 1276*0Sstevel@tonic-gate NCOL1_WIDTH, number_to_string(free_files_buf, 1277*0Sstevel@tonic-gate fsp->f_ffree, 1, 1), 1278*0Sstevel@tonic-gate SCOL1_WIDTH, free_files_str, 1279*0Sstevel@tonic-gate NCOL2_WIDTH, fsp->f_fsid, SCOL2_WIDTH, fsys_id_str, 1280*0Sstevel@tonic-gate fsp->f_fstr); 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate (void) printf("%*s %-*s %#*.*lx %-*s %*s %-*s\n\n", 1283*0Sstevel@tonic-gate NCOL1_WIDTH, fsp->f_basetype, SCOL1_WIDTH, fstype_str, 1284*0Sstevel@tonic-gate NCOL2_WIDTH, NCOL2_WIDTH-2, fsp->f_flag, SCOL2_WIDTH, flag_str, 1285*0Sstevel@tonic-gate NCOL3_WIDTH, number_to_string(fname_buf, 1286*0Sstevel@tonic-gate (unsigned long long)fsp->f_namemax, 1, 1), 1287*0Sstevel@tonic-gate SCOL3_WIDTH, fname_str); 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate static void 1292*0Sstevel@tonic-gate k_output(struct df_request *dfrp, struct statvfs64 *fsp) 1293*0Sstevel@tonic-gate { 1294*0Sstevel@tonic-gate fsblkcnt64_t total_blocks = fsp->f_blocks; 1295*0Sstevel@tonic-gate fsblkcnt64_t free_blocks = fsp->f_bfree; 1296*0Sstevel@tonic-gate fsblkcnt64_t available_blocks = fsp->f_bavail; 1297*0Sstevel@tonic-gate fsblkcnt64_t used_blocks; 1298*0Sstevel@tonic-gate char *file_system = DFR_SPECIAL(dfrp); 1299*0Sstevel@tonic-gate numbuf_t total_blocks_buf; 1300*0Sstevel@tonic-gate numbuf_t used_blocks_buf; 1301*0Sstevel@tonic-gate numbuf_t available_blocks_buf; 1302*0Sstevel@tonic-gate char capacity_buf[LINEBUF_SIZE]; 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate /* 1305*0Sstevel@tonic-gate * If the free block count is -1, don't trust anything but the total 1306*0Sstevel@tonic-gate * number of blocks. 1307*0Sstevel@tonic-gate */ 1308*0Sstevel@tonic-gate if (free_blocks == (fsblkcnt64_t)-1) { 1309*0Sstevel@tonic-gate used_blocks = (fsblkcnt64_t)-1; 1310*0Sstevel@tonic-gate (void) strcpy(capacity_buf, " 100%"); 1311*0Sstevel@tonic-gate } else { 1312*0Sstevel@tonic-gate fsblkcnt64_t reserved_blocks = free_blocks - available_blocks; 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate used_blocks = total_blocks - free_blocks; 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate /* 1317*0Sstevel@tonic-gate * The capacity estimation is bogus when available_blocks is 0 1318*0Sstevel@tonic-gate * and the super-user has allocated more space. The reason 1319*0Sstevel@tonic-gate * is that reserved_blocks is inaccurate in that case, because 1320*0Sstevel@tonic-gate * when the super-user allocates space, free_blocks is updated 1321*0Sstevel@tonic-gate * but available_blocks is not (since it can't drop below 0). 1322*0Sstevel@tonic-gate * 1323*0Sstevel@tonic-gate * XCU4 and POSIX.2 require that any fractional result of the 1324*0Sstevel@tonic-gate * capacity estimation be rounded to the next highest integer, 1325*0Sstevel@tonic-gate * hence the addition of 0.5. 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate (void) sprintf(capacity_buf, "%5.0f%%", 1328*0Sstevel@tonic-gate (total_blocks == 0) ? 0.0 : 1329*0Sstevel@tonic-gate ((double)used_blocks / 1330*0Sstevel@tonic-gate (double)(total_blocks - reserved_blocks)) 1331*0Sstevel@tonic-gate * 100.0 + 0.5); 1332*0Sstevel@tonic-gate } 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate /* 1335*0Sstevel@tonic-gate * The available_blocks can be less than 0 on a 4.x file system. 1336*0Sstevel@tonic-gate * Reset it to 0 in order to avoid printing negative numbers. 1337*0Sstevel@tonic-gate */ 1338*0Sstevel@tonic-gate if ((long long)available_blocks < (long long)0) 1339*0Sstevel@tonic-gate available_blocks = (fsblkcnt64_t)0; 1340*0Sstevel@tonic-gate /* 1341*0Sstevel@tonic-gate * Print long special device names (usually NFS mounts) in a line 1342*0Sstevel@tonic-gate * by themselves when the output is directed to a terminal. 1343*0Sstevel@tonic-gate */ 1344*0Sstevel@tonic-gate if (tty_output && strlen(file_system) > (size_t)FILESYSTEM_WIDTH) { 1345*0Sstevel@tonic-gate (void) printf("%s\n", file_system); 1346*0Sstevel@tonic-gate file_system = ""; 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (use_scaling) { /* comes from the -h option */ 1350*0Sstevel@tonic-gate (void) printf("%-*s %*s %*s %*s %-*s %-s\n", 1351*0Sstevel@tonic-gate FILESYSTEM_WIDTH, file_system, 1352*0Sstevel@tonic-gate SCALED_WIDTH, number_to_scaled_string(total_blocks_buf, 1353*0Sstevel@tonic-gate total_blocks, fsp->f_frsize, scale), 1354*0Sstevel@tonic-gate SCALED_WIDTH, number_to_scaled_string(used_blocks_buf, 1355*0Sstevel@tonic-gate used_blocks, fsp->f_frsize, scale), 1356*0Sstevel@tonic-gate AVAILABLE_WIDTH, number_to_scaled_string(available_blocks_buf, 1357*0Sstevel@tonic-gate available_blocks, fsp->f_frsize, scale), 1358*0Sstevel@tonic-gate CAPACITY_WIDTH, capacity_buf, 1359*0Sstevel@tonic-gate DFR_MOUNT_POINT(dfrp)); 1360*0Sstevel@tonic-gate return; 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate if (v_option) { 1364*0Sstevel@tonic-gate (void) printf("%-*.*s %-*.*s %*lld %*lld %*lld %-.*s\n", 1365*0Sstevel@tonic-gate IBCS2_MOUNT_POINT_WIDTH, IBCS2_MOUNT_POINT_WIDTH, 1366*0Sstevel@tonic-gate DFR_MOUNT_POINT(dfrp), 1367*0Sstevel@tonic-gate IBCS2_FILESYSTEM_WIDTH, IBCS2_FILESYSTEM_WIDTH, file_system, 1368*0Sstevel@tonic-gate BLOCK_WIDTH, total_blocks, 1369*0Sstevel@tonic-gate BLOCK_WIDTH, used_blocks, 1370*0Sstevel@tonic-gate BLOCK_WIDTH, available_blocks, 1371*0Sstevel@tonic-gate CAPACITY_WIDTH, capacity_buf); 1372*0Sstevel@tonic-gate return; 1373*0Sstevel@tonic-gate } 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate if (P_option && !k_option) { 1376*0Sstevel@tonic-gate (void) printf("%-*s %*s %*s %*s %-*s %-s\n", 1377*0Sstevel@tonic-gate FILESYSTEM_WIDTH, file_system, 1378*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(total_blocks_buf, 1379*0Sstevel@tonic-gate total_blocks, fsp->f_frsize, 512), 1380*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(used_blocks_buf, 1381*0Sstevel@tonic-gate used_blocks, fsp->f_frsize, 512), 1382*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(available_blocks_buf, 1383*0Sstevel@tonic-gate available_blocks, fsp->f_frsize, 512), 1384*0Sstevel@tonic-gate CAPACITY_WIDTH, capacity_buf, 1385*0Sstevel@tonic-gate DFR_MOUNT_POINT(dfrp)); 1386*0Sstevel@tonic-gate } else { 1387*0Sstevel@tonic-gate (void) printf("%-*s %*s %*s %*s %-*s %-s\n", 1388*0Sstevel@tonic-gate FILESYSTEM_WIDTH, file_system, 1389*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(total_blocks_buf, 1390*0Sstevel@tonic-gate total_blocks, fsp->f_frsize, 1024), 1391*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(used_blocks_buf, 1392*0Sstevel@tonic-gate used_blocks, fsp->f_frsize, 1024), 1393*0Sstevel@tonic-gate KBYTE_WIDTH, number_to_string(available_blocks_buf, 1394*0Sstevel@tonic-gate available_blocks, fsp->f_frsize, 1024), 1395*0Sstevel@tonic-gate CAPACITY_WIDTH, capacity_buf, 1396*0Sstevel@tonic-gate DFR_MOUNT_POINT(dfrp)); 1397*0Sstevel@tonic-gate } 1398*0Sstevel@tonic-gate } 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate /* 1401*0Sstevel@tonic-gate * The following is for internationalization support. 1402*0Sstevel@tonic-gate */ 1403*0Sstevel@tonic-gate static bool_int strings_initialized; 1404*0Sstevel@tonic-gate static char *files_str; 1405*0Sstevel@tonic-gate static char *blocks_str; 1406*0Sstevel@tonic-gate static char *total_str; 1407*0Sstevel@tonic-gate static char *kilobytes_str; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate static void 1410*0Sstevel@tonic-gate strings_init() 1411*0Sstevel@tonic-gate { 1412*0Sstevel@tonic-gate total_str = TRANSLATE("total"); 1413*0Sstevel@tonic-gate #ifdef _iBCS2 1414*0Sstevel@tonic-gate /* ISC/SCO print i-nodes instead of files */ 1415*0Sstevel@tonic-gate if (sysv3_set) 1416*0Sstevel@tonic-gate files_str = TRANSLATE("i-nodes"); 1417*0Sstevel@tonic-gate else 1418*0Sstevel@tonic-gate #endif /* _iBCS2 */ 1419*0Sstevel@tonic-gate files_str = TRANSLATE("files"); 1420*0Sstevel@tonic-gate blocks_str = TRANSLATE("blocks"); 1421*0Sstevel@tonic-gate kilobytes_str = TRANSLATE("kilobytes"); 1422*0Sstevel@tonic-gate strings_initialized = TRUE; 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate #define STRINGS_INIT() if (!strings_initialized) strings_init() 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate static void 1429*0Sstevel@tonic-gate t_output(struct df_request *dfrp, struct statvfs64 *fsp) 1430*0Sstevel@tonic-gate { 1431*0Sstevel@tonic-gate numbuf_t total_blocks_buf; 1432*0Sstevel@tonic-gate numbuf_t total_files_buf; 1433*0Sstevel@tonic-gate numbuf_t free_blocks_buf; 1434*0Sstevel@tonic-gate numbuf_t free_files_buf; 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate STRINGS_INIT(); 1437*0Sstevel@tonic-gate 1438*0Sstevel@tonic-gate (void) printf("%-*s(%-*s): %*s %s %*s %s\n", 1439*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1440*0Sstevel@tonic-gate SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp), 1441*0Sstevel@tonic-gate BLOCK_WIDTH, number_to_string(free_blocks_buf, 1442*0Sstevel@tonic-gate fsp->f_bfree, fsp->f_frsize, 512), 1443*0Sstevel@tonic-gate blocks_str, 1444*0Sstevel@tonic-gate NFILES_WIDTH, number_to_string(free_files_buf, 1445*0Sstevel@tonic-gate fsp->f_ffree, 1, 1), 1446*0Sstevel@tonic-gate files_str); 1447*0Sstevel@tonic-gate /* 1448*0Sstevel@tonic-gate * The total column used to use the same space as the mnt pt & special 1449*0Sstevel@tonic-gate * dev fields. However, this doesn't work with massive special dev 1450*0Sstevel@tonic-gate * fields * (eg > 500 chars) causing an enormous amount of white space 1451*0Sstevel@tonic-gate * before the total column (see bug 4100411). So the code was 1452*0Sstevel@tonic-gate * simplified to set the total column at the usual gap. 1453*0Sstevel@tonic-gate * This had the side effect of fixing a bug where the previously 1454*0Sstevel@tonic-gate * used static buffer was overflowed by the same massive special dev. 1455*0Sstevel@tonic-gate */ 1456*0Sstevel@tonic-gate (void) printf("%*s: %*s %s %*s %s\n", 1457*0Sstevel@tonic-gate MNT_SPEC_WIDTH, total_str, 1458*0Sstevel@tonic-gate BLOCK_WIDTH, number_to_string(total_blocks_buf, 1459*0Sstevel@tonic-gate fsp->f_blocks, fsp->f_frsize, 512), 1460*0Sstevel@tonic-gate blocks_str, 1461*0Sstevel@tonic-gate NFILES_WIDTH, number_to_string(total_files_buf, 1462*0Sstevel@tonic-gate fsp->f_files, 1, 1), 1463*0Sstevel@tonic-gate files_str); 1464*0Sstevel@tonic-gate } 1465*0Sstevel@tonic-gate 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate static void 1468*0Sstevel@tonic-gate eb_output(struct df_request *dfrp, struct statvfs64 *fsp) 1469*0Sstevel@tonic-gate { 1470*0Sstevel@tonic-gate numbuf_t free_files_buf; 1471*0Sstevel@tonic-gate numbuf_t free_kbytes_buf; 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate STRINGS_INIT(); 1474*0Sstevel@tonic-gate 1475*0Sstevel@tonic-gate (void) printf("%-*s(%-*s): %*s %s\n", 1476*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1477*0Sstevel@tonic-gate SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp), 1478*0Sstevel@tonic-gate MAX(KBYTE_WIDTH, NFILES_WIDTH), 1479*0Sstevel@tonic-gate number_to_string(free_kbytes_buf, 1480*0Sstevel@tonic-gate fsp->f_bfree, fsp->f_frsize, 1024), 1481*0Sstevel@tonic-gate kilobytes_str); 1482*0Sstevel@tonic-gate (void) printf("%-*s(%-*s): %*s %s\n", 1483*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1484*0Sstevel@tonic-gate SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp), 1485*0Sstevel@tonic-gate MAX(NFILES_WIDTH, NFILES_WIDTH), 1486*0Sstevel@tonic-gate number_to_string(free_files_buf, fsp->f_ffree, 1, 1), 1487*0Sstevel@tonic-gate files_str); 1488*0Sstevel@tonic-gate } 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate static void 1492*0Sstevel@tonic-gate e_output(struct df_request *dfrp, struct statvfs64 *fsp) 1493*0Sstevel@tonic-gate { 1494*0Sstevel@tonic-gate numbuf_t free_files_buf; 1495*0Sstevel@tonic-gate 1496*0Sstevel@tonic-gate (void) printf("%-*s %*s\n", 1497*0Sstevel@tonic-gate FILESYSTEM_WIDTH, DFR_SPECIAL(dfrp), 1498*0Sstevel@tonic-gate NFILES_WIDTH, 1499*0Sstevel@tonic-gate number_to_string(free_files_buf, fsp->f_ffree, 1, 1)); 1500*0Sstevel@tonic-gate } 1501*0Sstevel@tonic-gate 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gate static void 1504*0Sstevel@tonic-gate b_output(struct df_request *dfrp, struct statvfs64 *fsp) 1505*0Sstevel@tonic-gate { 1506*0Sstevel@tonic-gate numbuf_t free_blocks_buf; 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate (void) printf("%-*s %*s\n", 1509*0Sstevel@tonic-gate FILESYSTEM_WIDTH, DFR_SPECIAL(dfrp), 1510*0Sstevel@tonic-gate BLOCK_WIDTH, number_to_string(free_blocks_buf, 1511*0Sstevel@tonic-gate fsp->f_bfree, fsp->f_frsize, 1024)); 1512*0Sstevel@tonic-gate } 1513*0Sstevel@tonic-gate 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate /* ARGSUSED */ 1516*0Sstevel@tonic-gate static void 1517*0Sstevel@tonic-gate n_output(struct df_request *dfrp, struct statvfs64 *fsp) 1518*0Sstevel@tonic-gate { 1519*0Sstevel@tonic-gate (void) printf("%-*s: %-*s\n", 1520*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1521*0Sstevel@tonic-gate FSTYPE_WIDTH, dfrp->dfr_fstype); 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate static void 1526*0Sstevel@tonic-gate default_output(struct df_request *dfrp, struct statvfs64 *fsp) 1527*0Sstevel@tonic-gate { 1528*0Sstevel@tonic-gate numbuf_t free_blocks_buf; 1529*0Sstevel@tonic-gate numbuf_t free_files_buf; 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate STRINGS_INIT(); 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate (void) printf("%-*s(%-*s):%*s %s %*s %s\n", 1534*0Sstevel@tonic-gate MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp), 1535*0Sstevel@tonic-gate SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp), 1536*0Sstevel@tonic-gate BLOCK_WIDTH, number_to_string(free_blocks_buf, 1537*0Sstevel@tonic-gate fsp->f_bfree, fsp->f_frsize, 512), 1538*0Sstevel@tonic-gate blocks_str, 1539*0Sstevel@tonic-gate NFILES_WIDTH, number_to_string(free_files_buf, 1540*0Sstevel@tonic-gate fsp->f_ffree, 1, 1), 1541*0Sstevel@tonic-gate files_str); 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate /* ARGSUSED */ 1546*0Sstevel@tonic-gate static void 1547*0Sstevel@tonic-gate V_output(struct df_request *dfrp, struct statvfs64 *fsp) 1548*0Sstevel@tonic-gate { 1549*0Sstevel@tonic-gate char temp_buf[LINEBUF_SIZE]; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate if (df_options_len > 1) 1552*0Sstevel@tonic-gate (void) strcat(strcpy(temp_buf, df_options), " "); 1553*0Sstevel@tonic-gate else 1554*0Sstevel@tonic-gate temp_buf[0] = NUL; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate (void) printf("%s -F %s %s%s\n", 1557*0Sstevel@tonic-gate program_name, dfrp->dfr_fstype, temp_buf, 1558*0Sstevel@tonic-gate dfrp->dfr_cmd_arg ? dfrp->dfr_cmd_arg: DFR_SPECIAL(dfrp)); 1559*0Sstevel@tonic-gate } 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate /* 1563*0Sstevel@tonic-gate * This function is used to sort the array of df_requests according to fstype 1564*0Sstevel@tonic-gate */ 1565*0Sstevel@tonic-gate static int 1566*0Sstevel@tonic-gate df_reqcomp(const void *p1, const void *p2) 1567*0Sstevel@tonic-gate { 1568*0Sstevel@tonic-gate int v = strcmp(DFRP(p1)->dfr_fstype, DFRP(p2)->dfr_fstype); 1569*0Sstevel@tonic-gate 1570*0Sstevel@tonic-gate if (v != 0) 1571*0Sstevel@tonic-gate return (v); 1572*0Sstevel@tonic-gate else 1573*0Sstevel@tonic-gate return (DFRP(p1)->dfr_index - DFRP(p2)->dfr_index); 1574*0Sstevel@tonic-gate } 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gate static void 1578*0Sstevel@tonic-gate vfs_error(char *file, int status) 1579*0Sstevel@tonic-gate { 1580*0Sstevel@tonic-gate if (status == VFS_TOOLONG) 1581*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, "a line in %s exceeds %d characters", 1582*0Sstevel@tonic-gate file, MNT_LINE_MAX); 1583*0Sstevel@tonic-gate else if (status == VFS_TOOMANY) 1584*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, "a line in %s has too many fields", file); 1585*0Sstevel@tonic-gate else if (status == VFS_TOOFEW) 1586*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, "a line in %s has too few fields", file); 1587*0Sstevel@tonic-gate else 1588*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, "error while reading %s: %d", file, status); 1589*0Sstevel@tonic-gate } 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate 1592*0Sstevel@tonic-gate /* 1593*0Sstevel@tonic-gate * Try to determine the fstype for the specified block device. 1594*0Sstevel@tonic-gate * Return in order of decreasing preference: 1595*0Sstevel@tonic-gate * file system type from vfstab 1596*0Sstevel@tonic-gate * file system type as specified by -F option 1597*0Sstevel@tonic-gate * default file system type 1598*0Sstevel@tonic-gate */ 1599*0Sstevel@tonic-gate static char * 1600*0Sstevel@tonic-gate find_fstype(char *special) 1601*0Sstevel@tonic-gate { 1602*0Sstevel@tonic-gate struct vfstab vtab; 1603*0Sstevel@tonic-gate FILE *fp; 1604*0Sstevel@tonic-gate int status; 1605*0Sstevel@tonic-gate char *vfstab_file = VFS_TAB; 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate fp = xfopen(vfstab_file); 1608*0Sstevel@tonic-gate status = getvfsspec(fp, &vtab, special); 1609*0Sstevel@tonic-gate (void) fclose(fp); 1610*0Sstevel@tonic-gate if (status > 0) 1611*0Sstevel@tonic-gate vfs_error(vfstab_file, status); 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate if (status == 0) { 1614*0Sstevel@tonic-gate if (F_option && ! EQ(FSType, vtab.vfs_fstype)) 1615*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 1616*0Sstevel@tonic-gate "warning: %s is of type %s", special, vtab.vfs_fstype); 1617*0Sstevel@tonic-gate return (new_string(vtab.vfs_fstype)); 1618*0Sstevel@tonic-gate } 1619*0Sstevel@tonic-gate else 1620*0Sstevel@tonic-gate return (F_option ? FSType : default_fstype(special)); 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate /* 1624*0Sstevel@tonic-gate * When this function returns, the following fields are filled for all 1625*0Sstevel@tonic-gate * valid entries in the requests[] array: 1626*0Sstevel@tonic-gate * dfr_mte (if the file system is mounted) 1627*0Sstevel@tonic-gate * dfr_fstype 1628*0Sstevel@tonic-gate * dfr_index 1629*0Sstevel@tonic-gate * 1630*0Sstevel@tonic-gate * The function returns the number of errors that occurred while building 1631*0Sstevel@tonic-gate * the request list. 1632*0Sstevel@tonic-gate */ 1633*0Sstevel@tonic-gate static int 1634*0Sstevel@tonic-gate create_request_list( 1635*0Sstevel@tonic-gate int argc, 1636*0Sstevel@tonic-gate char *argv[], 1637*0Sstevel@tonic-gate struct df_request *requests_p[], 1638*0Sstevel@tonic-gate size_t *request_count) 1639*0Sstevel@tonic-gate { 1640*0Sstevel@tonic-gate struct df_request *requests; 1641*0Sstevel@tonic-gate struct df_request *dfrp; 1642*0Sstevel@tonic-gate size_t size; 1643*0Sstevel@tonic-gate size_t i; 1644*0Sstevel@tonic-gate size_t request_index = 0; 1645*0Sstevel@tonic-gate size_t max_requests; 1646*0Sstevel@tonic-gate int errors = 0; 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate /* 1649*0Sstevel@tonic-gate * If no args, use the mounted file systems, otherwise use the 1650*0Sstevel@tonic-gate * user-specified arguments. 1651*0Sstevel@tonic-gate */ 1652*0Sstevel@tonic-gate if (argc == 0) { 1653*0Sstevel@tonic-gate mtab_read_file(); 1654*0Sstevel@tonic-gate max_requests = mount_table_entries; 1655*0Sstevel@tonic-gate } else 1656*0Sstevel@tonic-gate max_requests = argc; 1657*0Sstevel@tonic-gate 1658*0Sstevel@tonic-gate size = max_requests * sizeof (struct df_request); 1659*0Sstevel@tonic-gate requests = xmalloc(size); 1660*0Sstevel@tonic-gate (void) memset(requests, 0, size); 1661*0Sstevel@tonic-gate 1662*0Sstevel@tonic-gate if (argc == 0) { 1663*0Sstevel@tonic-gate /* 1664*0Sstevel@tonic-gate * If -Z wasn't specified, we skip mounts in other 1665*0Sstevel@tonic-gate * zones. This obviously is a noop in a non-global 1666*0Sstevel@tonic-gate * zone. 1667*0Sstevel@tonic-gate */ 1668*0Sstevel@tonic-gate boolean_t showall = (getzoneid() != GLOBAL_ZONEID) || Z_option; 1669*0Sstevel@tonic-gate struct zone_summary *zsp; 1670*0Sstevel@tonic-gate 1671*0Sstevel@tonic-gate if (!showall) { 1672*0Sstevel@tonic-gate zsp = fs_get_zone_summaries(); 1673*0Sstevel@tonic-gate if (zsp == NULL) 1674*0Sstevel@tonic-gate errmsg(ERR_FATAL, 1675*0Sstevel@tonic-gate "unable to retrieve list of zones"); 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate for (i = 0; i < mount_table_entries; i++) { 1679*0Sstevel@tonic-gate struct extmnttab *mtp = mount_table[i].mte_mount; 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate if (EQ(mtp->mnt_fstype, MNTTYPE_SWAP)) 1682*0Sstevel@tonic-gate continue; 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate if (!showall) { 1685*0Sstevel@tonic-gate if (fs_mount_in_other_zone(zsp, 1686*0Sstevel@tonic-gate mtp->mnt_mountp)) 1687*0Sstevel@tonic-gate continue; 1688*0Sstevel@tonic-gate } 1689*0Sstevel@tonic-gate dfrp = &requests[request_index++]; 1690*0Sstevel@tonic-gate dfrp->dfr_mte = &mount_table[i]; 1691*0Sstevel@tonic-gate dfrp->dfr_fstype = mtp->mnt_fstype; 1692*0Sstevel@tonic-gate dfrp->dfr_index = i; 1693*0Sstevel@tonic-gate dfrp->dfr_valid = TRUE; 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate } else { 1696*0Sstevel@tonic-gate struct stat64 *arg_stat; /* array of stat structures */ 1697*0Sstevel@tonic-gate bool_int *valid_stat; /* which structures are valid */ 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate arg_stat = xmalloc(argc * sizeof (struct stat64)); 1700*0Sstevel@tonic-gate valid_stat = xmalloc(argc * sizeof (bool_int)); 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate /* 1703*0Sstevel@tonic-gate * Obtain stat64 information for each argument before 1704*0Sstevel@tonic-gate * constructing the list of mounted file systems. By 1705*0Sstevel@tonic-gate * touching all these places we force the automounter 1706*0Sstevel@tonic-gate * to establish any mounts required to access the arguments, 1707*0Sstevel@tonic-gate * so that the corresponding mount table entries will exist 1708*0Sstevel@tonic-gate * when we look for them. 1709*0Sstevel@tonic-gate * It is still possible that the automounter may timeout 1710*0Sstevel@tonic-gate * mounts between the time we read the mount table and the 1711*0Sstevel@tonic-gate * time we process the request. Even in that case, when 1712*0Sstevel@tonic-gate * we issue the statvfs64(2) for the mount point, the file 1713*0Sstevel@tonic-gate * system will be mounted again. The only problem will 1714*0Sstevel@tonic-gate * occur if the automounter maps change in the meantime 1715*0Sstevel@tonic-gate * and the mount point is eliminated. 1716*0Sstevel@tonic-gate */ 1717*0Sstevel@tonic-gate for (i = 0; i < argc; i++) 1718*0Sstevel@tonic-gate valid_stat[i] = (stat64(argv[i], &arg_stat[i]) == 0); 1719*0Sstevel@tonic-gate 1720*0Sstevel@tonic-gate mtab_read_file(); 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate for (i = 0; i < argc; i++) { 1723*0Sstevel@tonic-gate char *arg = argv[i]; 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate dfrp = &requests[request_index]; 1726*0Sstevel@tonic-gate 1727*0Sstevel@tonic-gate dfrp->dfr_index = request_index; 1728*0Sstevel@tonic-gate dfrp->dfr_cmd_arg = arg; 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate if (valid_stat[i]) { 1731*0Sstevel@tonic-gate if (S_ISBLK(arg_stat[i].st_mode)) { 1732*0Sstevel@tonic-gate bdev_mount_entry(dfrp); 1733*0Sstevel@tonic-gate dfrp->dfr_valid = TRUE; 1734*0Sstevel@tonic-gate } else if (S_ISDIR(arg_stat[i].st_mode) || 1735*0Sstevel@tonic-gate S_ISREG(arg_stat[i].st_mode) || 1736*0Sstevel@tonic-gate S_ISFIFO(arg_stat[i].st_mode)) { 1737*0Sstevel@tonic-gate path_mount_entry(dfrp, 1738*0Sstevel@tonic-gate arg_stat[i].st_dev); 1739*0Sstevel@tonic-gate if (! DFR_ISMOUNTEDFS(dfrp)) { 1740*0Sstevel@tonic-gate errors++; 1741*0Sstevel@tonic-gate continue; 1742*0Sstevel@tonic-gate } 1743*0Sstevel@tonic-gate dfrp->dfr_valid = TRUE; 1744*0Sstevel@tonic-gate } 1745*0Sstevel@tonic-gate } else { 1746*0Sstevel@tonic-gate resource_mount_entry(dfrp); 1747*0Sstevel@tonic-gate dfrp->dfr_valid = DFR_ISMOUNTEDFS(dfrp); 1748*0Sstevel@tonic-gate } 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate /* 1751*0Sstevel@tonic-gate * If we haven't managed to verify that the request 1752*0Sstevel@tonic-gate * is valid, we must have gotten a bad argument. 1753*0Sstevel@tonic-gate */ 1754*0Sstevel@tonic-gate if (!dfrp->dfr_valid) { 1755*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 1756*0Sstevel@tonic-gate "(%-10s) not a block device, directory or mounted resource", 1757*0Sstevel@tonic-gate arg); 1758*0Sstevel@tonic-gate errors++; 1759*0Sstevel@tonic-gate continue; 1760*0Sstevel@tonic-gate } 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate /* 1763*0Sstevel@tonic-gate * Determine the file system type. 1764*0Sstevel@tonic-gate */ 1765*0Sstevel@tonic-gate if (DFR_ISMOUNTEDFS(dfrp)) 1766*0Sstevel@tonic-gate dfrp->dfr_fstype = 1767*0Sstevel@tonic-gate dfrp->dfr_mte->mte_mount->mnt_fstype; 1768*0Sstevel@tonic-gate else 1769*0Sstevel@tonic-gate dfrp->dfr_fstype = 1770*0Sstevel@tonic-gate find_fstype(dfrp->dfr_cmd_arg); 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate request_index++; 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate } 1775*0Sstevel@tonic-gate *requests_p = requests; 1776*0Sstevel@tonic-gate *request_count = request_index; 1777*0Sstevel@tonic-gate return (errors); 1778*0Sstevel@tonic-gate } 1779*0Sstevel@tonic-gate 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate /* 1782*0Sstevel@tonic-gate * Select the appropriate function and flags to use for output. 1783*0Sstevel@tonic-gate * Notice that using both -e and -b options produces a different form of 1784*0Sstevel@tonic-gate * output than either of those two options alone; this is the behavior of 1785*0Sstevel@tonic-gate * the SVR4 df. 1786*0Sstevel@tonic-gate */ 1787*0Sstevel@tonic-gate static struct df_output * 1788*0Sstevel@tonic-gate select_output() 1789*0Sstevel@tonic-gate { 1790*0Sstevel@tonic-gate static struct df_output dfo; 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate /* 1793*0Sstevel@tonic-gate * The order of checking options follows the option precedence 1794*0Sstevel@tonic-gate * rules as they are listed in the man page. 1795*0Sstevel@tonic-gate */ 1796*0Sstevel@tonic-gate if (use_scaling) { /* comes from the -h option */ 1797*0Sstevel@tonic-gate dfo.dfo_func = k_output; 1798*0Sstevel@tonic-gate dfo.dfo_flags = DFO_HEADER + DFO_STATVFS; 1799*0Sstevel@tonic-gate } else if (V_option) { 1800*0Sstevel@tonic-gate dfo.dfo_func = V_output; 1801*0Sstevel@tonic-gate dfo.dfo_flags = DFO_NOFLAGS; 1802*0Sstevel@tonic-gate } else if (g_option) { 1803*0Sstevel@tonic-gate dfo.dfo_func = g_output; 1804*0Sstevel@tonic-gate dfo.dfo_flags = DFO_STATVFS; 1805*0Sstevel@tonic-gate } else if (k_option || P_option || v_option) { 1806*0Sstevel@tonic-gate dfo.dfo_func = k_output; 1807*0Sstevel@tonic-gate dfo.dfo_flags = DFO_HEADER + DFO_STATVFS; 1808*0Sstevel@tonic-gate } else if (t_option) { 1809*0Sstevel@tonic-gate dfo.dfo_func = t_output; 1810*0Sstevel@tonic-gate dfo.dfo_flags = DFO_STATVFS; 1811*0Sstevel@tonic-gate } else if (b_option && e_option) { 1812*0Sstevel@tonic-gate dfo.dfo_func = eb_output; 1813*0Sstevel@tonic-gate dfo.dfo_flags = DFO_STATVFS; 1814*0Sstevel@tonic-gate } else if (b_option) { 1815*0Sstevel@tonic-gate dfo.dfo_func = b_output; 1816*0Sstevel@tonic-gate dfo.dfo_flags = DFO_HEADER + DFO_STATVFS; 1817*0Sstevel@tonic-gate } else if (e_option) { 1818*0Sstevel@tonic-gate dfo.dfo_func = e_output; 1819*0Sstevel@tonic-gate dfo.dfo_flags = DFO_HEADER + DFO_STATVFS; 1820*0Sstevel@tonic-gate } else if (n_option) { 1821*0Sstevel@tonic-gate dfo.dfo_func = n_output; 1822*0Sstevel@tonic-gate dfo.dfo_flags = DFO_NOFLAGS; 1823*0Sstevel@tonic-gate } else { 1824*0Sstevel@tonic-gate dfo.dfo_func = default_output; 1825*0Sstevel@tonic-gate dfo.dfo_flags = DFO_STATVFS; 1826*0Sstevel@tonic-gate } 1827*0Sstevel@tonic-gate return (&dfo); 1828*0Sstevel@tonic-gate } 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate /* 1832*0Sstevel@tonic-gate * The (argc,argv) pair contains all the non-option arguments 1833*0Sstevel@tonic-gate */ 1834*0Sstevel@tonic-gate static void 1835*0Sstevel@tonic-gate do_df(int argc, char *argv[]) 1836*0Sstevel@tonic-gate { 1837*0Sstevel@tonic-gate size_t i; 1838*0Sstevel@tonic-gate struct df_request *requests; /* array of requests */ 1839*0Sstevel@tonic-gate size_t n_requests; 1840*0Sstevel@tonic-gate struct df_request *dfrp; 1841*0Sstevel@tonic-gate int errors; 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate errors = create_request_list(argc, argv, &requests, &n_requests); 1844*0Sstevel@tonic-gate 1845*0Sstevel@tonic-gate if (n_requests == 0) 1846*0Sstevel@tonic-gate exit(errors); 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate /* 1849*0Sstevel@tonic-gate * If we are going to run the FSType-specific df command, 1850*0Sstevel@tonic-gate * rearrange the requests so that we can issue a single command 1851*0Sstevel@tonic-gate * per file system type. 1852*0Sstevel@tonic-gate */ 1853*0Sstevel@tonic-gate if (o_option) { 1854*0Sstevel@tonic-gate size_t j; 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate /* 1857*0Sstevel@tonic-gate * qsort is not a stable sorting method (i.e. requests of 1858*0Sstevel@tonic-gate * the same file system type may be swapped, and hence appear 1859*0Sstevel@tonic-gate * in the output in a different order from the one in which 1860*0Sstevel@tonic-gate * they were listed in the command line). In order to force 1861*0Sstevel@tonic-gate * stability, we use the dfr_index field which is unique 1862*0Sstevel@tonic-gate * for each request. 1863*0Sstevel@tonic-gate */ 1864*0Sstevel@tonic-gate qsort(requests, 1865*0Sstevel@tonic-gate n_requests, sizeof (struct df_request), df_reqcomp); 1866*0Sstevel@tonic-gate for (i = 0; i < n_requests; i = j) { 1867*0Sstevel@tonic-gate char *fstype = requests[i].dfr_fstype; 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate for (j = i+1; j < n_requests; j++) 1870*0Sstevel@tonic-gate if (! EQ(fstype, requests[j].dfr_fstype)) 1871*0Sstevel@tonic-gate break; 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate /* 1874*0Sstevel@tonic-gate * At this point, requests in the range [i,j) are 1875*0Sstevel@tonic-gate * of the same type. 1876*0Sstevel@tonic-gate * 1877*0Sstevel@tonic-gate * If the -F option was used, and the user specified 1878*0Sstevel@tonic-gate * arguments, the filesystem types must match 1879*0Sstevel@tonic-gate * 1880*0Sstevel@tonic-gate * XXX: the alternative of doing this check here is to 1881*0Sstevel@tonic-gate * invoke prune_list, but then we have to 1882*0Sstevel@tonic-gate * modify this code to ignore invalid requests. 1883*0Sstevel@tonic-gate */ 1884*0Sstevel@tonic-gate if (F_option && ! EQ(fstype, FSType)) { 1885*0Sstevel@tonic-gate size_t k; 1886*0Sstevel@tonic-gate 1887*0Sstevel@tonic-gate for (k = i; k < j; k++) { 1888*0Sstevel@tonic-gate dfrp = &requests[k]; 1889*0Sstevel@tonic-gate if (dfrp->dfr_cmd_arg != NULL) { 1890*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 1891*0Sstevel@tonic-gate "Warning: %s mounted as a %s file system", 1892*0Sstevel@tonic-gate dfrp->dfr_cmd_arg, dfrp->dfr_fstype); 1893*0Sstevel@tonic-gate errors++; 1894*0Sstevel@tonic-gate } 1895*0Sstevel@tonic-gate } 1896*0Sstevel@tonic-gate } else 1897*0Sstevel@tonic-gate errors += run_fs_specific_df(&requests[i], j-i); 1898*0Sstevel@tonic-gate } 1899*0Sstevel@tonic-gate } else { 1900*0Sstevel@tonic-gate size_t valid_requests; 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate /* 1903*0Sstevel@tonic-gate * We have to prune the request list to avoid printing a header 1904*0Sstevel@tonic-gate * if there are no valid requests 1905*0Sstevel@tonic-gate */ 1906*0Sstevel@tonic-gate errors += prune_list(requests, n_requests, &valid_requests); 1907*0Sstevel@tonic-gate 1908*0Sstevel@tonic-gate if (valid_requests) { 1909*0Sstevel@tonic-gate struct df_output *dfop = select_output(); 1910*0Sstevel@tonic-gate 1911*0Sstevel@tonic-gate /* indicates if we already printed out a header line */ 1912*0Sstevel@tonic-gate int printed_header = 0; 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate for (i = 0; i < n_requests; i++) { 1915*0Sstevel@tonic-gate dfrp = &requests[i]; 1916*0Sstevel@tonic-gate if (! dfrp->dfr_valid) 1917*0Sstevel@tonic-gate continue; 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate /* 1920*0Sstevel@tonic-gate * If we don't have a mount point, 1921*0Sstevel@tonic-gate * this must be a block device. 1922*0Sstevel@tonic-gate */ 1923*0Sstevel@tonic-gate if (DFR_ISMOUNTEDFS(dfrp)) { 1924*0Sstevel@tonic-gate struct statvfs64 stvfs; 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate if ((dfop->dfo_flags & DFO_STATVFS) && 1927*0Sstevel@tonic-gate statvfs64(DFR_MOUNT_POINT(dfrp), 1928*0Sstevel@tonic-gate &stvfs) == -1) { 1929*0Sstevel@tonic-gate errmsg(ERR_PERROR, 1930*0Sstevel@tonic-gate "cannot statvfs %s:", 1931*0Sstevel@tonic-gate DFR_MOUNT_POINT(dfrp)); 1932*0Sstevel@tonic-gate errors++; 1933*0Sstevel@tonic-gate continue; 1934*0Sstevel@tonic-gate } 1935*0Sstevel@tonic-gate if ((!printed_header) && 1936*0Sstevel@tonic-gate (dfop->dfo_flags & DFO_HEADER)) { 1937*0Sstevel@tonic-gate print_header(); 1938*0Sstevel@tonic-gate printed_header = 1; 1939*0Sstevel@tonic-gate } 1940*0Sstevel@tonic-gate 1941*0Sstevel@tonic-gate (*dfop->dfo_func)(dfrp, &stvfs); 1942*0Sstevel@tonic-gate } else { 1943*0Sstevel@tonic-gate /* 1944*0Sstevel@tonic-gate * -h option only works for 1945*0Sstevel@tonic-gate * mounted filesystems 1946*0Sstevel@tonic-gate */ 1947*0Sstevel@tonic-gate if (use_scaling) { 1948*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 1949*0Sstevel@tonic-gate "-h option incompatible with unmounted special device (%s)", 1950*0Sstevel@tonic-gate dfrp->dfr_cmd_arg); 1951*0Sstevel@tonic-gate errors++; 1952*0Sstevel@tonic-gate continue; 1953*0Sstevel@tonic-gate } 1954*0Sstevel@tonic-gate errors += run_fs_specific_df(dfrp, 1); 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate } 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate exit(errors); 1960*0Sstevel@tonic-gate } 1961*0Sstevel@tonic-gate 1962*0Sstevel@tonic-gate 1963*0Sstevel@tonic-gate /* 1964*0Sstevel@tonic-gate * The rest of this file implements the devnm command 1965*0Sstevel@tonic-gate */ 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate static char * 1968*0Sstevel@tonic-gate find_dev_name(char *file, dev_t dev) 1969*0Sstevel@tonic-gate { 1970*0Sstevel@tonic-gate struct df_request dfreq; 1971*0Sstevel@tonic-gate 1972*0Sstevel@tonic-gate dfreq.dfr_cmd_arg = file; 1973*0Sstevel@tonic-gate dfreq.dfr_fstype = 0; 1974*0Sstevel@tonic-gate dfreq.dfr_mte = NULL; 1975*0Sstevel@tonic-gate path_mount_entry(&dfreq, dev); 1976*0Sstevel@tonic-gate return (DFR_ISMOUNTEDFS(&dfreq) ? DFR_SPECIAL(&dfreq) : NULL); 1977*0Sstevel@tonic-gate } 1978*0Sstevel@tonic-gate 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate static void 1981*0Sstevel@tonic-gate do_devnm(int argc, char *argv[]) 1982*0Sstevel@tonic-gate { 1983*0Sstevel@tonic-gate int arg; 1984*0Sstevel@tonic-gate int errors = 0; 1985*0Sstevel@tonic-gate char *dev_name; 1986*0Sstevel@tonic-gate 1987*0Sstevel@tonic-gate if (argc == 1) 1988*0Sstevel@tonic-gate errmsg(ERR_NONAME, "Usage: %s name ...", DEVNM_CMD); 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate mtab_read_file(); 1991*0Sstevel@tonic-gate 1992*0Sstevel@tonic-gate for (arg = 1; arg < argc; arg++) { 1993*0Sstevel@tonic-gate char *file = argv[arg]; 1994*0Sstevel@tonic-gate struct stat64 st; 1995*0Sstevel@tonic-gate 1996*0Sstevel@tonic-gate if (stat64(file, &st) == -1) { 1997*0Sstevel@tonic-gate errmsg(ERR_PERROR, "%s: ", file); 1998*0Sstevel@tonic-gate errors++; 1999*0Sstevel@tonic-gate continue; 2000*0Sstevel@tonic-gate } 2001*0Sstevel@tonic-gate 2002*0Sstevel@tonic-gate if (! is_remote_fs(st.st_fstype) && 2003*0Sstevel@tonic-gate ! EQ(st.st_fstype, MNTTYPE_TMPFS) && 2004*0Sstevel@tonic-gate (dev_name = find_dev_name(file, st.st_dev))) 2005*0Sstevel@tonic-gate (void) printf("%s %s\n", dev_name, file); 2006*0Sstevel@tonic-gate else 2007*0Sstevel@tonic-gate errmsg(ERR_NOFLAGS, 2008*0Sstevel@tonic-gate "%s not found", file); 2009*0Sstevel@tonic-gate } 2010*0Sstevel@tonic-gate exit(errors); 2011*0Sstevel@tonic-gate /* NOTREACHED */ 2012*0Sstevel@tonic-gate } 2013