10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51447Sakaplan * Common Development and Distribution License (the "License"). 61447Sakaplan * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 225902Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 300Sstevel@tonic-gate /* All Rights Reserved */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * List files or directories 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include <sys/param.h> 390Sstevel@tonic-gate #include <sys/types.h> 400Sstevel@tonic-gate #include <sys/mkdev.h> 410Sstevel@tonic-gate #include <sys/stat.h> 420Sstevel@tonic-gate #include <sys/acl.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <wchar.h> 450Sstevel@tonic-gate #include <stdio.h> 460Sstevel@tonic-gate #include <ctype.h> 470Sstevel@tonic-gate #include <dirent.h> 480Sstevel@tonic-gate #include <string.h> 490Sstevel@tonic-gate #include <locale.h> 500Sstevel@tonic-gate #include <curses.h> 510Sstevel@tonic-gate #include <termios.h> 520Sstevel@tonic-gate #include <stdlib.h> 530Sstevel@tonic-gate #include <widec.h> 540Sstevel@tonic-gate #include <locale.h> 550Sstevel@tonic-gate #include <wctype.h> 560Sstevel@tonic-gate #include <pwd.h> 570Sstevel@tonic-gate #include <grp.h> 580Sstevel@tonic-gate #include <limits.h> 590Sstevel@tonic-gate #include <fcntl.h> 600Sstevel@tonic-gate #include <unistd.h> 610Sstevel@tonic-gate #include <libgen.h> 620Sstevel@tonic-gate #include <errno.h> 63789Sahrens #include <aclutils.h> 645331Samw #include <libnvpair.h> 655331Samw #include <libcmdutils.h> 665331Samw #include <attr.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #ifndef STANDALONE 690Sstevel@tonic-gate #define TERMINFO 700Sstevel@tonic-gate #endif 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 740Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 755331Samw * the terminfo feature(pre 6.0 systems ?). 760Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 770Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate #ifdef NOTERMINFO 800Sstevel@tonic-gate #undef TERMINFO 810Sstevel@tonic-gate #endif 820Sstevel@tonic-gate 830Sstevel@tonic-gate #include <term.h> 840Sstevel@tonic-gate 850Sstevel@tonic-gate #define BFSIZE 16 860Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 870Sstevel@tonic-gate #define ISARG 0100000 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 910Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate #define LS_NOTREG 010000 940Sstevel@tonic-gate 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * Date and time formats 980Sstevel@tonic-gate * 990Sstevel@tonic-gate * b --- abbreviated month name 1000Sstevel@tonic-gate * e --- day number 1010Sstevel@tonic-gate * Y --- year in the form ccyy 1020Sstevel@tonic-gate * H --- hour(24-hour version) 1030Sstevel@tonic-gate * M --- minute 1040Sstevel@tonic-gate * F --- yyyy-mm-dd 1050Sstevel@tonic-gate * T --- hh:mm:ss 1060Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1070Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1080Sstevel@tonic-gate * not present in older C libraries 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate #define FORMAT1 " %b %e %Y " 1110Sstevel@tonic-gate #define FORMAT2 " %b %e %H:%M " 1120Sstevel@tonic-gate #define FORMAT3 " %b %e %T %Y " 1130Sstevel@tonic-gate #define FORMAT4 " %%F %%T.%.09ld %%z " 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate #undef BUFSIZ 1160Sstevel@tonic-gate #define BUFSIZ 4096 1170Sstevel@tonic-gate #define NUMBER_WIDTH 40 1180Sstevel@tonic-gate #define FMTSIZE 50 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate struct ditem { 1210Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1220Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1230Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1240Sstevel@tonic-gate }; 1255331Samw /* Holds boolean extended system attributes */ 1265331Samw struct attrb { 1275331Samw char *name; 1285331Samw }; 1295331Samw /* Holds timestamp extended system attributes */ 1305331Samw struct attrtm { 1315331Samw char *name; 1325331Samw uint64_t stm; 1335331Samw uint64_t nstm; 1345331Samw }; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate struct lbuf { 1370Sstevel@tonic-gate union { 1380Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 1390Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 1400Sstevel@tonic-gate } ln; 1410Sstevel@tonic-gate char ltype; /* filetype */ 1420Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 1430Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1440Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 1450Sstevel@tonic-gate uid_t luid; 1460Sstevel@tonic-gate gid_t lgid; 1470Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 1480Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 1490Sstevel@tonic-gate timestruc_t lmtime; 1505331Samw timestruc_t lat; 1515331Samw timestruc_t lct; 1525331Samw timestruc_t lmt; 1530Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 1540Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 1550Sstevel@tonic-gate int cycle; /* cycle detected flag */ 1560Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 157789Sahrens acl_t *aclp; /* ACL if present */ 1585331Samw struct attrb *exttr; /* boolean extended system attributes */ 1595331Samw struct attrtm *extm; /* timestamp extended system attributes */ 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate struct dchain { 1630Sstevel@tonic-gate char *dc_name; /* path name */ 1640Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 1650Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 1660Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 1670Sstevel@tonic-gate }; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 1710Sstevel@tonic-gate */ 1720Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 1750Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 1760Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 1770Sstevel@tonic-gate static char *curdir; /* the current directory */ 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 1800Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 1810Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 1820Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 1830Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 1840Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 1870Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 1880Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 1890Sstevel@tonic-gate static char *getname(uid_t); 1900Sstevel@tonic-gate static char *getgroup(gid_t); 1910Sstevel@tonic-gate static char *makename(char *, char *); 1920Sstevel@tonic-gate static void pentry(struct lbuf *); 1930Sstevel@tonic-gate static void column(void); 1940Sstevel@tonic-gate static void pmode(mode_t aflag); 1950Sstevel@tonic-gate static void selection(int *); 1960Sstevel@tonic-gate static void new_line(void); 1970Sstevel@tonic-gate static void rddir(char *, struct ditem *); 1980Sstevel@tonic-gate static int strcol(unsigned char *); 1990Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2000Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2010Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2020Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2030Sstevel@tonic-gate static void pprintf(char *, char *); 2040Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2050Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2060Sstevel@tonic-gate unsigned long long number, 2070Sstevel@tonic-gate long scale); 2080Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2090Sstevel@tonic-gate int, struct ditem *); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate static int aflg; 2120Sstevel@tonic-gate static int atflg; 2130Sstevel@tonic-gate static int bflg; 2140Sstevel@tonic-gate static int cflg; 2150Sstevel@tonic-gate static int dflg; 2160Sstevel@tonic-gate static int eflg; 2170Sstevel@tonic-gate static int fflg; 2180Sstevel@tonic-gate static int gflg; 2190Sstevel@tonic-gate static int hflg; 2200Sstevel@tonic-gate static int iflg; 2210Sstevel@tonic-gate static int lflg; 2220Sstevel@tonic-gate static int mflg; 2230Sstevel@tonic-gate static int nflg; 2240Sstevel@tonic-gate static int oflg; 2250Sstevel@tonic-gate static int pflg; 2260Sstevel@tonic-gate static int qflg; 2270Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2280Sstevel@tonic-gate static int sflg; 2290Sstevel@tonic-gate static int tflg; 2300Sstevel@tonic-gate static int uflg; 2310Sstevel@tonic-gate static int xflg; 2320Sstevel@tonic-gate static int Aflg; 2330Sstevel@tonic-gate static int Cflg; 2340Sstevel@tonic-gate static int Eflg; 2350Sstevel@tonic-gate static int Fflg; 2360Sstevel@tonic-gate static int Hflg; 2370Sstevel@tonic-gate static int Lflg; 2380Sstevel@tonic-gate static int Rflg; 2390Sstevel@tonic-gate static int Sflg; 240789Sahrens static int vflg; 2411420Smarks static int Vflg; 2425331Samw static int saflg; /* boolean extended system attr. */ 2435331Samw static int sacnt; /* number of extended system attr. */ 2445331Samw static int copt; 2455331Samw static int vopt; 2465331Samw static int tmflg; /* create time ext. system attr. */ 2475331Samw static int ctm; 2485331Samw static int atm; 2495331Samw static int mtm; 2505331Samw static int crtm; 2515331Samw static int alltm; 2520Sstevel@tonic-gate static long hscale; 2530Sstevel@tonic-gate static mode_t flags; 2540Sstevel@tonic-gate static int err = 0; /* Contains return code */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 2570Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 2580Sstevel@tonic-gate static char *lastuname = NULL; 2590Sstevel@tonic-gate static char *lastgname = NULL; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg are on */ 2620Sstevel@tonic-gate static int statreq; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate static char *dotp = "."; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 2670Sstevel@tonic-gate static time_t year, now; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate static int num_cols = 80; 2700Sstevel@tonic-gate static int colwidth; 2710Sstevel@tonic-gate static int filewidth; 2720Sstevel@tonic-gate static int fixedwidth; 2730Sstevel@tonic-gate static int nomocore; 2740Sstevel@tonic-gate static int curcol; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate static struct winsize win; 2770Sstevel@tonic-gate 2785331Samw static char time_buf[FMTSIZE]; /* array to hold day and time */ 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 2810Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 2840Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 2855331Samw /* Extended system attributes support */ 2865331Samw static int get_sysxattr(char *, struct lbuf *); 2875331Samw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 2885331Samw static void set_sysattrtm_display(char *, struct lbuf *); 2895331Samw static void format_time(const char *, time_t); 2905331Samw static void format_etime(const char *, time_t, time_t); 2915331Samw static void print_time(struct lbuf *); 2925331Samw static void format_attrtime(struct lbuf *); 2935331Samw static void *xmalloc(size_t, struct lbuf *); 2945331Samw static void free_sysattr(struct lbuf *); 2955331Samw static nvpair_t *pair; 2965331Samw static nvlist_t *response; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate int 2990Sstevel@tonic-gate main(int argc, char *argv[]) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate int c; 3020Sstevel@tonic-gate int i; 3030Sstevel@tonic-gate int width; 3040Sstevel@tonic-gate int amino = 0; 3050Sstevel@tonic-gate int opterr = 0; 3060Sstevel@tonic-gate struct lbuf *ep; 3070Sstevel@tonic-gate struct lbuf lb; 3080Sstevel@tonic-gate struct ditem *myinfo; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3110Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 3120Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 3130Sstevel@tonic-gate #endif 3140Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3150Sstevel@tonic-gate #ifdef STANDALONE 3160Sstevel@tonic-gate if (argv[0][0] == '\0') 3170Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 3180Sstevel@tonic-gate #endif 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 3210Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 3220Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 3230Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 3240Sstevel@tonic-gate if (isatty(1)) { 3250Sstevel@tonic-gate Cflg = 1; 3260Sstevel@tonic-gate mflg = 0; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate while ((c = getopt(argc, argv, 3305331Samw "aAbcCdeEfFghHilLmnopqrRsStux1@vV/:%:")) != EOF) 3310Sstevel@tonic-gate switch (c) { 3320Sstevel@tonic-gate case 'a': 3330Sstevel@tonic-gate aflg++; 3340Sstevel@tonic-gate continue; 3350Sstevel@tonic-gate case 'A': 3360Sstevel@tonic-gate Aflg++; 3370Sstevel@tonic-gate continue; 3380Sstevel@tonic-gate case 'b': 3390Sstevel@tonic-gate bflg = 1; 3400Sstevel@tonic-gate qflg = 0; 3410Sstevel@tonic-gate continue; 3420Sstevel@tonic-gate case 'c': 3430Sstevel@tonic-gate uflg = 0; 3445331Samw atm = 0; 3455331Samw ctm = 0; 3465331Samw mtm = 0; 3475331Samw crtm = 0; 3480Sstevel@tonic-gate cflg++; 3490Sstevel@tonic-gate continue; 3500Sstevel@tonic-gate case 'C': 3510Sstevel@tonic-gate Cflg = 1; 3520Sstevel@tonic-gate mflg = 0; 3530Sstevel@tonic-gate #ifdef XPG4 3540Sstevel@tonic-gate lflg = 0; 3550Sstevel@tonic-gate #endif 3560Sstevel@tonic-gate continue; 3570Sstevel@tonic-gate case 'd': 3580Sstevel@tonic-gate dflg++; 3590Sstevel@tonic-gate continue; 3600Sstevel@tonic-gate case 'e': 3610Sstevel@tonic-gate eflg++; 3620Sstevel@tonic-gate lflg++; 3630Sstevel@tonic-gate statreq++; 3640Sstevel@tonic-gate Eflg = 0; 3650Sstevel@tonic-gate continue; 3660Sstevel@tonic-gate case 'E': 3670Sstevel@tonic-gate Eflg++; 3680Sstevel@tonic-gate lflg++; 3690Sstevel@tonic-gate statreq++; 3700Sstevel@tonic-gate eflg = 0; 3710Sstevel@tonic-gate continue; 3720Sstevel@tonic-gate case 'f': 3730Sstevel@tonic-gate fflg++; 3740Sstevel@tonic-gate continue; 3750Sstevel@tonic-gate case 'F': 3760Sstevel@tonic-gate Fflg++; 3770Sstevel@tonic-gate statreq++; 3780Sstevel@tonic-gate continue; 3790Sstevel@tonic-gate case 'g': 3800Sstevel@tonic-gate gflg++; 3810Sstevel@tonic-gate lflg++; 3820Sstevel@tonic-gate statreq++; 3830Sstevel@tonic-gate continue; 3840Sstevel@tonic-gate case 'h': 3850Sstevel@tonic-gate hflg++; 3860Sstevel@tonic-gate hscale = 1024; 3870Sstevel@tonic-gate continue; 3880Sstevel@tonic-gate case 'H': 3890Sstevel@tonic-gate Hflg++; 3900Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 3910Sstevel@tonic-gate Lflg = 0; 3920Sstevel@tonic-gate continue; 3930Sstevel@tonic-gate case 'i': 3940Sstevel@tonic-gate iflg++; 3950Sstevel@tonic-gate continue; 3960Sstevel@tonic-gate case 'l': 3970Sstevel@tonic-gate lflg++; 3980Sstevel@tonic-gate statreq++; 3990Sstevel@tonic-gate Cflg = 0; 4000Sstevel@tonic-gate xflg = 0; 4010Sstevel@tonic-gate mflg = 0; 4020Sstevel@tonic-gate atflg = 0; 4030Sstevel@tonic-gate continue; 4040Sstevel@tonic-gate case 'L': 4050Sstevel@tonic-gate Lflg++; 4060Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 4070Sstevel@tonic-gate Hflg = 0; 4080Sstevel@tonic-gate continue; 4090Sstevel@tonic-gate case 'm': 4100Sstevel@tonic-gate Cflg = 0; 4110Sstevel@tonic-gate mflg = 1; 4120Sstevel@tonic-gate #ifdef XPG4 4130Sstevel@tonic-gate lflg = 0; 4140Sstevel@tonic-gate #endif 4150Sstevel@tonic-gate continue; 4160Sstevel@tonic-gate case 'n': 4170Sstevel@tonic-gate nflg++; 4180Sstevel@tonic-gate lflg++; 4190Sstevel@tonic-gate statreq++; 4200Sstevel@tonic-gate Cflg = 0; 4210Sstevel@tonic-gate xflg = 0; 4220Sstevel@tonic-gate mflg = 0; 4230Sstevel@tonic-gate atflg = 0; 4240Sstevel@tonic-gate continue; 4250Sstevel@tonic-gate case 'o': 4260Sstevel@tonic-gate oflg++; 4270Sstevel@tonic-gate lflg++; 4280Sstevel@tonic-gate statreq++; 4290Sstevel@tonic-gate continue; 4300Sstevel@tonic-gate case 'p': 4310Sstevel@tonic-gate pflg++; 4320Sstevel@tonic-gate statreq++; 4330Sstevel@tonic-gate continue; 4340Sstevel@tonic-gate case 'q': 4350Sstevel@tonic-gate qflg = 1; 4360Sstevel@tonic-gate bflg = 0; 4370Sstevel@tonic-gate continue; 4380Sstevel@tonic-gate case 'r': 4390Sstevel@tonic-gate rflg = -1; 4400Sstevel@tonic-gate continue; 4410Sstevel@tonic-gate case 'R': 4420Sstevel@tonic-gate Rflg++; 4430Sstevel@tonic-gate statreq++; 4440Sstevel@tonic-gate continue; 4450Sstevel@tonic-gate case 's': 4460Sstevel@tonic-gate sflg++; 4470Sstevel@tonic-gate statreq++; 4480Sstevel@tonic-gate continue; 4490Sstevel@tonic-gate case 'S': 4500Sstevel@tonic-gate tflg = 0; 4510Sstevel@tonic-gate Sflg++; 4520Sstevel@tonic-gate statreq++; 4530Sstevel@tonic-gate continue; 4540Sstevel@tonic-gate case 't': 4550Sstevel@tonic-gate Sflg = 0; 4560Sstevel@tonic-gate tflg++; 4570Sstevel@tonic-gate statreq++; 4580Sstevel@tonic-gate continue; 4590Sstevel@tonic-gate case 'u': 4600Sstevel@tonic-gate cflg = 0; 4615331Samw atm = 0; 4625331Samw ctm = 0; 4635331Samw mtm = 0; 4645331Samw crtm = 0; 4650Sstevel@tonic-gate uflg++; 4660Sstevel@tonic-gate continue; 4671420Smarks case 'V': 4681420Smarks Vflg++; 4691420Smarks /*FALLTHROUGH*/ 470789Sahrens case 'v': 471789Sahrens vflg++; 472789Sahrens #if !defined(XPG4) 473789Sahrens if (lflg) 474789Sahrens continue; 475789Sahrens #endif 476789Sahrens lflg++; 477789Sahrens statreq++; 478789Sahrens Cflg = 0; 479789Sahrens xflg = 0; 480789Sahrens mflg = 0; 481789Sahrens continue; 4820Sstevel@tonic-gate case 'x': 4830Sstevel@tonic-gate xflg = 1; 4840Sstevel@tonic-gate Cflg = 1; 4850Sstevel@tonic-gate mflg = 0; 4860Sstevel@tonic-gate #ifdef XPG4 4870Sstevel@tonic-gate lflg = 0; 4880Sstevel@tonic-gate #endif 4890Sstevel@tonic-gate continue; 4900Sstevel@tonic-gate case '1': 4910Sstevel@tonic-gate Cflg = 0; 4920Sstevel@tonic-gate continue; 4930Sstevel@tonic-gate case '@': 4940Sstevel@tonic-gate #if !defined(XPG4) 4950Sstevel@tonic-gate /* 4960Sstevel@tonic-gate * -l has precedence over -@ 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate if (lflg) 4990Sstevel@tonic-gate continue; 5000Sstevel@tonic-gate #endif 5010Sstevel@tonic-gate atflg++; 5020Sstevel@tonic-gate lflg++; 5030Sstevel@tonic-gate statreq++; 5040Sstevel@tonic-gate Cflg = 0; 5050Sstevel@tonic-gate xflg = 0; 5060Sstevel@tonic-gate mflg = 0; 5070Sstevel@tonic-gate continue; 5085331Samw case '/': 5095331Samw saflg++; 5105331Samw if (optarg != NULL) { 5115331Samw if (strcmp(optarg, "c") == 0) { 5125331Samw copt++; 5135331Samw vopt = 0; 5145331Samw } else if (strcmp(optarg, "v") == 0) { 5155331Samw vopt++; 5165331Samw copt = 0; 5175331Samw } else 5185331Samw opterr++; 5195331Samw } else 5205331Samw opterr++; 5215331Samw lflg++; 5225331Samw statreq++; 5235331Samw Cflg = 0; 5245331Samw xflg = 0; 5255331Samw mflg = 0; 5265331Samw continue; 5275331Samw case '%': 5285331Samw tmflg++; 5295331Samw if (optarg != NULL) { 5305331Samw if (strcmp(optarg, "ctime") == 0) { 5315331Samw ctm++; 5325331Samw atm = 0; 5335331Samw mtm = 0; 5345331Samw crtm = 0; 5355331Samw } else if (strcmp(optarg, "atime") == 0) { 5365331Samw atm++; 5375331Samw ctm = 0; 5385331Samw mtm = 0; 5395331Samw crtm = 0; 5405331Samw uflg = 0; 5415331Samw cflg = 0; 5425331Samw } else if (strcmp(optarg, "mtime") == 0) { 5435331Samw mtm++; 5445331Samw atm = 0; 5455331Samw ctm = 0; 5465331Samw crtm = 0; 5475331Samw uflg = 0; 5485331Samw cflg = 0; 5495331Samw } else if (strcmp(optarg, "crtime") == 0) { 5505331Samw crtm++; 5515331Samw atm = 0; 5525331Samw ctm = 0; 5535331Samw mtm = 0; 5545331Samw uflg = 0; 5555331Samw cflg = 0; 5565331Samw } else if (strcmp(optarg, "all") == 0) { 5575331Samw alltm++; 5585331Samw atm = 0; 5595331Samw ctm = 0; 5605331Samw mtm = 0; 5615331Samw crtm = 0; 5625331Samw } else 5635331Samw opterr++; 5645331Samw } else 5655331Samw opterr++; 5665331Samw 5675331Samw Sflg = 0; 5685331Samw statreq++; 5695331Samw mflg = 0; 5705331Samw continue; 5710Sstevel@tonic-gate case '?': 5720Sstevel@tonic-gate opterr++; 5730Sstevel@tonic-gate continue; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate if (opterr) { 5760Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5775331Samw "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@/%[c | v]" 5785331Samw "%%[atime | crtime | ctime | mtime | all]" 5795331Samw " [files]\n")); 5800Sstevel@tonic-gate exit(2); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (fflg) { 5840Sstevel@tonic-gate aflg++; 5850Sstevel@tonic-gate lflg = 0; 5860Sstevel@tonic-gate sflg = 0; 5870Sstevel@tonic-gate tflg = 0; 5880Sstevel@tonic-gate Sflg = 0; 5890Sstevel@tonic-gate statreq = 0; 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate fixedwidth = 2; 5930Sstevel@tonic-gate if (pflg || Fflg) 5940Sstevel@tonic-gate fixedwidth++; 5950Sstevel@tonic-gate if (iflg) 5960Sstevel@tonic-gate fixedwidth += 11; 5970Sstevel@tonic-gate if (sflg) 5980Sstevel@tonic-gate fixedwidth += 5; 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (lflg) { 6010Sstevel@tonic-gate if (!gflg && !oflg) 6020Sstevel@tonic-gate gflg = oflg = 1; 6030Sstevel@tonic-gate else 6040Sstevel@tonic-gate if (gflg && oflg) 6050Sstevel@tonic-gate gflg = oflg = 0; 6060Sstevel@tonic-gate Cflg = mflg = 0; 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate if (Cflg || mflg) { 6100Sstevel@tonic-gate char *clptr; 6110Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 6120Sstevel@tonic-gate num_cols = atoi(clptr); 6130Sstevel@tonic-gate #ifdef TERMINFO 6140Sstevel@tonic-gate else { 6150Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 6160Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate #endif 6190Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 6200Sstevel@tonic-gate /* assume it is an error */ 6210Sstevel@tonic-gate num_cols = 80; 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* allocate space for flist and the associated */ 6250Sstevel@tonic-gate /* data structures (lbufs) */ 6260Sstevel@tonic-gate maxfils = quantn; 6270Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 6280Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 6290Sstevel@tonic-gate perror("ls"); 6300Sstevel@tonic-gate exit(2); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * case when no names are given 6350Sstevel@tonic-gate * in ls-command and current 6360Sstevel@tonic-gate * directory is to be used 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate argv[optind] = dotp; 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 6450Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 6460Sstevel@tonic-gate * (actually, just the directories) visited, we 6470Sstevel@tonic-gate * maintain a directory ancestry list for a file 6480Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 6490Sstevel@tonic-gate * a parent directory passes its directory list 6500Sstevel@tonic-gate * info (device id, inode number, and a pointer to 6510Sstevel@tonic-gate * its parent) to each of its children. As we 6520Sstevel@tonic-gate * process a child that is a directory, we save 6530Sstevel@tonic-gate * its own personal directory list info. We then 6540Sstevel@tonic-gate * check to see if the child has already been 6550Sstevel@tonic-gate * processed by comparing its device id and inode 6560Sstevel@tonic-gate * number from its own personal directory list info 6570Sstevel@tonic-gate * to that of each of its ancestors. If there is a 6580Sstevel@tonic-gate * match, then we know we've detected a cycle. 6590Sstevel@tonic-gate */ 6600Sstevel@tonic-gate if (Rflg) { 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * This is the first parent in this lineage 6630Sstevel@tonic-gate * (first in a directory hierarchy), so 6640Sstevel@tonic-gate * this parent's parent doesn't exist. We 6650Sstevel@tonic-gate * only initialize myinfo when we are 6660Sstevel@tonic-gate * recursing, otherwise it's not used. 6670Sstevel@tonic-gate */ 6680Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 6690Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 6700Sstevel@tonic-gate perror("ls"); 6710Sstevel@tonic-gate exit(2); 6720Sstevel@tonic-gate } else { 6730Sstevel@tonic-gate myinfo->dev = 0; 6740Sstevel@tonic-gate myinfo->ino = 0; 6750Sstevel@tonic-gate myinfo->parent = NULL; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (Cflg || mflg) { 6800Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 6810Sstevel@tonic-gate if (width > filewidth) 6820Sstevel@tonic-gate filewidth = width; 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 6850Sstevel@tonic-gate 1, myinfo)) == NULL) { 6860Sstevel@tonic-gate if (nomocore) 6870Sstevel@tonic-gate exit(2); 6880Sstevel@tonic-gate err = 2; 6890Sstevel@tonic-gate optind++; 6900Sstevel@tonic-gate continue; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 6930Sstevel@tonic-gate ep->lflags |= ISARG; 6940Sstevel@tonic-gate optind++; 6950Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 6980Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 6990Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 7000Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 7010Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 7020Sstevel@tonic-gate break; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 7050Sstevel@tonic-gate for (; i < nargs; i++) { 7060Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 7070Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 7080Sstevel@tonic-gate if (nomocore) 7090Sstevel@tonic-gate exit(2); 7100Sstevel@tonic-gate /* -R: print subdirectories found */ 7110Sstevel@tonic-gate while (dfirst || cdfirst) { 7120Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 7130Sstevel@tonic-gate while (cdfirst) { 7140Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 7150Sstevel@tonic-gate dtemp = cdfirst; 7160Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 7170Sstevel@tonic-gate dtemp -> dc_next = dfirst; 7180Sstevel@tonic-gate dfirst = dtemp; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 7210Sstevel@tonic-gate dtemp = dfirst; 7220Sstevel@tonic-gate dfirst = dfirst->dc_next; 7230Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 7240Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 7250Sstevel@tonic-gate if (nomocore) 7260Sstevel@tonic-gate exit(2); 7270Sstevel@tonic-gate free(dtemp->dc_name); 7280Sstevel@tonic-gate free(dtemp); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate return (err); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 7360Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 7370Sstevel@tonic-gate */ 7380Sstevel@tonic-gate static void 7390Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 7400Sstevel@tonic-gate { 7410Sstevel@tonic-gate struct dchain *dp; 7420Sstevel@tonic-gate struct lbuf *ap; 7430Sstevel@tonic-gate char *pname; 7440Sstevel@tonic-gate int j; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate filewidth = 0; 7470Sstevel@tonic-gate curdir = name; 7480Sstevel@tonic-gate if (title) { 7490Sstevel@tonic-gate if (!first) 7500Sstevel@tonic-gate (void) putc('\n', stdout); 7510Sstevel@tonic-gate pprintf(name, ":"); 7520Sstevel@tonic-gate new_line(); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 7560Sstevel@tonic-gate * further. 7570Sstevel@tonic-gate */ 7580Sstevel@tonic-gate if (cdetect) { 7590Sstevel@tonic-gate if (lflg || sflg) { 7600Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 7610Sstevel@tonic-gate new_line(); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7640Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 7650Sstevel@tonic-gate return; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate nfiles = lp; 7690Sstevel@tonic-gate rddir(name, myinfo); 7700Sstevel@tonic-gate if (nomocore) 7710Sstevel@tonic-gate return; 7720Sstevel@tonic-gate if (fflg == 0) 7730Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 7740Sstevel@tonic-gate sizeof (struct lbuf *), 7750Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 7760Sstevel@tonic-gate if (Rflg) { 7770Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 7780Sstevel@tonic-gate ap = flist[j]; 7790Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 7800Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 7810Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 7820Sstevel@tonic-gate if (dp == NULL) { 7830Sstevel@tonic-gate perror("ls"); 7840Sstevel@tonic-gate exit(2); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 7870Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 7880Sstevel@tonic-gate perror("ls"); 7890Sstevel@tonic-gate exit(2); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 7920Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 7930Sstevel@tonic-gate dp->dc_next = dfirst; 7940Sstevel@tonic-gate dfirst = dp; 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate if (lflg || sflg) { 7990Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 8000Sstevel@tonic-gate new_line(); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* 8060Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 8070Sstevel@tonic-gate * by slp and lp. 8080Sstevel@tonic-gate */ 8090Sstevel@tonic-gate static void 8100Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 8110Sstevel@tonic-gate { 8120Sstevel@tonic-gate long row, nrows, i; 8130Sstevel@tonic-gate int col, ncols; 8140Sstevel@tonic-gate struct lbuf **ep; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate if (Cflg || mflg) { 8170Sstevel@tonic-gate if (colwidth > num_cols) { 8180Sstevel@tonic-gate ncols = 1; 8190Sstevel@tonic-gate } else { 8200Sstevel@tonic-gate ncols = num_cols / colwidth; 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 8250Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 8260Sstevel@tonic-gate pentry(*ep); 8270Sstevel@tonic-gate new_line(); 8280Sstevel@tonic-gate return; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate /* otherwise print -C columns */ 8310Sstevel@tonic-gate if (tot_flag) { 8320Sstevel@tonic-gate slp--; 8330Sstevel@tonic-gate row = 1; 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate else 8360Sstevel@tonic-gate row = 0; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 8390Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 8400Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 8410Sstevel@tonic-gate ep = slp + (nrows * col) + row; 8420Sstevel@tonic-gate if (ep < lp) 8430Sstevel@tonic-gate pentry(*ep); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate new_line(); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate /* 8500Sstevel@tonic-gate * print one output entry; 8510Sstevel@tonic-gate * if uid/gid is not found in the appropriate 8520Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 8530Sstevel@tonic-gate * user/group name; 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate static void 8560Sstevel@tonic-gate pentry(struct lbuf *ap) 8570Sstevel@tonic-gate { 8580Sstevel@tonic-gate struct lbuf *p; 8590Sstevel@tonic-gate numbuf_t hbuf; 8600Sstevel@tonic-gate char buf[BUFSIZ]; 8610Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 8620Sstevel@tonic-gate char *cp; 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate p = ap; 8650Sstevel@tonic-gate column(); 8660Sstevel@tonic-gate if (iflg) 8670Sstevel@tonic-gate if (mflg && !lflg) 8680Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 8690Sstevel@tonic-gate else 8700Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 8710Sstevel@tonic-gate if (sflg) 8720Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 8735331Samw (p->lblocks < 10000) ? "%4lld " : "%lld ", 8745331Samw (p->ltype != 'b' && p->ltype != 'c') ? 8755331Samw p->lblocks : 0LL); 8760Sstevel@tonic-gate if (lflg) { 8770Sstevel@tonic-gate (void) putchar(p->ltype); 8780Sstevel@tonic-gate curcol++; 8790Sstevel@tonic-gate pmode(p->lflags); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* ACL: additional access mode flag */ 8820Sstevel@tonic-gate (void) putchar(p->acl); 8830Sstevel@tonic-gate curcol++; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 8860Sstevel@tonic-gate if (oflg) 8870Sstevel@tonic-gate if (!nflg) { 8880Sstevel@tonic-gate cp = getname(p->luid); 8890Sstevel@tonic-gate curcol += printf("%-8s ", cp); 8900Sstevel@tonic-gate } else 8910Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 8920Sstevel@tonic-gate if (gflg) 8930Sstevel@tonic-gate if (!nflg) { 8940Sstevel@tonic-gate cp = getgroup(p->lgid); 8950Sstevel@tonic-gate curcol += printf("%-8s ", cp); 8960Sstevel@tonic-gate } else 8970Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 8980Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 8990Sstevel@tonic-gate curcol += printf("%3u, %2u", 9000Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 9010Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 9020Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 9030Sstevel@tonic-gate curcol += printf("%7s", 9040Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 9050Sstevel@tonic-gate } else { 9060Sstevel@tonic-gate curcol += printf((p->lsize < (off_t)10000000) ? 9070Sstevel@tonic-gate "%7lld" : "%lld", p->lsize); 9080Sstevel@tonic-gate } 9095331Samw if (eflg) 9105331Samw format_time(FORMAT3, p->lmtime.tv_sec); 9115331Samw else if (Eflg) 9120Sstevel@tonic-gate /* fill in nanoseconds first */ 9135331Samw format_etime(FORMAT4, p->lmtime.tv_sec, 9145331Samw p->lmtime.tv_nsec); 9155331Samw else { 9160Sstevel@tonic-gate if ((p->lmtime.tv_sec < year) || 9175331Samw (p->lmtime.tv_sec > now)) 9185331Samw format_time(FORMAT1, p->lmtime.tv_sec); 9195331Samw else 9205331Samw format_time(FORMAT2, p->lmtime.tv_sec); 9210Sstevel@tonic-gate } 9225331Samw /* format extended system attribute time */ 9235331Samw if (tmflg && crtm) 9245331Samw format_attrtime(p); 9255331Samw 9260Sstevel@tonic-gate curcol += printf("%s", time_buf); 9275331Samw 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * prevent both "->" and trailing marks 9310Sstevel@tonic-gate * from appearing 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate if (pflg && p->ltype == 'd') 9350Sstevel@tonic-gate dmark = "/"; 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 9380Sstevel@tonic-gate if (p->ltype == 'd') 9390Sstevel@tonic-gate dmark = "/"; 9400Sstevel@tonic-gate else if (p->ltype == 'D') 9410Sstevel@tonic-gate dmark = ">"; 9420Sstevel@tonic-gate else if (p->ltype == 'p') 9430Sstevel@tonic-gate dmark = "|"; 9440Sstevel@tonic-gate else if (p->ltype == 'l') 9450Sstevel@tonic-gate dmark = "@"; 9460Sstevel@tonic-gate else if (p->ltype == 's') 9470Sstevel@tonic-gate dmark = "="; 9480Sstevel@tonic-gate else if (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)) 9490Sstevel@tonic-gate dmark = "*"; 9500Sstevel@tonic-gate else 9510Sstevel@tonic-gate dmark = ""; 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate if (lflg && p->flinkto) { 9550Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 9560Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 9570Sstevel@tonic-gate dmark = buf; 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate if (p->lflags & ISARG) { 9600Sstevel@tonic-gate if (qflg || bflg) 9610Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 9620Sstevel@tonic-gate else { 9630Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 9640Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 9650Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate } else { 9680Sstevel@tonic-gate if (qflg || bflg) 9690Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 9700Sstevel@tonic-gate else { 9710Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 9720Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 9730Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate } 976789Sahrens 9775331Samw /* Display extended system attributes */ 9785331Samw if (saflg) { 9795331Samw int i; 9805331Samw 9815331Samw new_line(); 9825331Samw (void) printf(" \t{"); 9835331Samw if (p->exttr != NULL) { 9845331Samw int k = 0; 9855331Samw for (i = 0; i < sacnt; i++) { 9865331Samw if (p->exttr[i].name != NULL) 9875331Samw k++; 9885331Samw } 9895331Samw for (i = 0; i < sacnt; i++) { 9905331Samw if (p->exttr[i].name != NULL) { 9915331Samw (void) printf("%s", p->exttr[i].name); 9925331Samw k--; 9935331Samw if (vopt && (k != 0)) 9945331Samw (void) printf(","); 9955331Samw } 9965331Samw } 9975331Samw } 9985331Samw (void) printf("}\n"); 9995331Samw } 10005331Samw /* Display file timestamps and extended system attribute timestamps */ 10015331Samw if (tmflg && alltm) { 10025331Samw new_line(); 10035331Samw print_time(p); 10045331Samw new_line(); 10055331Samw } 1006789Sahrens if (vflg) { 1007789Sahrens new_line(); 1008789Sahrens if (p->aclp) { 10091420Smarks acl_printacl(p->aclp, num_cols, Vflg); 1010789Sahrens } 1011789Sahrens } 10125331Samw /* Free extended system attribute lists */ 10135331Samw if (saflg || tmflg) 10145331Samw free_sysattr(p); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate /* print various r,w,x permissions */ 10180Sstevel@tonic-gate static void 10190Sstevel@tonic-gate pmode(mode_t aflag) 10200Sstevel@tonic-gate { 10210Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 10220Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 10230Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 10240Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 10250Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 10260Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 10270Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 10280Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 10290Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 10300Sstevel@tonic-gate #ifdef XPG4 10310Sstevel@tonic-gate S_ISGID, 'L', '-'}; 10320Sstevel@tonic-gate #else 10330Sstevel@tonic-gate S_ISGID, 'l', '-'}; 10340Sstevel@tonic-gate #endif 10350Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 10360Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 10370Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 10380Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate int **mp; 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate flags = aflag; 10450Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 10460Sstevel@tonic-gate selection(*mp); 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate static void 10500Sstevel@tonic-gate selection(int *pairp) 10510Sstevel@tonic-gate { 10520Sstevel@tonic-gate int n; 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate n = *pairp++; 10550Sstevel@tonic-gate while (n-->0) { 10560Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 10570Sstevel@tonic-gate pairp++; 10580Sstevel@tonic-gate break; 10590Sstevel@tonic-gate } else { 10600Sstevel@tonic-gate pairp += 2; 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate (void) putchar(*pairp); 10640Sstevel@tonic-gate curcol++; 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate /* 10680Sstevel@tonic-gate * column: get to the beginning of the next column. 10690Sstevel@tonic-gate */ 10700Sstevel@tonic-gate static void 10710Sstevel@tonic-gate column(void) 10720Sstevel@tonic-gate { 10730Sstevel@tonic-gate if (curcol == 0) 10740Sstevel@tonic-gate return; 10750Sstevel@tonic-gate if (mflg) { 10760Sstevel@tonic-gate (void) putc(',', stdout); 10770Sstevel@tonic-gate curcol++; 10780Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 10790Sstevel@tonic-gate (void) putc('\n', stdout); 10800Sstevel@tonic-gate curcol = 0; 10810Sstevel@tonic-gate return; 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate (void) putc(' ', stdout); 10840Sstevel@tonic-gate curcol++; 10850Sstevel@tonic-gate return; 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate if (Cflg == 0) { 10880Sstevel@tonic-gate (void) putc('\n', stdout); 10890Sstevel@tonic-gate curcol = 0; 10900Sstevel@tonic-gate return; 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 10930Sstevel@tonic-gate (void) putc('\n', stdout); 10940Sstevel@tonic-gate curcol = 0; 10950Sstevel@tonic-gate return; 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate do { 10980Sstevel@tonic-gate (void) putc(' ', stdout); 10990Sstevel@tonic-gate curcol++; 11000Sstevel@tonic-gate } while (curcol % colwidth); 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate static void 11040Sstevel@tonic-gate new_line(void) 11050Sstevel@tonic-gate { 11060Sstevel@tonic-gate if (curcol) { 11070Sstevel@tonic-gate first = 0; 11080Sstevel@tonic-gate (void) putc('\n', stdout); 11090Sstevel@tonic-gate curcol = 0; 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate } 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate /* 11140Sstevel@tonic-gate * read each filename in directory dir and store its 11150Sstevel@tonic-gate * status in flist[nfiles] 11160Sstevel@tonic-gate * use makename() to form pathname dir/filename; 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate static void 11190Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate struct dirent *dentry; 11220Sstevel@tonic-gate DIR *dirf; 11230Sstevel@tonic-gate int j; 11240Sstevel@tonic-gate struct lbuf *ep; 11250Sstevel@tonic-gate int width; 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 11280Sstevel@tonic-gate (void) fflush(stdout); 11290Sstevel@tonic-gate perror(dir); 11300Sstevel@tonic-gate err = 2; 11310Sstevel@tonic-gate return; 11320Sstevel@tonic-gate } else { 11330Sstevel@tonic-gate tblocks = 0; 11340Sstevel@tonic-gate for (;;) { 11350Sstevel@tonic-gate errno = 0; 11360Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 11370Sstevel@tonic-gate break; 11380Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 11390Sstevel@tonic-gate (Aflg == 0 || 11400Sstevel@tonic-gate dentry->d_name[1] == '\0' || 11410Sstevel@tonic-gate dentry->d_name[1] == '.' && 11420Sstevel@tonic-gate dentry->d_name[2] == '\0')) 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * check for directory items '.', '..', 11450Sstevel@tonic-gate * and items without valid inode-number; 11460Sstevel@tonic-gate */ 11470Sstevel@tonic-gate continue; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate if (Cflg || mflg) { 11500Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 11510Sstevel@tonic-gate if (width > filewidth) 11520Sstevel@tonic-gate filewidth = width; 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 11550Sstevel@tonic-gate if (ep == NULL) { 11560Sstevel@tonic-gate if (nomocore) 11575331Samw exit(2); 11580Sstevel@tonic-gate continue; 11590Sstevel@tonic-gate } else { 11600Sstevel@tonic-gate ep->lnum = dentry->d_ino; 11610Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 11620Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 11630Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate if (errno) { 11670Sstevel@tonic-gate int sav_errno = errno; 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate (void) fprintf(stderr, 11700Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 11710Sstevel@tonic-gate dir, strerror(sav_errno)); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate (void) closedir(dirf); 11740Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate /* 11790Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 11800Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 11810Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 11820Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 11830Sstevel@tonic-gate * it is reported at the right time when printing the directory. 11840Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 11850Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 11860Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 11870Sstevel@tonic-gate * command line. 11880Sstevel@tonic-gate */ 11890Sstevel@tonic-gate static void 11900Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 11910Sstevel@tonic-gate int argfl, struct ditem *myparent) 11920Sstevel@tonic-gate { 11930Sstevel@tonic-gate size_t file_len; 11940Sstevel@tonic-gate struct ditem *myinfo; 11950Sstevel@tonic-gate struct ditem *tptr; 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate file_len = strlen(file); 11980Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 11990Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 12000Sstevel@tonic-gate /* 12010Sstevel@tonic-gate * Add this inode's ancestry 12020Sstevel@tonic-gate * info and insert it into the 12030Sstevel@tonic-gate * ancestry list by pointing 12040Sstevel@tonic-gate * back to its parent. We save 12050Sstevel@tonic-gate * it (in rep) with the other info 12060Sstevel@tonic-gate * we're gathering for this inode. 12070Sstevel@tonic-gate */ 12080Sstevel@tonic-gate if ((myinfo = malloc( 12090Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 12100Sstevel@tonic-gate perror("ls"); 12110Sstevel@tonic-gate exit(2); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 12140Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 12150Sstevel@tonic-gate myinfo->parent = myparent; 12160Sstevel@tonic-gate rep->ancinfo = myinfo; 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate /* 12190Sstevel@tonic-gate * If this node has the same device id and 12200Sstevel@tonic-gate * inode number of one of its ancestors, 12210Sstevel@tonic-gate * then we've detected a cycle. 12220Sstevel@tonic-gate */ 12230Sstevel@tonic-gate if (myparent != NULL) { 12240Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 12250Sstevel@tonic-gate tptr = tptr->parent) { 12260Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 12270Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 12280Sstevel@tonic-gate /* 12290Sstevel@tonic-gate * Cycle detected for this 12300Sstevel@tonic-gate * directory. Record the fact 12310Sstevel@tonic-gate * it is a cycle so we don't 12320Sstevel@tonic-gate * try to process this 12330Sstevel@tonic-gate * directory as we are 12340Sstevel@tonic-gate * walking through the 12350Sstevel@tonic-gate * list of directories. 12360Sstevel@tonic-gate */ 12370Sstevel@tonic-gate rep->cycle = 1; 12380Sstevel@tonic-gate err = 2; 12390Sstevel@tonic-gate break; 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate } 12450Sstevel@tonic-gate 12460Sstevel@tonic-gate /* 12476178Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 12486178Sny155746 * This is because, if the server's FS happens to be UFS, supporting 12496178Sny155746 * POSIX ACL's, then it does a special calculation of group mode 12506178Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 12516178Sny155746 * 12526178Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 12536178Sny155746 * algorithm is used for the group mode calculation only. 12546178Sny155746 * What is modified here from the algorithm is that only the 12556178Sny155746 * entries with flags ACE_GROUP are considered. For each entry 12566178Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 12576178Sny155746 * is checked if it is allowed. 12586373Sny155746 * We are not interested in perms for user and other, as they 12596178Sny155746 * were taken from st_mode value. 12606178Sny155746 * We are not interested in a_who field of ACE, as we need just 12616178Sny155746 * unix mode bits for the group. 12626178Sny155746 */ 12636373Sny155746 12646373Sny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 12656373Sny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 12666373Sny155746 12676178Sny155746 int 12686178Sny155746 grp_mask_to_mode(acl_t *acep) 12696178Sny155746 { 12706178Sny155746 int mode = 0, seen = 0; 12716178Sny155746 int acecnt; 12726373Sny155746 int flags; 12736178Sny155746 ace_t *ap; 12746178Sny155746 12756178Sny155746 acecnt = acl_cnt(acep); 12766178Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 12776373Sny155746 12786373Sny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 12796373Sny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 12806373Sny155746 continue; 12816373Sny155746 12826373Sny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 12836373Sny155746 continue; 12846373Sny155746 12856373Sny155746 /* 12866373Sny155746 * if it is first group@ or first everyone@ 12876373Sny155746 * for each of read, write and execute, then 12886373Sny155746 * that will be the group mode bit. 12896373Sny155746 */ 12906373Sny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 12916373Sny155746 if (flags == OWNED_GROUP || flags == ACE_EVERYONE) { 12926373Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 12936373Sny155746 if (!(seen & S_IRGRP)) { 12946373Sny155746 seen |= S_IRGRP; 12956373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 12966373Sny155746 mode |= S_IRGRP; 12976178Sny155746 } 12986373Sny155746 } 12996373Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 13006373Sny155746 if (!(seen & S_IWGRP)) { 13016373Sny155746 seen |= S_IWGRP; 13026373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 13036373Sny155746 mode |= S_IWGRP; 13046178Sny155746 } 13056373Sny155746 } 13066373Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 13076373Sny155746 if (!(seen & S_IXGRP)) { 13086373Sny155746 seen |= S_IXGRP; 13096373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 13106373Sny155746 mode |= S_IXGRP; 13116178Sny155746 } 13126178Sny155746 } 13136178Sny155746 } 13146178Sny155746 } 13156178Sny155746 return (mode); 13166178Sny155746 } 13176178Sny155746 13186178Sny155746 /* 13190Sstevel@tonic-gate * get status of file and recomputes tblocks; 13200Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 13210Sstevel@tonic-gate * for filename in a directory whose name is an 13220Sstevel@tonic-gate * argument in the command; 13230Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 13240Sstevel@tonic-gate * returns that pointer; 13250Sstevel@tonic-gate * returns NULL if failed; 13260Sstevel@tonic-gate */ 13270Sstevel@tonic-gate static struct lbuf * 13280Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 13290Sstevel@tonic-gate { 13300Sstevel@tonic-gate struct stat statb, statb1; 13310Sstevel@tonic-gate struct lbuf *rep; 13320Sstevel@tonic-gate char buf[BUFSIZ]; 13330Sstevel@tonic-gate ssize_t cc; 13340Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 13350Sstevel@tonic-gate int aclcnt; 1336789Sahrens int error; 13370Sstevel@tonic-gate aclent_t *tp; 13380Sstevel@tonic-gate o_mode_t groupperm, mask; 13390Sstevel@tonic-gate int grouppermfound, maskfound; 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate if (nomocore) 13420Sstevel@tonic-gate return (NULL); 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if (nfiles >= maxfils) { 13450Sstevel@tonic-gate /* 13460Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 13470Sstevel@tonic-gate * more space 13480Sstevel@tonic-gate */ 13490Sstevel@tonic-gate maxfils += quantn; 13500Sstevel@tonic-gate if (((flist = realloc(flist, 13510Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 13520Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 13530Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 13540Sstevel@tonic-gate perror("ls"); 13550Sstevel@tonic-gate nomocore = 1; 13560Sstevel@tonic-gate return (NULL); 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate /* 13610Sstevel@tonic-gate * nfiles is reset to nargs for each directory 13620Sstevel@tonic-gate * that is given as an argument maxn is checked 13630Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 13640Sstevel@tonic-gate * that already has one assigned. 13650Sstevel@tonic-gate */ 13660Sstevel@tonic-gate if (nfiles >= maxn) { 13670Sstevel@tonic-gate rep = nxtlbf++; 13680Sstevel@tonic-gate flist[nfiles++] = rep; 13690Sstevel@tonic-gate maxn = nfiles; 13700Sstevel@tonic-gate } else { 13710Sstevel@tonic-gate rep = flist[nfiles++]; 13720Sstevel@tonic-gate } 1373*6792Sbasabi 1374*6792Sbasabi /* Initialize */ 1375*6792Sbasabi 13760Sstevel@tonic-gate rep->lflags = (mode_t)0; 13770Sstevel@tonic-gate rep->flinkto = NULL; 13780Sstevel@tonic-gate rep->cycle = 0; 1379*6792Sbasabi rep->lat.tv_sec = time(NULL); 1380*6792Sbasabi rep->lat.tv_nsec = 0; 1381*6792Sbasabi rep->lct.tv_sec = time(NULL); 1382*6792Sbasabi rep->lct.tv_nsec = 0; 1383*6792Sbasabi rep->lmt.tv_sec = time(NULL); 1384*6792Sbasabi rep->lmt.tv_nsec = 0; 1385*6792Sbasabi rep->exttr = NULL; 1386*6792Sbasabi rep->extm = NULL; 1387*6792Sbasabi 13880Sstevel@tonic-gate if (argfl || statreq) { 13890Sstevel@tonic-gate int doacl; 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate if (lflg) 13920Sstevel@tonic-gate doacl = 1; 13930Sstevel@tonic-gate else 13940Sstevel@tonic-gate doacl = 0; 1395*6792Sbasabi 13960Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 13970Sstevel@tonic-gate if (argfl || errno != ENOENT || 13980Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 13990Sstevel@tonic-gate /* 14000Sstevel@tonic-gate * Avoid race between readdir and lstat. 14010Sstevel@tonic-gate * Print error message in case of dangling link. 14020Sstevel@tonic-gate */ 14030Sstevel@tonic-gate perror(file); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate nfiles--; 14060Sstevel@tonic-gate return (NULL); 14070Sstevel@tonic-gate } 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate /* 14100Sstevel@tonic-gate * If -H was specified, and the file linked to was 14110Sstevel@tonic-gate * not a directory, then we need to get the info 14120Sstevel@tonic-gate * for the symlink itself. 14130Sstevel@tonic-gate */ 14140Sstevel@tonic-gate if ((Hflg) && (argfl) && 14150Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 14160Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 14170Sstevel@tonic-gate perror(file); 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate rep->lnum = statb.st_ino; 14220Sstevel@tonic-gate rep->lsize = statb.st_size; 14230Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 14240Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 14250Sstevel@tonic-gate case S_IFDIR: 14260Sstevel@tonic-gate rep->ltype = 'd'; 14270Sstevel@tonic-gate if (Rflg) { 14280Sstevel@tonic-gate record_ancestry(file, &statb, rep, 14290Sstevel@tonic-gate argfl, myparent); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate break; 14320Sstevel@tonic-gate case S_IFBLK: 14330Sstevel@tonic-gate rep->ltype = 'b'; 14340Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 14350Sstevel@tonic-gate break; 14360Sstevel@tonic-gate case S_IFCHR: 14370Sstevel@tonic-gate rep->ltype = 'c'; 14380Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 14390Sstevel@tonic-gate break; 14400Sstevel@tonic-gate case S_IFIFO: 14410Sstevel@tonic-gate rep->ltype = 'p'; 14420Sstevel@tonic-gate break; 14430Sstevel@tonic-gate case S_IFSOCK: 14440Sstevel@tonic-gate rep->ltype = 's'; 14450Sstevel@tonic-gate rep->lsize = 0; 14460Sstevel@tonic-gate break; 14470Sstevel@tonic-gate case S_IFLNK: 14480Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 14490Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 14500Sstevel@tonic-gate ((Hflg) && (!argfl))) { 14510Sstevel@tonic-gate doacl = 0; 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate rep->ltype = 'l'; 14540Sstevel@tonic-gate if (lflg) { 14550Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 14560Sstevel@tonic-gate if (cc >= 0) { 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate /* 14590Sstevel@tonic-gate * follow the symbolic link 14600Sstevel@tonic-gate * to generate the appropriate 14610Sstevel@tonic-gate * Fflg marker for the object 14620Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 14630Sstevel@tonic-gate */ 14640Sstevel@tonic-gate if ((Fflg || pflg) && 14650Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 14660Sstevel@tonic-gate switch (statb1.st_mode & 14670Sstevel@tonic-gate S_IFMT) { 14680Sstevel@tonic-gate case S_IFDIR: 14690Sstevel@tonic-gate buf[cc++] = '/'; 14700Sstevel@tonic-gate break; 14710Sstevel@tonic-gate case S_IFSOCK: 14720Sstevel@tonic-gate buf[cc++] = '='; 14730Sstevel@tonic-gate break; 14741447Sakaplan case S_IFDOOR: 14751447Sakaplan buf[cc++] = '>'; 14761447Sakaplan break; 14771447Sakaplan case S_IFIFO: 14781447Sakaplan buf[cc++] = '|'; 14791447Sakaplan break; 14800Sstevel@tonic-gate default: 14810Sstevel@tonic-gate if ((statb1.st_mode & 14820Sstevel@tonic-gate ~S_IFMT) & 14830Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 14840Sstevel@tonic-gate S_IXOTH)) 14850Sstevel@tonic-gate buf[cc++] = '*'; 14860Sstevel@tonic-gate break; 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate } 14890Sstevel@tonic-gate buf[cc] = '\0'; 14900Sstevel@tonic-gate rep->flinkto = strdup(buf); 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate break; 14930Sstevel@tonic-gate } 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate /* 14960Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 14970Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 14980Sstevel@tonic-gate * when explicit arguments are specified. 14990Sstevel@tonic-gate */ 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate #ifdef XPG6 15020Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 15030Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 15040Sstevel@tonic-gate (stat(file, &statb1) < 0)) 15050Sstevel@tonic-gate #else 15060Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 15070Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 15080Sstevel@tonic-gate #endif /* XPG6 */ 15090Sstevel@tonic-gate break; 15100Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 15110Sstevel@tonic-gate statb = statb1; 15120Sstevel@tonic-gate rep->ltype = 'd'; 15130Sstevel@tonic-gate rep->lsize = statb1.st_size; 15140Sstevel@tonic-gate if (Rflg) { 15150Sstevel@tonic-gate record_ancestry(file, &statb, rep, 15160Sstevel@tonic-gate argfl, myparent); 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate break; 15200Sstevel@tonic-gate case S_IFDOOR: 15210Sstevel@tonic-gate rep->ltype = 'D'; 15220Sstevel@tonic-gate break; 15230Sstevel@tonic-gate case S_IFREG: 15240Sstevel@tonic-gate rep->ltype = '-'; 15250Sstevel@tonic-gate break; 15260Sstevel@tonic-gate case S_IFPORT: 15270Sstevel@tonic-gate rep->ltype = 'P'; 15280Sstevel@tonic-gate break; 15290Sstevel@tonic-gate default: 15300Sstevel@tonic-gate rep->ltype = '?'; 15310Sstevel@tonic-gate break; 15320Sstevel@tonic-gate } 15330Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 15360Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 15370Sstevel@tonic-gate 1538*6792Sbasabi rep->luid = statb.st_uid; 1539*6792Sbasabi rep->lgid = statb.st_gid; 1540*6792Sbasabi rep->lnl = statb.st_nlink; 1541*6792Sbasabi if (uflg || (tmflg && atm)) 1542*6792Sbasabi rep->lmtime = statb.st_atim; 1543*6792Sbasabi else if (cflg || (tmflg && ctm)) 1544*6792Sbasabi rep->lmtime = statb.st_ctim; 1545*6792Sbasabi else 1546*6792Sbasabi rep->lmtime = statb.st_mtim; 1547*6792Sbasabi rep->lat = statb.st_atim; 1548*6792Sbasabi rep->lct = statb.st_ctim; 1549*6792Sbasabi rep->lmt = statb.st_mtim; 1550*6792Sbasabi 15510Sstevel@tonic-gate /* ACL: check acl entries count */ 15520Sstevel@tonic-gate if (doacl) { 15530Sstevel@tonic-gate 1554789Sahrens error = acl_get(file, 0, &rep->aclp); 1555789Sahrens if (error) { 1556789Sahrens (void) fprintf(stderr, 1557789Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1558789Sahrens file, acl_strerror(error)); 1559*6792Sbasabi rep->acl = ' '; 1560*6792Sbasabi return (rep); 1561789Sahrens } 15620Sstevel@tonic-gate 1563789Sahrens rep->acl = ' '; 15640Sstevel@tonic-gate 1565789Sahrens if (rep->aclp && 1566789Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1567789Sahrens rep->acl = '+'; 15680Sstevel@tonic-gate /* 1569789Sahrens * Special handling for ufs aka aclent_t ACL's 15700Sstevel@tonic-gate */ 15716178Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 1572789Sahrens /* 1573789Sahrens * For files with non-trivial acls, the 1574789Sahrens * effective group permissions are the 1575789Sahrens * intersection of the GROUP_OBJ value 1576789Sahrens * and the CLASS_OBJ (acl mask) value. 1577789Sahrens * Determine both the GROUP_OBJ and 1578789Sahrens * CLASS_OBJ for this file and insert 1579789Sahrens * the logical AND of those two values 1580789Sahrens * in the group permissions field 1581789Sahrens * of the lflags value for this file. 1582789Sahrens */ 1583789Sahrens 1584789Sahrens /* 1585789Sahrens * Until found in acl list, assume 1586789Sahrens * maximum permissions for both group 1587789Sahrens * a nd mask. (Just in case the acl 1588789Sahrens * lacks either value for some reason.) 1589789Sahrens */ 1590789Sahrens groupperm = 07; 1591789Sahrens mask = 07; 1592789Sahrens grouppermfound = 0; 1593789Sahrens maskfound = 0; 1594789Sahrens aclcnt = acl_cnt(rep->aclp); 1595789Sahrens for (tp = 1596789Sahrens (aclent_t *)acl_data(rep->aclp); 1597789Sahrens aclcnt--; tp++) { 1598789Sahrens if (tp->a_type == GROUP_OBJ) { 1599789Sahrens groupperm = tp->a_perm; 1600789Sahrens grouppermfound = 1; 1601789Sahrens continue; 1602789Sahrens } 1603789Sahrens if (tp->a_type == CLASS_OBJ) { 1604789Sahrens mask = tp->a_perm; 1605789Sahrens maskfound = 1; 1606789Sahrens } 1607789Sahrens if (grouppermfound && maskfound) 1608789Sahrens break; 16090Sstevel@tonic-gate } 1610789Sahrens 16110Sstevel@tonic-gate 1612789Sahrens /* reset all the group bits */ 1613789Sahrens rep->lflags &= ~S_IRWXG; 16140Sstevel@tonic-gate 1615789Sahrens /* 1616789Sahrens * Now set them to the logical AND of 1617789Sahrens * the GROUP_OBJ permissions and the 1618789Sahrens * acl mask. 1619789Sahrens */ 16200Sstevel@tonic-gate 1621789Sahrens rep->lflags |= (groupperm & mask) << 3; 16220Sstevel@tonic-gate 16236178Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 16246178Sny155746 int mode; 16256178Sny155746 mode = grp_mask_to_mode(rep->aclp); 16266178Sny155746 rep->lflags &= ~S_IRWXG; 16276178Sny155746 rep->lflags |= mode; 1628789Sahrens } 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate 16311420Smarks if (!vflg && !Vflg && rep->aclp) { 16321420Smarks acl_free(rep->aclp); 16331420Smarks rep->aclp = NULL; 16341420Smarks } 16351420Smarks 16360Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 16370Sstevel@tonic-gate rep->acl = '@'; 16385331Samw 16390Sstevel@tonic-gate } else 16400Sstevel@tonic-gate rep->acl = ' '; 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 16450Sstevel@tonic-gate tblocks += rep->lblocks; 16465331Samw 16475331Samw /* Get extended system attributes */ 16485331Samw 16495331Samw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 16505331Samw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 16515331Samw int i; 16525331Samw 16535331Samw sacnt = attr_count(); 16545331Samw /* 16555331Samw * Allocate 'sacnt' size array to hold extended 16565331Samw * system attribute name (verbose) or respective 16575331Samw * symbol represenation (compact). 16585331Samw */ 16595331Samw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 16605331Samw rep); 16615331Samw 16625331Samw /* initialize boolean attribute list */ 16635331Samw for (i = 0; i < sacnt; i++) 16645331Samw rep->exttr[i].name = NULL; 16655331Samw if (get_sysxattr(file, rep) != 0) { 16665331Samw (void) fprintf(stderr, 16675331Samw gettext("ls:Failed to retrieve " 16685331Samw "extended system attribute from " 16695331Samw "%s\n"), file); 16705331Samw rep->exttr[0].name = xmalloc(2, rep); 16715331Samw (void) strlcpy(rep->exttr[0].name, "?", 2); 16725331Samw } 16735331Samw } 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate return (rep); 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate /* 16790Sstevel@tonic-gate * returns pathname of the form dir/file; 16800Sstevel@tonic-gate * dir and file are null-terminated strings. 16810Sstevel@tonic-gate */ 16820Sstevel@tonic-gate static char * 16830Sstevel@tonic-gate makename(char *dir, char *file) 16840Sstevel@tonic-gate { 16850Sstevel@tonic-gate /* 16860Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 16870Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 16880Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 16890Sstevel@tonic-gate * and the null character at the end. 16900Sstevel@tonic-gate * dfile is static as this is returned by makename(). 16910Sstevel@tonic-gate */ 16920Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 16930Sstevel@tonic-gate char *dp, *fp; 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate dp = dfile; 16960Sstevel@tonic-gate fp = dir; 16970Sstevel@tonic-gate while (*fp) 16980Sstevel@tonic-gate *dp++ = *fp++; 16990Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 17000Sstevel@tonic-gate *dp++ = '/'; 17010Sstevel@tonic-gate fp = file; 17020Sstevel@tonic-gate while (*fp) 17030Sstevel@tonic-gate *dp++ = *fp++; 17040Sstevel@tonic-gate *dp = '\0'; 17050Sstevel@tonic-gate return (dfile); 17060Sstevel@tonic-gate } 17070Sstevel@tonic-gate 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate #include <pwd.h> 17100Sstevel@tonic-gate #include <grp.h> 17110Sstevel@tonic-gate #include <utmpx.h> 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate struct utmpx utmp; 17140Sstevel@tonic-gate 17150Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 17160Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate 17190Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 17200Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 17210Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 17220Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 17230Sstevel@tonic-gate int initted; /* name has been filled in */ 17240Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 17250Sstevel@tonic-gate }; 17260Sstevel@tonic-gate static struct cachenode *names, *groups; 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate static struct cachenode * 17290Sstevel@tonic-gate findincache(struct cachenode **head, long val) 17300Sstevel@tonic-gate { 17310Sstevel@tonic-gate struct cachenode **parent = head; 17320Sstevel@tonic-gate struct cachenode *c = *parent; 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate while (c != NULL) { 17350Sstevel@tonic-gate if (val == c->val) { 17360Sstevel@tonic-gate /* found it */ 17370Sstevel@tonic-gate return (c); 17380Sstevel@tonic-gate } else if (val < c->val) { 17390Sstevel@tonic-gate parent = &c->lesschild; 17400Sstevel@tonic-gate c = c->lesschild; 17410Sstevel@tonic-gate } else { 17420Sstevel@tonic-gate parent = &c->grtrchild; 17430Sstevel@tonic-gate c = c->grtrchild; 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 17480Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 17490Sstevel@tonic-gate if (c == NULL) { 17500Sstevel@tonic-gate perror("ls"); 17510Sstevel@tonic-gate exit(2); 17520Sstevel@tonic-gate } 17530Sstevel@tonic-gate *parent = c; 17540Sstevel@tonic-gate c->val = val; 17550Sstevel@tonic-gate return (c); 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate /* 17590Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 17600Sstevel@tonic-gate * lastuid is set to uid. 17610Sstevel@tonic-gate */ 17620Sstevel@tonic-gate static char * 17630Sstevel@tonic-gate getname(uid_t uid) 17640Sstevel@tonic-gate { 17650Sstevel@tonic-gate struct passwd *pwent; 17660Sstevel@tonic-gate struct cachenode *c; 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 17690Sstevel@tonic-gate return (lastuname); 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate c = findincache(&names, uid); 17720Sstevel@tonic-gate if (c->initted == 0) { 17730Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 17740Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 17750Sstevel@tonic-gate } else { 17760Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 17770Sstevel@tonic-gate } 17780Sstevel@tonic-gate c->initted = 1; 17790Sstevel@tonic-gate } 17800Sstevel@tonic-gate lastuid = uid; 17810Sstevel@tonic-gate lastuname = &c->name[0]; 17820Sstevel@tonic-gate return (lastuname); 17830Sstevel@tonic-gate } 17840Sstevel@tonic-gate 17850Sstevel@tonic-gate /* 17860Sstevel@tonic-gate * get name from cache, or group file for a given gid; 17870Sstevel@tonic-gate * lastgid is set to gid. 17880Sstevel@tonic-gate */ 17890Sstevel@tonic-gate static char * 17900Sstevel@tonic-gate getgroup(gid_t gid) 17910Sstevel@tonic-gate { 17920Sstevel@tonic-gate struct group *grent; 17930Sstevel@tonic-gate struct cachenode *c; 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 17960Sstevel@tonic-gate return (lastgname); 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate c = findincache(&groups, gid); 17990Sstevel@tonic-gate if (c->initted == 0) { 18000Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 18010Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 18020Sstevel@tonic-gate } else { 18030Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate c->initted = 1; 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate lastgid = gid; 18080Sstevel@tonic-gate lastgname = &c->name[0]; 18090Sstevel@tonic-gate return (lastgname); 18100Sstevel@tonic-gate } 18110Sstevel@tonic-gate 18120Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 18130Sstevel@tonic-gate static int 18140Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 18150Sstevel@tonic-gate { 18160Sstevel@tonic-gate struct lbuf *p1, *p2; 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate p1 = *pp1; 18190Sstevel@tonic-gate p2 = *pp2; 18200Sstevel@tonic-gate if (dflg == 0) { 18210Sstevel@tonic-gate /* 18220Sstevel@tonic-gate * compare two names in ls-command one of which is file 18230Sstevel@tonic-gate * and the other is a directory; 18240Sstevel@tonic-gate * this portion is not used for comparing files within 18250Sstevel@tonic-gate * a directory name of ls-command; 18260Sstevel@tonic-gate */ 18270Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 18280Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 18290Sstevel@tonic-gate return (1); 18300Sstevel@tonic-gate } else { 18310Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 18320Sstevel@tonic-gate return (-1); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate if (tflg) { 18360Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 18370Sstevel@tonic-gate return (rflg); 18380Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 18390Sstevel@tonic-gate return (-rflg); 18400Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 18410Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 18420Sstevel@tonic-gate return (rflg); 18430Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 18440Sstevel@tonic-gate return (-rflg); 18450Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 18460Sstevel@tonic-gate } else if (Sflg) { 18470Sstevel@tonic-gate /* 18480Sstevel@tonic-gate * The size stored in lsize can be either the 18490Sstevel@tonic-gate * size or the major minor number (in the case of 18500Sstevel@tonic-gate * block and character special devices). If it's 18510Sstevel@tonic-gate * a major minor number, then the size is considered 18520Sstevel@tonic-gate * to be zero and we want to fall through and sort 18530Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 18540Sstevel@tonic-gate * to the size of p1 we want to fall through and 18550Sstevel@tonic-gate * sort by name. 18560Sstevel@tonic-gate */ 18570Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 18585331Samw (p1->ltype == 'c') ? 0 : p1->lsize; 18590Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 18605331Samw (p2->ltype == 'c') ? 0 : p2->lsize; 18610Sstevel@tonic-gate if (p2size > p1size) { 18620Sstevel@tonic-gate return (rflg); 18630Sstevel@tonic-gate } else if (p2size < p1size) { 18640Sstevel@tonic-gate return (-rflg); 18650Sstevel@tonic-gate } 18660Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 18670Sstevel@tonic-gate } 18680Sstevel@tonic-gate return (rflg * strcoll( 18690Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 18700Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 18710Sstevel@tonic-gate } 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate static void 18740Sstevel@tonic-gate pprintf(char *s1, char *s2) 18750Sstevel@tonic-gate { 18760Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 18770Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 18780Sstevel@tonic-gate } 18790Sstevel@tonic-gate 18800Sstevel@tonic-gate static void 18810Sstevel@tonic-gate csi_pprintf(unsigned char *s) 18820Sstevel@tonic-gate { 18830Sstevel@tonic-gate unsigned char *cp; 18840Sstevel@tonic-gate char c; 18850Sstevel@tonic-gate int i; 18860Sstevel@tonic-gate int c_len; 18870Sstevel@tonic-gate int p_col; 18880Sstevel@tonic-gate wchar_t pcode; 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate if (!qflg && !bflg) { 18910Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 18920Sstevel@tonic-gate (void) putchar(*cp); 18930Sstevel@tonic-gate curcol++; 18940Sstevel@tonic-gate } 18950Sstevel@tonic-gate return; 18960Sstevel@tonic-gate } 18970Sstevel@tonic-gate 18980Sstevel@tonic-gate for (cp = s; *cp; ) { 18990Sstevel@tonic-gate if (isascii(c = *cp)) { 19000Sstevel@tonic-gate if (!isprint(c)) { 19010Sstevel@tonic-gate if (qflg) { 19020Sstevel@tonic-gate c = '?'; 19030Sstevel@tonic-gate } else { 19040Sstevel@tonic-gate curcol += 3; 19050Sstevel@tonic-gate (void) putc('\\', stdout); 19060Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 19070Sstevel@tonic-gate (void) putc(c, stdout); 19080Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 19090Sstevel@tonic-gate (void) putc(c, stdout); 19100Sstevel@tonic-gate c = '0' + (*cp & 07); 19110Sstevel@tonic-gate } 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate curcol++; 19140Sstevel@tonic-gate cp++; 19150Sstevel@tonic-gate (void) putc(c, stdout); 19160Sstevel@tonic-gate continue; 19170Sstevel@tonic-gate } 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 19200Sstevel@tonic-gate c_len = 1; 19210Sstevel@tonic-gate goto not_print; 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate 19240Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 19250Sstevel@tonic-gate (void) putwchar(pcode); 19260Sstevel@tonic-gate cp += c_len; 19270Sstevel@tonic-gate curcol += p_col; 19280Sstevel@tonic-gate continue; 19290Sstevel@tonic-gate } 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate not_print: 19320Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 19330Sstevel@tonic-gate if (qflg) { 19340Sstevel@tonic-gate c = '?'; 19350Sstevel@tonic-gate } else { 19360Sstevel@tonic-gate curcol += 3; 19370Sstevel@tonic-gate (void) putc('\\', stdout); 19380Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 19390Sstevel@tonic-gate (void) putc(c, stdout); 19400Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 19410Sstevel@tonic-gate (void) putc(c, stdout); 19420Sstevel@tonic-gate c = '0' + (*cp & 07); 19430Sstevel@tonic-gate } 19440Sstevel@tonic-gate curcol++; 19450Sstevel@tonic-gate (void) putc(c, stdout); 19460Sstevel@tonic-gate cp++; 19470Sstevel@tonic-gate } 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate } 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate static int 19520Sstevel@tonic-gate strcol(unsigned char *s1) 19530Sstevel@tonic-gate { 19540Sstevel@tonic-gate int w; 19550Sstevel@tonic-gate int w_col; 19560Sstevel@tonic-gate int len; 19570Sstevel@tonic-gate wchar_t wc; 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate w = 0; 19600Sstevel@tonic-gate while (*s1) { 19610Sstevel@tonic-gate if (isascii(*s1)) { 19620Sstevel@tonic-gate w++; 19630Sstevel@tonic-gate s1++; 19640Sstevel@tonic-gate continue; 19650Sstevel@tonic-gate } 19660Sstevel@tonic-gate 19670Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 19680Sstevel@tonic-gate w++; 19690Sstevel@tonic-gate s1++; 19700Sstevel@tonic-gate continue; 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 19740Sstevel@tonic-gate w_col = len; 19750Sstevel@tonic-gate s1 += len; 19760Sstevel@tonic-gate w += w_col; 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate return (w); 19790Sstevel@tonic-gate } 19800Sstevel@tonic-gate 19810Sstevel@tonic-gate /* 19820Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 19830Sstevel@tonic-gate * result in the caller-supplied buffer. 19840Sstevel@tonic-gate * 19850Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 19860Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 19870Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 19880Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 19890Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 19900Sstevel@tonic-gate * the final number has only a single significant digit, we compute 19910Sstevel@tonic-gate * tenths of units to provide a second significant digit. 19920Sstevel@tonic-gate * 19930Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 19940Sstevel@tonic-gate * converted to "-1". 19950Sstevel@tonic-gate * 19960Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 19970Sstevel@tonic-gate */ 19980Sstevel@tonic-gate static char * 19990Sstevel@tonic-gate number_to_scaled_string( 20000Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 20010Sstevel@tonic-gate unsigned long long number, /* convert this number */ 20020Sstevel@tonic-gate long scale) 20030Sstevel@tonic-gate { 20040Sstevel@tonic-gate unsigned long long save; 20050Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 20060Sstevel@tonic-gate char *uom = "KMGTPE"; 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate if ((long long)number == (long long)-1) { 20090Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 20100Sstevel@tonic-gate return (buf); 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate save = number; 20140Sstevel@tonic-gate number = number / scale; 20150Sstevel@tonic-gate 20160Sstevel@tonic-gate /* 20170Sstevel@tonic-gate * Now we have number as a count of scale units. 20180Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 20190Sstevel@tonic-gate * 20200Sstevel@tonic-gate * The largest value number could have had entering the routine is 20210Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 20220Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 20230Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 20240Sstevel@tonic-gate */ 20250Sstevel@tonic-gate if (number < (unsigned long long)scale) { 20260Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 20270Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 20280Sstevel@tonic-gate uom++; 20290Sstevel@tonic-gate number = 1; 20300Sstevel@tonic-gate } 20310Sstevel@tonic-gate } 20320Sstevel@tonic-gate } else { 20330Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 20340Sstevel@tonic-gate uom++; /* next unit of measurement */ 20350Sstevel@tonic-gate save = number; 20360Sstevel@tonic-gate /* 20370Sstevel@tonic-gate * If we're over half way to the next unit of 20380Sstevel@tonic-gate * 'scale' bytes (which means we should round 20390Sstevel@tonic-gate * up), then adding half of 'scale' prior to 20400Sstevel@tonic-gate * the division will push us into that next 20410Sstevel@tonic-gate * unit of scale when we perform the division 20420Sstevel@tonic-gate */ 20430Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 20440Sstevel@tonic-gate } 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 20480Sstevel@tonic-gate if ((save / scale) < 10) { 20490Sstevel@tonic-gate /* snprintf() will round for us */ 20500Sstevel@tonic-gate float fnum = (float)save / scale; 20510Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 20520Sstevel@tonic-gate fnum, *uom); 20530Sstevel@tonic-gate } else { 20540Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 20550Sstevel@tonic-gate number, *uom); 20560Sstevel@tonic-gate } 20570Sstevel@tonic-gate return (buf); 20580Sstevel@tonic-gate } 20595331Samw 20605331Samw /* Get extended system attributes and set the display */ 20615331Samw 20625331Samw int 20635331Samw get_sysxattr(char *fname, struct lbuf *rep) 20645331Samw { 20655331Samw boolean_t value; 20665331Samw data_type_t type; 20675331Samw int error; 20685331Samw char *name; 20695331Samw int i; 20705331Samw 20715331Samw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 20725331Samw &response)) != 0) { 20735331Samw perror("ls:getattrat"); 20745331Samw return (error); 20755331Samw } 20765331Samw 20775331Samw /* 20785331Samw * Allocate 'sacnt' size array to hold extended timestamp 20795331Samw * system attributes and initialize the array. 20805331Samw */ 20815331Samw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 20825331Samw for (i = 0; i < sacnt; i++) { 20835331Samw rep->extm[i].stm = 0; 20845331Samw rep->extm[i].nstm = 0; 20855331Samw rep->extm[i].name = NULL; 20865331Samw } 20875331Samw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 20885331Samw name = nvpair_name(pair); 20895331Samw type = nvpair_type(pair); 20905331Samw if (type == DATA_TYPE_BOOLEAN_VALUE) { 20915331Samw error = nvpair_value_boolean_value(pair, &value); 20925331Samw if (error) { 20935331Samw (void) fprintf(stderr, 20945331Samw gettext("nvpair_value_boolean_value " 20955331Samw "failed: error = %d\n"), error); 20965331Samw continue; 20975331Samw } 20985331Samw if (name != NULL) 20995331Samw set_sysattrb_display(name, value, rep); 21005331Samw continue; 21015331Samw } else if (type == DATA_TYPE_UINT64_ARRAY) { 21025331Samw if (name != NULL) 21035331Samw set_sysattrtm_display(name, rep); 21045331Samw continue; 21055331Samw } 21065331Samw } 21075331Samw nvlist_free(response); 21085331Samw return (0); 21095331Samw } 21105331Samw 21115331Samw /* Set extended system attribute boolean display */ 21125331Samw 21135331Samw void 21145331Samw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 21155331Samw { 21165331Samw f_attr_t fattr; 21175331Samw const char *opt; 21185331Samw size_t len; 21195331Samw 21205331Samw fattr = name_to_attr(name); 21215331Samw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 21225331Samw if (vopt) { 21235331Samw len = strlen(name); 21245331Samw if (val) { 21255331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 21265331Samw (void) strlcpy(rep->exttr[fattr].name, name, 21275331Samw len + 1); 21285331Samw } else { 21295331Samw rep->exttr[fattr].name = xmalloc(len + 3, rep); 21305331Samw (void) snprintf(rep->exttr[fattr].name, len + 3, 21315331Samw "no%s", name); 21325331Samw } 21335331Samw } else { 21345331Samw opt = attr_to_option(fattr); 21355331Samw if (opt != NULL) { 21365331Samw len = strlen(opt); 21375331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 21385331Samw if (val) 21395331Samw (void) strlcpy(rep->exttr[fattr].name, 21405331Samw opt, len + 1); 21415331Samw else 21425331Samw (void) strlcpy(rep->exttr[fattr].name, 21435331Samw "-", len + 1); 21445331Samw } 21455331Samw } 21465331Samw } 21475331Samw } 21485331Samw 21495331Samw /* Set extended system attribute timestamp display */ 21505331Samw 21515331Samw void 21525331Samw set_sysattrtm_display(char *name, struct lbuf *rep) 21535331Samw { 21545331Samw uint_t nelem; 21555331Samw uint64_t *value; 21565331Samw int i; 21575331Samw size_t len; 21585331Samw 21595331Samw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 21605331Samw if (*value != NULL) { 21615331Samw len = strlen(name); 21625331Samw i = 0; 21635331Samw while (rep->extm[i].stm != 0 && i < sacnt) 21645331Samw i++; 21655331Samw rep->extm[i].stm = value[0]; 21665331Samw rep->extm[i].nstm = value[1]; 21675331Samw rep->extm[i].name = xmalloc(len + 1, rep); 21685331Samw (void) strlcpy(rep->extm[i].name, name, len + 1); 21695331Samw } 21705331Samw } 21715331Samw } 21725331Samw 21735331Samw void 21745331Samw format_time(const char *format, time_t sec) 21755331Samw { 21765331Samw 21775331Samw (void) strftime(time_buf, sizeof (time_buf), 21785331Samw dcgettext(NULL, format, LC_TIME), 21795331Samw localtime(&sec)); 21805331Samw } 21815331Samw 21825331Samw void 21835331Samw format_etime(const char *format, time_t sec, time_t nsec) 21845331Samw { 21855331Samw char fmt_buf[FMTSIZE]; 21865331Samw 21875331Samw (void) snprintf(fmt_buf, FMTSIZE, 21885331Samw format, nsec); 21895331Samw (void) strftime(time_buf, sizeof (time_buf), 21905331Samw fmt_buf, localtime(&sec)); 21915331Samw } 21925331Samw 21935331Samw /* Format timestamp extended system attributes */ 21945331Samw 21955331Samw void 21965331Samw format_attrtime(struct lbuf *p) 21975331Samw { 21985331Samw int tmattr = 0; 21995331Samw int i; 22005331Samw 22015331Samw if (p->extm != NULL) { 22025331Samw for (i = 0; i < sacnt; i++) { 22035331Samw if (p->extm[i].name != NULL) { 22045331Samw tmattr = 1; 22055331Samw break; 22065331Samw } 22075331Samw } 22085331Samw } 22095331Samw if (tmattr) { 22105331Samw if (Eflg) 22115331Samw format_etime(FORMAT4, (time_t)p->extm[i].stm, 22125331Samw (time_t)p->extm[i].nstm); 22135331Samw else { 22145331Samw if ((p->lmtime.tv_sec < year) || 22155331Samw (p->lmtime.tv_sec > now)) 22165331Samw format_time(FORMAT1, 22175331Samw (time_t)p->extm[i].stm); 22185331Samw else 22195331Samw format_time(FORMAT2, 22205331Samw (time_t)p->extm[i].stm); 22215331Samw } 22225331Samw } 22235331Samw } 22245331Samw 22255331Samw void 22265331Samw print_time(struct lbuf *p) 22275331Samw { 22285331Samw int i = 0; 22295331Samw 22305331Samw new_line(); 22315331Samw if (Eflg) { 22325331Samw format_etime(FORMAT4, p->lat.tv_sec, p->lat.tv_nsec); 22335331Samw (void) printf(" timestamp: atime %s\n", 22345331Samw time_buf); 22355331Samw format_etime(FORMAT4, p->lct.tv_sec, p->lct.tv_nsec); 22365331Samw (void) printf(" timestamp: ctime %s\n", 22375331Samw time_buf); 22385331Samw format_etime(FORMAT4, p->lmt.tv_sec, p->lmt.tv_nsec); 22395331Samw (void) printf(" timestamp: mtime %s\n", 22405331Samw time_buf); 22415331Samw if (p->extm != NULL) { 22425331Samw while (p->extm[i].nstm != 0 && i < sacnt) { 22435331Samw format_etime(FORMAT4, p->extm[i].stm, 22445331Samw p->extm[i].nstm); 22455331Samw if (p->extm[i].name != NULL) { 22465331Samw (void) printf(" timestamp:" 22475331Samw " %s %s\n", 22485331Samw p->extm[i].name, time_buf); 22495331Samw } 22505331Samw i++; 22515331Samw } 22525331Samw } 22535331Samw } else { 22545331Samw format_time(FORMAT3, p->lat.tv_sec); 22555331Samw (void) printf(" timestamp: atime %s\n", 22565331Samw time_buf); 22575331Samw format_time(FORMAT3, p->lct.tv_sec); 22585331Samw (void) printf(" timestamp: ctime %s\n", 22595331Samw time_buf); 22605331Samw format_time(FORMAT3, p->lmt.tv_sec); 22615331Samw (void) printf(" timestamp: mtime %s\n", 22625331Samw time_buf); 22635331Samw if (p->extm != NULL) { 22645331Samw while (p->extm[i].stm != 0 && i < sacnt) { 22655331Samw format_time(FORMAT3, p->extm[i].stm); 22665331Samw if (p->extm[i].name != NULL) { 22675331Samw (void) printf(" timestamp:" 22685331Samw " %s %s\n", 22695331Samw p->extm[i].name, time_buf); 22705331Samw } 22715331Samw i++; 22725331Samw } 22735331Samw } 22745331Samw } 22755331Samw } 22765331Samw 22775331Samw /* Free extended system attribute lists */ 22785331Samw 22795331Samw void 22805331Samw free_sysattr(struct lbuf *p) 22815331Samw { 22825331Samw int i; 22835331Samw 22845331Samw if (p->exttr != NULL) { 22855331Samw for (i = 0; i < sacnt; i++) { 22865331Samw if (p->exttr[i].name != NULL) 22875331Samw free(p->exttr[i].name); 22885331Samw } 22895331Samw free(p->exttr); 22905331Samw } 22915331Samw if (p->extm != NULL) { 22925331Samw for (i = 0; i < sacnt; i++) { 22935331Samw if (p->extm[i].name != NULL) 22945331Samw free(p->extm[i].name); 22955331Samw } 22965331Samw free(p->extm); 22975331Samw } 22985331Samw } 22995331Samw 23005331Samw /* Allocate extended system attribute list */ 23015331Samw 23025331Samw void * 23035331Samw xmalloc(size_t size, struct lbuf *p) 23045331Samw { 23055331Samw if ((p = malloc(size)) == NULL) { 23065331Samw perror("ls"); 23075331Samw free_sysattr(p); 23085331Samw nvlist_free(response); 23095331Samw exit(2); 23105331Samw } 23115331Samw return (p); 23125331Samw } 2313