1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* 36*7c478bd9Sstevel@tonic-gate * List files or directories 37*7c478bd9Sstevel@tonic-gate */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate #include <wchar.h> 46*7c478bd9Sstevel@tonic-gate #include <stdio.h> 47*7c478bd9Sstevel@tonic-gate #include <ctype.h> 48*7c478bd9Sstevel@tonic-gate #include <dirent.h> 49*7c478bd9Sstevel@tonic-gate #include <string.h> 50*7c478bd9Sstevel@tonic-gate #include <locale.h> 51*7c478bd9Sstevel@tonic-gate #include <curses.h> 52*7c478bd9Sstevel@tonic-gate #include <termios.h> 53*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 54*7c478bd9Sstevel@tonic-gate #include <widec.h> 55*7c478bd9Sstevel@tonic-gate #include <locale.h> 56*7c478bd9Sstevel@tonic-gate #include <wctype.h> 57*7c478bd9Sstevel@tonic-gate #include <pwd.h> 58*7c478bd9Sstevel@tonic-gate #include <grp.h> 59*7c478bd9Sstevel@tonic-gate #include <limits.h> 60*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 61*7c478bd9Sstevel@tonic-gate #include <unistd.h> 62*7c478bd9Sstevel@tonic-gate #include <libgen.h> 63*7c478bd9Sstevel@tonic-gate #include <errno.h> 64*7c478bd9Sstevel@tonic-gate #include <libcmdutils.h> 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #ifndef STANDALONE 67*7c478bd9Sstevel@tonic-gate #define TERMINFO 68*7c478bd9Sstevel@tonic-gate #endif 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 72*7c478bd9Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 73*7c478bd9Sstevel@tonic-gate * the terminfo feature(pre 6.0 sytems ?). 74*7c478bd9Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 75*7c478bd9Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO 78*7c478bd9Sstevel@tonic-gate #undef TERMINFO 79*7c478bd9Sstevel@tonic-gate #endif 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate #include <term.h> 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate #define BFSIZE 16 84*7c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 85*7c478bd9Sstevel@tonic-gate #define ISARG 0100000 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 89*7c478bd9Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate #define LS_NOTREG 010000 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate /* 95*7c478bd9Sstevel@tonic-gate * Date and time formats 96*7c478bd9Sstevel@tonic-gate * 97*7c478bd9Sstevel@tonic-gate * b --- abbreviated month name 98*7c478bd9Sstevel@tonic-gate * e --- day number 99*7c478bd9Sstevel@tonic-gate * Y --- year in the form ccyy 100*7c478bd9Sstevel@tonic-gate * H --- hour(24-hour version) 101*7c478bd9Sstevel@tonic-gate * M --- minute 102*7c478bd9Sstevel@tonic-gate * F --- yyyy-mm-dd 103*7c478bd9Sstevel@tonic-gate * T --- hh:mm:ss 104*7c478bd9Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 105*7c478bd9Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 106*7c478bd9Sstevel@tonic-gate * not present in older C libraries 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate #define FORMAT1 " %b %e %Y " 109*7c478bd9Sstevel@tonic-gate #define FORMAT2 " %b %e %H:%M " 110*7c478bd9Sstevel@tonic-gate #define FORMAT3 " %b %e %T %Y " 111*7c478bd9Sstevel@tonic-gate #define FORMAT4 " %%F %%T.%.09ld %%z " 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate #undef BUFSIZ 114*7c478bd9Sstevel@tonic-gate #define BUFSIZ 4096 115*7c478bd9Sstevel@tonic-gate #define NUMBER_WIDTH 40 116*7c478bd9Sstevel@tonic-gate #define FMTSIZE 50 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate struct ditem { 119*7c478bd9Sstevel@tonic-gate dev_t dev; /* directory items device number */ 120*7c478bd9Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 121*7c478bd9Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 122*7c478bd9Sstevel@tonic-gate }; 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate struct lbuf { 125*7c478bd9Sstevel@tonic-gate union { 126*7c478bd9Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 127*7c478bd9Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 128*7c478bd9Sstevel@tonic-gate } ln; 129*7c478bd9Sstevel@tonic-gate char ltype; /* filetype */ 130*7c478bd9Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 131*7c478bd9Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 132*7c478bd9Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 133*7c478bd9Sstevel@tonic-gate uid_t luid; 134*7c478bd9Sstevel@tonic-gate gid_t lgid; 135*7c478bd9Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 136*7c478bd9Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 137*7c478bd9Sstevel@tonic-gate timestruc_t lmtime; 138*7c478bd9Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 139*7c478bd9Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 140*7c478bd9Sstevel@tonic-gate int cycle; /* cycle detected flag */ 141*7c478bd9Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 142*7c478bd9Sstevel@tonic-gate }; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate struct dchain { 145*7c478bd9Sstevel@tonic-gate char *dc_name; /* path name */ 146*7c478bd9Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 147*7c478bd9Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 148*7c478bd9Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 149*7c478bd9Sstevel@tonic-gate }; 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 157*7c478bd9Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 158*7c478bd9Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 159*7c478bd9Sstevel@tonic-gate static char *curdir; /* the current directory */ 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 162*7c478bd9Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 163*7c478bd9Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 164*7c478bd9Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 165*7c478bd9Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 166*7c478bd9Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 169*7c478bd9Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 170*7c478bd9Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 171*7c478bd9Sstevel@tonic-gate static char *getname(uid_t); 172*7c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 173*7c478bd9Sstevel@tonic-gate static char *makename(char *, char *); 174*7c478bd9Sstevel@tonic-gate static void pentry(struct lbuf *); 175*7c478bd9Sstevel@tonic-gate static void column(void); 176*7c478bd9Sstevel@tonic-gate static void pmode(mode_t aflag); 177*7c478bd9Sstevel@tonic-gate static void selection(int *); 178*7c478bd9Sstevel@tonic-gate static void new_line(void); 179*7c478bd9Sstevel@tonic-gate static void rddir(char *, struct ditem *); 180*7c478bd9Sstevel@tonic-gate static int strcol(unsigned char *); 181*7c478bd9Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 182*7c478bd9Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 183*7c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 184*7c478bd9Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 185*7c478bd9Sstevel@tonic-gate static void pprintf(char *, char *); 186*7c478bd9Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 187*7c478bd9Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 188*7c478bd9Sstevel@tonic-gate unsigned long long number, 189*7c478bd9Sstevel@tonic-gate long scale); 190*7c478bd9Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 191*7c478bd9Sstevel@tonic-gate int, struct ditem *); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate static int aflg; 194*7c478bd9Sstevel@tonic-gate static int atflg; 195*7c478bd9Sstevel@tonic-gate static int bflg; 196*7c478bd9Sstevel@tonic-gate static int cflg; 197*7c478bd9Sstevel@tonic-gate static int dflg; 198*7c478bd9Sstevel@tonic-gate static int eflg; 199*7c478bd9Sstevel@tonic-gate static int fflg; 200*7c478bd9Sstevel@tonic-gate static int gflg; 201*7c478bd9Sstevel@tonic-gate static int hflg; 202*7c478bd9Sstevel@tonic-gate static int iflg; 203*7c478bd9Sstevel@tonic-gate static int lflg; 204*7c478bd9Sstevel@tonic-gate static int mflg; 205*7c478bd9Sstevel@tonic-gate static int nflg; 206*7c478bd9Sstevel@tonic-gate static int oflg; 207*7c478bd9Sstevel@tonic-gate static int pflg; 208*7c478bd9Sstevel@tonic-gate static int qflg; 209*7c478bd9Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 210*7c478bd9Sstevel@tonic-gate static int sflg; 211*7c478bd9Sstevel@tonic-gate static int tflg; 212*7c478bd9Sstevel@tonic-gate static int uflg; 213*7c478bd9Sstevel@tonic-gate static int xflg; 214*7c478bd9Sstevel@tonic-gate static int Aflg; 215*7c478bd9Sstevel@tonic-gate static int Cflg; 216*7c478bd9Sstevel@tonic-gate static int Eflg; 217*7c478bd9Sstevel@tonic-gate static int Fflg; 218*7c478bd9Sstevel@tonic-gate static int Hflg; 219*7c478bd9Sstevel@tonic-gate static int Lflg; 220*7c478bd9Sstevel@tonic-gate static int Rflg; 221*7c478bd9Sstevel@tonic-gate static int Sflg; 222*7c478bd9Sstevel@tonic-gate static long hscale; 223*7c478bd9Sstevel@tonic-gate static mode_t flags; 224*7c478bd9Sstevel@tonic-gate static int err = 0; /* Contains return code */ 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 227*7c478bd9Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 228*7c478bd9Sstevel@tonic-gate static char *lastuname = NULL; 229*7c478bd9Sstevel@tonic-gate static char *lastgname = NULL; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg are on */ 232*7c478bd9Sstevel@tonic-gate static int statreq; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate static char *dotp = "."; 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 237*7c478bd9Sstevel@tonic-gate static time_t year, now; 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate static int num_cols = 80; 240*7c478bd9Sstevel@tonic-gate static int colwidth; 241*7c478bd9Sstevel@tonic-gate static int filewidth; 242*7c478bd9Sstevel@tonic-gate static int fixedwidth; 243*7c478bd9Sstevel@tonic-gate static int nomocore; 244*7c478bd9Sstevel@tonic-gate static int curcol; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate static struct winsize win; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static char time_buf[50]; /* array to hold day and time */ 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 251*7c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 254*7c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate int 257*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate int c; 260*7c478bd9Sstevel@tonic-gate int i; 261*7c478bd9Sstevel@tonic-gate int width; 262*7c478bd9Sstevel@tonic-gate int amino = 0; 263*7c478bd9Sstevel@tonic-gate int opterr = 0; 264*7c478bd9Sstevel@tonic-gate struct lbuf *ep; 265*7c478bd9Sstevel@tonic-gate struct lbuf lb; 266*7c478bd9Sstevel@tonic-gate struct ditem *myinfo; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 269*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 270*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 271*7c478bd9Sstevel@tonic-gate #endif 272*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 273*7c478bd9Sstevel@tonic-gate #ifdef STANDALONE 274*7c478bd9Sstevel@tonic-gate if (argv[0][0] == '\0') 275*7c478bd9Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 276*7c478bd9Sstevel@tonic-gate #endif 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 279*7c478bd9Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 280*7c478bd9Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 281*7c478bd9Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 282*7c478bd9Sstevel@tonic-gate if (isatty(1)) { 283*7c478bd9Sstevel@tonic-gate Cflg = 1; 284*7c478bd9Sstevel@tonic-gate mflg = 0; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, 289*7c478bd9Sstevel@tonic-gate "aAbcCdeEfFghHilLmnopqrRsStux1@")) != EOF) 290*7c478bd9Sstevel@tonic-gate switch (c) { 291*7c478bd9Sstevel@tonic-gate case 'a': 292*7c478bd9Sstevel@tonic-gate aflg++; 293*7c478bd9Sstevel@tonic-gate continue; 294*7c478bd9Sstevel@tonic-gate case 'A': 295*7c478bd9Sstevel@tonic-gate Aflg++; 296*7c478bd9Sstevel@tonic-gate continue; 297*7c478bd9Sstevel@tonic-gate case 'b': 298*7c478bd9Sstevel@tonic-gate bflg = 1; 299*7c478bd9Sstevel@tonic-gate qflg = 0; 300*7c478bd9Sstevel@tonic-gate continue; 301*7c478bd9Sstevel@tonic-gate case 'c': 302*7c478bd9Sstevel@tonic-gate uflg = 0; 303*7c478bd9Sstevel@tonic-gate cflg++; 304*7c478bd9Sstevel@tonic-gate continue; 305*7c478bd9Sstevel@tonic-gate case 'C': 306*7c478bd9Sstevel@tonic-gate Cflg = 1; 307*7c478bd9Sstevel@tonic-gate mflg = 0; 308*7c478bd9Sstevel@tonic-gate #ifdef XPG4 309*7c478bd9Sstevel@tonic-gate lflg = 0; 310*7c478bd9Sstevel@tonic-gate #endif 311*7c478bd9Sstevel@tonic-gate continue; 312*7c478bd9Sstevel@tonic-gate case 'd': 313*7c478bd9Sstevel@tonic-gate dflg++; 314*7c478bd9Sstevel@tonic-gate continue; 315*7c478bd9Sstevel@tonic-gate case 'e': 316*7c478bd9Sstevel@tonic-gate eflg++; 317*7c478bd9Sstevel@tonic-gate lflg++; 318*7c478bd9Sstevel@tonic-gate statreq++; 319*7c478bd9Sstevel@tonic-gate Eflg = 0; 320*7c478bd9Sstevel@tonic-gate continue; 321*7c478bd9Sstevel@tonic-gate case 'E': 322*7c478bd9Sstevel@tonic-gate Eflg++; 323*7c478bd9Sstevel@tonic-gate lflg++; 324*7c478bd9Sstevel@tonic-gate statreq++; 325*7c478bd9Sstevel@tonic-gate eflg = 0; 326*7c478bd9Sstevel@tonic-gate continue; 327*7c478bd9Sstevel@tonic-gate case 'f': 328*7c478bd9Sstevel@tonic-gate fflg++; 329*7c478bd9Sstevel@tonic-gate continue; 330*7c478bd9Sstevel@tonic-gate case 'F': 331*7c478bd9Sstevel@tonic-gate Fflg++; 332*7c478bd9Sstevel@tonic-gate statreq++; 333*7c478bd9Sstevel@tonic-gate continue; 334*7c478bd9Sstevel@tonic-gate case 'g': 335*7c478bd9Sstevel@tonic-gate gflg++; 336*7c478bd9Sstevel@tonic-gate lflg++; 337*7c478bd9Sstevel@tonic-gate statreq++; 338*7c478bd9Sstevel@tonic-gate continue; 339*7c478bd9Sstevel@tonic-gate case 'h': 340*7c478bd9Sstevel@tonic-gate hflg++; 341*7c478bd9Sstevel@tonic-gate hscale = 1024; 342*7c478bd9Sstevel@tonic-gate continue; 343*7c478bd9Sstevel@tonic-gate case 'H': 344*7c478bd9Sstevel@tonic-gate Hflg++; 345*7c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 346*7c478bd9Sstevel@tonic-gate Lflg = 0; 347*7c478bd9Sstevel@tonic-gate continue; 348*7c478bd9Sstevel@tonic-gate case 'i': 349*7c478bd9Sstevel@tonic-gate iflg++; 350*7c478bd9Sstevel@tonic-gate continue; 351*7c478bd9Sstevel@tonic-gate case 'l': 352*7c478bd9Sstevel@tonic-gate lflg++; 353*7c478bd9Sstevel@tonic-gate statreq++; 354*7c478bd9Sstevel@tonic-gate Cflg = 0; 355*7c478bd9Sstevel@tonic-gate xflg = 0; 356*7c478bd9Sstevel@tonic-gate mflg = 0; 357*7c478bd9Sstevel@tonic-gate atflg = 0; 358*7c478bd9Sstevel@tonic-gate continue; 359*7c478bd9Sstevel@tonic-gate case 'L': 360*7c478bd9Sstevel@tonic-gate Lflg++; 361*7c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 362*7c478bd9Sstevel@tonic-gate Hflg = 0; 363*7c478bd9Sstevel@tonic-gate continue; 364*7c478bd9Sstevel@tonic-gate case 'm': 365*7c478bd9Sstevel@tonic-gate Cflg = 0; 366*7c478bd9Sstevel@tonic-gate mflg = 1; 367*7c478bd9Sstevel@tonic-gate #ifdef XPG4 368*7c478bd9Sstevel@tonic-gate lflg = 0; 369*7c478bd9Sstevel@tonic-gate #endif 370*7c478bd9Sstevel@tonic-gate continue; 371*7c478bd9Sstevel@tonic-gate case 'n': 372*7c478bd9Sstevel@tonic-gate nflg++; 373*7c478bd9Sstevel@tonic-gate lflg++; 374*7c478bd9Sstevel@tonic-gate statreq++; 375*7c478bd9Sstevel@tonic-gate Cflg = 0; 376*7c478bd9Sstevel@tonic-gate xflg = 0; 377*7c478bd9Sstevel@tonic-gate mflg = 0; 378*7c478bd9Sstevel@tonic-gate atflg = 0; 379*7c478bd9Sstevel@tonic-gate continue; 380*7c478bd9Sstevel@tonic-gate case 'o': 381*7c478bd9Sstevel@tonic-gate oflg++; 382*7c478bd9Sstevel@tonic-gate lflg++; 383*7c478bd9Sstevel@tonic-gate statreq++; 384*7c478bd9Sstevel@tonic-gate continue; 385*7c478bd9Sstevel@tonic-gate case 'p': 386*7c478bd9Sstevel@tonic-gate pflg++; 387*7c478bd9Sstevel@tonic-gate statreq++; 388*7c478bd9Sstevel@tonic-gate continue; 389*7c478bd9Sstevel@tonic-gate case 'q': 390*7c478bd9Sstevel@tonic-gate qflg = 1; 391*7c478bd9Sstevel@tonic-gate bflg = 0; 392*7c478bd9Sstevel@tonic-gate continue; 393*7c478bd9Sstevel@tonic-gate case 'r': 394*7c478bd9Sstevel@tonic-gate rflg = -1; 395*7c478bd9Sstevel@tonic-gate continue; 396*7c478bd9Sstevel@tonic-gate case 'R': 397*7c478bd9Sstevel@tonic-gate Rflg++; 398*7c478bd9Sstevel@tonic-gate statreq++; 399*7c478bd9Sstevel@tonic-gate continue; 400*7c478bd9Sstevel@tonic-gate case 's': 401*7c478bd9Sstevel@tonic-gate sflg++; 402*7c478bd9Sstevel@tonic-gate statreq++; 403*7c478bd9Sstevel@tonic-gate continue; 404*7c478bd9Sstevel@tonic-gate case 'S': 405*7c478bd9Sstevel@tonic-gate tflg = 0; 406*7c478bd9Sstevel@tonic-gate Sflg++; 407*7c478bd9Sstevel@tonic-gate statreq++; 408*7c478bd9Sstevel@tonic-gate continue; 409*7c478bd9Sstevel@tonic-gate case 't': 410*7c478bd9Sstevel@tonic-gate Sflg = 0; 411*7c478bd9Sstevel@tonic-gate tflg++; 412*7c478bd9Sstevel@tonic-gate statreq++; 413*7c478bd9Sstevel@tonic-gate continue; 414*7c478bd9Sstevel@tonic-gate case 'u': 415*7c478bd9Sstevel@tonic-gate cflg = 0; 416*7c478bd9Sstevel@tonic-gate uflg++; 417*7c478bd9Sstevel@tonic-gate continue; 418*7c478bd9Sstevel@tonic-gate case 'x': 419*7c478bd9Sstevel@tonic-gate xflg = 1; 420*7c478bd9Sstevel@tonic-gate Cflg = 1; 421*7c478bd9Sstevel@tonic-gate mflg = 0; 422*7c478bd9Sstevel@tonic-gate #ifdef XPG4 423*7c478bd9Sstevel@tonic-gate lflg = 0; 424*7c478bd9Sstevel@tonic-gate #endif 425*7c478bd9Sstevel@tonic-gate continue; 426*7c478bd9Sstevel@tonic-gate case '1': 427*7c478bd9Sstevel@tonic-gate Cflg = 0; 428*7c478bd9Sstevel@tonic-gate continue; 429*7c478bd9Sstevel@tonic-gate case '@': 430*7c478bd9Sstevel@tonic-gate #if !defined(XPG4) 431*7c478bd9Sstevel@tonic-gate /* 432*7c478bd9Sstevel@tonic-gate * -l has precedence over -@ 433*7c478bd9Sstevel@tonic-gate */ 434*7c478bd9Sstevel@tonic-gate if (lflg) 435*7c478bd9Sstevel@tonic-gate continue; 436*7c478bd9Sstevel@tonic-gate #endif 437*7c478bd9Sstevel@tonic-gate atflg++; 438*7c478bd9Sstevel@tonic-gate lflg++; 439*7c478bd9Sstevel@tonic-gate statreq++; 440*7c478bd9Sstevel@tonic-gate Cflg = 0; 441*7c478bd9Sstevel@tonic-gate xflg = 0; 442*7c478bd9Sstevel@tonic-gate mflg = 0; 443*7c478bd9Sstevel@tonic-gate continue; 444*7c478bd9Sstevel@tonic-gate case '?': 445*7c478bd9Sstevel@tonic-gate opterr++; 446*7c478bd9Sstevel@tonic-gate continue; 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate if (opterr) { 449*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 450*7c478bd9Sstevel@tonic-gate "usage: ls -aAbcCdeEfFghHilLmnopqrRsStux1@ [files]\n")); 451*7c478bd9Sstevel@tonic-gate exit(2); 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate if (fflg) { 455*7c478bd9Sstevel@tonic-gate aflg++; 456*7c478bd9Sstevel@tonic-gate lflg = 0; 457*7c478bd9Sstevel@tonic-gate sflg = 0; 458*7c478bd9Sstevel@tonic-gate tflg = 0; 459*7c478bd9Sstevel@tonic-gate Sflg = 0; 460*7c478bd9Sstevel@tonic-gate statreq = 0; 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate fixedwidth = 2; 464*7c478bd9Sstevel@tonic-gate if (pflg || Fflg) 465*7c478bd9Sstevel@tonic-gate fixedwidth++; 466*7c478bd9Sstevel@tonic-gate if (iflg) 467*7c478bd9Sstevel@tonic-gate fixedwidth += 11; 468*7c478bd9Sstevel@tonic-gate if (sflg) 469*7c478bd9Sstevel@tonic-gate fixedwidth += 5; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (lflg) { 472*7c478bd9Sstevel@tonic-gate if (!gflg && !oflg) 473*7c478bd9Sstevel@tonic-gate gflg = oflg = 1; 474*7c478bd9Sstevel@tonic-gate else 475*7c478bd9Sstevel@tonic-gate if (gflg && oflg) 476*7c478bd9Sstevel@tonic-gate gflg = oflg = 0; 477*7c478bd9Sstevel@tonic-gate Cflg = mflg = 0; 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 481*7c478bd9Sstevel@tonic-gate char *clptr; 482*7c478bd9Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 483*7c478bd9Sstevel@tonic-gate num_cols = atoi(clptr); 484*7c478bd9Sstevel@tonic-gate #ifdef TERMINFO 485*7c478bd9Sstevel@tonic-gate else { 486*7c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 487*7c478bd9Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate #endif 490*7c478bd9Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 491*7c478bd9Sstevel@tonic-gate /* assume it is an error */ 492*7c478bd9Sstevel@tonic-gate num_cols = 80; 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate /* allocate space for flist and the associated */ 496*7c478bd9Sstevel@tonic-gate /* data structures (lbufs) */ 497*7c478bd9Sstevel@tonic-gate maxfils = quantn; 498*7c478bd9Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 499*7c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 500*7c478bd9Sstevel@tonic-gate perror("ls"); 501*7c478bd9Sstevel@tonic-gate exit(2); 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * case when no names are given 506*7c478bd9Sstevel@tonic-gate * in ls-command and current 507*7c478bd9Sstevel@tonic-gate * directory is to be used 508*7c478bd9Sstevel@tonic-gate */ 509*7c478bd9Sstevel@tonic-gate argv[optind] = dotp; 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate /* 515*7c478bd9Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 516*7c478bd9Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 517*7c478bd9Sstevel@tonic-gate * (actually, just the directories) visited, we 518*7c478bd9Sstevel@tonic-gate * maintain a directory ancestry list for a file 519*7c478bd9Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 520*7c478bd9Sstevel@tonic-gate * a parent directory passes its directory list 521*7c478bd9Sstevel@tonic-gate * info (device id, inode number, and a pointer to 522*7c478bd9Sstevel@tonic-gate * its parent) to each of its children. As we 523*7c478bd9Sstevel@tonic-gate * process a child that is a directory, we save 524*7c478bd9Sstevel@tonic-gate * its own personal directory list info. We then 525*7c478bd9Sstevel@tonic-gate * check to see if the child has already been 526*7c478bd9Sstevel@tonic-gate * processed by comparing its device id and inode 527*7c478bd9Sstevel@tonic-gate * number from its own personal directory list info 528*7c478bd9Sstevel@tonic-gate * to that of each of its ancestors. If there is a 529*7c478bd9Sstevel@tonic-gate * match, then we know we've detected a cycle. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate if (Rflg) { 532*7c478bd9Sstevel@tonic-gate /* 533*7c478bd9Sstevel@tonic-gate * This is the first parent in this lineage 534*7c478bd9Sstevel@tonic-gate * (first in a directory hierarchy), so 535*7c478bd9Sstevel@tonic-gate * this parent's parent doesn't exist. We 536*7c478bd9Sstevel@tonic-gate * only initialize myinfo when we are 537*7c478bd9Sstevel@tonic-gate * recursing, otherwise it's not used. 538*7c478bd9Sstevel@tonic-gate */ 539*7c478bd9Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 540*7c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 541*7c478bd9Sstevel@tonic-gate perror("ls"); 542*7c478bd9Sstevel@tonic-gate exit(2); 543*7c478bd9Sstevel@tonic-gate } else { 544*7c478bd9Sstevel@tonic-gate myinfo->dev = 0; 545*7c478bd9Sstevel@tonic-gate myinfo->ino = 0; 546*7c478bd9Sstevel@tonic-gate myinfo->parent = NULL; 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 551*7c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 552*7c478bd9Sstevel@tonic-gate if (width > filewidth) 553*7c478bd9Sstevel@tonic-gate filewidth = width; 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 556*7c478bd9Sstevel@tonic-gate 1, myinfo)) == NULL) { 557*7c478bd9Sstevel@tonic-gate if (nomocore) 558*7c478bd9Sstevel@tonic-gate exit(2); 559*7c478bd9Sstevel@tonic-gate err = 2; 560*7c478bd9Sstevel@tonic-gate optind++; 561*7c478bd9Sstevel@tonic-gate continue; 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 564*7c478bd9Sstevel@tonic-gate ep->lflags |= ISARG; 565*7c478bd9Sstevel@tonic-gate optind++; 566*7c478bd9Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 569*7c478bd9Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 570*7c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 571*7c478bd9Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 572*7c478bd9Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 573*7c478bd9Sstevel@tonic-gate break; 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 576*7c478bd9Sstevel@tonic-gate for (; i < nargs; i++) { 577*7c478bd9Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 578*7c478bd9Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 579*7c478bd9Sstevel@tonic-gate if (nomocore) 580*7c478bd9Sstevel@tonic-gate exit(2); 581*7c478bd9Sstevel@tonic-gate /* -R: print subdirectories found */ 582*7c478bd9Sstevel@tonic-gate while (dfirst || cdfirst) { 583*7c478bd9Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 584*7c478bd9Sstevel@tonic-gate while (cdfirst) { 585*7c478bd9Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 586*7c478bd9Sstevel@tonic-gate dtemp = cdfirst; 587*7c478bd9Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 588*7c478bd9Sstevel@tonic-gate dtemp -> dc_next = dfirst; 589*7c478bd9Sstevel@tonic-gate dfirst = dtemp; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 592*7c478bd9Sstevel@tonic-gate dtemp = dfirst; 593*7c478bd9Sstevel@tonic-gate dfirst = dfirst->dc_next; 594*7c478bd9Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 595*7c478bd9Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 596*7c478bd9Sstevel@tonic-gate if (nomocore) 597*7c478bd9Sstevel@tonic-gate exit(2); 598*7c478bd9Sstevel@tonic-gate free(dtemp->dc_name); 599*7c478bd9Sstevel@tonic-gate free(dtemp); 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate return (err); 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* 606*7c478bd9Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 607*7c478bd9Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 608*7c478bd9Sstevel@tonic-gate */ 609*7c478bd9Sstevel@tonic-gate static void 610*7c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 611*7c478bd9Sstevel@tonic-gate { 612*7c478bd9Sstevel@tonic-gate struct dchain *dp; 613*7c478bd9Sstevel@tonic-gate struct lbuf *ap; 614*7c478bd9Sstevel@tonic-gate char *pname; 615*7c478bd9Sstevel@tonic-gate int j; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate filewidth = 0; 618*7c478bd9Sstevel@tonic-gate curdir = name; 619*7c478bd9Sstevel@tonic-gate if (title) { 620*7c478bd9Sstevel@tonic-gate if (!first) 621*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 622*7c478bd9Sstevel@tonic-gate pprintf(name, ":"); 623*7c478bd9Sstevel@tonic-gate new_line(); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 627*7c478bd9Sstevel@tonic-gate * further. 628*7c478bd9Sstevel@tonic-gate */ 629*7c478bd9Sstevel@tonic-gate if (cdetect) { 630*7c478bd9Sstevel@tonic-gate if (lflg || sflg) { 631*7c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 632*7c478bd9Sstevel@tonic-gate new_line(); 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 635*7c478bd9Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 636*7c478bd9Sstevel@tonic-gate return; 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate nfiles = lp; 640*7c478bd9Sstevel@tonic-gate rddir(name, myinfo); 641*7c478bd9Sstevel@tonic-gate if (nomocore) 642*7c478bd9Sstevel@tonic-gate return; 643*7c478bd9Sstevel@tonic-gate if (fflg == 0) 644*7c478bd9Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 645*7c478bd9Sstevel@tonic-gate sizeof (struct lbuf *), 646*7c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 647*7c478bd9Sstevel@tonic-gate if (Rflg) { 648*7c478bd9Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 649*7c478bd9Sstevel@tonic-gate ap = flist[j]; 650*7c478bd9Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 651*7c478bd9Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 652*7c478bd9Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 653*7c478bd9Sstevel@tonic-gate if (dp == NULL) { 654*7c478bd9Sstevel@tonic-gate perror("ls"); 655*7c478bd9Sstevel@tonic-gate exit(2); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 658*7c478bd9Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 659*7c478bd9Sstevel@tonic-gate perror("ls"); 660*7c478bd9Sstevel@tonic-gate exit(2); 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 663*7c478bd9Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 664*7c478bd9Sstevel@tonic-gate dp->dc_next = dfirst; 665*7c478bd9Sstevel@tonic-gate dfirst = dp; 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate if (lflg || sflg) { 670*7c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 671*7c478bd9Sstevel@tonic-gate new_line(); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 678*7c478bd9Sstevel@tonic-gate * by slp and lp. 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate static void 681*7c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 682*7c478bd9Sstevel@tonic-gate { 683*7c478bd9Sstevel@tonic-gate long row, nrows, i; 684*7c478bd9Sstevel@tonic-gate int col, ncols; 685*7c478bd9Sstevel@tonic-gate struct lbuf **ep; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 688*7c478bd9Sstevel@tonic-gate if (colwidth > num_cols) { 689*7c478bd9Sstevel@tonic-gate ncols = 1; 690*7c478bd9Sstevel@tonic-gate } else { 691*7c478bd9Sstevel@tonic-gate ncols = num_cols / colwidth; 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 696*7c478bd9Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 697*7c478bd9Sstevel@tonic-gate pentry(*ep); 698*7c478bd9Sstevel@tonic-gate new_line(); 699*7c478bd9Sstevel@tonic-gate return; 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate /* otherwise print -C columns */ 702*7c478bd9Sstevel@tonic-gate if (tot_flag) { 703*7c478bd9Sstevel@tonic-gate slp--; 704*7c478bd9Sstevel@tonic-gate row = 1; 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate else 707*7c478bd9Sstevel@tonic-gate row = 0; 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 710*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 711*7c478bd9Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 712*7c478bd9Sstevel@tonic-gate ep = slp + (nrows * col) + row; 713*7c478bd9Sstevel@tonic-gate if (ep < lp) 714*7c478bd9Sstevel@tonic-gate pentry(*ep); 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate new_line(); 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * print one output entry; 722*7c478bd9Sstevel@tonic-gate * if uid/gid is not found in the appropriate 723*7c478bd9Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 724*7c478bd9Sstevel@tonic-gate * user/group name; 725*7c478bd9Sstevel@tonic-gate */ 726*7c478bd9Sstevel@tonic-gate static void 727*7c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap) 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate struct lbuf *p; 730*7c478bd9Sstevel@tonic-gate numbuf_t hbuf; 731*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 732*7c478bd9Sstevel@tonic-gate char fmt_buf[FMTSIZE]; 733*7c478bd9Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 734*7c478bd9Sstevel@tonic-gate char *cp; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate p = ap; 737*7c478bd9Sstevel@tonic-gate column(); 738*7c478bd9Sstevel@tonic-gate if (iflg) 739*7c478bd9Sstevel@tonic-gate if (mflg && !lflg) 740*7c478bd9Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 741*7c478bd9Sstevel@tonic-gate else 742*7c478bd9Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 743*7c478bd9Sstevel@tonic-gate if (sflg) 744*7c478bd9Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 745*7c478bd9Sstevel@tonic-gate (p->lblocks < 10000) ? "%4lld " : "%lld ", 746*7c478bd9Sstevel@tonic-gate (p->ltype != 'b' && p->ltype != 'c') ? 747*7c478bd9Sstevel@tonic-gate p->lblocks : 0LL); 748*7c478bd9Sstevel@tonic-gate if (lflg) { 749*7c478bd9Sstevel@tonic-gate (void) putchar(p->ltype); 750*7c478bd9Sstevel@tonic-gate curcol++; 751*7c478bd9Sstevel@tonic-gate pmode(p->lflags); 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate /* ACL: additional access mode flag */ 754*7c478bd9Sstevel@tonic-gate (void) putchar(p->acl); 755*7c478bd9Sstevel@tonic-gate curcol++; 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 758*7c478bd9Sstevel@tonic-gate if (oflg) 759*7c478bd9Sstevel@tonic-gate if (!nflg) { 760*7c478bd9Sstevel@tonic-gate cp = getname(p->luid); 761*7c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 762*7c478bd9Sstevel@tonic-gate } else 763*7c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 764*7c478bd9Sstevel@tonic-gate if (gflg) 765*7c478bd9Sstevel@tonic-gate if (!nflg) { 766*7c478bd9Sstevel@tonic-gate cp = getgroup(p->lgid); 767*7c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 768*7c478bd9Sstevel@tonic-gate } else 769*7c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 770*7c478bd9Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 771*7c478bd9Sstevel@tonic-gate curcol += printf("%3u, %2u", 772*7c478bd9Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 773*7c478bd9Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 774*7c478bd9Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 775*7c478bd9Sstevel@tonic-gate curcol += printf("%7s", 776*7c478bd9Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 777*7c478bd9Sstevel@tonic-gate } else { 778*7c478bd9Sstevel@tonic-gate curcol += printf((p->lsize < (off_t)10000000) ? 779*7c478bd9Sstevel@tonic-gate "%7lld" : "%lld", p->lsize); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate if (eflg) { 782*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 783*7c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT3, LC_TIME), 784*7c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 785*7c478bd9Sstevel@tonic-gate } else if (Eflg) { 786*7c478bd9Sstevel@tonic-gate /* fill in nanoseconds first */ 787*7c478bd9Sstevel@tonic-gate (void) snprintf(fmt_buf, sizeof (fmt_buf), 788*7c478bd9Sstevel@tonic-gate FORMAT4, p->lmtime.tv_nsec); 789*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 790*7c478bd9Sstevel@tonic-gate fmt_buf, localtime(&p->lmtime.tv_sec)); 791*7c478bd9Sstevel@tonic-gate } else { 792*7c478bd9Sstevel@tonic-gate if ((p->lmtime.tv_sec < year) || 793*7c478bd9Sstevel@tonic-gate (p->lmtime.tv_sec > now)) { 794*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 795*7c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT1, LC_TIME), 796*7c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 797*7c478bd9Sstevel@tonic-gate } else { 798*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 799*7c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT2, LC_TIME), 800*7c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate curcol += printf("%s", time_buf); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * prevent both "->" and trailing marks 808*7c478bd9Sstevel@tonic-gate * from appearing 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate if (pflg && p->ltype == 'd') 812*7c478bd9Sstevel@tonic-gate dmark = "/"; 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 815*7c478bd9Sstevel@tonic-gate if (p->ltype == 'd') 816*7c478bd9Sstevel@tonic-gate dmark = "/"; 817*7c478bd9Sstevel@tonic-gate else if (p->ltype == 'D') 818*7c478bd9Sstevel@tonic-gate dmark = ">"; 819*7c478bd9Sstevel@tonic-gate else if (p->ltype == 'p') 820*7c478bd9Sstevel@tonic-gate dmark = "|"; 821*7c478bd9Sstevel@tonic-gate else if (p->ltype == 'l') 822*7c478bd9Sstevel@tonic-gate dmark = "@"; 823*7c478bd9Sstevel@tonic-gate else if (p->ltype == 's') 824*7c478bd9Sstevel@tonic-gate dmark = "="; 825*7c478bd9Sstevel@tonic-gate else if (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)) 826*7c478bd9Sstevel@tonic-gate dmark = "*"; 827*7c478bd9Sstevel@tonic-gate else 828*7c478bd9Sstevel@tonic-gate dmark = ""; 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate if (lflg && p->flinkto) { 832*7c478bd9Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 833*7c478bd9Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 834*7c478bd9Sstevel@tonic-gate dmark = buf; 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate if (p->lflags & ISARG) { 838*7c478bd9Sstevel@tonic-gate if (qflg || bflg) 839*7c478bd9Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 840*7c478bd9Sstevel@tonic-gate else { 841*7c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 842*7c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 843*7c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate } else { 846*7c478bd9Sstevel@tonic-gate if (qflg || bflg) 847*7c478bd9Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 848*7c478bd9Sstevel@tonic-gate else { 849*7c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 850*7c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 851*7c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate } 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */ 857*7c478bd9Sstevel@tonic-gate static void 858*7c478bd9Sstevel@tonic-gate pmode(mode_t aflag) 859*7c478bd9Sstevel@tonic-gate { 860*7c478bd9Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 861*7c478bd9Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 862*7c478bd9Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 863*7c478bd9Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 864*7c478bd9Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 865*7c478bd9Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 866*7c478bd9Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 867*7c478bd9Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 868*7c478bd9Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 869*7c478bd9Sstevel@tonic-gate #ifdef XPG4 870*7c478bd9Sstevel@tonic-gate S_ISGID, 'L', '-'}; 871*7c478bd9Sstevel@tonic-gate #else 872*7c478bd9Sstevel@tonic-gate S_ISGID, 'l', '-'}; 873*7c478bd9Sstevel@tonic-gate #endif 874*7c478bd9Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 875*7c478bd9Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 876*7c478bd9Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 877*7c478bd9Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate int **mp; 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate flags = aflag; 884*7c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 885*7c478bd9Sstevel@tonic-gate selection(*mp); 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate static void 889*7c478bd9Sstevel@tonic-gate selection(int *pairp) 890*7c478bd9Sstevel@tonic-gate { 891*7c478bd9Sstevel@tonic-gate int n; 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate n = *pairp++; 894*7c478bd9Sstevel@tonic-gate while (n-->0) { 895*7c478bd9Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 896*7c478bd9Sstevel@tonic-gate pairp++; 897*7c478bd9Sstevel@tonic-gate break; 898*7c478bd9Sstevel@tonic-gate } else { 899*7c478bd9Sstevel@tonic-gate pairp += 2; 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate (void) putchar(*pairp); 903*7c478bd9Sstevel@tonic-gate curcol++; 904*7c478bd9Sstevel@tonic-gate } 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* 907*7c478bd9Sstevel@tonic-gate * column: get to the beginning of the next column. 908*7c478bd9Sstevel@tonic-gate */ 909*7c478bd9Sstevel@tonic-gate static void 910*7c478bd9Sstevel@tonic-gate column(void) 911*7c478bd9Sstevel@tonic-gate { 912*7c478bd9Sstevel@tonic-gate if (curcol == 0) 913*7c478bd9Sstevel@tonic-gate return; 914*7c478bd9Sstevel@tonic-gate if (mflg) { 915*7c478bd9Sstevel@tonic-gate (void) putc(',', stdout); 916*7c478bd9Sstevel@tonic-gate curcol++; 917*7c478bd9Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 918*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 919*7c478bd9Sstevel@tonic-gate curcol = 0; 920*7c478bd9Sstevel@tonic-gate return; 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 923*7c478bd9Sstevel@tonic-gate curcol++; 924*7c478bd9Sstevel@tonic-gate return; 925*7c478bd9Sstevel@tonic-gate } 926*7c478bd9Sstevel@tonic-gate if (Cflg == 0) { 927*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 928*7c478bd9Sstevel@tonic-gate curcol = 0; 929*7c478bd9Sstevel@tonic-gate return; 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 932*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 933*7c478bd9Sstevel@tonic-gate curcol = 0; 934*7c478bd9Sstevel@tonic-gate return; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate do { 937*7c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 938*7c478bd9Sstevel@tonic-gate curcol++; 939*7c478bd9Sstevel@tonic-gate } while (curcol % colwidth); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate static void 943*7c478bd9Sstevel@tonic-gate new_line(void) 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate if (curcol) { 946*7c478bd9Sstevel@tonic-gate first = 0; 947*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 948*7c478bd9Sstevel@tonic-gate curcol = 0; 949*7c478bd9Sstevel@tonic-gate } 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate /* 953*7c478bd9Sstevel@tonic-gate * read each filename in directory dir and store its 954*7c478bd9Sstevel@tonic-gate * status in flist[nfiles] 955*7c478bd9Sstevel@tonic-gate * use makename() to form pathname dir/filename; 956*7c478bd9Sstevel@tonic-gate */ 957*7c478bd9Sstevel@tonic-gate static void 958*7c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 959*7c478bd9Sstevel@tonic-gate { 960*7c478bd9Sstevel@tonic-gate struct dirent *dentry; 961*7c478bd9Sstevel@tonic-gate DIR *dirf; 962*7c478bd9Sstevel@tonic-gate int j; 963*7c478bd9Sstevel@tonic-gate struct lbuf *ep; 964*7c478bd9Sstevel@tonic-gate int width; 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 967*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 968*7c478bd9Sstevel@tonic-gate perror(dir); 969*7c478bd9Sstevel@tonic-gate err = 2; 970*7c478bd9Sstevel@tonic-gate return; 971*7c478bd9Sstevel@tonic-gate } else { 972*7c478bd9Sstevel@tonic-gate tblocks = 0; 973*7c478bd9Sstevel@tonic-gate for (;;) { 974*7c478bd9Sstevel@tonic-gate errno = 0; 975*7c478bd9Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 976*7c478bd9Sstevel@tonic-gate break; 977*7c478bd9Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 978*7c478bd9Sstevel@tonic-gate (Aflg == 0 || 979*7c478bd9Sstevel@tonic-gate dentry->d_name[1] == '\0' || 980*7c478bd9Sstevel@tonic-gate dentry->d_name[1] == '.' && 981*7c478bd9Sstevel@tonic-gate dentry->d_name[2] == '\0')) 982*7c478bd9Sstevel@tonic-gate /* 983*7c478bd9Sstevel@tonic-gate * check for directory items '.', '..', 984*7c478bd9Sstevel@tonic-gate * and items without valid inode-number; 985*7c478bd9Sstevel@tonic-gate */ 986*7c478bd9Sstevel@tonic-gate continue; 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 989*7c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 990*7c478bd9Sstevel@tonic-gate if (width > filewidth) 991*7c478bd9Sstevel@tonic-gate filewidth = width; 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 994*7c478bd9Sstevel@tonic-gate if (ep == NULL) { 995*7c478bd9Sstevel@tonic-gate if (nomocore) 996*7c478bd9Sstevel@tonic-gate return; 997*7c478bd9Sstevel@tonic-gate continue; 998*7c478bd9Sstevel@tonic-gate } else { 999*7c478bd9Sstevel@tonic-gate ep->lnum = dentry->d_ino; 1000*7c478bd9Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 1001*7c478bd9Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 1002*7c478bd9Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 1003*7c478bd9Sstevel@tonic-gate } 1004*7c478bd9Sstevel@tonic-gate } 1005*7c478bd9Sstevel@tonic-gate if (errno) { 1006*7c478bd9Sstevel@tonic-gate int sav_errno = errno; 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1009*7c478bd9Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 1010*7c478bd9Sstevel@tonic-gate dir, strerror(sav_errno)); 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate (void) closedir(dirf); 1013*7c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate /* 1018*7c478bd9Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 1019*7c478bd9Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 1020*7c478bd9Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 1021*7c478bd9Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 1022*7c478bd9Sstevel@tonic-gate * it is reported at the right time when printing the directory. 1023*7c478bd9Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 1024*7c478bd9Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 1025*7c478bd9Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 1026*7c478bd9Sstevel@tonic-gate * command line. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate static void 1029*7c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 1030*7c478bd9Sstevel@tonic-gate int argfl, struct ditem *myparent) 1031*7c478bd9Sstevel@tonic-gate { 1032*7c478bd9Sstevel@tonic-gate size_t file_len; 1033*7c478bd9Sstevel@tonic-gate struct ditem *myinfo; 1034*7c478bd9Sstevel@tonic-gate struct ditem *tptr; 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate file_len = strlen(file); 1037*7c478bd9Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 1038*7c478bd9Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 1039*7c478bd9Sstevel@tonic-gate /* 1040*7c478bd9Sstevel@tonic-gate * Add this inode's ancestry 1041*7c478bd9Sstevel@tonic-gate * info and insert it into the 1042*7c478bd9Sstevel@tonic-gate * ancestry list by pointing 1043*7c478bd9Sstevel@tonic-gate * back to its parent. We save 1044*7c478bd9Sstevel@tonic-gate * it (in rep) with the other info 1045*7c478bd9Sstevel@tonic-gate * we're gathering for this inode. 1046*7c478bd9Sstevel@tonic-gate */ 1047*7c478bd9Sstevel@tonic-gate if ((myinfo = malloc( 1048*7c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 1049*7c478bd9Sstevel@tonic-gate perror("ls"); 1050*7c478bd9Sstevel@tonic-gate exit(2); 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 1053*7c478bd9Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 1054*7c478bd9Sstevel@tonic-gate myinfo->parent = myparent; 1055*7c478bd9Sstevel@tonic-gate rep->ancinfo = myinfo; 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* 1058*7c478bd9Sstevel@tonic-gate * If this node has the same device id and 1059*7c478bd9Sstevel@tonic-gate * inode number of one of its ancestors, 1060*7c478bd9Sstevel@tonic-gate * then we've detected a cycle. 1061*7c478bd9Sstevel@tonic-gate */ 1062*7c478bd9Sstevel@tonic-gate if (myparent != NULL) { 1063*7c478bd9Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 1064*7c478bd9Sstevel@tonic-gate tptr = tptr->parent) { 1065*7c478bd9Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 1066*7c478bd9Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 1067*7c478bd9Sstevel@tonic-gate /* 1068*7c478bd9Sstevel@tonic-gate * Cycle detected for this 1069*7c478bd9Sstevel@tonic-gate * directory. Record the fact 1070*7c478bd9Sstevel@tonic-gate * it is a cycle so we don't 1071*7c478bd9Sstevel@tonic-gate * try to process this 1072*7c478bd9Sstevel@tonic-gate * directory as we are 1073*7c478bd9Sstevel@tonic-gate * walking through the 1074*7c478bd9Sstevel@tonic-gate * list of directories. 1075*7c478bd9Sstevel@tonic-gate */ 1076*7c478bd9Sstevel@tonic-gate rep->cycle = 1; 1077*7c478bd9Sstevel@tonic-gate err = 2; 1078*7c478bd9Sstevel@tonic-gate break; 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate /* 1086*7c478bd9Sstevel@tonic-gate * get status of file and recomputes tblocks; 1087*7c478bd9Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 1088*7c478bd9Sstevel@tonic-gate * for filename in a directory whose name is an 1089*7c478bd9Sstevel@tonic-gate * argument in the command; 1090*7c478bd9Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 1091*7c478bd9Sstevel@tonic-gate * returns that pointer; 1092*7c478bd9Sstevel@tonic-gate * returns NULL if failed; 1093*7c478bd9Sstevel@tonic-gate */ 1094*7c478bd9Sstevel@tonic-gate static struct lbuf * 1095*7c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 1096*7c478bd9Sstevel@tonic-gate { 1097*7c478bd9Sstevel@tonic-gate struct stat statb, statb1; 1098*7c478bd9Sstevel@tonic-gate struct lbuf *rep; 1099*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 1100*7c478bd9Sstevel@tonic-gate ssize_t cc; 1101*7c478bd9Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 1102*7c478bd9Sstevel@tonic-gate int aclcnt; 1103*7c478bd9Sstevel@tonic-gate aclent_t *aclp; 1104*7c478bd9Sstevel@tonic-gate aclent_t *tp; 1105*7c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 1106*7c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate if (nomocore) 1109*7c478bd9Sstevel@tonic-gate return (NULL); 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate if (nfiles >= maxfils) { 1112*7c478bd9Sstevel@tonic-gate /* 1113*7c478bd9Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 1114*7c478bd9Sstevel@tonic-gate * more space 1115*7c478bd9Sstevel@tonic-gate */ 1116*7c478bd9Sstevel@tonic-gate maxfils += quantn; 1117*7c478bd9Sstevel@tonic-gate if (((flist = realloc(flist, 1118*7c478bd9Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 1119*7c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 1120*7c478bd9Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 1121*7c478bd9Sstevel@tonic-gate perror("ls"); 1122*7c478bd9Sstevel@tonic-gate nomocore = 1; 1123*7c478bd9Sstevel@tonic-gate return (NULL); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* 1128*7c478bd9Sstevel@tonic-gate * nfiles is reset to nargs for each directory 1129*7c478bd9Sstevel@tonic-gate * that is given as an argument maxn is checked 1130*7c478bd9Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 1131*7c478bd9Sstevel@tonic-gate * that already has one assigned. 1132*7c478bd9Sstevel@tonic-gate */ 1133*7c478bd9Sstevel@tonic-gate if (nfiles >= maxn) { 1134*7c478bd9Sstevel@tonic-gate rep = nxtlbf++; 1135*7c478bd9Sstevel@tonic-gate flist[nfiles++] = rep; 1136*7c478bd9Sstevel@tonic-gate maxn = nfiles; 1137*7c478bd9Sstevel@tonic-gate } else { 1138*7c478bd9Sstevel@tonic-gate rep = flist[nfiles++]; 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate rep->lflags = (mode_t)0; 1141*7c478bd9Sstevel@tonic-gate rep->flinkto = NULL; 1142*7c478bd9Sstevel@tonic-gate rep->cycle = 0; 1143*7c478bd9Sstevel@tonic-gate if (argfl || statreq) { 1144*7c478bd9Sstevel@tonic-gate int doacl; 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate if (lflg) 1147*7c478bd9Sstevel@tonic-gate doacl = 1; 1148*7c478bd9Sstevel@tonic-gate else 1149*7c478bd9Sstevel@tonic-gate doacl = 0; 1150*7c478bd9Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 1151*7c478bd9Sstevel@tonic-gate if (argfl || errno != ENOENT || 1152*7c478bd9Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 1153*7c478bd9Sstevel@tonic-gate /* 1154*7c478bd9Sstevel@tonic-gate * Avoid race between readdir and lstat. 1155*7c478bd9Sstevel@tonic-gate * Print error message in case of dangling link. 1156*7c478bd9Sstevel@tonic-gate */ 1157*7c478bd9Sstevel@tonic-gate perror(file); 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate nfiles--; 1160*7c478bd9Sstevel@tonic-gate return (NULL); 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate /* 1164*7c478bd9Sstevel@tonic-gate * If -H was specified, and the file linked to was 1165*7c478bd9Sstevel@tonic-gate * not a directory, then we need to get the info 1166*7c478bd9Sstevel@tonic-gate * for the symlink itself. 1167*7c478bd9Sstevel@tonic-gate */ 1168*7c478bd9Sstevel@tonic-gate if ((Hflg) && (argfl) && 1169*7c478bd9Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 1170*7c478bd9Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 1171*7c478bd9Sstevel@tonic-gate perror(file); 1172*7c478bd9Sstevel@tonic-gate } 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate rep->lnum = statb.st_ino; 1176*7c478bd9Sstevel@tonic-gate rep->lsize = statb.st_size; 1177*7c478bd9Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 1178*7c478bd9Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 1179*7c478bd9Sstevel@tonic-gate case S_IFDIR: 1180*7c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 1181*7c478bd9Sstevel@tonic-gate if (Rflg) { 1182*7c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 1183*7c478bd9Sstevel@tonic-gate argfl, myparent); 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate break; 1186*7c478bd9Sstevel@tonic-gate case S_IFBLK: 1187*7c478bd9Sstevel@tonic-gate rep->ltype = 'b'; 1188*7c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 1189*7c478bd9Sstevel@tonic-gate break; 1190*7c478bd9Sstevel@tonic-gate case S_IFCHR: 1191*7c478bd9Sstevel@tonic-gate rep->ltype = 'c'; 1192*7c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 1193*7c478bd9Sstevel@tonic-gate break; 1194*7c478bd9Sstevel@tonic-gate case S_IFIFO: 1195*7c478bd9Sstevel@tonic-gate rep->ltype = 'p'; 1196*7c478bd9Sstevel@tonic-gate break; 1197*7c478bd9Sstevel@tonic-gate case S_IFSOCK: 1198*7c478bd9Sstevel@tonic-gate rep->ltype = 's'; 1199*7c478bd9Sstevel@tonic-gate rep->lsize = 0; 1200*7c478bd9Sstevel@tonic-gate break; 1201*7c478bd9Sstevel@tonic-gate case S_IFLNK: 1202*7c478bd9Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 1203*7c478bd9Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 1204*7c478bd9Sstevel@tonic-gate ((Hflg) && (!argfl))) { 1205*7c478bd9Sstevel@tonic-gate doacl = 0; 1206*7c478bd9Sstevel@tonic-gate } 1207*7c478bd9Sstevel@tonic-gate rep->ltype = 'l'; 1208*7c478bd9Sstevel@tonic-gate if (lflg) { 1209*7c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 1210*7c478bd9Sstevel@tonic-gate if (cc >= 0) { 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * follow the symbolic link 1214*7c478bd9Sstevel@tonic-gate * to generate the appropriate 1215*7c478bd9Sstevel@tonic-gate * Fflg marker for the object 1216*7c478bd9Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 1217*7c478bd9Sstevel@tonic-gate */ 1218*7c478bd9Sstevel@tonic-gate if ((Fflg || pflg) && 1219*7c478bd9Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 1220*7c478bd9Sstevel@tonic-gate switch (statb1.st_mode & 1221*7c478bd9Sstevel@tonic-gate S_IFMT) { 1222*7c478bd9Sstevel@tonic-gate case S_IFDIR: 1223*7c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 1224*7c478bd9Sstevel@tonic-gate break; 1225*7c478bd9Sstevel@tonic-gate case S_IFSOCK: 1226*7c478bd9Sstevel@tonic-gate buf[cc++] = '='; 1227*7c478bd9Sstevel@tonic-gate break; 1228*7c478bd9Sstevel@tonic-gate default: 1229*7c478bd9Sstevel@tonic-gate if ((statb1.st_mode & 1230*7c478bd9Sstevel@tonic-gate ~S_IFMT) & 1231*7c478bd9Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 1232*7c478bd9Sstevel@tonic-gate S_IXOTH)) 1233*7c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 1234*7c478bd9Sstevel@tonic-gate break; 1235*7c478bd9Sstevel@tonic-gate } 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate buf[cc] = '\0'; 1238*7c478bd9Sstevel@tonic-gate rep->flinkto = strdup(buf); 1239*7c478bd9Sstevel@tonic-gate } 1240*7c478bd9Sstevel@tonic-gate break; 1241*7c478bd9Sstevel@tonic-gate } 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate /* 1244*7c478bd9Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 1245*7c478bd9Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 1246*7c478bd9Sstevel@tonic-gate * when explicit arguments are specified. 1247*7c478bd9Sstevel@tonic-gate */ 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate #ifdef XPG6 1250*7c478bd9Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 1251*7c478bd9Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 1252*7c478bd9Sstevel@tonic-gate (stat(file, &statb1) < 0)) 1253*7c478bd9Sstevel@tonic-gate #else 1254*7c478bd9Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 1255*7c478bd9Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 1256*7c478bd9Sstevel@tonic-gate #endif /* XPG6 */ 1257*7c478bd9Sstevel@tonic-gate break; 1258*7c478bd9Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 1259*7c478bd9Sstevel@tonic-gate statb = statb1; 1260*7c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 1261*7c478bd9Sstevel@tonic-gate rep->lsize = statb1.st_size; 1262*7c478bd9Sstevel@tonic-gate if (Rflg) { 1263*7c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 1264*7c478bd9Sstevel@tonic-gate argfl, myparent); 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate break; 1268*7c478bd9Sstevel@tonic-gate case S_IFDOOR: 1269*7c478bd9Sstevel@tonic-gate rep->ltype = 'D'; 1270*7c478bd9Sstevel@tonic-gate break; 1271*7c478bd9Sstevel@tonic-gate case S_IFREG: 1272*7c478bd9Sstevel@tonic-gate rep->ltype = '-'; 1273*7c478bd9Sstevel@tonic-gate break; 1274*7c478bd9Sstevel@tonic-gate case S_IFPORT: 1275*7c478bd9Sstevel@tonic-gate rep->ltype = 'P'; 1276*7c478bd9Sstevel@tonic-gate break; 1277*7c478bd9Sstevel@tonic-gate default: 1278*7c478bd9Sstevel@tonic-gate rep->ltype = '?'; 1279*7c478bd9Sstevel@tonic-gate break; 1280*7c478bd9Sstevel@tonic-gate } 1281*7c478bd9Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 1284*7c478bd9Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 1287*7c478bd9Sstevel@tonic-gate if (doacl) { 1288*7c478bd9Sstevel@tonic-gate rep->acl = ' '; 1289*7c478bd9Sstevel@tonic-gate if ((aclcnt = acl(file, GETACLCNT, 0, NULL)) > 1290*7c478bd9Sstevel@tonic-gate MIN_ACL_ENTRIES) { 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate /* this file has a non-trivial acl */ 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate rep->acl = '+'; 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate /* 1297*7c478bd9Sstevel@tonic-gate * For files with non-trivial acls, the 1298*7c478bd9Sstevel@tonic-gate * effective group permissions are the 1299*7c478bd9Sstevel@tonic-gate * intersection of the GROUP_OBJ value and 1300*7c478bd9Sstevel@tonic-gate * the CLASS_OBJ (acl mask) value. Determine 1301*7c478bd9Sstevel@tonic-gate * both the GROUP_OBJ and CLASS_OBJ for this 1302*7c478bd9Sstevel@tonic-gate * file and insert the logical AND of those 1303*7c478bd9Sstevel@tonic-gate * two values in the group permissions field 1304*7c478bd9Sstevel@tonic-gate * of the lflags value for this file. 1305*7c478bd9Sstevel@tonic-gate */ 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate if ((aclp = (aclent_t *)malloc( 1308*7c478bd9Sstevel@tonic-gate (sizeof (aclent_t)) * aclcnt)) == NULL) { 1309*7c478bd9Sstevel@tonic-gate perror("ls"); 1310*7c478bd9Sstevel@tonic-gate exit(2); 1311*7c478bd9Sstevel@tonic-gate } 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate if (acl(file, GETACL, aclcnt, aclp) < 0) { 1314*7c478bd9Sstevel@tonic-gate free(aclp); 1315*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: "); 1316*7c478bd9Sstevel@tonic-gate perror(file); 1317*7c478bd9Sstevel@tonic-gate nfiles--; 1318*7c478bd9Sstevel@tonic-gate err = 2; 1319*7c478bd9Sstevel@tonic-gate return (NULL); 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * Until found in acl list, assume maximum 1324*7c478bd9Sstevel@tonic-gate * permissions for both group and mask. (Just 1325*7c478bd9Sstevel@tonic-gate * in case the acl lacks either value for 1326*7c478bd9Sstevel@tonic-gate * some reason.) 1327*7c478bd9Sstevel@tonic-gate */ 1328*7c478bd9Sstevel@tonic-gate groupperm = 07; 1329*7c478bd9Sstevel@tonic-gate mask = 07; 1330*7c478bd9Sstevel@tonic-gate grouppermfound = 0; 1331*7c478bd9Sstevel@tonic-gate maskfound = 0; 1332*7c478bd9Sstevel@tonic-gate for (tp = aclp; aclcnt--; tp++) { 1333*7c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 1334*7c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 1335*7c478bd9Sstevel@tonic-gate grouppermfound = 1; 1336*7c478bd9Sstevel@tonic-gate continue; 1337*7c478bd9Sstevel@tonic-gate } 1338*7c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 1339*7c478bd9Sstevel@tonic-gate mask = tp->a_perm; 1340*7c478bd9Sstevel@tonic-gate maskfound = 1; 1341*7c478bd9Sstevel@tonic-gate } 1342*7c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 1343*7c478bd9Sstevel@tonic-gate break; 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate free(aclp); 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate /* reset all the group bits */ 1349*7c478bd9Sstevel@tonic-gate rep->lflags &= ~S_IRWXG; 1350*7c478bd9Sstevel@tonic-gate 1351*7c478bd9Sstevel@tonic-gate /* 1352*7c478bd9Sstevel@tonic-gate * Now set them to the logical AND of the 1353*7c478bd9Sstevel@tonic-gate * GROUP_OBJ permissions and the acl mask. 1354*7c478bd9Sstevel@tonic-gate */ 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate rep->lflags |= (groupperm & mask) << 3; 1357*7c478bd9Sstevel@tonic-gate } 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 1360*7c478bd9Sstevel@tonic-gate rep->acl = '@'; 1361*7c478bd9Sstevel@tonic-gate } else 1362*7c478bd9Sstevel@tonic-gate rep->acl = ' '; 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 1365*7c478bd9Sstevel@tonic-gate 1366*7c478bd9Sstevel@tonic-gate rep->luid = statb.st_uid; 1367*7c478bd9Sstevel@tonic-gate rep->lgid = statb.st_gid; 1368*7c478bd9Sstevel@tonic-gate rep->lnl = statb.st_nlink; 1369*7c478bd9Sstevel@tonic-gate if (uflg) 1370*7c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_atim; 1371*7c478bd9Sstevel@tonic-gate else if (cflg) 1372*7c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_ctim; 1373*7c478bd9Sstevel@tonic-gate else 1374*7c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_mtim; 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 1377*7c478bd9Sstevel@tonic-gate tblocks += rep->lblocks; 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate return (rep); 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate /* 1383*7c478bd9Sstevel@tonic-gate * returns pathname of the form dir/file; 1384*7c478bd9Sstevel@tonic-gate * dir and file are null-terminated strings. 1385*7c478bd9Sstevel@tonic-gate */ 1386*7c478bd9Sstevel@tonic-gate static char * 1387*7c478bd9Sstevel@tonic-gate makename(char *dir, char *file) 1388*7c478bd9Sstevel@tonic-gate { 1389*7c478bd9Sstevel@tonic-gate /* 1390*7c478bd9Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 1391*7c478bd9Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 1392*7c478bd9Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 1393*7c478bd9Sstevel@tonic-gate * and the null character at the end. 1394*7c478bd9Sstevel@tonic-gate * dfile is static as this is returned by makename(). 1395*7c478bd9Sstevel@tonic-gate */ 1396*7c478bd9Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 1397*7c478bd9Sstevel@tonic-gate char *dp, *fp; 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate dp = dfile; 1400*7c478bd9Sstevel@tonic-gate fp = dir; 1401*7c478bd9Sstevel@tonic-gate while (*fp) 1402*7c478bd9Sstevel@tonic-gate *dp++ = *fp++; 1403*7c478bd9Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 1404*7c478bd9Sstevel@tonic-gate *dp++ = '/'; 1405*7c478bd9Sstevel@tonic-gate fp = file; 1406*7c478bd9Sstevel@tonic-gate while (*fp) 1407*7c478bd9Sstevel@tonic-gate *dp++ = *fp++; 1408*7c478bd9Sstevel@tonic-gate *dp = '\0'; 1409*7c478bd9Sstevel@tonic-gate return (dfile); 1410*7c478bd9Sstevel@tonic-gate } 1411*7c478bd9Sstevel@tonic-gate 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate #include <pwd.h> 1414*7c478bd9Sstevel@tonic-gate #include <grp.h> 1415*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate struct utmpx utmp; 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 1420*7c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 1421*7c478bd9Sstevel@tonic-gate 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 1424*7c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 1425*7c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 1426*7c478bd9Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 1427*7c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 1428*7c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 1429*7c478bd9Sstevel@tonic-gate }; 1430*7c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups; 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate static struct cachenode * 1433*7c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val) 1434*7c478bd9Sstevel@tonic-gate { 1435*7c478bd9Sstevel@tonic-gate struct cachenode **parent = head; 1436*7c478bd9Sstevel@tonic-gate struct cachenode *c = *parent; 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate while (c != NULL) { 1439*7c478bd9Sstevel@tonic-gate if (val == c->val) { 1440*7c478bd9Sstevel@tonic-gate /* found it */ 1441*7c478bd9Sstevel@tonic-gate return (c); 1442*7c478bd9Sstevel@tonic-gate } else if (val < c->val) { 1443*7c478bd9Sstevel@tonic-gate parent = &c->lesschild; 1444*7c478bd9Sstevel@tonic-gate c = c->lesschild; 1445*7c478bd9Sstevel@tonic-gate } else { 1446*7c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 1447*7c478bd9Sstevel@tonic-gate c = c->grtrchild; 1448*7c478bd9Sstevel@tonic-gate } 1449*7c478bd9Sstevel@tonic-gate } 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 1452*7c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 1453*7c478bd9Sstevel@tonic-gate if (c == NULL) { 1454*7c478bd9Sstevel@tonic-gate perror("ls"); 1455*7c478bd9Sstevel@tonic-gate exit(2); 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate *parent = c; 1458*7c478bd9Sstevel@tonic-gate c->val = val; 1459*7c478bd9Sstevel@tonic-gate return (c); 1460*7c478bd9Sstevel@tonic-gate } 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate /* 1463*7c478bd9Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 1464*7c478bd9Sstevel@tonic-gate * lastuid is set to uid. 1465*7c478bd9Sstevel@tonic-gate */ 1466*7c478bd9Sstevel@tonic-gate static char * 1467*7c478bd9Sstevel@tonic-gate getname(uid_t uid) 1468*7c478bd9Sstevel@tonic-gate { 1469*7c478bd9Sstevel@tonic-gate struct passwd *pwent; 1470*7c478bd9Sstevel@tonic-gate struct cachenode *c; 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 1473*7c478bd9Sstevel@tonic-gate return (lastuname); 1474*7c478bd9Sstevel@tonic-gate 1475*7c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 1476*7c478bd9Sstevel@tonic-gate if (c->initted == 0) { 1477*7c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 1478*7c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 1479*7c478bd9Sstevel@tonic-gate } else { 1480*7c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 1481*7c478bd9Sstevel@tonic-gate } 1482*7c478bd9Sstevel@tonic-gate c->initted = 1; 1483*7c478bd9Sstevel@tonic-gate } 1484*7c478bd9Sstevel@tonic-gate lastuid = uid; 1485*7c478bd9Sstevel@tonic-gate lastuname = &c->name[0]; 1486*7c478bd9Sstevel@tonic-gate return (lastuname); 1487*7c478bd9Sstevel@tonic-gate } 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate /* 1490*7c478bd9Sstevel@tonic-gate * get name from cache, or group file for a given gid; 1491*7c478bd9Sstevel@tonic-gate * lastgid is set to gid. 1492*7c478bd9Sstevel@tonic-gate */ 1493*7c478bd9Sstevel@tonic-gate static char * 1494*7c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 1495*7c478bd9Sstevel@tonic-gate { 1496*7c478bd9Sstevel@tonic-gate struct group *grent; 1497*7c478bd9Sstevel@tonic-gate struct cachenode *c; 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 1500*7c478bd9Sstevel@tonic-gate return (lastgname); 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 1503*7c478bd9Sstevel@tonic-gate if (c->initted == 0) { 1504*7c478bd9Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 1505*7c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 1506*7c478bd9Sstevel@tonic-gate } else { 1507*7c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 1508*7c478bd9Sstevel@tonic-gate } 1509*7c478bd9Sstevel@tonic-gate c->initted = 1; 1510*7c478bd9Sstevel@tonic-gate } 1511*7c478bd9Sstevel@tonic-gate lastgid = gid; 1512*7c478bd9Sstevel@tonic-gate lastgname = &c->name[0]; 1513*7c478bd9Sstevel@tonic-gate return (lastgname); 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 1517*7c478bd9Sstevel@tonic-gate static int 1518*7c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 1519*7c478bd9Sstevel@tonic-gate { 1520*7c478bd9Sstevel@tonic-gate struct lbuf *p1, *p2; 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate p1 = *pp1; 1523*7c478bd9Sstevel@tonic-gate p2 = *pp2; 1524*7c478bd9Sstevel@tonic-gate if (dflg == 0) { 1525*7c478bd9Sstevel@tonic-gate /* 1526*7c478bd9Sstevel@tonic-gate * compare two names in ls-command one of which is file 1527*7c478bd9Sstevel@tonic-gate * and the other is a directory; 1528*7c478bd9Sstevel@tonic-gate * this portion is not used for comparing files within 1529*7c478bd9Sstevel@tonic-gate * a directory name of ls-command; 1530*7c478bd9Sstevel@tonic-gate */ 1531*7c478bd9Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 1532*7c478bd9Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 1533*7c478bd9Sstevel@tonic-gate return (1); 1534*7c478bd9Sstevel@tonic-gate } else { 1535*7c478bd9Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 1536*7c478bd9Sstevel@tonic-gate return (-1); 1537*7c478bd9Sstevel@tonic-gate } 1538*7c478bd9Sstevel@tonic-gate } 1539*7c478bd9Sstevel@tonic-gate if (tflg) { 1540*7c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 1541*7c478bd9Sstevel@tonic-gate return (rflg); 1542*7c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 1543*7c478bd9Sstevel@tonic-gate return (-rflg); 1544*7c478bd9Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 1545*7c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 1546*7c478bd9Sstevel@tonic-gate return (rflg); 1547*7c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 1548*7c478bd9Sstevel@tonic-gate return (-rflg); 1549*7c478bd9Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 1550*7c478bd9Sstevel@tonic-gate } else if (Sflg) { 1551*7c478bd9Sstevel@tonic-gate /* 1552*7c478bd9Sstevel@tonic-gate * The size stored in lsize can be either the 1553*7c478bd9Sstevel@tonic-gate * size or the major minor number (in the case of 1554*7c478bd9Sstevel@tonic-gate * block and character special devices). If it's 1555*7c478bd9Sstevel@tonic-gate * a major minor number, then the size is considered 1556*7c478bd9Sstevel@tonic-gate * to be zero and we want to fall through and sort 1557*7c478bd9Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 1558*7c478bd9Sstevel@tonic-gate * to the size of p1 we want to fall through and 1559*7c478bd9Sstevel@tonic-gate * sort by name. 1560*7c478bd9Sstevel@tonic-gate */ 1561*7c478bd9Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 1562*7c478bd9Sstevel@tonic-gate (p1->ltype == 'c') ? 0 : p1->lsize; 1563*7c478bd9Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 1564*7c478bd9Sstevel@tonic-gate (p2->ltype == 'c') ? 0 : p2->lsize; 1565*7c478bd9Sstevel@tonic-gate if (p2size > p1size) { 1566*7c478bd9Sstevel@tonic-gate return (rflg); 1567*7c478bd9Sstevel@tonic-gate } else if (p2size < p1size) { 1568*7c478bd9Sstevel@tonic-gate return (-rflg); 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 1571*7c478bd9Sstevel@tonic-gate } 1572*7c478bd9Sstevel@tonic-gate return (rflg * strcoll( 1573*7c478bd9Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 1574*7c478bd9Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 1575*7c478bd9Sstevel@tonic-gate } 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate static void 1578*7c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2) 1579*7c478bd9Sstevel@tonic-gate { 1580*7c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 1581*7c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate static void 1585*7c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s) 1586*7c478bd9Sstevel@tonic-gate { 1587*7c478bd9Sstevel@tonic-gate unsigned char *cp; 1588*7c478bd9Sstevel@tonic-gate char c; 1589*7c478bd9Sstevel@tonic-gate int i; 1590*7c478bd9Sstevel@tonic-gate int c_len; 1591*7c478bd9Sstevel@tonic-gate int p_col; 1592*7c478bd9Sstevel@tonic-gate wchar_t pcode; 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate if (!qflg && !bflg) { 1595*7c478bd9Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 1596*7c478bd9Sstevel@tonic-gate (void) putchar(*cp); 1597*7c478bd9Sstevel@tonic-gate curcol++; 1598*7c478bd9Sstevel@tonic-gate } 1599*7c478bd9Sstevel@tonic-gate return; 1600*7c478bd9Sstevel@tonic-gate } 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate for (cp = s; *cp; ) { 1603*7c478bd9Sstevel@tonic-gate if (isascii(c = *cp)) { 1604*7c478bd9Sstevel@tonic-gate if (!isprint(c)) { 1605*7c478bd9Sstevel@tonic-gate if (qflg) { 1606*7c478bd9Sstevel@tonic-gate c = '?'; 1607*7c478bd9Sstevel@tonic-gate } else { 1608*7c478bd9Sstevel@tonic-gate curcol += 3; 1609*7c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 1610*7c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 1611*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1612*7c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 1613*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1614*7c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 1615*7c478bd9Sstevel@tonic-gate } 1616*7c478bd9Sstevel@tonic-gate } 1617*7c478bd9Sstevel@tonic-gate curcol++; 1618*7c478bd9Sstevel@tonic-gate cp++; 1619*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1620*7c478bd9Sstevel@tonic-gate continue; 1621*7c478bd9Sstevel@tonic-gate } 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 1624*7c478bd9Sstevel@tonic-gate c_len = 1; 1625*7c478bd9Sstevel@tonic-gate goto not_print; 1626*7c478bd9Sstevel@tonic-gate } 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 1629*7c478bd9Sstevel@tonic-gate (void) putwchar(pcode); 1630*7c478bd9Sstevel@tonic-gate cp += c_len; 1631*7c478bd9Sstevel@tonic-gate curcol += p_col; 1632*7c478bd9Sstevel@tonic-gate continue; 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate not_print: 1636*7c478bd9Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 1637*7c478bd9Sstevel@tonic-gate if (qflg) { 1638*7c478bd9Sstevel@tonic-gate c = '?'; 1639*7c478bd9Sstevel@tonic-gate } else { 1640*7c478bd9Sstevel@tonic-gate curcol += 3; 1641*7c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 1642*7c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 1643*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1644*7c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 1645*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1646*7c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate curcol++; 1649*7c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 1650*7c478bd9Sstevel@tonic-gate cp++; 1651*7c478bd9Sstevel@tonic-gate } 1652*7c478bd9Sstevel@tonic-gate } 1653*7c478bd9Sstevel@tonic-gate } 1654*7c478bd9Sstevel@tonic-gate 1655*7c478bd9Sstevel@tonic-gate static int 1656*7c478bd9Sstevel@tonic-gate strcol(unsigned char *s1) 1657*7c478bd9Sstevel@tonic-gate { 1658*7c478bd9Sstevel@tonic-gate int w; 1659*7c478bd9Sstevel@tonic-gate int w_col; 1660*7c478bd9Sstevel@tonic-gate int len; 1661*7c478bd9Sstevel@tonic-gate wchar_t wc; 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate w = 0; 1664*7c478bd9Sstevel@tonic-gate while (*s1) { 1665*7c478bd9Sstevel@tonic-gate if (isascii(*s1)) { 1666*7c478bd9Sstevel@tonic-gate w++; 1667*7c478bd9Sstevel@tonic-gate s1++; 1668*7c478bd9Sstevel@tonic-gate continue; 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 1672*7c478bd9Sstevel@tonic-gate w++; 1673*7c478bd9Sstevel@tonic-gate s1++; 1674*7c478bd9Sstevel@tonic-gate continue; 1675*7c478bd9Sstevel@tonic-gate } 1676*7c478bd9Sstevel@tonic-gate 1677*7c478bd9Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 1678*7c478bd9Sstevel@tonic-gate w_col = len; 1679*7c478bd9Sstevel@tonic-gate s1 += len; 1680*7c478bd9Sstevel@tonic-gate w += w_col; 1681*7c478bd9Sstevel@tonic-gate } 1682*7c478bd9Sstevel@tonic-gate return (w); 1683*7c478bd9Sstevel@tonic-gate } 1684*7c478bd9Sstevel@tonic-gate 1685*7c478bd9Sstevel@tonic-gate /* 1686*7c478bd9Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 1687*7c478bd9Sstevel@tonic-gate * result in the caller-supplied buffer. 1688*7c478bd9Sstevel@tonic-gate * 1689*7c478bd9Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 1690*7c478bd9Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 1691*7c478bd9Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 1692*7c478bd9Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 1693*7c478bd9Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 1694*7c478bd9Sstevel@tonic-gate * the final number has only a single significant digit, we compute 1695*7c478bd9Sstevel@tonic-gate * tenths of units to provide a second significant digit. 1696*7c478bd9Sstevel@tonic-gate * 1697*7c478bd9Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 1698*7c478bd9Sstevel@tonic-gate * converted to "-1". 1699*7c478bd9Sstevel@tonic-gate * 1700*7c478bd9Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 1701*7c478bd9Sstevel@tonic-gate */ 1702*7c478bd9Sstevel@tonic-gate static char * 1703*7c478bd9Sstevel@tonic-gate number_to_scaled_string( 1704*7c478bd9Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 1705*7c478bd9Sstevel@tonic-gate unsigned long long number, /* convert this number */ 1706*7c478bd9Sstevel@tonic-gate long scale) 1707*7c478bd9Sstevel@tonic-gate { 1708*7c478bd9Sstevel@tonic-gate unsigned long long save; 1709*7c478bd9Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 1710*7c478bd9Sstevel@tonic-gate char *uom = "KMGTPE"; 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate if ((long long)number == (long long)-1) { 1713*7c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 1714*7c478bd9Sstevel@tonic-gate return (buf); 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate save = number; 1718*7c478bd9Sstevel@tonic-gate number = number / scale; 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * Now we have number as a count of scale units. 1722*7c478bd9Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 1723*7c478bd9Sstevel@tonic-gate * 1724*7c478bd9Sstevel@tonic-gate * The largest value number could have had entering the routine is 1725*7c478bd9Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 1726*7c478bd9Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 1727*7c478bd9Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 1728*7c478bd9Sstevel@tonic-gate */ 1729*7c478bd9Sstevel@tonic-gate if (number < (unsigned long long)scale) { 1730*7c478bd9Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 1731*7c478bd9Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 1732*7c478bd9Sstevel@tonic-gate uom++; 1733*7c478bd9Sstevel@tonic-gate number = 1; 1734*7c478bd9Sstevel@tonic-gate } 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate } else { 1737*7c478bd9Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 1738*7c478bd9Sstevel@tonic-gate uom++; /* next unit of measurement */ 1739*7c478bd9Sstevel@tonic-gate save = number; 1740*7c478bd9Sstevel@tonic-gate /* 1741*7c478bd9Sstevel@tonic-gate * If we're over half way to the next unit of 1742*7c478bd9Sstevel@tonic-gate * 'scale' bytes (which means we should round 1743*7c478bd9Sstevel@tonic-gate * up), then adding half of 'scale' prior to 1744*7c478bd9Sstevel@tonic-gate * the division will push us into that next 1745*7c478bd9Sstevel@tonic-gate * unit of scale when we perform the division 1746*7c478bd9Sstevel@tonic-gate */ 1747*7c478bd9Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 1748*7c478bd9Sstevel@tonic-gate } 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 1752*7c478bd9Sstevel@tonic-gate if ((save / scale) < 10) { 1753*7c478bd9Sstevel@tonic-gate /* snprintf() will round for us */ 1754*7c478bd9Sstevel@tonic-gate float fnum = (float)save / scale; 1755*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 1756*7c478bd9Sstevel@tonic-gate fnum, *uom); 1757*7c478bd9Sstevel@tonic-gate } else { 1758*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 1759*7c478bd9Sstevel@tonic-gate number, *uom); 1760*7c478bd9Sstevel@tonic-gate } 1761*7c478bd9Sstevel@tonic-gate return (buf); 1762*7c478bd9Sstevel@tonic-gate } 1763