17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52236845bSakaplan * Common Development and Distribution License (the "License"). 62236845bSakaplan * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22575bd8a2Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 307c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * List files or directories 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <sys/acl.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <wchar.h> 457c478bd9Sstevel@tonic-gate #include <stdio.h> 467c478bd9Sstevel@tonic-gate #include <ctype.h> 477c478bd9Sstevel@tonic-gate #include <dirent.h> 487c478bd9Sstevel@tonic-gate #include <string.h> 497c478bd9Sstevel@tonic-gate #include <locale.h> 507c478bd9Sstevel@tonic-gate #include <curses.h> 517c478bd9Sstevel@tonic-gate #include <termios.h> 527c478bd9Sstevel@tonic-gate #include <stdlib.h> 537c478bd9Sstevel@tonic-gate #include <widec.h> 547c478bd9Sstevel@tonic-gate #include <locale.h> 557c478bd9Sstevel@tonic-gate #include <wctype.h> 567c478bd9Sstevel@tonic-gate #include <pwd.h> 577c478bd9Sstevel@tonic-gate #include <grp.h> 587c478bd9Sstevel@tonic-gate #include <limits.h> 597c478bd9Sstevel@tonic-gate #include <fcntl.h> 607c478bd9Sstevel@tonic-gate #include <unistd.h> 617c478bd9Sstevel@tonic-gate #include <libgen.h> 627c478bd9Sstevel@tonic-gate #include <errno.h> 63fa9e4066Sahrens #include <aclutils.h> 64da6c28aaSamw #include <libnvpair.h> 65da6c28aaSamw #include <libcmdutils.h> 66da6c28aaSamw #include <attr.h> 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #ifndef STANDALONE 697c478bd9Sstevel@tonic-gate #define TERMINFO 707c478bd9Sstevel@tonic-gate #endif 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 747c478bd9Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 75da6c28aaSamw * the terminfo feature(pre 6.0 systems ?). 767c478bd9Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 777c478bd9Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO 807c478bd9Sstevel@tonic-gate #undef TERMINFO 817c478bd9Sstevel@tonic-gate #endif 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #include <term.h> 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate #define BFSIZE 16 867c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 877c478bd9Sstevel@tonic-gate #define ISARG 0100000 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 917c478bd9Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate #define LS_NOTREG 010000 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Date and time formats 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * b --- abbreviated month name 1007c478bd9Sstevel@tonic-gate * e --- day number 1017c478bd9Sstevel@tonic-gate * Y --- year in the form ccyy 1027c478bd9Sstevel@tonic-gate * H --- hour(24-hour version) 1037c478bd9Sstevel@tonic-gate * M --- minute 1047c478bd9Sstevel@tonic-gate * F --- yyyy-mm-dd 1057c478bd9Sstevel@tonic-gate * T --- hh:mm:ss 1067c478bd9Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1077c478bd9Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1087c478bd9Sstevel@tonic-gate * not present in older C libraries 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate #define FORMAT1 " %b %e %Y " 1117c478bd9Sstevel@tonic-gate #define FORMAT2 " %b %e %H:%M " 1127c478bd9Sstevel@tonic-gate #define FORMAT3 " %b %e %T %Y " 1137c478bd9Sstevel@tonic-gate #define FORMAT4 " %%F %%T.%.09ld %%z " 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #undef BUFSIZ 1167c478bd9Sstevel@tonic-gate #define BUFSIZ 4096 1177c478bd9Sstevel@tonic-gate #define NUMBER_WIDTH 40 1187c478bd9Sstevel@tonic-gate #define FMTSIZE 50 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate struct ditem { 1217c478bd9Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1227c478bd9Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1237c478bd9Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1247c478bd9Sstevel@tonic-gate }; 125da6c28aaSamw /* Holds boolean extended system attributes */ 126da6c28aaSamw struct attrb { 127da6c28aaSamw char *name; 128da6c28aaSamw }; 129da6c28aaSamw /* Holds timestamp extended system attributes */ 130da6c28aaSamw struct attrtm { 131da6c28aaSamw char *name; 132da6c28aaSamw uint64_t stm; 133da6c28aaSamw uint64_t nstm; 134da6c28aaSamw }; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate struct lbuf { 1377c478bd9Sstevel@tonic-gate union { 1387c478bd9Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 1397c478bd9Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 1407c478bd9Sstevel@tonic-gate } ln; 1417c478bd9Sstevel@tonic-gate char ltype; /* filetype */ 1427c478bd9Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 1437c478bd9Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1447c478bd9Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 1457c478bd9Sstevel@tonic-gate uid_t luid; 1467c478bd9Sstevel@tonic-gate gid_t lgid; 1477c478bd9Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 1487c478bd9Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 1497c478bd9Sstevel@tonic-gate timestruc_t lmtime; 150da6c28aaSamw timestruc_t lat; 151da6c28aaSamw timestruc_t lct; 152da6c28aaSamw timestruc_t lmt; 1537c478bd9Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 1547c478bd9Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 1557c478bd9Sstevel@tonic-gate int cycle; /* cycle detected flag */ 1567c478bd9Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 157fa9e4066Sahrens acl_t *aclp; /* ACL if present */ 158da6c28aaSamw struct attrb *exttr; /* boolean extended system attributes */ 159da6c28aaSamw struct attrtm *extm; /* timestamp extended system attributes */ 1607c478bd9Sstevel@tonic-gate }; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate struct dchain { 1637c478bd9Sstevel@tonic-gate char *dc_name; /* path name */ 1647c478bd9Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 1657c478bd9Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 1667c478bd9Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 1677c478bd9Sstevel@tonic-gate }; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 1757c478bd9Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 1767c478bd9Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 1777c478bd9Sstevel@tonic-gate static char *curdir; /* the current directory */ 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 1807c478bd9Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 1817c478bd9Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 1827c478bd9Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 1837c478bd9Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 1847c478bd9Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 1877c478bd9Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 1887c478bd9Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 1897c478bd9Sstevel@tonic-gate static char *getname(uid_t); 1907c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 1917c478bd9Sstevel@tonic-gate static char *makename(char *, char *); 1927c478bd9Sstevel@tonic-gate static void pentry(struct lbuf *); 1937c478bd9Sstevel@tonic-gate static void column(void); 1947c478bd9Sstevel@tonic-gate static void pmode(mode_t aflag); 1957c478bd9Sstevel@tonic-gate static void selection(int *); 1967c478bd9Sstevel@tonic-gate static void new_line(void); 1977c478bd9Sstevel@tonic-gate static void rddir(char *, struct ditem *); 1987c478bd9Sstevel@tonic-gate static int strcol(unsigned char *); 1997c478bd9Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2007c478bd9Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2017c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2027c478bd9Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2037c478bd9Sstevel@tonic-gate static void pprintf(char *, char *); 2047c478bd9Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2057c478bd9Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2067c478bd9Sstevel@tonic-gate unsigned long long number, 2077c478bd9Sstevel@tonic-gate long scale); 2087c478bd9Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2097c478bd9Sstevel@tonic-gate int, struct ditem *); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate static int aflg; 2127c478bd9Sstevel@tonic-gate static int atflg; 2137c478bd9Sstevel@tonic-gate static int bflg; 2147c478bd9Sstevel@tonic-gate static int cflg; 2157c478bd9Sstevel@tonic-gate static int dflg; 2167c478bd9Sstevel@tonic-gate static int eflg; 2177c478bd9Sstevel@tonic-gate static int fflg; 2187c478bd9Sstevel@tonic-gate static int gflg; 2197c478bd9Sstevel@tonic-gate static int hflg; 2207c478bd9Sstevel@tonic-gate static int iflg; 2217c478bd9Sstevel@tonic-gate static int lflg; 2227c478bd9Sstevel@tonic-gate static int mflg; 2237c478bd9Sstevel@tonic-gate static int nflg; 2247c478bd9Sstevel@tonic-gate static int oflg; 2257c478bd9Sstevel@tonic-gate static int pflg; 2267c478bd9Sstevel@tonic-gate static int qflg; 2277c478bd9Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2287c478bd9Sstevel@tonic-gate static int sflg; 2297c478bd9Sstevel@tonic-gate static int tflg; 2307c478bd9Sstevel@tonic-gate static int uflg; 2317c478bd9Sstevel@tonic-gate static int xflg; 2327c478bd9Sstevel@tonic-gate static int Aflg; 2337c478bd9Sstevel@tonic-gate static int Cflg; 2347c478bd9Sstevel@tonic-gate static int Eflg; 2357c478bd9Sstevel@tonic-gate static int Fflg; 2367c478bd9Sstevel@tonic-gate static int Hflg; 2377c478bd9Sstevel@tonic-gate static int Lflg; 2387c478bd9Sstevel@tonic-gate static int Rflg; 2397c478bd9Sstevel@tonic-gate static int Sflg; 240fa9e4066Sahrens static int vflg; 2415a5eeccaSmarks static int Vflg; 242da6c28aaSamw static int saflg; /* boolean extended system attr. */ 243da6c28aaSamw static int sacnt; /* number of extended system attr. */ 244da6c28aaSamw static int copt; 245da6c28aaSamw static int vopt; 246da6c28aaSamw static int tmflg; /* create time ext. system attr. */ 247da6c28aaSamw static int ctm; 248da6c28aaSamw static int atm; 249da6c28aaSamw static int mtm; 250da6c28aaSamw static int crtm; 251da6c28aaSamw static int alltm; 2527c478bd9Sstevel@tonic-gate static long hscale; 2537c478bd9Sstevel@tonic-gate static mode_t flags; 2547c478bd9Sstevel@tonic-gate static int err = 0; /* Contains return code */ 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 2577c478bd9Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 2587c478bd9Sstevel@tonic-gate static char *lastuname = NULL; 2597c478bd9Sstevel@tonic-gate static char *lastgname = NULL; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg are on */ 2627c478bd9Sstevel@tonic-gate static int statreq; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate static char *dotp = "."; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 2677c478bd9Sstevel@tonic-gate static time_t year, now; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate static int num_cols = 80; 2707c478bd9Sstevel@tonic-gate static int colwidth; 2717c478bd9Sstevel@tonic-gate static int filewidth; 2727c478bd9Sstevel@tonic-gate static int fixedwidth; 2737c478bd9Sstevel@tonic-gate static int nomocore; 2747c478bd9Sstevel@tonic-gate static int curcol; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate static struct winsize win; 2777c478bd9Sstevel@tonic-gate 278da6c28aaSamw static char time_buf[FMTSIZE]; /* array to hold day and time */ 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 2817c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 2847c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 285da6c28aaSamw /* Extended system attributes support */ 286da6c28aaSamw static int get_sysxattr(char *, struct lbuf *); 287da6c28aaSamw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 288da6c28aaSamw static void set_sysattrtm_display(char *, struct lbuf *); 289da6c28aaSamw static void format_time(const char *, time_t); 290da6c28aaSamw static void format_etime(const char *, time_t, time_t); 291da6c28aaSamw static void print_time(struct lbuf *); 292da6c28aaSamw static void format_attrtime(struct lbuf *); 293da6c28aaSamw static void *xmalloc(size_t, struct lbuf *); 294da6c28aaSamw static void free_sysattr(struct lbuf *); 295da6c28aaSamw static nvpair_t *pair; 296da6c28aaSamw static nvlist_t *response; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate int 2997c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate int c; 3027c478bd9Sstevel@tonic-gate int i; 3037c478bd9Sstevel@tonic-gate int width; 3047c478bd9Sstevel@tonic-gate int amino = 0; 3057c478bd9Sstevel@tonic-gate int opterr = 0; 3067c478bd9Sstevel@tonic-gate struct lbuf *ep; 3077c478bd9Sstevel@tonic-gate struct lbuf lb; 3087c478bd9Sstevel@tonic-gate struct ditem *myinfo; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3117c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 3127c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 3137c478bd9Sstevel@tonic-gate #endif 3147c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3157c478bd9Sstevel@tonic-gate #ifdef STANDALONE 3167c478bd9Sstevel@tonic-gate if (argv[0][0] == '\0') 3177c478bd9Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 3187c478bd9Sstevel@tonic-gate #endif 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 3217c478bd9Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 3227c478bd9Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 3237c478bd9Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 3247c478bd9Sstevel@tonic-gate if (isatty(1)) { 3257c478bd9Sstevel@tonic-gate Cflg = 1; 3267c478bd9Sstevel@tonic-gate mflg = 0; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, 330da6c28aaSamw "aAbcCdeEfFghHilLmnopqrRsStux1@vV/:%:")) != EOF) 3317c478bd9Sstevel@tonic-gate switch (c) { 3327c478bd9Sstevel@tonic-gate case 'a': 3337c478bd9Sstevel@tonic-gate aflg++; 3347c478bd9Sstevel@tonic-gate continue; 3357c478bd9Sstevel@tonic-gate case 'A': 3367c478bd9Sstevel@tonic-gate Aflg++; 3377c478bd9Sstevel@tonic-gate continue; 3387c478bd9Sstevel@tonic-gate case 'b': 3397c478bd9Sstevel@tonic-gate bflg = 1; 3407c478bd9Sstevel@tonic-gate qflg = 0; 3417c478bd9Sstevel@tonic-gate continue; 3427c478bd9Sstevel@tonic-gate case 'c': 3437c478bd9Sstevel@tonic-gate uflg = 0; 344da6c28aaSamw atm = 0; 345da6c28aaSamw ctm = 0; 346da6c28aaSamw mtm = 0; 347da6c28aaSamw crtm = 0; 3487c478bd9Sstevel@tonic-gate cflg++; 3497c478bd9Sstevel@tonic-gate continue; 3507c478bd9Sstevel@tonic-gate case 'C': 3517c478bd9Sstevel@tonic-gate Cflg = 1; 3527c478bd9Sstevel@tonic-gate mflg = 0; 3537c478bd9Sstevel@tonic-gate #ifdef XPG4 3547c478bd9Sstevel@tonic-gate lflg = 0; 3557c478bd9Sstevel@tonic-gate #endif 3567c478bd9Sstevel@tonic-gate continue; 3577c478bd9Sstevel@tonic-gate case 'd': 3587c478bd9Sstevel@tonic-gate dflg++; 3597c478bd9Sstevel@tonic-gate continue; 3607c478bd9Sstevel@tonic-gate case 'e': 3617c478bd9Sstevel@tonic-gate eflg++; 3627c478bd9Sstevel@tonic-gate lflg++; 3637c478bd9Sstevel@tonic-gate statreq++; 3647c478bd9Sstevel@tonic-gate Eflg = 0; 3657c478bd9Sstevel@tonic-gate continue; 3667c478bd9Sstevel@tonic-gate case 'E': 3677c478bd9Sstevel@tonic-gate Eflg++; 3687c478bd9Sstevel@tonic-gate lflg++; 3697c478bd9Sstevel@tonic-gate statreq++; 3707c478bd9Sstevel@tonic-gate eflg = 0; 3717c478bd9Sstevel@tonic-gate continue; 3727c478bd9Sstevel@tonic-gate case 'f': 3737c478bd9Sstevel@tonic-gate fflg++; 3747c478bd9Sstevel@tonic-gate continue; 3757c478bd9Sstevel@tonic-gate case 'F': 3767c478bd9Sstevel@tonic-gate Fflg++; 3777c478bd9Sstevel@tonic-gate statreq++; 3787c478bd9Sstevel@tonic-gate continue; 3797c478bd9Sstevel@tonic-gate case 'g': 3807c478bd9Sstevel@tonic-gate gflg++; 3817c478bd9Sstevel@tonic-gate lflg++; 3827c478bd9Sstevel@tonic-gate statreq++; 3837c478bd9Sstevel@tonic-gate continue; 3847c478bd9Sstevel@tonic-gate case 'h': 3857c478bd9Sstevel@tonic-gate hflg++; 3867c478bd9Sstevel@tonic-gate hscale = 1024; 3877c478bd9Sstevel@tonic-gate continue; 3887c478bd9Sstevel@tonic-gate case 'H': 3897c478bd9Sstevel@tonic-gate Hflg++; 3907c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 3917c478bd9Sstevel@tonic-gate Lflg = 0; 3927c478bd9Sstevel@tonic-gate continue; 3937c478bd9Sstevel@tonic-gate case 'i': 3947c478bd9Sstevel@tonic-gate iflg++; 3957c478bd9Sstevel@tonic-gate continue; 3967c478bd9Sstevel@tonic-gate case 'l': 3977c478bd9Sstevel@tonic-gate lflg++; 3987c478bd9Sstevel@tonic-gate statreq++; 3997c478bd9Sstevel@tonic-gate Cflg = 0; 4007c478bd9Sstevel@tonic-gate xflg = 0; 4017c478bd9Sstevel@tonic-gate mflg = 0; 4027c478bd9Sstevel@tonic-gate atflg = 0; 4037c478bd9Sstevel@tonic-gate continue; 4047c478bd9Sstevel@tonic-gate case 'L': 4057c478bd9Sstevel@tonic-gate Lflg++; 4067c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 4077c478bd9Sstevel@tonic-gate Hflg = 0; 4087c478bd9Sstevel@tonic-gate continue; 4097c478bd9Sstevel@tonic-gate case 'm': 4107c478bd9Sstevel@tonic-gate Cflg = 0; 4117c478bd9Sstevel@tonic-gate mflg = 1; 4127c478bd9Sstevel@tonic-gate #ifdef XPG4 4137c478bd9Sstevel@tonic-gate lflg = 0; 4147c478bd9Sstevel@tonic-gate #endif 4157c478bd9Sstevel@tonic-gate continue; 4167c478bd9Sstevel@tonic-gate case 'n': 4177c478bd9Sstevel@tonic-gate nflg++; 4187c478bd9Sstevel@tonic-gate lflg++; 4197c478bd9Sstevel@tonic-gate statreq++; 4207c478bd9Sstevel@tonic-gate Cflg = 0; 4217c478bd9Sstevel@tonic-gate xflg = 0; 4227c478bd9Sstevel@tonic-gate mflg = 0; 4237c478bd9Sstevel@tonic-gate atflg = 0; 4247c478bd9Sstevel@tonic-gate continue; 4257c478bd9Sstevel@tonic-gate case 'o': 4267c478bd9Sstevel@tonic-gate oflg++; 4277c478bd9Sstevel@tonic-gate lflg++; 4287c478bd9Sstevel@tonic-gate statreq++; 4297c478bd9Sstevel@tonic-gate continue; 4307c478bd9Sstevel@tonic-gate case 'p': 4317c478bd9Sstevel@tonic-gate pflg++; 4327c478bd9Sstevel@tonic-gate statreq++; 4337c478bd9Sstevel@tonic-gate continue; 4347c478bd9Sstevel@tonic-gate case 'q': 4357c478bd9Sstevel@tonic-gate qflg = 1; 4367c478bd9Sstevel@tonic-gate bflg = 0; 4377c478bd9Sstevel@tonic-gate continue; 4387c478bd9Sstevel@tonic-gate case 'r': 4397c478bd9Sstevel@tonic-gate rflg = -1; 4407c478bd9Sstevel@tonic-gate continue; 4417c478bd9Sstevel@tonic-gate case 'R': 4427c478bd9Sstevel@tonic-gate Rflg++; 4437c478bd9Sstevel@tonic-gate statreq++; 4447c478bd9Sstevel@tonic-gate continue; 4457c478bd9Sstevel@tonic-gate case 's': 4467c478bd9Sstevel@tonic-gate sflg++; 4477c478bd9Sstevel@tonic-gate statreq++; 4487c478bd9Sstevel@tonic-gate continue; 4497c478bd9Sstevel@tonic-gate case 'S': 4507c478bd9Sstevel@tonic-gate tflg = 0; 4517c478bd9Sstevel@tonic-gate Sflg++; 4527c478bd9Sstevel@tonic-gate statreq++; 4537c478bd9Sstevel@tonic-gate continue; 4547c478bd9Sstevel@tonic-gate case 't': 4557c478bd9Sstevel@tonic-gate Sflg = 0; 4567c478bd9Sstevel@tonic-gate tflg++; 4577c478bd9Sstevel@tonic-gate statreq++; 4587c478bd9Sstevel@tonic-gate continue; 4597c478bd9Sstevel@tonic-gate case 'u': 4607c478bd9Sstevel@tonic-gate cflg = 0; 461da6c28aaSamw atm = 0; 462da6c28aaSamw ctm = 0; 463da6c28aaSamw mtm = 0; 464da6c28aaSamw crtm = 0; 4657c478bd9Sstevel@tonic-gate uflg++; 4667c478bd9Sstevel@tonic-gate continue; 4675a5eeccaSmarks case 'V': 4685a5eeccaSmarks Vflg++; 4695a5eeccaSmarks /*FALLTHROUGH*/ 470fa9e4066Sahrens case 'v': 471fa9e4066Sahrens vflg++; 472fa9e4066Sahrens #if !defined(XPG4) 473fa9e4066Sahrens if (lflg) 474fa9e4066Sahrens continue; 475fa9e4066Sahrens #endif 476fa9e4066Sahrens lflg++; 477fa9e4066Sahrens statreq++; 478fa9e4066Sahrens Cflg = 0; 479fa9e4066Sahrens xflg = 0; 480fa9e4066Sahrens mflg = 0; 481fa9e4066Sahrens continue; 4827c478bd9Sstevel@tonic-gate case 'x': 4837c478bd9Sstevel@tonic-gate xflg = 1; 4847c478bd9Sstevel@tonic-gate Cflg = 1; 4857c478bd9Sstevel@tonic-gate mflg = 0; 4867c478bd9Sstevel@tonic-gate #ifdef XPG4 4877c478bd9Sstevel@tonic-gate lflg = 0; 4887c478bd9Sstevel@tonic-gate #endif 4897c478bd9Sstevel@tonic-gate continue; 4907c478bd9Sstevel@tonic-gate case '1': 4917c478bd9Sstevel@tonic-gate Cflg = 0; 4927c478bd9Sstevel@tonic-gate continue; 4937c478bd9Sstevel@tonic-gate case '@': 4947c478bd9Sstevel@tonic-gate #if !defined(XPG4) 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * -l has precedence over -@ 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate if (lflg) 4997c478bd9Sstevel@tonic-gate continue; 5007c478bd9Sstevel@tonic-gate #endif 5017c478bd9Sstevel@tonic-gate atflg++; 5027c478bd9Sstevel@tonic-gate lflg++; 5037c478bd9Sstevel@tonic-gate statreq++; 5047c478bd9Sstevel@tonic-gate Cflg = 0; 5057c478bd9Sstevel@tonic-gate xflg = 0; 5067c478bd9Sstevel@tonic-gate mflg = 0; 5077c478bd9Sstevel@tonic-gate continue; 508da6c28aaSamw case '/': 509da6c28aaSamw saflg++; 510da6c28aaSamw if (optarg != NULL) { 511da6c28aaSamw if (strcmp(optarg, "c") == 0) { 512da6c28aaSamw copt++; 513da6c28aaSamw vopt = 0; 514da6c28aaSamw } else if (strcmp(optarg, "v") == 0) { 515da6c28aaSamw vopt++; 516da6c28aaSamw copt = 0; 517da6c28aaSamw } else 518da6c28aaSamw opterr++; 519da6c28aaSamw } else 520da6c28aaSamw opterr++; 521da6c28aaSamw lflg++; 522da6c28aaSamw statreq++; 523da6c28aaSamw Cflg = 0; 524da6c28aaSamw xflg = 0; 525da6c28aaSamw mflg = 0; 526da6c28aaSamw continue; 527da6c28aaSamw case '%': 528da6c28aaSamw tmflg++; 529da6c28aaSamw if (optarg != NULL) { 530da6c28aaSamw if (strcmp(optarg, "ctime") == 0) { 531da6c28aaSamw ctm++; 532da6c28aaSamw atm = 0; 533da6c28aaSamw mtm = 0; 534da6c28aaSamw crtm = 0; 535da6c28aaSamw } else if (strcmp(optarg, "atime") == 0) { 536da6c28aaSamw atm++; 537da6c28aaSamw ctm = 0; 538da6c28aaSamw mtm = 0; 539da6c28aaSamw crtm = 0; 540da6c28aaSamw uflg = 0; 541da6c28aaSamw cflg = 0; 542da6c28aaSamw } else if (strcmp(optarg, "mtime") == 0) { 543da6c28aaSamw mtm++; 544da6c28aaSamw atm = 0; 545da6c28aaSamw ctm = 0; 546da6c28aaSamw crtm = 0; 547da6c28aaSamw uflg = 0; 548da6c28aaSamw cflg = 0; 549da6c28aaSamw } else if (strcmp(optarg, "crtime") == 0) { 550da6c28aaSamw crtm++; 551da6c28aaSamw atm = 0; 552da6c28aaSamw ctm = 0; 553da6c28aaSamw mtm = 0; 554da6c28aaSamw uflg = 0; 555da6c28aaSamw cflg = 0; 556da6c28aaSamw } else if (strcmp(optarg, "all") == 0) { 557da6c28aaSamw alltm++; 558da6c28aaSamw atm = 0; 559da6c28aaSamw ctm = 0; 560da6c28aaSamw mtm = 0; 561da6c28aaSamw crtm = 0; 562da6c28aaSamw } else 563da6c28aaSamw opterr++; 564da6c28aaSamw } else 565da6c28aaSamw opterr++; 566da6c28aaSamw 567da6c28aaSamw Sflg = 0; 568da6c28aaSamw statreq++; 569da6c28aaSamw mflg = 0; 570da6c28aaSamw continue; 5717c478bd9Sstevel@tonic-gate case '?': 5727c478bd9Sstevel@tonic-gate opterr++; 5737c478bd9Sstevel@tonic-gate continue; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate if (opterr) { 5767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 577da6c28aaSamw "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@/%[c | v]" 578da6c28aaSamw "%%[atime | crtime | ctime | mtime | all]" 579da6c28aaSamw " [files]\n")); 5807c478bd9Sstevel@tonic-gate exit(2); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if (fflg) { 5847c478bd9Sstevel@tonic-gate aflg++; 5857c478bd9Sstevel@tonic-gate lflg = 0; 5867c478bd9Sstevel@tonic-gate sflg = 0; 5877c478bd9Sstevel@tonic-gate tflg = 0; 5887c478bd9Sstevel@tonic-gate Sflg = 0; 5897c478bd9Sstevel@tonic-gate statreq = 0; 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate fixedwidth = 2; 5937c478bd9Sstevel@tonic-gate if (pflg || Fflg) 5947c478bd9Sstevel@tonic-gate fixedwidth++; 5957c478bd9Sstevel@tonic-gate if (iflg) 5967c478bd9Sstevel@tonic-gate fixedwidth += 11; 5977c478bd9Sstevel@tonic-gate if (sflg) 5987c478bd9Sstevel@tonic-gate fixedwidth += 5; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate if (lflg) { 6017c478bd9Sstevel@tonic-gate if (!gflg && !oflg) 6027c478bd9Sstevel@tonic-gate gflg = oflg = 1; 6037c478bd9Sstevel@tonic-gate else 6047c478bd9Sstevel@tonic-gate if (gflg && oflg) 6057c478bd9Sstevel@tonic-gate gflg = oflg = 0; 6067c478bd9Sstevel@tonic-gate Cflg = mflg = 0; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 6107c478bd9Sstevel@tonic-gate char *clptr; 6117c478bd9Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 6127c478bd9Sstevel@tonic-gate num_cols = atoi(clptr); 6137c478bd9Sstevel@tonic-gate #ifdef TERMINFO 6147c478bd9Sstevel@tonic-gate else { 6157c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 6167c478bd9Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate #endif 6197c478bd9Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 6207c478bd9Sstevel@tonic-gate /* assume it is an error */ 6217c478bd9Sstevel@tonic-gate num_cols = 80; 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* allocate space for flist and the associated */ 6257c478bd9Sstevel@tonic-gate /* data structures (lbufs) */ 6267c478bd9Sstevel@tonic-gate maxfils = quantn; 6277c478bd9Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 6287c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 6297c478bd9Sstevel@tonic-gate perror("ls"); 6307c478bd9Sstevel@tonic-gate exit(2); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * case when no names are given 6357c478bd9Sstevel@tonic-gate * in ls-command and current 6367c478bd9Sstevel@tonic-gate * directory is to be used 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate argv[optind] = dotp; 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 6457c478bd9Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 6467c478bd9Sstevel@tonic-gate * (actually, just the directories) visited, we 6477c478bd9Sstevel@tonic-gate * maintain a directory ancestry list for a file 6487c478bd9Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 6497c478bd9Sstevel@tonic-gate * a parent directory passes its directory list 6507c478bd9Sstevel@tonic-gate * info (device id, inode number, and a pointer to 6517c478bd9Sstevel@tonic-gate * its parent) to each of its children. As we 6527c478bd9Sstevel@tonic-gate * process a child that is a directory, we save 6537c478bd9Sstevel@tonic-gate * its own personal directory list info. We then 6547c478bd9Sstevel@tonic-gate * check to see if the child has already been 6557c478bd9Sstevel@tonic-gate * processed by comparing its device id and inode 6567c478bd9Sstevel@tonic-gate * number from its own personal directory list info 6577c478bd9Sstevel@tonic-gate * to that of each of its ancestors. If there is a 6587c478bd9Sstevel@tonic-gate * match, then we know we've detected a cycle. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate if (Rflg) { 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * This is the first parent in this lineage 6637c478bd9Sstevel@tonic-gate * (first in a directory hierarchy), so 6647c478bd9Sstevel@tonic-gate * this parent's parent doesn't exist. We 6657c478bd9Sstevel@tonic-gate * only initialize myinfo when we are 6667c478bd9Sstevel@tonic-gate * recursing, otherwise it's not used. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 6697c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 6707c478bd9Sstevel@tonic-gate perror("ls"); 6717c478bd9Sstevel@tonic-gate exit(2); 6727c478bd9Sstevel@tonic-gate } else { 6737c478bd9Sstevel@tonic-gate myinfo->dev = 0; 6747c478bd9Sstevel@tonic-gate myinfo->ino = 0; 6757c478bd9Sstevel@tonic-gate myinfo->parent = NULL; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 6807c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 6817c478bd9Sstevel@tonic-gate if (width > filewidth) 6827c478bd9Sstevel@tonic-gate filewidth = width; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 6857c478bd9Sstevel@tonic-gate 1, myinfo)) == NULL) { 6867c478bd9Sstevel@tonic-gate if (nomocore) 6877c478bd9Sstevel@tonic-gate exit(2); 6887c478bd9Sstevel@tonic-gate err = 2; 6897c478bd9Sstevel@tonic-gate optind++; 6907c478bd9Sstevel@tonic-gate continue; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 6937c478bd9Sstevel@tonic-gate ep->lflags |= ISARG; 6947c478bd9Sstevel@tonic-gate optind++; 6957c478bd9Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 6987c478bd9Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 6997c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 7007c478bd9Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 7017c478bd9Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 7027c478bd9Sstevel@tonic-gate break; 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 7057c478bd9Sstevel@tonic-gate for (; i < nargs; i++) { 7067c478bd9Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 7077c478bd9Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 7087c478bd9Sstevel@tonic-gate if (nomocore) 7097c478bd9Sstevel@tonic-gate exit(2); 7107c478bd9Sstevel@tonic-gate /* -R: print subdirectories found */ 7117c478bd9Sstevel@tonic-gate while (dfirst || cdfirst) { 7127c478bd9Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 7137c478bd9Sstevel@tonic-gate while (cdfirst) { 7147c478bd9Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 7157c478bd9Sstevel@tonic-gate dtemp = cdfirst; 7167c478bd9Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 7177c478bd9Sstevel@tonic-gate dtemp -> dc_next = dfirst; 7187c478bd9Sstevel@tonic-gate dfirst = dtemp; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 7217c478bd9Sstevel@tonic-gate dtemp = dfirst; 7227c478bd9Sstevel@tonic-gate dfirst = dfirst->dc_next; 7237c478bd9Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 7247c478bd9Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 7257c478bd9Sstevel@tonic-gate if (nomocore) 7267c478bd9Sstevel@tonic-gate exit(2); 7277c478bd9Sstevel@tonic-gate free(dtemp->dc_name); 7287c478bd9Sstevel@tonic-gate free(dtemp); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate return (err); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 7367c478bd9Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate static void 7397c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 7407c478bd9Sstevel@tonic-gate { 7417c478bd9Sstevel@tonic-gate struct dchain *dp; 7427c478bd9Sstevel@tonic-gate struct lbuf *ap; 7437c478bd9Sstevel@tonic-gate char *pname; 7447c478bd9Sstevel@tonic-gate int j; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate filewidth = 0; 7477c478bd9Sstevel@tonic-gate curdir = name; 7487c478bd9Sstevel@tonic-gate if (title) { 7497c478bd9Sstevel@tonic-gate if (!first) 7507c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 7517c478bd9Sstevel@tonic-gate pprintf(name, ":"); 7527c478bd9Sstevel@tonic-gate new_line(); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 7567c478bd9Sstevel@tonic-gate * further. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate if (cdetect) { 7597c478bd9Sstevel@tonic-gate if (lflg || sflg) { 7607c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 7617c478bd9Sstevel@tonic-gate new_line(); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7647c478bd9Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 7657c478bd9Sstevel@tonic-gate return; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate nfiles = lp; 7697c478bd9Sstevel@tonic-gate rddir(name, myinfo); 7707c478bd9Sstevel@tonic-gate if (nomocore) 7717c478bd9Sstevel@tonic-gate return; 7727c478bd9Sstevel@tonic-gate if (fflg == 0) 7737c478bd9Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 7747c478bd9Sstevel@tonic-gate sizeof (struct lbuf *), 7757c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 7767c478bd9Sstevel@tonic-gate if (Rflg) { 7777c478bd9Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 7787c478bd9Sstevel@tonic-gate ap = flist[j]; 7797c478bd9Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 7807c478bd9Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 7817c478bd9Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 7827c478bd9Sstevel@tonic-gate if (dp == NULL) { 7837c478bd9Sstevel@tonic-gate perror("ls"); 7847c478bd9Sstevel@tonic-gate exit(2); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 7877c478bd9Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 7887c478bd9Sstevel@tonic-gate perror("ls"); 7897c478bd9Sstevel@tonic-gate exit(2); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 7927c478bd9Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 7937c478bd9Sstevel@tonic-gate dp->dc_next = dfirst; 7947c478bd9Sstevel@tonic-gate dfirst = dp; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate if (lflg || sflg) { 7997c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 8007c478bd9Sstevel@tonic-gate new_line(); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 8077c478bd9Sstevel@tonic-gate * by slp and lp. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate static void 8107c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 8117c478bd9Sstevel@tonic-gate { 8127c478bd9Sstevel@tonic-gate long row, nrows, i; 8137c478bd9Sstevel@tonic-gate int col, ncols; 8147c478bd9Sstevel@tonic-gate struct lbuf **ep; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 8177c478bd9Sstevel@tonic-gate if (colwidth > num_cols) { 8187c478bd9Sstevel@tonic-gate ncols = 1; 8197c478bd9Sstevel@tonic-gate } else { 8207c478bd9Sstevel@tonic-gate ncols = num_cols / colwidth; 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 8257c478bd9Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 8267c478bd9Sstevel@tonic-gate pentry(*ep); 8277c478bd9Sstevel@tonic-gate new_line(); 8287c478bd9Sstevel@tonic-gate return; 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate /* otherwise print -C columns */ 8317c478bd9Sstevel@tonic-gate if (tot_flag) { 8327c478bd9Sstevel@tonic-gate slp--; 8337c478bd9Sstevel@tonic-gate row = 1; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate else 8367c478bd9Sstevel@tonic-gate row = 0; 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 8397c478bd9Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 8407c478bd9Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 8417c478bd9Sstevel@tonic-gate ep = slp + (nrows * col) + row; 8427c478bd9Sstevel@tonic-gate if (ep < lp) 8437c478bd9Sstevel@tonic-gate pentry(*ep); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate new_line(); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * print one output entry; 8517c478bd9Sstevel@tonic-gate * if uid/gid is not found in the appropriate 8527c478bd9Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 8537c478bd9Sstevel@tonic-gate * user/group name; 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate static void 8567c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate struct lbuf *p; 8597c478bd9Sstevel@tonic-gate numbuf_t hbuf; 8607c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 8617c478bd9Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 8627c478bd9Sstevel@tonic-gate char *cp; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate p = ap; 8657c478bd9Sstevel@tonic-gate column(); 8667c478bd9Sstevel@tonic-gate if (iflg) 8677c478bd9Sstevel@tonic-gate if (mflg && !lflg) 8687c478bd9Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 8697c478bd9Sstevel@tonic-gate else 8707c478bd9Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 8717c478bd9Sstevel@tonic-gate if (sflg) 8727c478bd9Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 8737c478bd9Sstevel@tonic-gate (p->lblocks < 10000) ? "%4lld " : "%lld ", 8747c478bd9Sstevel@tonic-gate (p->ltype != 'b' && p->ltype != 'c') ? 8757c478bd9Sstevel@tonic-gate p->lblocks : 0LL); 8767c478bd9Sstevel@tonic-gate if (lflg) { 8777c478bd9Sstevel@tonic-gate (void) putchar(p->ltype); 8787c478bd9Sstevel@tonic-gate curcol++; 8797c478bd9Sstevel@tonic-gate pmode(p->lflags); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* ACL: additional access mode flag */ 8827c478bd9Sstevel@tonic-gate (void) putchar(p->acl); 8837c478bd9Sstevel@tonic-gate curcol++; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 8867c478bd9Sstevel@tonic-gate if (oflg) 8877c478bd9Sstevel@tonic-gate if (!nflg) { 8887c478bd9Sstevel@tonic-gate cp = getname(p->luid); 8897c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 8907c478bd9Sstevel@tonic-gate } else 8917c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 8927c478bd9Sstevel@tonic-gate if (gflg) 8937c478bd9Sstevel@tonic-gate if (!nflg) { 8947c478bd9Sstevel@tonic-gate cp = getgroup(p->lgid); 8957c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 8967c478bd9Sstevel@tonic-gate } else 8977c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 8987c478bd9Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 8997c478bd9Sstevel@tonic-gate curcol += printf("%3u, %2u", 9007c478bd9Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 9017c478bd9Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 9027c478bd9Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 9037c478bd9Sstevel@tonic-gate curcol += printf("%7s", 9047c478bd9Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 9057c478bd9Sstevel@tonic-gate } else { 9067c478bd9Sstevel@tonic-gate curcol += printf((p->lsize < (off_t)10000000) ? 9077c478bd9Sstevel@tonic-gate "%7lld" : "%lld", p->lsize); 9087c478bd9Sstevel@tonic-gate } 909da6c28aaSamw if (eflg) 910da6c28aaSamw format_time(FORMAT3, p->lmtime.tv_sec); 911da6c28aaSamw else if (Eflg) 9127c478bd9Sstevel@tonic-gate /* fill in nanoseconds first */ 913da6c28aaSamw format_etime(FORMAT4, p->lmtime.tv_sec, 914da6c28aaSamw p->lmtime.tv_nsec); 915da6c28aaSamw else { 9167c478bd9Sstevel@tonic-gate if ((p->lmtime.tv_sec < year) || 917da6c28aaSamw (p->lmtime.tv_sec > now)) 918da6c28aaSamw format_time(FORMAT1, p->lmtime.tv_sec); 919da6c28aaSamw else 920da6c28aaSamw format_time(FORMAT2, p->lmtime.tv_sec); 9217c478bd9Sstevel@tonic-gate } 922da6c28aaSamw /* format extended system attribute time */ 923da6c28aaSamw if (tmflg && crtm) 924da6c28aaSamw format_attrtime(p); 9257c478bd9Sstevel@tonic-gate 926da6c28aaSamw curcol += printf("%s", time_buf); 927da6c28aaSamw 928da6c28aaSamw } 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * prevent both "->" and trailing marks 9317c478bd9Sstevel@tonic-gate * from appearing 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if (pflg && p->ltype == 'd') 9357c478bd9Sstevel@tonic-gate dmark = "/"; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 9387c478bd9Sstevel@tonic-gate if (p->ltype == 'd') 9397c478bd9Sstevel@tonic-gate dmark = "/"; 9407c478bd9Sstevel@tonic-gate else if (p->ltype == 'D') 9417c478bd9Sstevel@tonic-gate dmark = ">"; 9427c478bd9Sstevel@tonic-gate else if (p->ltype == 'p') 9437c478bd9Sstevel@tonic-gate dmark = "|"; 9447c478bd9Sstevel@tonic-gate else if (p->ltype == 'l') 9457c478bd9Sstevel@tonic-gate dmark = "@"; 9467c478bd9Sstevel@tonic-gate else if (p->ltype == 's') 9477c478bd9Sstevel@tonic-gate dmark = "="; 9487c478bd9Sstevel@tonic-gate else if (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)) 9497c478bd9Sstevel@tonic-gate dmark = "*"; 9507c478bd9Sstevel@tonic-gate else 9517c478bd9Sstevel@tonic-gate dmark = ""; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (lflg && p->flinkto) { 9557c478bd9Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 9567c478bd9Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 9577c478bd9Sstevel@tonic-gate dmark = buf; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate if (p->lflags & ISARG) { 9617c478bd9Sstevel@tonic-gate if (qflg || bflg) 9627c478bd9Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 9637c478bd9Sstevel@tonic-gate else { 9647c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 9657c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 9667c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate } else { 9697c478bd9Sstevel@tonic-gate if (qflg || bflg) 9707c478bd9Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 9717c478bd9Sstevel@tonic-gate else { 9727c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 9737c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 9747c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate } 977fa9e4066Sahrens 978da6c28aaSamw /* Display extended system attributes */ 979da6c28aaSamw if (saflg) { 980da6c28aaSamw int i; 981da6c28aaSamw 982da6c28aaSamw new_line(); 983da6c28aaSamw (void) printf(" \t{"); 984da6c28aaSamw if (p->exttr != NULL) { 985da6c28aaSamw int k = 0; 986da6c28aaSamw for (i = 0; i < sacnt; i++) { 987da6c28aaSamw if (p->exttr[i].name != NULL) 988da6c28aaSamw k++; 989da6c28aaSamw } 990da6c28aaSamw for (i = 0; i < sacnt; i++) { 991da6c28aaSamw if (p->exttr[i].name != NULL) { 992da6c28aaSamw (void) printf("%s", p->exttr[i].name); 993da6c28aaSamw k--; 994da6c28aaSamw if (vopt && (k != 0)) 995da6c28aaSamw (void) printf(","); 996da6c28aaSamw } 997da6c28aaSamw } 998da6c28aaSamw } 999da6c28aaSamw (void) printf("}\n"); 1000da6c28aaSamw } 1001da6c28aaSamw /* Display file timestamps and extended system attribute timestamps */ 1002da6c28aaSamw if (tmflg && alltm) { 1003da6c28aaSamw new_line(); 1004da6c28aaSamw print_time(p); 1005da6c28aaSamw new_line(); 1006da6c28aaSamw } 1007fa9e4066Sahrens if (vflg) { 1008fa9e4066Sahrens new_line(); 1009fa9e4066Sahrens if (p->aclp) { 10105a5eeccaSmarks acl_printacl(p->aclp, num_cols, Vflg); 1011fa9e4066Sahrens } 1012fa9e4066Sahrens } 1013da6c28aaSamw /* Free extended system attribute lists */ 1014da6c28aaSamw if (saflg || tmflg) 1015da6c28aaSamw free_sysattr(p); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */ 10197c478bd9Sstevel@tonic-gate static void 10207c478bd9Sstevel@tonic-gate pmode(mode_t aflag) 10217c478bd9Sstevel@tonic-gate { 10227c478bd9Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 10237c478bd9Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 10247c478bd9Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 10257c478bd9Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 10267c478bd9Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 10277c478bd9Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 10287c478bd9Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 10297c478bd9Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 10307c478bd9Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 10317c478bd9Sstevel@tonic-gate #ifdef XPG4 10327c478bd9Sstevel@tonic-gate S_ISGID, 'L', '-'}; 10337c478bd9Sstevel@tonic-gate #else 10347c478bd9Sstevel@tonic-gate S_ISGID, 'l', '-'}; 10357c478bd9Sstevel@tonic-gate #endif 10367c478bd9Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 10377c478bd9Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 10387c478bd9Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 10397c478bd9Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate int **mp; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate flags = aflag; 10467c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 10477c478bd9Sstevel@tonic-gate selection(*mp); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate static void 10517c478bd9Sstevel@tonic-gate selection(int *pairp) 10527c478bd9Sstevel@tonic-gate { 10537c478bd9Sstevel@tonic-gate int n; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate n = *pairp++; 10567c478bd9Sstevel@tonic-gate while (n-->0) { 10577c478bd9Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 10587c478bd9Sstevel@tonic-gate pairp++; 10597c478bd9Sstevel@tonic-gate break; 10607c478bd9Sstevel@tonic-gate } else { 10617c478bd9Sstevel@tonic-gate pairp += 2; 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate (void) putchar(*pairp); 10657c478bd9Sstevel@tonic-gate curcol++; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * column: get to the beginning of the next column. 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate static void 10727c478bd9Sstevel@tonic-gate column(void) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate if (curcol == 0) 10757c478bd9Sstevel@tonic-gate return; 10767c478bd9Sstevel@tonic-gate if (mflg) { 10777c478bd9Sstevel@tonic-gate (void) putc(',', stdout); 10787c478bd9Sstevel@tonic-gate curcol++; 10797c478bd9Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 10807c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 10817c478bd9Sstevel@tonic-gate curcol = 0; 10827c478bd9Sstevel@tonic-gate return; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 10857c478bd9Sstevel@tonic-gate curcol++; 10867c478bd9Sstevel@tonic-gate return; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate if (Cflg == 0) { 10897c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 10907c478bd9Sstevel@tonic-gate curcol = 0; 10917c478bd9Sstevel@tonic-gate return; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 10947c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 10957c478bd9Sstevel@tonic-gate curcol = 0; 10967c478bd9Sstevel@tonic-gate return; 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate do { 10997c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 11007c478bd9Sstevel@tonic-gate curcol++; 11017c478bd9Sstevel@tonic-gate } while (curcol % colwidth); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate static void 11057c478bd9Sstevel@tonic-gate new_line(void) 11067c478bd9Sstevel@tonic-gate { 11077c478bd9Sstevel@tonic-gate if (curcol) { 11087c478bd9Sstevel@tonic-gate first = 0; 11097c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 11107c478bd9Sstevel@tonic-gate curcol = 0; 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * read each filename in directory dir and store its 11167c478bd9Sstevel@tonic-gate * status in flist[nfiles] 11177c478bd9Sstevel@tonic-gate * use makename() to form pathname dir/filename; 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate static void 11207c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate struct dirent *dentry; 11237c478bd9Sstevel@tonic-gate DIR *dirf; 11247c478bd9Sstevel@tonic-gate int j; 11257c478bd9Sstevel@tonic-gate struct lbuf *ep; 11267c478bd9Sstevel@tonic-gate int width; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 11297c478bd9Sstevel@tonic-gate (void) fflush(stdout); 11307c478bd9Sstevel@tonic-gate perror(dir); 11317c478bd9Sstevel@tonic-gate err = 2; 11327c478bd9Sstevel@tonic-gate return; 11337c478bd9Sstevel@tonic-gate } else { 11347c478bd9Sstevel@tonic-gate tblocks = 0; 11357c478bd9Sstevel@tonic-gate for (;;) { 11367c478bd9Sstevel@tonic-gate errno = 0; 11377c478bd9Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 11387c478bd9Sstevel@tonic-gate break; 11397c478bd9Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 11407c478bd9Sstevel@tonic-gate (Aflg == 0 || 11417c478bd9Sstevel@tonic-gate dentry->d_name[1] == '\0' || 11427c478bd9Sstevel@tonic-gate dentry->d_name[1] == '.' && 11437c478bd9Sstevel@tonic-gate dentry->d_name[2] == '\0')) 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * check for directory items '.', '..', 11467c478bd9Sstevel@tonic-gate * and items without valid inode-number; 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate continue; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 11517c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 11527c478bd9Sstevel@tonic-gate if (width > filewidth) 11537c478bd9Sstevel@tonic-gate filewidth = width; 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 11567c478bd9Sstevel@tonic-gate if (ep == NULL) { 11577c478bd9Sstevel@tonic-gate if (nomocore) 1158da6c28aaSamw exit(2); 11597c478bd9Sstevel@tonic-gate continue; 11607c478bd9Sstevel@tonic-gate } else { 11617c478bd9Sstevel@tonic-gate ep->lnum = dentry->d_ino; 11627c478bd9Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 11637c478bd9Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 11647c478bd9Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate if (errno) { 11687c478bd9Sstevel@tonic-gate int sav_errno = errno; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11717c478bd9Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 11727c478bd9Sstevel@tonic-gate dir, strerror(sav_errno)); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate (void) closedir(dirf); 11757c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate /* 11807c478bd9Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 11817c478bd9Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 11827c478bd9Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 11837c478bd9Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 11847c478bd9Sstevel@tonic-gate * it is reported at the right time when printing the directory. 11857c478bd9Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 11867c478bd9Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 11877c478bd9Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 11887c478bd9Sstevel@tonic-gate * command line. 11897c478bd9Sstevel@tonic-gate */ 11907c478bd9Sstevel@tonic-gate static void 11917c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 11927c478bd9Sstevel@tonic-gate int argfl, struct ditem *myparent) 11937c478bd9Sstevel@tonic-gate { 11947c478bd9Sstevel@tonic-gate size_t file_len; 11957c478bd9Sstevel@tonic-gate struct ditem *myinfo; 11967c478bd9Sstevel@tonic-gate struct ditem *tptr; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate file_len = strlen(file); 11997c478bd9Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 12007c478bd9Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * Add this inode's ancestry 12037c478bd9Sstevel@tonic-gate * info and insert it into the 12047c478bd9Sstevel@tonic-gate * ancestry list by pointing 12057c478bd9Sstevel@tonic-gate * back to its parent. We save 12067c478bd9Sstevel@tonic-gate * it (in rep) with the other info 12077c478bd9Sstevel@tonic-gate * we're gathering for this inode. 12087c478bd9Sstevel@tonic-gate */ 12097c478bd9Sstevel@tonic-gate if ((myinfo = malloc( 12107c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 12117c478bd9Sstevel@tonic-gate perror("ls"); 12127c478bd9Sstevel@tonic-gate exit(2); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 12157c478bd9Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 12167c478bd9Sstevel@tonic-gate myinfo->parent = myparent; 12177c478bd9Sstevel@tonic-gate rep->ancinfo = myinfo; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * If this node has the same device id and 12217c478bd9Sstevel@tonic-gate * inode number of one of its ancestors, 12227c478bd9Sstevel@tonic-gate * then we've detected a cycle. 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate if (myparent != NULL) { 12257c478bd9Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 12267c478bd9Sstevel@tonic-gate tptr = tptr->parent) { 12277c478bd9Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 12287c478bd9Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 12297c478bd9Sstevel@tonic-gate /* 12307c478bd9Sstevel@tonic-gate * Cycle detected for this 12317c478bd9Sstevel@tonic-gate * directory. Record the fact 12327c478bd9Sstevel@tonic-gate * it is a cycle so we don't 12337c478bd9Sstevel@tonic-gate * try to process this 12347c478bd9Sstevel@tonic-gate * directory as we are 12357c478bd9Sstevel@tonic-gate * walking through the 12367c478bd9Sstevel@tonic-gate * list of directories. 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate rep->cycle = 1; 12397c478bd9Sstevel@tonic-gate err = 2; 12407c478bd9Sstevel@tonic-gate break; 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate /* 1248*64d425a7Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 1249*64d425a7Sny155746 * This is because, if the server's FS happens to be UFS, supporting 1250*64d425a7Sny155746 * POSIX ACL's, then it does a special calculation of group mode 1251*64d425a7Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 1252*64d425a7Sny155746 * 1253*64d425a7Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 1254*64d425a7Sny155746 * algorithm is used for the group mode calculation only. 1255*64d425a7Sny155746 * What is modified here from the algorithm is that only the 1256*64d425a7Sny155746 * entries with flags ACE_GROUP are considered. For each entry 1257*64d425a7Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 1258*64d425a7Sny155746 * is checked if it is allowed. 1259*64d425a7Sny155746 * We are not interested in perms for owner@ and other@, as they 1260*64d425a7Sny155746 * were taken from st_mode value. 1261*64d425a7Sny155746 * We are not interested in a_who field of ACE, as we need just 1262*64d425a7Sny155746 * unix mode bits for the group. 1263*64d425a7Sny155746 */ 1264*64d425a7Sny155746 int 1265*64d425a7Sny155746 grp_mask_to_mode(acl_t *acep) 1266*64d425a7Sny155746 { 1267*64d425a7Sny155746 int mode = 0, seen = 0; 1268*64d425a7Sny155746 int acecnt; 1269*64d425a7Sny155746 ace_t *ap; 1270*64d425a7Sny155746 1271*64d425a7Sny155746 acecnt = acl_cnt(acep); 1272*64d425a7Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 1273*64d425a7Sny155746 if ((ap->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE || 1274*64d425a7Sny155746 ap->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 1275*64d425a7Sny155746 !(ap->a_flags & ACE_INHERIT_ONLY_ACE)) { 1276*64d425a7Sny155746 if (ap->a_flags & ACE_GROUP) { 1277*64d425a7Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 1278*64d425a7Sny155746 if (!(seen & S_IRGRP)) { 1279*64d425a7Sny155746 seen |= S_IRGRP; 1280*64d425a7Sny155746 if (ap->a_type == 1281*64d425a7Sny155746 ACE_ACCESS_ALLOWED_ACE_TYPE) 1282*64d425a7Sny155746 mode |= S_IRGRP; 1283*64d425a7Sny155746 } 1284*64d425a7Sny155746 } 1285*64d425a7Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 1286*64d425a7Sny155746 if (!(seen & S_IWGRP)) { 1287*64d425a7Sny155746 seen |= S_IWGRP; 1288*64d425a7Sny155746 if (ap->a_type == 1289*64d425a7Sny155746 ACE_ACCESS_ALLOWED_ACE_TYPE) 1290*64d425a7Sny155746 mode |= S_IWGRP; 1291*64d425a7Sny155746 } 1292*64d425a7Sny155746 } 1293*64d425a7Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 1294*64d425a7Sny155746 if (!(seen & S_IXGRP)) { 1295*64d425a7Sny155746 seen |= S_IXGRP; 1296*64d425a7Sny155746 if (ap->a_type == 1297*64d425a7Sny155746 ACE_ACCESS_ALLOWED_ACE_TYPE) 1298*64d425a7Sny155746 mode |= S_IXGRP; 1299*64d425a7Sny155746 } 1300*64d425a7Sny155746 } 1301*64d425a7Sny155746 } 1302*64d425a7Sny155746 } 1303*64d425a7Sny155746 } 1304*64d425a7Sny155746 return (mode); 1305*64d425a7Sny155746 } 1306*64d425a7Sny155746 1307*64d425a7Sny155746 /* 13087c478bd9Sstevel@tonic-gate * get status of file and recomputes tblocks; 13097c478bd9Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 13107c478bd9Sstevel@tonic-gate * for filename in a directory whose name is an 13117c478bd9Sstevel@tonic-gate * argument in the command; 13127c478bd9Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 13137c478bd9Sstevel@tonic-gate * returns that pointer; 13147c478bd9Sstevel@tonic-gate * returns NULL if failed; 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate static struct lbuf * 13177c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 13187c478bd9Sstevel@tonic-gate { 13197c478bd9Sstevel@tonic-gate struct stat statb, statb1; 13207c478bd9Sstevel@tonic-gate struct lbuf *rep; 13217c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 13227c478bd9Sstevel@tonic-gate ssize_t cc; 13237c478bd9Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 13247c478bd9Sstevel@tonic-gate int aclcnt; 1325fa9e4066Sahrens int error; 13267c478bd9Sstevel@tonic-gate aclent_t *tp; 13277c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 13287c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (nomocore) 13317c478bd9Sstevel@tonic-gate return (NULL); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate if (nfiles >= maxfils) { 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 13367c478bd9Sstevel@tonic-gate * more space 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate maxfils += quantn; 13397c478bd9Sstevel@tonic-gate if (((flist = realloc(flist, 13407c478bd9Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 13417c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 13427c478bd9Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 13437c478bd9Sstevel@tonic-gate perror("ls"); 13447c478bd9Sstevel@tonic-gate nomocore = 1; 13457c478bd9Sstevel@tonic-gate return (NULL); 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * nfiles is reset to nargs for each directory 13517c478bd9Sstevel@tonic-gate * that is given as an argument maxn is checked 13527c478bd9Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 13537c478bd9Sstevel@tonic-gate * that already has one assigned. 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate if (nfiles >= maxn) { 13567c478bd9Sstevel@tonic-gate rep = nxtlbf++; 13577c478bd9Sstevel@tonic-gate flist[nfiles++] = rep; 13587c478bd9Sstevel@tonic-gate maxn = nfiles; 13597c478bd9Sstevel@tonic-gate } else { 13607c478bd9Sstevel@tonic-gate rep = flist[nfiles++]; 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate rep->lflags = (mode_t)0; 13637c478bd9Sstevel@tonic-gate rep->flinkto = NULL; 13647c478bd9Sstevel@tonic-gate rep->cycle = 0; 13657c478bd9Sstevel@tonic-gate if (argfl || statreq) { 13667c478bd9Sstevel@tonic-gate int doacl; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (lflg) 13697c478bd9Sstevel@tonic-gate doacl = 1; 13707c478bd9Sstevel@tonic-gate else 13717c478bd9Sstevel@tonic-gate doacl = 0; 13727c478bd9Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 13737c478bd9Sstevel@tonic-gate if (argfl || errno != ENOENT || 13747c478bd9Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * Avoid race between readdir and lstat. 13777c478bd9Sstevel@tonic-gate * Print error message in case of dangling link. 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate perror(file); 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate nfiles--; 13827c478bd9Sstevel@tonic-gate return (NULL); 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * If -H was specified, and the file linked to was 13877c478bd9Sstevel@tonic-gate * not a directory, then we need to get the info 13887c478bd9Sstevel@tonic-gate * for the symlink itself. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate if ((Hflg) && (argfl) && 13917c478bd9Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 13927c478bd9Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 13937c478bd9Sstevel@tonic-gate perror(file); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate rep->lnum = statb.st_ino; 13987c478bd9Sstevel@tonic-gate rep->lsize = statb.st_size; 13997c478bd9Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 14007c478bd9Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 14017c478bd9Sstevel@tonic-gate case S_IFDIR: 14027c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 14037c478bd9Sstevel@tonic-gate if (Rflg) { 14047c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 14057c478bd9Sstevel@tonic-gate argfl, myparent); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate break; 14087c478bd9Sstevel@tonic-gate case S_IFBLK: 14097c478bd9Sstevel@tonic-gate rep->ltype = 'b'; 14107c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 14117c478bd9Sstevel@tonic-gate break; 14127c478bd9Sstevel@tonic-gate case S_IFCHR: 14137c478bd9Sstevel@tonic-gate rep->ltype = 'c'; 14147c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate case S_IFIFO: 14177c478bd9Sstevel@tonic-gate rep->ltype = 'p'; 14187c478bd9Sstevel@tonic-gate break; 14197c478bd9Sstevel@tonic-gate case S_IFSOCK: 14207c478bd9Sstevel@tonic-gate rep->ltype = 's'; 14217c478bd9Sstevel@tonic-gate rep->lsize = 0; 14227c478bd9Sstevel@tonic-gate break; 14237c478bd9Sstevel@tonic-gate case S_IFLNK: 14247c478bd9Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 14257c478bd9Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 14267c478bd9Sstevel@tonic-gate ((Hflg) && (!argfl))) { 14277c478bd9Sstevel@tonic-gate doacl = 0; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate rep->ltype = 'l'; 14307c478bd9Sstevel@tonic-gate if (lflg) { 14317c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 14327c478bd9Sstevel@tonic-gate if (cc >= 0) { 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* 14357c478bd9Sstevel@tonic-gate * follow the symbolic link 14367c478bd9Sstevel@tonic-gate * to generate the appropriate 14377c478bd9Sstevel@tonic-gate * Fflg marker for the object 14387c478bd9Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 14397c478bd9Sstevel@tonic-gate */ 14407c478bd9Sstevel@tonic-gate if ((Fflg || pflg) && 14417c478bd9Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 14427c478bd9Sstevel@tonic-gate switch (statb1.st_mode & 14437c478bd9Sstevel@tonic-gate S_IFMT) { 14447c478bd9Sstevel@tonic-gate case S_IFDIR: 14457c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 14467c478bd9Sstevel@tonic-gate break; 14477c478bd9Sstevel@tonic-gate case S_IFSOCK: 14487c478bd9Sstevel@tonic-gate buf[cc++] = '='; 14497c478bd9Sstevel@tonic-gate break; 14502236845bSakaplan case S_IFDOOR: 14512236845bSakaplan buf[cc++] = '>'; 14522236845bSakaplan break; 14532236845bSakaplan case S_IFIFO: 14542236845bSakaplan buf[cc++] = '|'; 14552236845bSakaplan break; 14567c478bd9Sstevel@tonic-gate default: 14577c478bd9Sstevel@tonic-gate if ((statb1.st_mode & 14587c478bd9Sstevel@tonic-gate ~S_IFMT) & 14597c478bd9Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 14607c478bd9Sstevel@tonic-gate S_IXOTH)) 14617c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 14627c478bd9Sstevel@tonic-gate break; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate buf[cc] = '\0'; 14667c478bd9Sstevel@tonic-gate rep->flinkto = strdup(buf); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate break; 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate /* 14727c478bd9Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 14737c478bd9Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 14747c478bd9Sstevel@tonic-gate * when explicit arguments are specified. 14757c478bd9Sstevel@tonic-gate */ 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate #ifdef XPG6 14787c478bd9Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 14797c478bd9Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 14807c478bd9Sstevel@tonic-gate (stat(file, &statb1) < 0)) 14817c478bd9Sstevel@tonic-gate #else 14827c478bd9Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 14837c478bd9Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 14847c478bd9Sstevel@tonic-gate #endif /* XPG6 */ 14857c478bd9Sstevel@tonic-gate break; 14867c478bd9Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 14877c478bd9Sstevel@tonic-gate statb = statb1; 14887c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 14897c478bd9Sstevel@tonic-gate rep->lsize = statb1.st_size; 14907c478bd9Sstevel@tonic-gate if (Rflg) { 14917c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 14927c478bd9Sstevel@tonic-gate argfl, myparent); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate break; 14967c478bd9Sstevel@tonic-gate case S_IFDOOR: 14977c478bd9Sstevel@tonic-gate rep->ltype = 'D'; 14987c478bd9Sstevel@tonic-gate break; 14997c478bd9Sstevel@tonic-gate case S_IFREG: 15007c478bd9Sstevel@tonic-gate rep->ltype = '-'; 15017c478bd9Sstevel@tonic-gate break; 15027c478bd9Sstevel@tonic-gate case S_IFPORT: 15037c478bd9Sstevel@tonic-gate rep->ltype = 'P'; 15047c478bd9Sstevel@tonic-gate break; 15057c478bd9Sstevel@tonic-gate default: 15067c478bd9Sstevel@tonic-gate rep->ltype = '?'; 15077c478bd9Sstevel@tonic-gate break; 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 15127c478bd9Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 15157c478bd9Sstevel@tonic-gate if (doacl) { 15167c478bd9Sstevel@tonic-gate 1517fa9e4066Sahrens error = acl_get(file, 0, &rep->aclp); 1518fa9e4066Sahrens if (error) { 1519fa9e4066Sahrens (void) fprintf(stderr, 1520fa9e4066Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1521fa9e4066Sahrens file, acl_strerror(error)); 15227c478bd9Sstevel@tonic-gate return (NULL); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 1525fa9e4066Sahrens rep->acl = ' '; 1526fa9e4066Sahrens 1527fa9e4066Sahrens if (rep->aclp && 1528fa9e4066Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1529fa9e4066Sahrens rep->acl = '+'; 15307c478bd9Sstevel@tonic-gate /* 1531fa9e4066Sahrens * Special handling for ufs aka aclent_t ACL's 1532fa9e4066Sahrens */ 1533*64d425a7Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 1534fa9e4066Sahrens /* 1535fa9e4066Sahrens * For files with non-trivial acls, the 1536fa9e4066Sahrens * effective group permissions are the 1537fa9e4066Sahrens * intersection of the GROUP_OBJ value 1538fa9e4066Sahrens * and the CLASS_OBJ (acl mask) value. 1539fa9e4066Sahrens * Determine both the GROUP_OBJ and 1540fa9e4066Sahrens * CLASS_OBJ for this file and insert 1541fa9e4066Sahrens * the logical AND of those two values 1542fa9e4066Sahrens * in the group permissions field 1543fa9e4066Sahrens * of the lflags value for this file. 1544fa9e4066Sahrens */ 1545fa9e4066Sahrens 1546fa9e4066Sahrens /* 1547fa9e4066Sahrens * Until found in acl list, assume 1548fa9e4066Sahrens * maximum permissions for both group 1549fa9e4066Sahrens * a nd mask. (Just in case the acl 1550fa9e4066Sahrens * lacks either value for some reason.) 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate groupperm = 07; 15537c478bd9Sstevel@tonic-gate mask = 07; 15547c478bd9Sstevel@tonic-gate grouppermfound = 0; 15557c478bd9Sstevel@tonic-gate maskfound = 0; 1556fa9e4066Sahrens aclcnt = acl_cnt(rep->aclp); 1557fa9e4066Sahrens for (tp = 1558fa9e4066Sahrens (aclent_t *)acl_data(rep->aclp); 1559fa9e4066Sahrens aclcnt--; tp++) { 15607c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 15617c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 15627c478bd9Sstevel@tonic-gate grouppermfound = 1; 15637c478bd9Sstevel@tonic-gate continue; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 15667c478bd9Sstevel@tonic-gate mask = tp->a_perm; 15677c478bd9Sstevel@tonic-gate maskfound = 1; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 15707c478bd9Sstevel@tonic-gate break; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* reset all the group bits */ 15757c478bd9Sstevel@tonic-gate rep->lflags &= ~S_IRWXG; 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 1578fa9e4066Sahrens * Now set them to the logical AND of 1579fa9e4066Sahrens * the GROUP_OBJ permissions and the 1580fa9e4066Sahrens * acl mask. 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate rep->lflags |= (groupperm & mask) << 3; 1584fa9e4066Sahrens 1585*64d425a7Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 1586*64d425a7Sny155746 int mode; 1587*64d425a7Sny155746 mode = grp_mask_to_mode(rep->aclp); 1588*64d425a7Sny155746 rep->lflags &= ~S_IRWXG; 1589*64d425a7Sny155746 rep->lflags |= mode; 1590fa9e4066Sahrens } 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15935a5eeccaSmarks if (!vflg && !Vflg && rep->aclp) { 15945a5eeccaSmarks acl_free(rep->aclp); 15955a5eeccaSmarks rep->aclp = NULL; 15965a5eeccaSmarks } 15975a5eeccaSmarks 15987c478bd9Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 15997c478bd9Sstevel@tonic-gate rep->acl = '@'; 1600da6c28aaSamw 16017c478bd9Sstevel@tonic-gate } else 16027c478bd9Sstevel@tonic-gate rep->acl = ' '; 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate rep->luid = statb.st_uid; 16077c478bd9Sstevel@tonic-gate rep->lgid = statb.st_gid; 16087c478bd9Sstevel@tonic-gate rep->lnl = statb.st_nlink; 1609da6c28aaSamw if (uflg || (tmflg && atm)) 16107c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_atim; 1611da6c28aaSamw else if (cflg || (tmflg && ctm)) 16127c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_ctim; 16137c478bd9Sstevel@tonic-gate else 16147c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_mtim; 1615da6c28aaSamw rep->lat = statb.st_atim; 1616da6c28aaSamw rep->lct = statb.st_ctim; 1617da6c28aaSamw rep->lmt = statb.st_mtim; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 16207c478bd9Sstevel@tonic-gate tblocks += rep->lblocks; 1621da6c28aaSamw 1622da6c28aaSamw /* Get extended system attributes */ 1623da6c28aaSamw 1624da6c28aaSamw rep->exttr = NULL; 1625da6c28aaSamw rep->extm = NULL; 1626da6c28aaSamw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 1627da6c28aaSamw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 1628da6c28aaSamw int i; 1629da6c28aaSamw 1630da6c28aaSamw sacnt = attr_count(); 1631da6c28aaSamw /* 1632da6c28aaSamw * Allocate 'sacnt' size array to hold extended 1633da6c28aaSamw * system attribute name (verbose) or respective 1634da6c28aaSamw * symbol represenation (compact). 1635da6c28aaSamw */ 1636da6c28aaSamw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 1637da6c28aaSamw rep); 1638da6c28aaSamw 1639da6c28aaSamw /* initialize boolean attribute list */ 1640da6c28aaSamw for (i = 0; i < sacnt; i++) 1641da6c28aaSamw rep->exttr[i].name = NULL; 1642da6c28aaSamw if (get_sysxattr(file, rep) != 0) { 1643da6c28aaSamw (void) fprintf(stderr, 1644da6c28aaSamw gettext("ls:Failed to retrieve " 1645da6c28aaSamw "extended system attribute from " 1646da6c28aaSamw "%s\n"), file); 1647da6c28aaSamw rep->exttr[0].name = xmalloc(2, rep); 1648da6c28aaSamw (void) strlcpy(rep->exttr[0].name, "?", 2); 1649da6c28aaSamw } 1650da6c28aaSamw } 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate return (rep); 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 16567c478bd9Sstevel@tonic-gate * returns pathname of the form dir/file; 16577c478bd9Sstevel@tonic-gate * dir and file are null-terminated strings. 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate static char * 16607c478bd9Sstevel@tonic-gate makename(char *dir, char *file) 16617c478bd9Sstevel@tonic-gate { 16627c478bd9Sstevel@tonic-gate /* 16637c478bd9Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 16647c478bd9Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 16657c478bd9Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 16667c478bd9Sstevel@tonic-gate * and the null character at the end. 16677c478bd9Sstevel@tonic-gate * dfile is static as this is returned by makename(). 16687c478bd9Sstevel@tonic-gate */ 16697c478bd9Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 16707c478bd9Sstevel@tonic-gate char *dp, *fp; 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate dp = dfile; 16737c478bd9Sstevel@tonic-gate fp = dir; 16747c478bd9Sstevel@tonic-gate while (*fp) 16757c478bd9Sstevel@tonic-gate *dp++ = *fp++; 16767c478bd9Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 16777c478bd9Sstevel@tonic-gate *dp++ = '/'; 16787c478bd9Sstevel@tonic-gate fp = file; 16797c478bd9Sstevel@tonic-gate while (*fp) 16807c478bd9Sstevel@tonic-gate *dp++ = *fp++; 16817c478bd9Sstevel@tonic-gate *dp = '\0'; 16827c478bd9Sstevel@tonic-gate return (dfile); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate #include <pwd.h> 16877c478bd9Sstevel@tonic-gate #include <grp.h> 16887c478bd9Sstevel@tonic-gate #include <utmpx.h> 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate struct utmpx utmp; 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 16937c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 16977c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 16987c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 16997c478bd9Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 17007c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 17017c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 17027c478bd9Sstevel@tonic-gate }; 17037c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups; 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate static struct cachenode * 17067c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val) 17077c478bd9Sstevel@tonic-gate { 17087c478bd9Sstevel@tonic-gate struct cachenode **parent = head; 17097c478bd9Sstevel@tonic-gate struct cachenode *c = *parent; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate while (c != NULL) { 17127c478bd9Sstevel@tonic-gate if (val == c->val) { 17137c478bd9Sstevel@tonic-gate /* found it */ 17147c478bd9Sstevel@tonic-gate return (c); 17157c478bd9Sstevel@tonic-gate } else if (val < c->val) { 17167c478bd9Sstevel@tonic-gate parent = &c->lesschild; 17177c478bd9Sstevel@tonic-gate c = c->lesschild; 17187c478bd9Sstevel@tonic-gate } else { 17197c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 17207c478bd9Sstevel@tonic-gate c = c->grtrchild; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 17257c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 17267c478bd9Sstevel@tonic-gate if (c == NULL) { 17277c478bd9Sstevel@tonic-gate perror("ls"); 17287c478bd9Sstevel@tonic-gate exit(2); 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate *parent = c; 17317c478bd9Sstevel@tonic-gate c->val = val; 17327c478bd9Sstevel@tonic-gate return (c); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 17377c478bd9Sstevel@tonic-gate * lastuid is set to uid. 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate static char * 17407c478bd9Sstevel@tonic-gate getname(uid_t uid) 17417c478bd9Sstevel@tonic-gate { 17427c478bd9Sstevel@tonic-gate struct passwd *pwent; 17437c478bd9Sstevel@tonic-gate struct cachenode *c; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 17467c478bd9Sstevel@tonic-gate return (lastuname); 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 17497c478bd9Sstevel@tonic-gate if (c->initted == 0) { 17507c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 17517c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 17527c478bd9Sstevel@tonic-gate } else { 17537c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate c->initted = 1; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate lastuid = uid; 17587c478bd9Sstevel@tonic-gate lastuname = &c->name[0]; 17597c478bd9Sstevel@tonic-gate return (lastuname); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * get name from cache, or group file for a given gid; 17647c478bd9Sstevel@tonic-gate * lastgid is set to gid. 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate static char * 17677c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate struct group *grent; 17707c478bd9Sstevel@tonic-gate struct cachenode *c; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 17737c478bd9Sstevel@tonic-gate return (lastgname); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 17767c478bd9Sstevel@tonic-gate if (c->initted == 0) { 17777c478bd9Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 17787c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 17797c478bd9Sstevel@tonic-gate } else { 17807c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate c->initted = 1; 17837c478bd9Sstevel@tonic-gate } 17847c478bd9Sstevel@tonic-gate lastgid = gid; 17857c478bd9Sstevel@tonic-gate lastgname = &c->name[0]; 17867c478bd9Sstevel@tonic-gate return (lastgname); 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 17907c478bd9Sstevel@tonic-gate static int 17917c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 17927c478bd9Sstevel@tonic-gate { 17937c478bd9Sstevel@tonic-gate struct lbuf *p1, *p2; 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate p1 = *pp1; 17967c478bd9Sstevel@tonic-gate p2 = *pp2; 17977c478bd9Sstevel@tonic-gate if (dflg == 0) { 17987c478bd9Sstevel@tonic-gate /* 17997c478bd9Sstevel@tonic-gate * compare two names in ls-command one of which is file 18007c478bd9Sstevel@tonic-gate * and the other is a directory; 18017c478bd9Sstevel@tonic-gate * this portion is not used for comparing files within 18027c478bd9Sstevel@tonic-gate * a directory name of ls-command; 18037c478bd9Sstevel@tonic-gate */ 18047c478bd9Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 18057c478bd9Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 18067c478bd9Sstevel@tonic-gate return (1); 18077c478bd9Sstevel@tonic-gate } else { 18087c478bd9Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 18097c478bd9Sstevel@tonic-gate return (-1); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate if (tflg) { 18137c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 18147c478bd9Sstevel@tonic-gate return (rflg); 18157c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 18167c478bd9Sstevel@tonic-gate return (-rflg); 18177c478bd9Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 18187c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 18197c478bd9Sstevel@tonic-gate return (rflg); 18207c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 18217c478bd9Sstevel@tonic-gate return (-rflg); 18227c478bd9Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 18237c478bd9Sstevel@tonic-gate } else if (Sflg) { 18247c478bd9Sstevel@tonic-gate /* 18257c478bd9Sstevel@tonic-gate * The size stored in lsize can be either the 18267c478bd9Sstevel@tonic-gate * size or the major minor number (in the case of 18277c478bd9Sstevel@tonic-gate * block and character special devices). If it's 18287c478bd9Sstevel@tonic-gate * a major minor number, then the size is considered 18297c478bd9Sstevel@tonic-gate * to be zero and we want to fall through and sort 18307c478bd9Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 18317c478bd9Sstevel@tonic-gate * to the size of p1 we want to fall through and 18327c478bd9Sstevel@tonic-gate * sort by name. 18337c478bd9Sstevel@tonic-gate */ 18347c478bd9Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 18357c478bd9Sstevel@tonic-gate (p1->ltype == 'c') ? 0 : p1->lsize; 18367c478bd9Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 18377c478bd9Sstevel@tonic-gate (p2->ltype == 'c') ? 0 : p2->lsize; 18387c478bd9Sstevel@tonic-gate if (p2size > p1size) { 18397c478bd9Sstevel@tonic-gate return (rflg); 18407c478bd9Sstevel@tonic-gate } else if (p2size < p1size) { 18417c478bd9Sstevel@tonic-gate return (-rflg); 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate return (rflg * strcoll( 18467c478bd9Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 18477c478bd9Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate static void 18517c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2) 18527c478bd9Sstevel@tonic-gate { 18537c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 18547c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate static void 18587c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s) 18597c478bd9Sstevel@tonic-gate { 18607c478bd9Sstevel@tonic-gate unsigned char *cp; 18617c478bd9Sstevel@tonic-gate char c; 18627c478bd9Sstevel@tonic-gate int i; 18637c478bd9Sstevel@tonic-gate int c_len; 18647c478bd9Sstevel@tonic-gate int p_col; 18657c478bd9Sstevel@tonic-gate wchar_t pcode; 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate if (!qflg && !bflg) { 18687c478bd9Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 18697c478bd9Sstevel@tonic-gate (void) putchar(*cp); 18707c478bd9Sstevel@tonic-gate curcol++; 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate return; 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate for (cp = s; *cp; ) { 18767c478bd9Sstevel@tonic-gate if (isascii(c = *cp)) { 18777c478bd9Sstevel@tonic-gate if (!isprint(c)) { 18787c478bd9Sstevel@tonic-gate if (qflg) { 18797c478bd9Sstevel@tonic-gate c = '?'; 18807c478bd9Sstevel@tonic-gate } else { 18817c478bd9Sstevel@tonic-gate curcol += 3; 18827c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 18837c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 18847c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 18857c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 18867c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 18877c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate curcol++; 18917c478bd9Sstevel@tonic-gate cp++; 18927c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 18937c478bd9Sstevel@tonic-gate continue; 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 18977c478bd9Sstevel@tonic-gate c_len = 1; 18987c478bd9Sstevel@tonic-gate goto not_print; 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 19027c478bd9Sstevel@tonic-gate (void) putwchar(pcode); 19037c478bd9Sstevel@tonic-gate cp += c_len; 19047c478bd9Sstevel@tonic-gate curcol += p_col; 19057c478bd9Sstevel@tonic-gate continue; 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate not_print: 19097c478bd9Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 19107c478bd9Sstevel@tonic-gate if (qflg) { 19117c478bd9Sstevel@tonic-gate c = '?'; 19127c478bd9Sstevel@tonic-gate } else { 19137c478bd9Sstevel@tonic-gate curcol += 3; 19147c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 19157c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 19167c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 19177c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 19187c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 19197c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate curcol++; 19227c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 19237c478bd9Sstevel@tonic-gate cp++; 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate static int 19297c478bd9Sstevel@tonic-gate strcol(unsigned char *s1) 19307c478bd9Sstevel@tonic-gate { 19317c478bd9Sstevel@tonic-gate int w; 19327c478bd9Sstevel@tonic-gate int w_col; 19337c478bd9Sstevel@tonic-gate int len; 19347c478bd9Sstevel@tonic-gate wchar_t wc; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate w = 0; 19377c478bd9Sstevel@tonic-gate while (*s1) { 19387c478bd9Sstevel@tonic-gate if (isascii(*s1)) { 19397c478bd9Sstevel@tonic-gate w++; 19407c478bd9Sstevel@tonic-gate s1++; 19417c478bd9Sstevel@tonic-gate continue; 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 19457c478bd9Sstevel@tonic-gate w++; 19467c478bd9Sstevel@tonic-gate s1++; 19477c478bd9Sstevel@tonic-gate continue; 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 19517c478bd9Sstevel@tonic-gate w_col = len; 19527c478bd9Sstevel@tonic-gate s1 += len; 19537c478bd9Sstevel@tonic-gate w += w_col; 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate return (w); 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 19607c478bd9Sstevel@tonic-gate * result in the caller-supplied buffer. 19617c478bd9Sstevel@tonic-gate * 19627c478bd9Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 19637c478bd9Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 19647c478bd9Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 19657c478bd9Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 19667c478bd9Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 19677c478bd9Sstevel@tonic-gate * the final number has only a single significant digit, we compute 19687c478bd9Sstevel@tonic-gate * tenths of units to provide a second significant digit. 19697c478bd9Sstevel@tonic-gate * 19707c478bd9Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 19717c478bd9Sstevel@tonic-gate * converted to "-1". 19727c478bd9Sstevel@tonic-gate * 19737c478bd9Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 19747c478bd9Sstevel@tonic-gate */ 19757c478bd9Sstevel@tonic-gate static char * 19767c478bd9Sstevel@tonic-gate number_to_scaled_string( 19777c478bd9Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 19787c478bd9Sstevel@tonic-gate unsigned long long number, /* convert this number */ 19797c478bd9Sstevel@tonic-gate long scale) 19807c478bd9Sstevel@tonic-gate { 19817c478bd9Sstevel@tonic-gate unsigned long long save; 19827c478bd9Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 19837c478bd9Sstevel@tonic-gate char *uom = "KMGTPE"; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate if ((long long)number == (long long)-1) { 19867c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 19877c478bd9Sstevel@tonic-gate return (buf); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate save = number; 19917c478bd9Sstevel@tonic-gate number = number / scale; 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * Now we have number as a count of scale units. 19957c478bd9Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 19967c478bd9Sstevel@tonic-gate * 19977c478bd9Sstevel@tonic-gate * The largest value number could have had entering the routine is 19987c478bd9Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 19997c478bd9Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 20007c478bd9Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate if (number < (unsigned long long)scale) { 20037c478bd9Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 20047c478bd9Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 20057c478bd9Sstevel@tonic-gate uom++; 20067c478bd9Sstevel@tonic-gate number = 1; 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate } else { 20107c478bd9Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 20117c478bd9Sstevel@tonic-gate uom++; /* next unit of measurement */ 20127c478bd9Sstevel@tonic-gate save = number; 20137c478bd9Sstevel@tonic-gate /* 20147c478bd9Sstevel@tonic-gate * If we're over half way to the next unit of 20157c478bd9Sstevel@tonic-gate * 'scale' bytes (which means we should round 20167c478bd9Sstevel@tonic-gate * up), then adding half of 'scale' prior to 20177c478bd9Sstevel@tonic-gate * the division will push us into that next 20187c478bd9Sstevel@tonic-gate * unit of scale when we perform the division 20197c478bd9Sstevel@tonic-gate */ 20207c478bd9Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 20257c478bd9Sstevel@tonic-gate if ((save / scale) < 10) { 20267c478bd9Sstevel@tonic-gate /* snprintf() will round for us */ 20277c478bd9Sstevel@tonic-gate float fnum = (float)save / scale; 20287c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 20297c478bd9Sstevel@tonic-gate fnum, *uom); 20307c478bd9Sstevel@tonic-gate } else { 20317c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 20327c478bd9Sstevel@tonic-gate number, *uom); 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate return (buf); 20357c478bd9Sstevel@tonic-gate } 2036da6c28aaSamw 2037da6c28aaSamw /* Get extended system attributes and set the display */ 2038da6c28aaSamw 2039da6c28aaSamw int 2040da6c28aaSamw get_sysxattr(char *fname, struct lbuf *rep) 2041da6c28aaSamw { 2042da6c28aaSamw boolean_t value; 2043da6c28aaSamw data_type_t type; 2044da6c28aaSamw int error; 2045da6c28aaSamw char *name; 2046da6c28aaSamw int i; 2047da6c28aaSamw 2048da6c28aaSamw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 2049da6c28aaSamw &response)) != 0) { 2050da6c28aaSamw perror("ls:getattrat"); 2051da6c28aaSamw return (error); 2052da6c28aaSamw } 2053da6c28aaSamw 2054da6c28aaSamw /* 2055da6c28aaSamw * Allocate 'sacnt' size array to hold extended timestamp 2056da6c28aaSamw * system attributes and initialize the array. 2057da6c28aaSamw */ 2058da6c28aaSamw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 2059da6c28aaSamw for (i = 0; i < sacnt; i++) { 2060da6c28aaSamw rep->extm[i].stm = 0; 2061da6c28aaSamw rep->extm[i].nstm = 0; 2062da6c28aaSamw rep->extm[i].name = NULL; 2063da6c28aaSamw } 2064da6c28aaSamw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 2065da6c28aaSamw name = nvpair_name(pair); 2066da6c28aaSamw type = nvpair_type(pair); 2067da6c28aaSamw if (type == DATA_TYPE_BOOLEAN_VALUE) { 2068da6c28aaSamw error = nvpair_value_boolean_value(pair, &value); 2069da6c28aaSamw if (error) { 2070da6c28aaSamw (void) fprintf(stderr, 2071da6c28aaSamw gettext("nvpair_value_boolean_value " 2072da6c28aaSamw "failed: error = %d\n"), error); 2073da6c28aaSamw continue; 2074da6c28aaSamw } 2075da6c28aaSamw if (name != NULL) 2076da6c28aaSamw set_sysattrb_display(name, value, rep); 2077da6c28aaSamw continue; 2078da6c28aaSamw } else if (type == DATA_TYPE_UINT64_ARRAY) { 2079da6c28aaSamw if (name != NULL) 2080da6c28aaSamw set_sysattrtm_display(name, rep); 2081da6c28aaSamw continue; 2082da6c28aaSamw } 2083da6c28aaSamw } 2084da6c28aaSamw nvlist_free(response); 2085da6c28aaSamw return (0); 2086da6c28aaSamw } 2087da6c28aaSamw 2088da6c28aaSamw /* Set extended system attribute boolean display */ 2089da6c28aaSamw 2090da6c28aaSamw void 2091da6c28aaSamw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 2092da6c28aaSamw { 2093da6c28aaSamw f_attr_t fattr; 2094da6c28aaSamw const char *opt; 2095da6c28aaSamw size_t len; 2096da6c28aaSamw 2097da6c28aaSamw fattr = name_to_attr(name); 2098da6c28aaSamw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 2099da6c28aaSamw if (vopt) { 2100da6c28aaSamw len = strlen(name); 2101da6c28aaSamw if (val) { 2102da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2103da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, name, 2104da6c28aaSamw len + 1); 2105da6c28aaSamw } else { 2106da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 3, rep); 2107da6c28aaSamw (void) snprintf(rep->exttr[fattr].name, len + 3, 2108da6c28aaSamw "no%s", name); 2109da6c28aaSamw } 2110da6c28aaSamw } else { 2111da6c28aaSamw opt = attr_to_option(fattr); 2112da6c28aaSamw if (opt != NULL) { 2113da6c28aaSamw len = strlen(opt); 2114da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2115da6c28aaSamw if (val) 2116da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2117da6c28aaSamw opt, len + 1); 2118da6c28aaSamw else 2119da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2120da6c28aaSamw "-", len + 1); 2121da6c28aaSamw } 2122da6c28aaSamw } 2123da6c28aaSamw } 2124da6c28aaSamw } 2125da6c28aaSamw 2126da6c28aaSamw /* Set extended system attribute timestamp display */ 2127da6c28aaSamw 2128da6c28aaSamw void 2129da6c28aaSamw set_sysattrtm_display(char *name, struct lbuf *rep) 2130da6c28aaSamw { 2131da6c28aaSamw uint_t nelem; 2132da6c28aaSamw uint64_t *value; 2133da6c28aaSamw int i; 2134da6c28aaSamw size_t len; 2135da6c28aaSamw 2136da6c28aaSamw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 2137da6c28aaSamw if (*value != NULL) { 2138da6c28aaSamw len = strlen(name); 2139da6c28aaSamw i = 0; 2140da6c28aaSamw while (rep->extm[i].stm != 0 && i < sacnt) 2141da6c28aaSamw i++; 2142da6c28aaSamw rep->extm[i].stm = value[0]; 2143da6c28aaSamw rep->extm[i].nstm = value[1]; 2144da6c28aaSamw rep->extm[i].name = xmalloc(len + 1, rep); 2145da6c28aaSamw (void) strlcpy(rep->extm[i].name, name, len + 1); 2146da6c28aaSamw } 2147da6c28aaSamw } 2148da6c28aaSamw } 2149da6c28aaSamw 2150da6c28aaSamw void 2151da6c28aaSamw format_time(const char *format, time_t sec) 2152da6c28aaSamw { 2153da6c28aaSamw 2154da6c28aaSamw (void) strftime(time_buf, sizeof (time_buf), 2155da6c28aaSamw dcgettext(NULL, format, LC_TIME), 2156da6c28aaSamw localtime(&sec)); 2157da6c28aaSamw } 2158da6c28aaSamw 2159da6c28aaSamw void 2160da6c28aaSamw format_etime(const char *format, time_t sec, time_t nsec) 2161da6c28aaSamw { 2162da6c28aaSamw char fmt_buf[FMTSIZE]; 2163da6c28aaSamw 2164da6c28aaSamw (void) snprintf(fmt_buf, FMTSIZE, 2165da6c28aaSamw format, nsec); 2166da6c28aaSamw (void) strftime(time_buf, sizeof (time_buf), 2167da6c28aaSamw fmt_buf, localtime(&sec)); 2168da6c28aaSamw } 2169da6c28aaSamw 2170da6c28aaSamw /* Format timestamp extended system attributes */ 2171da6c28aaSamw 2172da6c28aaSamw void 2173da6c28aaSamw format_attrtime(struct lbuf *p) 2174da6c28aaSamw { 2175da6c28aaSamw int tmattr = 0; 2176da6c28aaSamw int i; 2177da6c28aaSamw 2178da6c28aaSamw if (p->extm != NULL) { 2179da6c28aaSamw for (i = 0; i < sacnt; i++) { 2180da6c28aaSamw if (p->extm[i].name != NULL) { 2181da6c28aaSamw tmattr = 1; 2182da6c28aaSamw break; 2183da6c28aaSamw } 2184da6c28aaSamw } 2185da6c28aaSamw } 2186da6c28aaSamw if (tmattr) { 2187da6c28aaSamw if (Eflg) 2188da6c28aaSamw format_etime(FORMAT4, (time_t)p->extm[i].stm, 2189da6c28aaSamw (time_t)p->extm[i].nstm); 2190da6c28aaSamw else { 2191da6c28aaSamw if ((p->lmtime.tv_sec < year) || 2192da6c28aaSamw (p->lmtime.tv_sec > now)) 2193da6c28aaSamw format_time(FORMAT1, 2194da6c28aaSamw (time_t)p->extm[i].stm); 2195da6c28aaSamw else 2196da6c28aaSamw format_time(FORMAT2, 2197da6c28aaSamw (time_t)p->extm[i].stm); 2198da6c28aaSamw } 2199da6c28aaSamw } 2200da6c28aaSamw } 2201da6c28aaSamw 2202da6c28aaSamw void 2203da6c28aaSamw print_time(struct lbuf *p) 2204da6c28aaSamw { 2205da6c28aaSamw int i = 0; 2206da6c28aaSamw 2207da6c28aaSamw new_line(); 2208da6c28aaSamw if (Eflg) { 2209da6c28aaSamw format_etime(FORMAT4, p->lat.tv_sec, p->lat.tv_nsec); 2210da6c28aaSamw (void) printf(" timestamp: atime %s\n", 2211da6c28aaSamw time_buf); 2212da6c28aaSamw format_etime(FORMAT4, p->lct.tv_sec, p->lct.tv_nsec); 2213da6c28aaSamw (void) printf(" timestamp: ctime %s\n", 2214da6c28aaSamw time_buf); 2215da6c28aaSamw format_etime(FORMAT4, p->lmt.tv_sec, p->lmt.tv_nsec); 2216da6c28aaSamw (void) printf(" timestamp: mtime %s\n", 2217da6c28aaSamw time_buf); 2218da6c28aaSamw if (p->extm != NULL) { 2219da6c28aaSamw while (p->extm[i].nstm != 0 && i < sacnt) { 2220da6c28aaSamw format_etime(FORMAT4, p->extm[i].stm, 2221da6c28aaSamw p->extm[i].nstm); 2222da6c28aaSamw if (p->extm[i].name != NULL) { 2223da6c28aaSamw (void) printf(" timestamp:" 2224da6c28aaSamw " %s %s\n", 2225da6c28aaSamw p->extm[i].name, time_buf); 2226da6c28aaSamw } 2227da6c28aaSamw i++; 2228da6c28aaSamw } 2229da6c28aaSamw } 2230da6c28aaSamw } else { 2231da6c28aaSamw format_time(FORMAT3, p->lat.tv_sec); 2232da6c28aaSamw (void) printf(" timestamp: atime %s\n", 2233da6c28aaSamw time_buf); 2234da6c28aaSamw format_time(FORMAT3, p->lct.tv_sec); 2235da6c28aaSamw (void) printf(" timestamp: ctime %s\n", 2236da6c28aaSamw time_buf); 2237da6c28aaSamw format_time(FORMAT3, p->lmt.tv_sec); 2238da6c28aaSamw (void) printf(" timestamp: mtime %s\n", 2239da6c28aaSamw time_buf); 2240da6c28aaSamw if (p->extm != NULL) { 2241da6c28aaSamw while (p->extm[i].stm != 0 && i < sacnt) { 2242da6c28aaSamw format_time(FORMAT3, p->extm[i].stm); 2243da6c28aaSamw if (p->extm[i].name != NULL) { 2244da6c28aaSamw (void) printf(" timestamp:" 2245da6c28aaSamw " %s %s\n", 2246da6c28aaSamw p->extm[i].name, time_buf); 2247da6c28aaSamw } 2248da6c28aaSamw i++; 2249da6c28aaSamw } 2250da6c28aaSamw } 2251da6c28aaSamw } 2252da6c28aaSamw } 2253da6c28aaSamw 2254da6c28aaSamw /* Free extended system attribute lists */ 2255da6c28aaSamw 2256da6c28aaSamw void 2257da6c28aaSamw free_sysattr(struct lbuf *p) 2258da6c28aaSamw { 2259da6c28aaSamw int i; 2260da6c28aaSamw 2261da6c28aaSamw if (p->exttr != NULL) { 2262da6c28aaSamw for (i = 0; i < sacnt; i++) { 2263da6c28aaSamw if (p->exttr[i].name != NULL) 2264da6c28aaSamw free(p->exttr[i].name); 2265da6c28aaSamw } 2266da6c28aaSamw free(p->exttr); 2267da6c28aaSamw } 2268da6c28aaSamw if (p->extm != NULL) { 2269da6c28aaSamw for (i = 0; i < sacnt; i++) { 2270da6c28aaSamw if (p->extm[i].name != NULL) 2271da6c28aaSamw free(p->extm[i].name); 2272da6c28aaSamw } 2273da6c28aaSamw free(p->extm); 2274da6c28aaSamw } 2275da6c28aaSamw } 2276da6c28aaSamw 2277da6c28aaSamw /* Allocate extended system attribute list */ 2278da6c28aaSamw 2279da6c28aaSamw void * 2280da6c28aaSamw xmalloc(size_t size, struct lbuf *p) 2281da6c28aaSamw { 2282da6c28aaSamw if ((p = malloc(size)) == NULL) { 2283da6c28aaSamw perror("ls"); 2284da6c28aaSamw free_sysattr(p); 2285da6c28aaSamw nvlist_free(response); 2286da6c28aaSamw exit(2); 2287da6c28aaSamw } 2288da6c28aaSamw return (p); 2289da6c28aaSamw } 2290