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 */ 21*5e1c72e1SJason King 227c478bd9Sstevel@tonic-gate /* 23*5e1c72e1SJason King * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*5e1c72e1SJason King * Use is subject to license terms. 25*5e1c72e1SJason King */ 26*5e1c72e1SJason King 27*5e1c72e1SJason King /* 28*5e1c72e1SJason King * Copyright 2009 Jason King. All rights reserved. 297c478bd9Sstevel@tonic-gate * Use is subject to license terms. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 337c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 367c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * List files or directories 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/param.h> 437c478bd9Sstevel@tonic-gate #include <sys/types.h> 447c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 457c478bd9Sstevel@tonic-gate #include <sys/stat.h> 467c478bd9Sstevel@tonic-gate #include <sys/acl.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <wchar.h> 497c478bd9Sstevel@tonic-gate #include <stdio.h> 507c478bd9Sstevel@tonic-gate #include <ctype.h> 517c478bd9Sstevel@tonic-gate #include <dirent.h> 527c478bd9Sstevel@tonic-gate #include <string.h> 537c478bd9Sstevel@tonic-gate #include <locale.h> 547c478bd9Sstevel@tonic-gate #include <curses.h> 55*5e1c72e1SJason King #include <term.h> 567c478bd9Sstevel@tonic-gate #include <termios.h> 577c478bd9Sstevel@tonic-gate #include <stdlib.h> 587c478bd9Sstevel@tonic-gate #include <widec.h> 597c478bd9Sstevel@tonic-gate #include <locale.h> 607c478bd9Sstevel@tonic-gate #include <wctype.h> 617c478bd9Sstevel@tonic-gate #include <pwd.h> 627c478bd9Sstevel@tonic-gate #include <grp.h> 637c478bd9Sstevel@tonic-gate #include <limits.h> 647c478bd9Sstevel@tonic-gate #include <fcntl.h> 657c478bd9Sstevel@tonic-gate #include <unistd.h> 667c478bd9Sstevel@tonic-gate #include <libgen.h> 677c478bd9Sstevel@tonic-gate #include <errno.h> 68fa9e4066Sahrens #include <aclutils.h> 69da6c28aaSamw #include <libnvpair.h> 70da6c28aaSamw #include <libcmdutils.h> 71da6c28aaSamw #include <attr.h> 72*5e1c72e1SJason King #include <getopt.h> 73*5e1c72e1SJason King #include <inttypes.h> 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #ifndef STANDALONE 767c478bd9Sstevel@tonic-gate #define TERMINFO 777c478bd9Sstevel@tonic-gate #endif 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 817c478bd9Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 82da6c28aaSamw * the terminfo feature(pre 6.0 systems ?). 837c478bd9Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 847c478bd9Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO 877c478bd9Sstevel@tonic-gate #undef TERMINFO 887c478bd9Sstevel@tonic-gate #endif 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #include <term.h> 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate #define BFSIZE 16 937c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 947c478bd9Sstevel@tonic-gate #define ISARG 0100000 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 987c478bd9Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate #define LS_NOTREG 010000 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * Date and time formats 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * b --- abbreviated month name 1077c478bd9Sstevel@tonic-gate * e --- day number 1087c478bd9Sstevel@tonic-gate * Y --- year in the form ccyy 1097c478bd9Sstevel@tonic-gate * H --- hour(24-hour version) 1107c478bd9Sstevel@tonic-gate * M --- minute 1117c478bd9Sstevel@tonic-gate * F --- yyyy-mm-dd 1127c478bd9Sstevel@tonic-gate * T --- hh:mm:ss 1137c478bd9Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1147c478bd9Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1157c478bd9Sstevel@tonic-gate * not present in older C libraries 1167c478bd9Sstevel@tonic-gate */ 117*5e1c72e1SJason King #define FORMAT_OLD " %b %e %Y " 118*5e1c72e1SJason King #define FORMAT_NEW " %b %e %H:%M " 119*5e1c72e1SJason King #define FORMAT_LONG " %b %e %T %Y " 120*5e1c72e1SJason King #define FORMAT_ISO_FULL " %%F %%T.%.09ld %%z " 121*5e1c72e1SJason King #define FORMAT_ISO_LONG " %F %R " 122*5e1c72e1SJason King #define FORMAT_ISO_NEW " %m-%d %H:%M " 123*5e1c72e1SJason King #define FORMAT_ISO_OLD " %F " 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #undef BUFSIZ 1267c478bd9Sstevel@tonic-gate #define BUFSIZ 4096 1277c478bd9Sstevel@tonic-gate #define NUMBER_WIDTH 40 1287c478bd9Sstevel@tonic-gate #define FMTSIZE 50 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate struct ditem { 1317c478bd9Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1327c478bd9Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1337c478bd9Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1347c478bd9Sstevel@tonic-gate }; 135da6c28aaSamw /* Holds boolean extended system attributes */ 136da6c28aaSamw struct attrb { 137da6c28aaSamw char *name; 138da6c28aaSamw }; 139da6c28aaSamw /* Holds timestamp extended system attributes */ 140da6c28aaSamw struct attrtm { 141da6c28aaSamw char *name; 142da6c28aaSamw uint64_t stm; 143da6c28aaSamw uint64_t nstm; 144da6c28aaSamw }; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate struct lbuf { 1477c478bd9Sstevel@tonic-gate union { 1487c478bd9Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 1497c478bd9Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 1507c478bd9Sstevel@tonic-gate } ln; 1517c478bd9Sstevel@tonic-gate char ltype; /* filetype */ 1527c478bd9Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 1537c478bd9Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1547c478bd9Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 1557c478bd9Sstevel@tonic-gate uid_t luid; 1567c478bd9Sstevel@tonic-gate gid_t lgid; 1577c478bd9Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 1587c478bd9Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 1597c478bd9Sstevel@tonic-gate timestruc_t lmtime; 160da6c28aaSamw timestruc_t lat; 161da6c28aaSamw timestruc_t lct; 162da6c28aaSamw timestruc_t lmt; 1637c478bd9Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 1647c478bd9Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 1657c478bd9Sstevel@tonic-gate int cycle; /* cycle detected flag */ 1667c478bd9Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 167fa9e4066Sahrens acl_t *aclp; /* ACL if present */ 168da6c28aaSamw struct attrb *exttr; /* boolean extended system attributes */ 169da6c28aaSamw struct attrtm *extm; /* timestamp extended system attributes */ 1707c478bd9Sstevel@tonic-gate }; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate struct dchain { 1737c478bd9Sstevel@tonic-gate char *dc_name; /* path name */ 1747c478bd9Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 1757c478bd9Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 1767c478bd9Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 1777c478bd9Sstevel@tonic-gate }; 1787c478bd9Sstevel@tonic-gate 179*5e1c72e1SJason King #define LSA_NONE (0) 180*5e1c72e1SJason King #define LSA_BOLD (1L << 0) 181*5e1c72e1SJason King #define LSA_UNDERSCORE (1L << 1) 182*5e1c72e1SJason King #define LSA_BLINK (1L << 2) 183*5e1c72e1SJason King #define LSA_REVERSE (1L << 3) 184*5e1c72e1SJason King #define LSA_CONCEALED (1L << 4) 185*5e1c72e1SJason King 186*5e1c72e1SJason King /* these should be ordered most general to most specific */ 187*5e1c72e1SJason King typedef enum LS_CFTYPE { 188*5e1c72e1SJason King LS_NORMAL, 189*5e1c72e1SJason King LS_FILE, 190*5e1c72e1SJason King LS_EXEC, 191*5e1c72e1SJason King LS_DIR, 192*5e1c72e1SJason King LS_LINK, 193*5e1c72e1SJason King LS_FIFO, 194*5e1c72e1SJason King LS_SOCK, 195*5e1c72e1SJason King LS_DOOR, 196*5e1c72e1SJason King LS_BLK, 197*5e1c72e1SJason King LS_CHR, 198*5e1c72e1SJason King LS_PORT, 199*5e1c72e1SJason King LS_STICKY, 200*5e1c72e1SJason King LS_ORPHAN, 201*5e1c72e1SJason King LS_SETGID, 202*5e1c72e1SJason King LS_SETUID, 203*5e1c72e1SJason King LS_OTHER_WRITABLE, 204*5e1c72e1SJason King LS_STICKY_OTHER_WRITABLE, 205*5e1c72e1SJason King LS_PAT 206*5e1c72e1SJason King } ls_cftype_t; 207*5e1c72e1SJason King 208*5e1c72e1SJason King typedef struct ls_color { 209*5e1c72e1SJason King char *sfx; 210*5e1c72e1SJason King ls_cftype_t ftype; 211*5e1c72e1SJason King int attr; 212*5e1c72e1SJason King int fg; 213*5e1c72e1SJason King int bg; 214*5e1c72e1SJason King } ls_color_t; 215*5e1c72e1SJason King 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 2227c478bd9Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 2237c478bd9Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 2247c478bd9Sstevel@tonic-gate static char *curdir; /* the current directory */ 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 2277c478bd9Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 2287c478bd9Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 2297c478bd9Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 2307c478bd9Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 2317c478bd9Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 2347c478bd9Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 2357c478bd9Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 2367c478bd9Sstevel@tonic-gate static char *getname(uid_t); 2377c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 2387c478bd9Sstevel@tonic-gate static char *makename(char *, char *); 2397c478bd9Sstevel@tonic-gate static void pentry(struct lbuf *); 2407c478bd9Sstevel@tonic-gate static void column(void); 2417c478bd9Sstevel@tonic-gate static void pmode(mode_t aflag); 2427c478bd9Sstevel@tonic-gate static void selection(int *); 2437c478bd9Sstevel@tonic-gate static void new_line(void); 2447c478bd9Sstevel@tonic-gate static void rddir(char *, struct ditem *); 2457c478bd9Sstevel@tonic-gate static int strcol(unsigned char *); 2467c478bd9Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2477c478bd9Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2487c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2497c478bd9Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2507c478bd9Sstevel@tonic-gate static void pprintf(char *, char *); 2517c478bd9Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2527c478bd9Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2537c478bd9Sstevel@tonic-gate unsigned long long number, 2547c478bd9Sstevel@tonic-gate long scale); 2557c478bd9Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2567c478bd9Sstevel@tonic-gate int, struct ditem *); 257*5e1c72e1SJason King static void ls_color_init(void); 258*5e1c72e1SJason King static void ls_start_color(struct lbuf *); 259*5e1c72e1SJason King static void ls_end_color(void); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate static int aflg; 2627c478bd9Sstevel@tonic-gate static int atflg; 2637c478bd9Sstevel@tonic-gate static int bflg; 2647c478bd9Sstevel@tonic-gate static int cflg; 2657c478bd9Sstevel@tonic-gate static int dflg; 2667c478bd9Sstevel@tonic-gate static int eflg; 2677c478bd9Sstevel@tonic-gate static int fflg; 2687c478bd9Sstevel@tonic-gate static int gflg; 2697c478bd9Sstevel@tonic-gate static int hflg; 2707c478bd9Sstevel@tonic-gate static int iflg; 2717c478bd9Sstevel@tonic-gate static int lflg; 2727c478bd9Sstevel@tonic-gate static int mflg; 2737c478bd9Sstevel@tonic-gate static int nflg; 2747c478bd9Sstevel@tonic-gate static int oflg; 2757c478bd9Sstevel@tonic-gate static int pflg; 2767c478bd9Sstevel@tonic-gate static int qflg; 2777c478bd9Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2787c478bd9Sstevel@tonic-gate static int sflg; 2797c478bd9Sstevel@tonic-gate static int tflg; 2807c478bd9Sstevel@tonic-gate static int uflg; 281*5e1c72e1SJason King static int Uflg; 282*5e1c72e1SJason King static int wflg; 2837c478bd9Sstevel@tonic-gate static int xflg; 2847c478bd9Sstevel@tonic-gate static int Aflg; 285*5e1c72e1SJason King static int Bflg; 2867c478bd9Sstevel@tonic-gate static int Cflg; 2877c478bd9Sstevel@tonic-gate static int Eflg; 2887c478bd9Sstevel@tonic-gate static int Fflg; 2897c478bd9Sstevel@tonic-gate static int Hflg; 2907c478bd9Sstevel@tonic-gate static int Lflg; 2917c478bd9Sstevel@tonic-gate static int Rflg; 2927c478bd9Sstevel@tonic-gate static int Sflg; 293fa9e4066Sahrens static int vflg; 2945a5eeccaSmarks static int Vflg; 295da6c28aaSamw static int saflg; /* boolean extended system attr. */ 296da6c28aaSamw static int sacnt; /* number of extended system attr. */ 297da6c28aaSamw static int copt; 298da6c28aaSamw static int vopt; 299da6c28aaSamw static int tmflg; /* create time ext. system attr. */ 300da6c28aaSamw static int ctm; 301da6c28aaSamw static int atm; 302da6c28aaSamw static int mtm; 303da6c28aaSamw static int crtm; 304da6c28aaSamw static int alltm; 3057c478bd9Sstevel@tonic-gate static long hscale; 3067c478bd9Sstevel@tonic-gate static mode_t flags; 3077c478bd9Sstevel@tonic-gate static int err = 0; /* Contains return code */ 308*5e1c72e1SJason King static int colorflg; 309*5e1c72e1SJason King static int file_typeflg; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 3127c478bd9Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 3137c478bd9Sstevel@tonic-gate static char *lastuname = NULL; 3147c478bd9Sstevel@tonic-gate static char *lastgname = NULL; 3157c478bd9Sstevel@tonic-gate 316*5e1c72e1SJason King /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */ 3177c478bd9Sstevel@tonic-gate static int statreq; 3187c478bd9Sstevel@tonic-gate 319*5e1c72e1SJason King static uint64_t block_size = 1; 3207c478bd9Sstevel@tonic-gate static char *dotp = "."; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 3237c478bd9Sstevel@tonic-gate static time_t year, now; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate static int num_cols = 80; 3267c478bd9Sstevel@tonic-gate static int colwidth; 3277c478bd9Sstevel@tonic-gate static int filewidth; 3287c478bd9Sstevel@tonic-gate static int fixedwidth; 3297c478bd9Sstevel@tonic-gate static int nomocore; 3307c478bd9Sstevel@tonic-gate static int curcol; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate static struct winsize win; 3337c478bd9Sstevel@tonic-gate 334*5e1c72e1SJason King /* if time_fmt_new is left NULL, time_fmt_old is used for all times */ 335*5e1c72e1SJason King static const char *time_fmt_old = FORMAT_OLD; /* non-recent files */ 336*5e1c72e1SJason King static const char *time_fmt_new = FORMAT_NEW; /* recent files */ 337*5e1c72e1SJason King static int time_custom; /* != 0 if a custom format */ 338da6c28aaSamw static char time_buf[FMTSIZE]; /* array to hold day and time */ 3397c478bd9Sstevel@tonic-gate 340*5e1c72e1SJason King static int lsc_debug; 341*5e1c72e1SJason King static ls_color_t *lsc_match; 342*5e1c72e1SJason King static ls_color_t *lsc_colors; 343*5e1c72e1SJason King static size_t lsc_ncolors; 344*5e1c72e1SJason King static char *lsc_bold; 345*5e1c72e1SJason King static char *lsc_underline; 346*5e1c72e1SJason King static char *lsc_blink; 347*5e1c72e1SJason King static char *lsc_reverse; 348*5e1c72e1SJason King static char *lsc_concealed; 349*5e1c72e1SJason King static char *lsc_none; 350*5e1c72e1SJason King static char *lsc_setfg; 351*5e1c72e1SJason King static char *lsc_setbg; 352*5e1c72e1SJason King 3537c478bd9Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 3547c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 3577c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 358da6c28aaSamw /* Extended system attributes support */ 359da6c28aaSamw static int get_sysxattr(char *, struct lbuf *); 360da6c28aaSamw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 361da6c28aaSamw static void set_sysattrtm_display(char *, struct lbuf *); 362*5e1c72e1SJason King static void format_time(time_t, time_t); 363da6c28aaSamw static void print_time(struct lbuf *); 364da6c28aaSamw static void format_attrtime(struct lbuf *); 365da6c28aaSamw static void *xmalloc(size_t, struct lbuf *); 366da6c28aaSamw static void free_sysattr(struct lbuf *); 367da6c28aaSamw static nvpair_t *pair; 368da6c28aaSamw static nvlist_t *response; 36956798e90Sbasabi static int acl_err; 3707c478bd9Sstevel@tonic-gate 371*5e1c72e1SJason King const struct option long_options[] = { 372*5e1c72e1SJason King { "all", no_argument, NULL, 'a' }, 373*5e1c72e1SJason King { "almost-all", no_argument, NULL, 'A' }, 374*5e1c72e1SJason King { "escape", no_argument, NULL, 'b' }, 375*5e1c72e1SJason King { "classify", no_argument, NULL, 'F' }, 376*5e1c72e1SJason King { "human-readable", no_argument, NULL, 'h' }, 377*5e1c72e1SJason King { "dereference", no_argument, NULL, 'L' }, 378*5e1c72e1SJason King { "dereference-command-line", no_argument, NULL, 'H' }, 379*5e1c72e1SJason King { "ignore-backups", no_argument, NULL, 'B' }, 380*5e1c72e1SJason King { "inode", no_argument, NULL, 'i' }, 381*5e1c72e1SJason King { "numeric-uid-gid", no_argument, NULL, 'n' }, 382*5e1c72e1SJason King { "no-group", no_argument, NULL, 'o' }, 383*5e1c72e1SJason King { "hide-control-chars", no_argument, NULL, 'q' }, 384*5e1c72e1SJason King { "reverse", no_argument, NULL, 'r' }, 385*5e1c72e1SJason King { "recursive", no_argument, NULL, 'R' }, 386*5e1c72e1SJason King { "size", no_argument, NULL, 's' }, 387*5e1c72e1SJason King { "width", required_argument, NULL, 'w' }, 388*5e1c72e1SJason King 389*5e1c72e1SJason King /* no short options for these */ 390*5e1c72e1SJason King { "block-size", required_argument, NULL, 0 }, 391*5e1c72e1SJason King { "full-time", no_argument, NULL, 0 }, 392*5e1c72e1SJason King { "si", no_argument, NULL, 0 }, 393*5e1c72e1SJason King { "color", optional_argument, NULL, 0 }, 394*5e1c72e1SJason King { "colour", optional_argument, NULL, 0}, 395*5e1c72e1SJason King { "file-type", no_argument, NULL, 0 }, 396*5e1c72e1SJason King { "time-style", required_argument, NULL, 0 }, 397*5e1c72e1SJason King 398*5e1c72e1SJason King {0, 0, 0, 0} 399*5e1c72e1SJason King }; 400*5e1c72e1SJason King 4017c478bd9Sstevel@tonic-gate int 4027c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate int c; 4057c478bd9Sstevel@tonic-gate int i; 4067c478bd9Sstevel@tonic-gate int width; 4077c478bd9Sstevel@tonic-gate int amino = 0; 4087c478bd9Sstevel@tonic-gate int opterr = 0; 409*5e1c72e1SJason King int option_index = 0; 4107c478bd9Sstevel@tonic-gate struct lbuf *ep; 4117c478bd9Sstevel@tonic-gate struct lbuf lb; 4127c478bd9Sstevel@tonic-gate struct ditem *myinfo; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4157c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 4167c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 4177c478bd9Sstevel@tonic-gate #endif 4187c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4197c478bd9Sstevel@tonic-gate #ifdef STANDALONE 4207c478bd9Sstevel@tonic-gate if (argv[0][0] == '\0') 4217c478bd9Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 4227c478bd9Sstevel@tonic-gate #endif 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 4257c478bd9Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 4267c478bd9Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 4277c478bd9Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 4287c478bd9Sstevel@tonic-gate if (isatty(1)) { 4297c478bd9Sstevel@tonic-gate Cflg = 1; 4307c478bd9Sstevel@tonic-gate mflg = 0; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 433*5e1c72e1SJason King while ((c = getopt_long(argc, argv, 434*5e1c72e1SJason King "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options, 435*5e1c72e1SJason King &option_index)) != -1) 4367c478bd9Sstevel@tonic-gate switch (c) { 437*5e1c72e1SJason King case 0: 438*5e1c72e1SJason King /* non-short options */ 439*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 440*5e1c72e1SJason King "color") == 0 || 441*5e1c72e1SJason King strcmp(long_options[option_index].name, 442*5e1c72e1SJason King "colour") == 0) { 443*5e1c72e1SJason King if (optarg == NULL || 444*5e1c72e1SJason King strcmp(optarg, "always") == 0 || 445*5e1c72e1SJason King strcmp(optarg, "yes") == 0 || 446*5e1c72e1SJason King strcmp(optarg, "force") == 0) { 447*5e1c72e1SJason King colorflg++; 448*5e1c72e1SJason King statreq++; 449*5e1c72e1SJason King continue; 450*5e1c72e1SJason King } 451*5e1c72e1SJason King 452*5e1c72e1SJason King if ((strcmp(optarg, "auto") == 0 || 453*5e1c72e1SJason King strcmp(optarg, "tty") == 0 || 454*5e1c72e1SJason King strcmp(optarg, "if-tty") == 0) && 455*5e1c72e1SJason King isatty(1) == 1) { 456*5e1c72e1SJason King colorflg++; 457*5e1c72e1SJason King statreq++; 458*5e1c72e1SJason King continue; 459*5e1c72e1SJason King } 460*5e1c72e1SJason King 461*5e1c72e1SJason King if (strcmp(optarg, "never") == 0 || 462*5e1c72e1SJason King strcmp(optarg, "no") == 0 || 463*5e1c72e1SJason King strcmp(optarg, "none") == 0) { 464*5e1c72e1SJason King colorflg = 0; 465*5e1c72e1SJason King continue; 466*5e1c72e1SJason King } 467*5e1c72e1SJason King (void) fprintf(stderr, 468*5e1c72e1SJason King gettext("Invalid argument '%s' for " 469*5e1c72e1SJason King "--color\n"), optarg); 470*5e1c72e1SJason King ++opterr; 471*5e1c72e1SJason King continue; 472*5e1c72e1SJason King } 473*5e1c72e1SJason King 474*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 475*5e1c72e1SJason King "si") == 0) { 476*5e1c72e1SJason King hflg++; 477*5e1c72e1SJason King hscale = 1000; 478*5e1c72e1SJason King continue; 479*5e1c72e1SJason King } 480*5e1c72e1SJason King 481*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 482*5e1c72e1SJason King "block-size") == 0) { 483*5e1c72e1SJason King size_t scale_len = strlen(optarg); 484*5e1c72e1SJason King uint64_t scale = 1; 485*5e1c72e1SJason King uint64_t kilo = 1024; 486*5e1c72e1SJason King char scale_c; 487*5e1c72e1SJason King 488*5e1c72e1SJason King if (scale_len == 0) { 489*5e1c72e1SJason King (void) fprintf(stderr, gettext( 490*5e1c72e1SJason King "Invalid block size \'%s\'\n"), 491*5e1c72e1SJason King optarg); 492*5e1c72e1SJason King exit(1); 493*5e1c72e1SJason King } 494*5e1c72e1SJason King 495*5e1c72e1SJason King scale_c = optarg[scale_len - 1]; 496*5e1c72e1SJason King if (scale_c == 'B') { 497*5e1c72e1SJason King /* need at least digit, scale, B */ 498*5e1c72e1SJason King if (scale_len < 3) { 499*5e1c72e1SJason King (void) fprintf(stderr, gettext( 500*5e1c72e1SJason King "Invalid block size " 501*5e1c72e1SJason King "\'%s\'\n"), optarg); 502*5e1c72e1SJason King exit(1); 503*5e1c72e1SJason King } 504*5e1c72e1SJason King kilo = 1000; 505*5e1c72e1SJason King scale_c = optarg[scale_len - 2]; 506*5e1c72e1SJason King if (isdigit(scale_c)) { 507*5e1c72e1SJason King (void) fprintf(stderr, 508*5e1c72e1SJason King gettext("Invalid block size" 509*5e1c72e1SJason King " \'%s\'\n"), optarg); 510*5e1c72e1SJason King exit(1); 511*5e1c72e1SJason King } 512*5e1c72e1SJason King /* 513*5e1c72e1SJason King * make optarg[scale_len - 1] point to 514*5e1c72e1SJason King * the scale factor 515*5e1c72e1SJason King */ 516*5e1c72e1SJason King --scale_len; 517*5e1c72e1SJason King } 518*5e1c72e1SJason King 519*5e1c72e1SJason King switch (scale_c) { 520*5e1c72e1SJason King case 'y': 521*5e1c72e1SJason King case 'Y': 522*5e1c72e1SJason King scale *= kilo; 523*5e1c72e1SJason King /*FALLTHROUGH*/ 524*5e1c72e1SJason King case 'Z': 525*5e1c72e1SJason King case 'z': 526*5e1c72e1SJason King scale *= kilo; 527*5e1c72e1SJason King /*FALLTHROUGH*/ 528*5e1c72e1SJason King case 'E': 529*5e1c72e1SJason King case 'e': 530*5e1c72e1SJason King scale *= kilo; 531*5e1c72e1SJason King /*FALLTHROUGH*/ 532*5e1c72e1SJason King case 'P': 533*5e1c72e1SJason King case 'p': 534*5e1c72e1SJason King scale *= kilo; 535*5e1c72e1SJason King /*FALLTHROUGH*/ 536*5e1c72e1SJason King case 'T': 537*5e1c72e1SJason King case 't': 538*5e1c72e1SJason King scale *= kilo; 539*5e1c72e1SJason King /*FALLTHROUGH*/ 540*5e1c72e1SJason King case 'G': 541*5e1c72e1SJason King case 'g': 542*5e1c72e1SJason King scale *= kilo; 543*5e1c72e1SJason King /*FALLTHROUGH*/ 544*5e1c72e1SJason King case 'M': 545*5e1c72e1SJason King case 'm': 546*5e1c72e1SJason King scale *= kilo; 547*5e1c72e1SJason King /*FALLTHROUGH*/ 548*5e1c72e1SJason King case 'K': 549*5e1c72e1SJason King case 'k': 550*5e1c72e1SJason King scale *= kilo; 551*5e1c72e1SJason King break; 552*5e1c72e1SJason King default: 553*5e1c72e1SJason King if (!isdigit(scale_c)) { 554*5e1c72e1SJason King (void) fprintf(stderr, 555*5e1c72e1SJason King gettext("Invalid character " 556*5e1c72e1SJason King "following block size in " 557*5e1c72e1SJason King "\'%s\'\n"), optarg); 558*5e1c72e1SJason King exit(1); 559*5e1c72e1SJason King } 560*5e1c72e1SJason King } 561*5e1c72e1SJason King 562*5e1c72e1SJason King /* NULL out scale constant if present */ 563*5e1c72e1SJason King if (scale > 1 && !isdigit(scale_c)) 564*5e1c72e1SJason King optarg[scale_len - 1] = '\0'; 565*5e1c72e1SJason King 566*5e1c72e1SJason King /* Based on testing, this is what GNU ls does */ 567*5e1c72e1SJason King block_size = strtoll(optarg, NULL, 0) * scale; 568*5e1c72e1SJason King if (block_size < 1) { 569*5e1c72e1SJason King (void) fprintf(stderr, 570*5e1c72e1SJason King gettext("Invalid block size " 571*5e1c72e1SJason King "\'%s\'\n"), optarg); 572*5e1c72e1SJason King exit(1); 573*5e1c72e1SJason King } 574*5e1c72e1SJason King continue; 575*5e1c72e1SJason King } 576*5e1c72e1SJason King 577*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 578*5e1c72e1SJason King "file-type") == 0) { 579*5e1c72e1SJason King file_typeflg++; 580*5e1c72e1SJason King Fflg++; 581*5e1c72e1SJason King statreq++; 582*5e1c72e1SJason King continue; 583*5e1c72e1SJason King } 584*5e1c72e1SJason King 585*5e1c72e1SJason King 586*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 587*5e1c72e1SJason King "full-time") == 0) { 588*5e1c72e1SJason King Eflg++; 589*5e1c72e1SJason King statreq++; 590*5e1c72e1SJason King eflg = 0; 591*5e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 592*5e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 593*5e1c72e1SJason King continue; 594*5e1c72e1SJason King } 595*5e1c72e1SJason King 596*5e1c72e1SJason King if (strcmp(long_options[option_index].name, 597*5e1c72e1SJason King "time-style") == 0) { 598*5e1c72e1SJason King /* like -E, but doesn't imply -l */ 599*5e1c72e1SJason King if (strcmp(optarg, "full-iso") == 0) { 600*5e1c72e1SJason King Eflg++; 601*5e1c72e1SJason King statreq++; 602*5e1c72e1SJason King eflg = 0; 603*5e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 604*5e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 605*5e1c72e1SJason King continue; 606*5e1c72e1SJason King } 607*5e1c72e1SJason King if (strcmp(optarg, "long-iso") == 0) { 608*5e1c72e1SJason King statreq++; 609*5e1c72e1SJason King Eflg = 0; 610*5e1c72e1SJason King eflg = 0; 611*5e1c72e1SJason King time_fmt_old = FORMAT_ISO_LONG; 612*5e1c72e1SJason King time_fmt_new = FORMAT_ISO_LONG; 613*5e1c72e1SJason King continue; 614*5e1c72e1SJason King } 615*5e1c72e1SJason King if (strcmp(optarg, "iso") == 0) { 616*5e1c72e1SJason King statreq++; 617*5e1c72e1SJason King Eflg = 0; 618*5e1c72e1SJason King eflg = 0; 619*5e1c72e1SJason King time_fmt_old = FORMAT_ISO_OLD; 620*5e1c72e1SJason King time_fmt_new = FORMAT_ISO_NEW; 621*5e1c72e1SJason King continue; 622*5e1c72e1SJason King } 623*5e1c72e1SJason King /* should be the default */ 624*5e1c72e1SJason King if (strcmp(optarg, "locale") == 0) { 625*5e1c72e1SJason King time_fmt_old = FORMAT_OLD; 626*5e1c72e1SJason King time_fmt_new = FORMAT_NEW; 627*5e1c72e1SJason King continue; 628*5e1c72e1SJason King } 629*5e1c72e1SJason King if (optarg[0] == '+') { 630*5e1c72e1SJason King char *told, *tnew; 631*5e1c72e1SJason King char *p; 632*5e1c72e1SJason King size_t timelen = strlen(optarg); 633*5e1c72e1SJason King 634*5e1c72e1SJason King p = strchr(optarg, '\n'); 635*5e1c72e1SJason King if (p != NULL) 636*5e1c72e1SJason King *p++ = '\0'; 637*5e1c72e1SJason King 638*5e1c72e1SJason King /* 639*5e1c72e1SJason King * Time format requires a leading and 640*5e1c72e1SJason King * trailing space 641*5e1c72e1SJason King * Add room for 3 spaces + 2 nulls 642*5e1c72e1SJason King * The + in optarg is replaced with 643*5e1c72e1SJason King * a space. 644*5e1c72e1SJason King */ 645*5e1c72e1SJason King timelen += 2 + 3; 646*5e1c72e1SJason King told = malloc(timelen); 647*5e1c72e1SJason King if (told == NULL) { 648*5e1c72e1SJason King perror("Out of memory"); 649*5e1c72e1SJason King exit(1); 650*5e1c72e1SJason King } 651*5e1c72e1SJason King 652*5e1c72e1SJason King (void) memset(told, 0, timelen); 653*5e1c72e1SJason King told[0] = ' '; 654*5e1c72e1SJason King (void) strlcat(told, &optarg[1], 655*5e1c72e1SJason King timelen); 656*5e1c72e1SJason King (void) strlcat(told, " ", timelen); 657*5e1c72e1SJason King 658*5e1c72e1SJason King if (p != NULL) { 659*5e1c72e1SJason King size_t tnew_len; 660*5e1c72e1SJason King 661*5e1c72e1SJason King tnew = told + strlen(told) + 1; 662*5e1c72e1SJason King tnew_len = timelen - 663*5e1c72e1SJason King strlen(told) - 1; 664*5e1c72e1SJason King 665*5e1c72e1SJason King tnew[0] = ' '; 666*5e1c72e1SJason King (void) strlcat(tnew, p, 667*5e1c72e1SJason King tnew_len); 668*5e1c72e1SJason King (void) strlcat(tnew, " ", 669*5e1c72e1SJason King tnew_len); 670*5e1c72e1SJason King time_fmt_new = 671*5e1c72e1SJason King (const char *)tnew; 672*5e1c72e1SJason King } else { 673*5e1c72e1SJason King time_fmt_new = 674*5e1c72e1SJason King (const char *)told; 675*5e1c72e1SJason King } 676*5e1c72e1SJason King 677*5e1c72e1SJason King time_fmt_old = (const char *)told; 678*5e1c72e1SJason King time_custom = 1; 679*5e1c72e1SJason King continue; 680*5e1c72e1SJason King } 681*5e1c72e1SJason King continue; 682*5e1c72e1SJason King } 683*5e1c72e1SJason King 684*5e1c72e1SJason King continue; 685*5e1c72e1SJason King 6867c478bd9Sstevel@tonic-gate case 'a': 6877c478bd9Sstevel@tonic-gate aflg++; 6887c478bd9Sstevel@tonic-gate continue; 6897c478bd9Sstevel@tonic-gate case 'A': 6907c478bd9Sstevel@tonic-gate Aflg++; 6917c478bd9Sstevel@tonic-gate continue; 6927c478bd9Sstevel@tonic-gate case 'b': 6937c478bd9Sstevel@tonic-gate bflg = 1; 6947c478bd9Sstevel@tonic-gate qflg = 0; 6957c478bd9Sstevel@tonic-gate continue; 696*5e1c72e1SJason King case 'B': 697*5e1c72e1SJason King Bflg = 1; 698*5e1c72e1SJason King continue; 6997c478bd9Sstevel@tonic-gate case 'c': 7007c478bd9Sstevel@tonic-gate uflg = 0; 701da6c28aaSamw atm = 0; 702da6c28aaSamw ctm = 0; 703da6c28aaSamw mtm = 0; 704da6c28aaSamw crtm = 0; 7057c478bd9Sstevel@tonic-gate cflg++; 7067c478bd9Sstevel@tonic-gate continue; 7077c478bd9Sstevel@tonic-gate case 'C': 7087c478bd9Sstevel@tonic-gate Cflg = 1; 7097c478bd9Sstevel@tonic-gate mflg = 0; 7107c478bd9Sstevel@tonic-gate #ifdef XPG4 7117c478bd9Sstevel@tonic-gate lflg = 0; 7127c478bd9Sstevel@tonic-gate #endif 7137c478bd9Sstevel@tonic-gate continue; 7147c478bd9Sstevel@tonic-gate case 'd': 7157c478bd9Sstevel@tonic-gate dflg++; 7167c478bd9Sstevel@tonic-gate continue; 7177c478bd9Sstevel@tonic-gate case 'e': 7187c478bd9Sstevel@tonic-gate eflg++; 7197c478bd9Sstevel@tonic-gate lflg++; 7207c478bd9Sstevel@tonic-gate statreq++; 7217c478bd9Sstevel@tonic-gate Eflg = 0; 722*5e1c72e1SJason King time_fmt_old = FORMAT_LONG; 723*5e1c72e1SJason King time_fmt_new = FORMAT_LONG; 7247c478bd9Sstevel@tonic-gate continue; 7257c478bd9Sstevel@tonic-gate case 'E': 7267c478bd9Sstevel@tonic-gate Eflg++; 7277c478bd9Sstevel@tonic-gate lflg++; 7287c478bd9Sstevel@tonic-gate statreq++; 7297c478bd9Sstevel@tonic-gate eflg = 0; 730*5e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 731*5e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 7327c478bd9Sstevel@tonic-gate continue; 7337c478bd9Sstevel@tonic-gate case 'f': 7347c478bd9Sstevel@tonic-gate fflg++; 7357c478bd9Sstevel@tonic-gate continue; 7367c478bd9Sstevel@tonic-gate case 'F': 7377c478bd9Sstevel@tonic-gate Fflg++; 7387c478bd9Sstevel@tonic-gate statreq++; 7397c478bd9Sstevel@tonic-gate continue; 7407c478bd9Sstevel@tonic-gate case 'g': 7417c478bd9Sstevel@tonic-gate gflg++; 7427c478bd9Sstevel@tonic-gate lflg++; 7437c478bd9Sstevel@tonic-gate statreq++; 7447c478bd9Sstevel@tonic-gate continue; 7457c478bd9Sstevel@tonic-gate case 'h': 7467c478bd9Sstevel@tonic-gate hflg++; 7477c478bd9Sstevel@tonic-gate hscale = 1024; 7487c478bd9Sstevel@tonic-gate continue; 7497c478bd9Sstevel@tonic-gate case 'H': 7507c478bd9Sstevel@tonic-gate Hflg++; 7517c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7527c478bd9Sstevel@tonic-gate Lflg = 0; 7537c478bd9Sstevel@tonic-gate continue; 7547c478bd9Sstevel@tonic-gate case 'i': 7557c478bd9Sstevel@tonic-gate iflg++; 7567c478bd9Sstevel@tonic-gate continue; 757*5e1c72e1SJason King case 'k': 758*5e1c72e1SJason King block_size = 1024; 759*5e1c72e1SJason King continue; 7607c478bd9Sstevel@tonic-gate case 'l': 7617c478bd9Sstevel@tonic-gate lflg++; 7627c478bd9Sstevel@tonic-gate statreq++; 7637c478bd9Sstevel@tonic-gate Cflg = 0; 7647c478bd9Sstevel@tonic-gate xflg = 0; 7657c478bd9Sstevel@tonic-gate mflg = 0; 7667c478bd9Sstevel@tonic-gate atflg = 0; 7677c478bd9Sstevel@tonic-gate continue; 7687c478bd9Sstevel@tonic-gate case 'L': 7697c478bd9Sstevel@tonic-gate Lflg++; 7707c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7717c478bd9Sstevel@tonic-gate Hflg = 0; 7727c478bd9Sstevel@tonic-gate continue; 7737c478bd9Sstevel@tonic-gate case 'm': 7747c478bd9Sstevel@tonic-gate Cflg = 0; 7757c478bd9Sstevel@tonic-gate mflg = 1; 7767c478bd9Sstevel@tonic-gate #ifdef XPG4 7777c478bd9Sstevel@tonic-gate lflg = 0; 7787c478bd9Sstevel@tonic-gate #endif 7797c478bd9Sstevel@tonic-gate continue; 7807c478bd9Sstevel@tonic-gate case 'n': 7817c478bd9Sstevel@tonic-gate nflg++; 7827c478bd9Sstevel@tonic-gate lflg++; 7837c478bd9Sstevel@tonic-gate statreq++; 7847c478bd9Sstevel@tonic-gate Cflg = 0; 7857c478bd9Sstevel@tonic-gate xflg = 0; 7867c478bd9Sstevel@tonic-gate mflg = 0; 7877c478bd9Sstevel@tonic-gate atflg = 0; 7887c478bd9Sstevel@tonic-gate continue; 7897c478bd9Sstevel@tonic-gate case 'o': 7907c478bd9Sstevel@tonic-gate oflg++; 7917c478bd9Sstevel@tonic-gate lflg++; 7927c478bd9Sstevel@tonic-gate statreq++; 7937c478bd9Sstevel@tonic-gate continue; 7947c478bd9Sstevel@tonic-gate case 'p': 7957c478bd9Sstevel@tonic-gate pflg++; 7967c478bd9Sstevel@tonic-gate statreq++; 7977c478bd9Sstevel@tonic-gate continue; 7987c478bd9Sstevel@tonic-gate case 'q': 7997c478bd9Sstevel@tonic-gate qflg = 1; 8007c478bd9Sstevel@tonic-gate bflg = 0; 8017c478bd9Sstevel@tonic-gate continue; 8027c478bd9Sstevel@tonic-gate case 'r': 8037c478bd9Sstevel@tonic-gate rflg = -1; 8047c478bd9Sstevel@tonic-gate continue; 8057c478bd9Sstevel@tonic-gate case 'R': 8067c478bd9Sstevel@tonic-gate Rflg++; 8077c478bd9Sstevel@tonic-gate statreq++; 8087c478bd9Sstevel@tonic-gate continue; 8097c478bd9Sstevel@tonic-gate case 's': 8107c478bd9Sstevel@tonic-gate sflg++; 8117c478bd9Sstevel@tonic-gate statreq++; 8127c478bd9Sstevel@tonic-gate continue; 8137c478bd9Sstevel@tonic-gate case 'S': 8147c478bd9Sstevel@tonic-gate tflg = 0; 815*5e1c72e1SJason King Uflg = 0; 8167c478bd9Sstevel@tonic-gate Sflg++; 8177c478bd9Sstevel@tonic-gate statreq++; 8187c478bd9Sstevel@tonic-gate continue; 8197c478bd9Sstevel@tonic-gate case 't': 8207c478bd9Sstevel@tonic-gate Sflg = 0; 821*5e1c72e1SJason King Uflg = 0; 8227c478bd9Sstevel@tonic-gate tflg++; 8237c478bd9Sstevel@tonic-gate statreq++; 8247c478bd9Sstevel@tonic-gate continue; 825*5e1c72e1SJason King case 'U': 826*5e1c72e1SJason King Sflg = 0; 827*5e1c72e1SJason King tflg = 0; 828*5e1c72e1SJason King Uflg++; 829*5e1c72e1SJason King continue; 8307c478bd9Sstevel@tonic-gate case 'u': 8317c478bd9Sstevel@tonic-gate cflg = 0; 832da6c28aaSamw atm = 0; 833da6c28aaSamw ctm = 0; 834da6c28aaSamw mtm = 0; 835da6c28aaSamw crtm = 0; 8367c478bd9Sstevel@tonic-gate uflg++; 8377c478bd9Sstevel@tonic-gate continue; 8385a5eeccaSmarks case 'V': 8395a5eeccaSmarks Vflg++; 8405a5eeccaSmarks /*FALLTHROUGH*/ 841fa9e4066Sahrens case 'v': 842fa9e4066Sahrens vflg++; 843fa9e4066Sahrens #if !defined(XPG4) 844fa9e4066Sahrens if (lflg) 845fa9e4066Sahrens continue; 846fa9e4066Sahrens #endif 847fa9e4066Sahrens lflg++; 848fa9e4066Sahrens statreq++; 849fa9e4066Sahrens Cflg = 0; 850fa9e4066Sahrens xflg = 0; 851fa9e4066Sahrens mflg = 0; 852fa9e4066Sahrens continue; 853*5e1c72e1SJason King case 'w': 854*5e1c72e1SJason King wflg++; 855*5e1c72e1SJason King num_cols = atoi(optarg); 856*5e1c72e1SJason King continue; 8577c478bd9Sstevel@tonic-gate case 'x': 8587c478bd9Sstevel@tonic-gate xflg = 1; 8597c478bd9Sstevel@tonic-gate Cflg = 1; 8607c478bd9Sstevel@tonic-gate mflg = 0; 8617c478bd9Sstevel@tonic-gate #ifdef XPG4 8627c478bd9Sstevel@tonic-gate lflg = 0; 8637c478bd9Sstevel@tonic-gate #endif 8647c478bd9Sstevel@tonic-gate continue; 8657c478bd9Sstevel@tonic-gate case '1': 8667c478bd9Sstevel@tonic-gate Cflg = 0; 8677c478bd9Sstevel@tonic-gate continue; 8687c478bd9Sstevel@tonic-gate case '@': 8697c478bd9Sstevel@tonic-gate #if !defined(XPG4) 8707c478bd9Sstevel@tonic-gate /* 8717c478bd9Sstevel@tonic-gate * -l has precedence over -@ 8727c478bd9Sstevel@tonic-gate */ 8737c478bd9Sstevel@tonic-gate if (lflg) 8747c478bd9Sstevel@tonic-gate continue; 8757c478bd9Sstevel@tonic-gate #endif 8767c478bd9Sstevel@tonic-gate atflg++; 8777c478bd9Sstevel@tonic-gate lflg++; 8787c478bd9Sstevel@tonic-gate statreq++; 8797c478bd9Sstevel@tonic-gate Cflg = 0; 8807c478bd9Sstevel@tonic-gate xflg = 0; 8817c478bd9Sstevel@tonic-gate mflg = 0; 8827c478bd9Sstevel@tonic-gate continue; 883da6c28aaSamw case '/': 884da6c28aaSamw saflg++; 885da6c28aaSamw if (optarg != NULL) { 886da6c28aaSamw if (strcmp(optarg, "c") == 0) { 887da6c28aaSamw copt++; 888da6c28aaSamw vopt = 0; 889da6c28aaSamw } else if (strcmp(optarg, "v") == 0) { 890da6c28aaSamw vopt++; 891da6c28aaSamw copt = 0; 892da6c28aaSamw } else 893da6c28aaSamw opterr++; 894da6c28aaSamw } else 895da6c28aaSamw opterr++; 896da6c28aaSamw lflg++; 897da6c28aaSamw statreq++; 898da6c28aaSamw Cflg = 0; 899da6c28aaSamw xflg = 0; 900da6c28aaSamw mflg = 0; 901da6c28aaSamw continue; 902da6c28aaSamw case '%': 903da6c28aaSamw tmflg++; 904da6c28aaSamw if (optarg != NULL) { 905da6c28aaSamw if (strcmp(optarg, "ctime") == 0) { 906da6c28aaSamw ctm++; 907da6c28aaSamw atm = 0; 908da6c28aaSamw mtm = 0; 909da6c28aaSamw crtm = 0; 910da6c28aaSamw } else if (strcmp(optarg, "atime") == 0) { 911da6c28aaSamw atm++; 912da6c28aaSamw ctm = 0; 913da6c28aaSamw mtm = 0; 914da6c28aaSamw crtm = 0; 915da6c28aaSamw uflg = 0; 916da6c28aaSamw cflg = 0; 917da6c28aaSamw } else if (strcmp(optarg, "mtime") == 0) { 918da6c28aaSamw mtm++; 919da6c28aaSamw atm = 0; 920da6c28aaSamw ctm = 0; 921da6c28aaSamw crtm = 0; 922da6c28aaSamw uflg = 0; 923da6c28aaSamw cflg = 0; 924da6c28aaSamw } else if (strcmp(optarg, "crtime") == 0) { 925da6c28aaSamw crtm++; 926da6c28aaSamw atm = 0; 927da6c28aaSamw ctm = 0; 928da6c28aaSamw mtm = 0; 929da6c28aaSamw uflg = 0; 930da6c28aaSamw cflg = 0; 931da6c28aaSamw } else if (strcmp(optarg, "all") == 0) { 932da6c28aaSamw alltm++; 933da6c28aaSamw atm = 0; 934da6c28aaSamw ctm = 0; 935da6c28aaSamw mtm = 0; 936da6c28aaSamw crtm = 0; 937da6c28aaSamw } else 938da6c28aaSamw opterr++; 939da6c28aaSamw } else 940da6c28aaSamw opterr++; 941da6c28aaSamw 942da6c28aaSamw Sflg = 0; 943da6c28aaSamw statreq++; 944da6c28aaSamw mflg = 0; 945da6c28aaSamw continue; 9467c478bd9Sstevel@tonic-gate case '?': 9477c478bd9Sstevel@tonic-gate opterr++; 9487c478bd9Sstevel@tonic-gate continue; 9497c478bd9Sstevel@tonic-gate } 950*5e1c72e1SJason King 9517c478bd9Sstevel@tonic-gate if (opterr) { 9527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 953*5e1c72e1SJason King "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]" 954da6c28aaSamw "%%[atime | crtime | ctime | mtime | all]" 955da6c28aaSamw " [files]\n")); 9567c478bd9Sstevel@tonic-gate exit(2); 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (fflg) { 9607c478bd9Sstevel@tonic-gate aflg++; 9617c478bd9Sstevel@tonic-gate lflg = 0; 9627c478bd9Sstevel@tonic-gate sflg = 0; 9637c478bd9Sstevel@tonic-gate tflg = 0; 9647c478bd9Sstevel@tonic-gate Sflg = 0; 9657c478bd9Sstevel@tonic-gate statreq = 0; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate fixedwidth = 2; 9697c478bd9Sstevel@tonic-gate if (pflg || Fflg) 9707c478bd9Sstevel@tonic-gate fixedwidth++; 9717c478bd9Sstevel@tonic-gate if (iflg) 9727c478bd9Sstevel@tonic-gate fixedwidth += 11; 9737c478bd9Sstevel@tonic-gate if (sflg) 9747c478bd9Sstevel@tonic-gate fixedwidth += 5; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate if (lflg) { 9777c478bd9Sstevel@tonic-gate if (!gflg && !oflg) 9787c478bd9Sstevel@tonic-gate gflg = oflg = 1; 9797c478bd9Sstevel@tonic-gate else 9807c478bd9Sstevel@tonic-gate if (gflg && oflg) 9817c478bd9Sstevel@tonic-gate gflg = oflg = 0; 9827c478bd9Sstevel@tonic-gate Cflg = mflg = 0; 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 985*5e1c72e1SJason King if (!wflg && (Cflg || mflg)) { 9867c478bd9Sstevel@tonic-gate char *clptr; 9877c478bd9Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 9887c478bd9Sstevel@tonic-gate num_cols = atoi(clptr); 9897c478bd9Sstevel@tonic-gate #ifdef TERMINFO 9907c478bd9Sstevel@tonic-gate else { 9917c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 9927c478bd9Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate #endif 995*5e1c72e1SJason King } 996*5e1c72e1SJason King 9977c478bd9Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 9987c478bd9Sstevel@tonic-gate /* assume it is an error */ 9997c478bd9Sstevel@tonic-gate num_cols = 80; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* allocate space for flist and the associated */ 10027c478bd9Sstevel@tonic-gate /* data structures (lbufs) */ 10037c478bd9Sstevel@tonic-gate maxfils = quantn; 10047c478bd9Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 10057c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 10067c478bd9Sstevel@tonic-gate perror("ls"); 10077c478bd9Sstevel@tonic-gate exit(2); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 10107c478bd9Sstevel@tonic-gate /* 10117c478bd9Sstevel@tonic-gate * case when no names are given 10127c478bd9Sstevel@tonic-gate * in ls-command and current 10137c478bd9Sstevel@tonic-gate * directory is to be used 10147c478bd9Sstevel@tonic-gate */ 10157c478bd9Sstevel@tonic-gate argv[optind] = dotp; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 10227c478bd9Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 10237c478bd9Sstevel@tonic-gate * (actually, just the directories) visited, we 10247c478bd9Sstevel@tonic-gate * maintain a directory ancestry list for a file 10257c478bd9Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 10267c478bd9Sstevel@tonic-gate * a parent directory passes its directory list 10277c478bd9Sstevel@tonic-gate * info (device id, inode number, and a pointer to 10287c478bd9Sstevel@tonic-gate * its parent) to each of its children. As we 10297c478bd9Sstevel@tonic-gate * process a child that is a directory, we save 10307c478bd9Sstevel@tonic-gate * its own personal directory list info. We then 10317c478bd9Sstevel@tonic-gate * check to see if the child has already been 10327c478bd9Sstevel@tonic-gate * processed by comparing its device id and inode 10337c478bd9Sstevel@tonic-gate * number from its own personal directory list info 10347c478bd9Sstevel@tonic-gate * to that of each of its ancestors. If there is a 10357c478bd9Sstevel@tonic-gate * match, then we know we've detected a cycle. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate if (Rflg) { 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * This is the first parent in this lineage 10407c478bd9Sstevel@tonic-gate * (first in a directory hierarchy), so 10417c478bd9Sstevel@tonic-gate * this parent's parent doesn't exist. We 10427c478bd9Sstevel@tonic-gate * only initialize myinfo when we are 10437c478bd9Sstevel@tonic-gate * recursing, otherwise it's not used. 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 10467c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 10477c478bd9Sstevel@tonic-gate perror("ls"); 10487c478bd9Sstevel@tonic-gate exit(2); 10497c478bd9Sstevel@tonic-gate } else { 10507c478bd9Sstevel@tonic-gate myinfo->dev = 0; 10517c478bd9Sstevel@tonic-gate myinfo->ino = 0; 10527c478bd9Sstevel@tonic-gate myinfo->parent = NULL; 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 10577c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 10587c478bd9Sstevel@tonic-gate if (width > filewidth) 10597c478bd9Sstevel@tonic-gate filewidth = width; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 10627c478bd9Sstevel@tonic-gate 1, myinfo)) == NULL) { 10637c478bd9Sstevel@tonic-gate if (nomocore) 10647c478bd9Sstevel@tonic-gate exit(2); 10657c478bd9Sstevel@tonic-gate err = 2; 10667c478bd9Sstevel@tonic-gate optind++; 10677c478bd9Sstevel@tonic-gate continue; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 10707c478bd9Sstevel@tonic-gate ep->lflags |= ISARG; 10717c478bd9Sstevel@tonic-gate optind++; 10727c478bd9Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 107356798e90Sbasabi if (acl_err) 107456798e90Sbasabi err = 2; 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 1077*5e1c72e1SJason King if (!Uflg) 10787c478bd9Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 10797c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 10807c478bd9Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 10817c478bd9Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 10827c478bd9Sstevel@tonic-gate break; 10837c478bd9Sstevel@tonic-gate } 1084*5e1c72e1SJason King 1085*5e1c72e1SJason King if (colorflg) 1086*5e1c72e1SJason King ls_color_init(); 1087*5e1c72e1SJason King 10887c478bd9Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 10897c478bd9Sstevel@tonic-gate for (; i < nargs; i++) { 10907c478bd9Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 10917c478bd9Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 10927c478bd9Sstevel@tonic-gate if (nomocore) 10937c478bd9Sstevel@tonic-gate exit(2); 10947c478bd9Sstevel@tonic-gate /* -R: print subdirectories found */ 10957c478bd9Sstevel@tonic-gate while (dfirst || cdfirst) { 10967c478bd9Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 10977c478bd9Sstevel@tonic-gate while (cdfirst) { 10987c478bd9Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 10997c478bd9Sstevel@tonic-gate dtemp = cdfirst; 11007c478bd9Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 11017c478bd9Sstevel@tonic-gate dtemp -> dc_next = dfirst; 11027c478bd9Sstevel@tonic-gate dfirst = dtemp; 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 11057c478bd9Sstevel@tonic-gate dtemp = dfirst; 11067c478bd9Sstevel@tonic-gate dfirst = dfirst->dc_next; 11077c478bd9Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 11087c478bd9Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 11097c478bd9Sstevel@tonic-gate if (nomocore) 11107c478bd9Sstevel@tonic-gate exit(2); 11117c478bd9Sstevel@tonic-gate free(dtemp->dc_name); 11127c478bd9Sstevel@tonic-gate free(dtemp); 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate } 1115*5e1c72e1SJason King 11167c478bd9Sstevel@tonic-gate return (err); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 11217c478bd9Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 11227c478bd9Sstevel@tonic-gate */ 11237c478bd9Sstevel@tonic-gate static void 11247c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 11257c478bd9Sstevel@tonic-gate { 11267c478bd9Sstevel@tonic-gate struct dchain *dp; 11277c478bd9Sstevel@tonic-gate struct lbuf *ap; 11287c478bd9Sstevel@tonic-gate char *pname; 11297c478bd9Sstevel@tonic-gate int j; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate filewidth = 0; 11327c478bd9Sstevel@tonic-gate curdir = name; 11337c478bd9Sstevel@tonic-gate if (title) { 11347c478bd9Sstevel@tonic-gate if (!first) 11357c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 11367c478bd9Sstevel@tonic-gate pprintf(name, ":"); 11377c478bd9Sstevel@tonic-gate new_line(); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate /* 11407c478bd9Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 11417c478bd9Sstevel@tonic-gate * further. 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate if (cdetect) { 11447c478bd9Sstevel@tonic-gate if (lflg || sflg) { 11457c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 11467c478bd9Sstevel@tonic-gate new_line(); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11497c478bd9Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 11507c478bd9Sstevel@tonic-gate return; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate nfiles = lp; 11547c478bd9Sstevel@tonic-gate rddir(name, myinfo); 11557c478bd9Sstevel@tonic-gate if (nomocore) 11567c478bd9Sstevel@tonic-gate return; 1157*5e1c72e1SJason King if (fflg == 0 && Uflg == 0) 11587c478bd9Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 11597c478bd9Sstevel@tonic-gate sizeof (struct lbuf *), 11607c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 11617c478bd9Sstevel@tonic-gate if (Rflg) { 11627c478bd9Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 11637c478bd9Sstevel@tonic-gate ap = flist[j]; 11647c478bd9Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 11657c478bd9Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 11667c478bd9Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 11677c478bd9Sstevel@tonic-gate if (dp == NULL) { 11687c478bd9Sstevel@tonic-gate perror("ls"); 11697c478bd9Sstevel@tonic-gate exit(2); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 11727c478bd9Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 11737c478bd9Sstevel@tonic-gate perror("ls"); 11747c478bd9Sstevel@tonic-gate exit(2); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 11777c478bd9Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 11787c478bd9Sstevel@tonic-gate dp->dc_next = dfirst; 11797c478bd9Sstevel@tonic-gate dfirst = dp; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate if (lflg || sflg) { 11847c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 11857c478bd9Sstevel@tonic-gate new_line(); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* 11917c478bd9Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 11927c478bd9Sstevel@tonic-gate * by slp and lp. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate static void 11957c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 11967c478bd9Sstevel@tonic-gate { 11977c478bd9Sstevel@tonic-gate long row, nrows, i; 11987c478bd9Sstevel@tonic-gate int col, ncols; 11997c478bd9Sstevel@tonic-gate struct lbuf **ep; 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 12027c478bd9Sstevel@tonic-gate if (colwidth > num_cols) { 12037c478bd9Sstevel@tonic-gate ncols = 1; 12047c478bd9Sstevel@tonic-gate } else { 12057c478bd9Sstevel@tonic-gate ncols = num_cols / colwidth; 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 12107c478bd9Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 12117c478bd9Sstevel@tonic-gate pentry(*ep); 12127c478bd9Sstevel@tonic-gate new_line(); 12137c478bd9Sstevel@tonic-gate return; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate /* otherwise print -C columns */ 12167c478bd9Sstevel@tonic-gate if (tot_flag) { 12177c478bd9Sstevel@tonic-gate slp--; 12187c478bd9Sstevel@tonic-gate row = 1; 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate else 12217c478bd9Sstevel@tonic-gate row = 0; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 12247c478bd9Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 12257c478bd9Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 12267c478bd9Sstevel@tonic-gate ep = slp + (nrows * col) + row; 12277c478bd9Sstevel@tonic-gate if (ep < lp) 12287c478bd9Sstevel@tonic-gate pentry(*ep); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate new_line(); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * print one output entry; 12367c478bd9Sstevel@tonic-gate * if uid/gid is not found in the appropriate 12377c478bd9Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 12387c478bd9Sstevel@tonic-gate * user/group name; 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate static void 12417c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap) 12427c478bd9Sstevel@tonic-gate { 12437c478bd9Sstevel@tonic-gate struct lbuf *p; 12447c478bd9Sstevel@tonic-gate numbuf_t hbuf; 12457c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 12467c478bd9Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 12477c478bd9Sstevel@tonic-gate char *cp; 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate p = ap; 12507c478bd9Sstevel@tonic-gate column(); 12517c478bd9Sstevel@tonic-gate if (iflg) 12527c478bd9Sstevel@tonic-gate if (mflg && !lflg) 12537c478bd9Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 12547c478bd9Sstevel@tonic-gate else 12557c478bd9Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 12567c478bd9Sstevel@tonic-gate if (sflg) 12577c478bd9Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 12587c478bd9Sstevel@tonic-gate (p->lblocks < 10000) ? "%4lld " : "%lld ", 12597c478bd9Sstevel@tonic-gate (p->ltype != 'b' && p->ltype != 'c') ? 12607c478bd9Sstevel@tonic-gate p->lblocks : 0LL); 12617c478bd9Sstevel@tonic-gate if (lflg) { 12627c478bd9Sstevel@tonic-gate (void) putchar(p->ltype); 12637c478bd9Sstevel@tonic-gate curcol++; 12647c478bd9Sstevel@tonic-gate pmode(p->lflags); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* ACL: additional access mode flag */ 12677c478bd9Sstevel@tonic-gate (void) putchar(p->acl); 12687c478bd9Sstevel@tonic-gate curcol++; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 12717c478bd9Sstevel@tonic-gate if (oflg) 12727c478bd9Sstevel@tonic-gate if (!nflg) { 12737c478bd9Sstevel@tonic-gate cp = getname(p->luid); 12747c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12757c478bd9Sstevel@tonic-gate } else 12767c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 12777c478bd9Sstevel@tonic-gate if (gflg) 12787c478bd9Sstevel@tonic-gate if (!nflg) { 12797c478bd9Sstevel@tonic-gate cp = getgroup(p->lgid); 12807c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12817c478bd9Sstevel@tonic-gate } else 12827c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 12837c478bd9Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 12847c478bd9Sstevel@tonic-gate curcol += printf("%3u, %2u", 12857c478bd9Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 12867c478bd9Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 12877c478bd9Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 12887c478bd9Sstevel@tonic-gate curcol += printf("%7s", 12897c478bd9Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 12907c478bd9Sstevel@tonic-gate } else { 1291*5e1c72e1SJason King uint64_t bsize = p->lsize / block_size; 1292*5e1c72e1SJason King 1293*5e1c72e1SJason King /* 1294*5e1c72e1SJason King * Round up only when using blocks > 1 byte, otherwise 1295*5e1c72e1SJason King * 'normal' sizes display 1 byte too large. 1296*5e1c72e1SJason King */ 1297*5e1c72e1SJason King if (p->lsize % block_size != 0) 1298*5e1c72e1SJason King bsize++; 1299*5e1c72e1SJason King 1300*5e1c72e1SJason King curcol += printf("%7" PRIu64, bsize); 13017c478bd9Sstevel@tonic-gate } 1302*5e1c72e1SJason King format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec); 1303da6c28aaSamw /* format extended system attribute time */ 1304da6c28aaSamw if (tmflg && crtm) 1305da6c28aaSamw format_attrtime(p); 13067c478bd9Sstevel@tonic-gate 1307da6c28aaSamw curcol += printf("%s", time_buf); 1308da6c28aaSamw 1309da6c28aaSamw } 13107c478bd9Sstevel@tonic-gate /* 13117c478bd9Sstevel@tonic-gate * prevent both "->" and trailing marks 13127c478bd9Sstevel@tonic-gate * from appearing 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate if (pflg && p->ltype == 'd') 13167c478bd9Sstevel@tonic-gate dmark = "/"; 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 13197c478bd9Sstevel@tonic-gate if (p->ltype == 'd') 13207c478bd9Sstevel@tonic-gate dmark = "/"; 13217c478bd9Sstevel@tonic-gate else if (p->ltype == 'D') 13227c478bd9Sstevel@tonic-gate dmark = ">"; 13237c478bd9Sstevel@tonic-gate else if (p->ltype == 'p') 13247c478bd9Sstevel@tonic-gate dmark = "|"; 13257c478bd9Sstevel@tonic-gate else if (p->ltype == 'l') 13267c478bd9Sstevel@tonic-gate dmark = "@"; 13277c478bd9Sstevel@tonic-gate else if (p->ltype == 's') 13287c478bd9Sstevel@tonic-gate dmark = "="; 1329*5e1c72e1SJason King else if (!file_typeflg && 1330*5e1c72e1SJason King (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))) 13317c478bd9Sstevel@tonic-gate dmark = "*"; 13327c478bd9Sstevel@tonic-gate else 13337c478bd9Sstevel@tonic-gate dmark = ""; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate if (lflg && p->flinkto) { 13377c478bd9Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 13387c478bd9Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 13397c478bd9Sstevel@tonic-gate dmark = buf; 13407c478bd9Sstevel@tonic-gate } 1341*5e1c72e1SJason King 1342*5e1c72e1SJason King if (colorflg) 1343*5e1c72e1SJason King ls_start_color(p); 1344*5e1c72e1SJason King 13457c478bd9Sstevel@tonic-gate if (p->lflags & ISARG) { 13467c478bd9Sstevel@tonic-gate if (qflg || bflg) 13477c478bd9Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 13487c478bd9Sstevel@tonic-gate else { 13497c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 13507c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 13517c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate } else { 13547c478bd9Sstevel@tonic-gate if (qflg || bflg) 13557c478bd9Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 13567c478bd9Sstevel@tonic-gate else { 13577c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 13587c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 13597c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate } 1362fa9e4066Sahrens 1363*5e1c72e1SJason King if (colorflg) 1364*5e1c72e1SJason King ls_end_color(); 1365*5e1c72e1SJason King 1366da6c28aaSamw /* Display extended system attributes */ 1367da6c28aaSamw if (saflg) { 1368da6c28aaSamw int i; 1369da6c28aaSamw 1370da6c28aaSamw new_line(); 1371da6c28aaSamw (void) printf(" \t{"); 1372da6c28aaSamw if (p->exttr != NULL) { 1373da6c28aaSamw int k = 0; 1374da6c28aaSamw for (i = 0; i < sacnt; i++) { 1375da6c28aaSamw if (p->exttr[i].name != NULL) 1376da6c28aaSamw k++; 1377da6c28aaSamw } 1378da6c28aaSamw for (i = 0; i < sacnt; i++) { 1379da6c28aaSamw if (p->exttr[i].name != NULL) { 1380da6c28aaSamw (void) printf("%s", p->exttr[i].name); 1381da6c28aaSamw k--; 1382da6c28aaSamw if (vopt && (k != 0)) 1383da6c28aaSamw (void) printf(","); 1384da6c28aaSamw } 1385da6c28aaSamw } 1386da6c28aaSamw } 1387da6c28aaSamw (void) printf("}\n"); 1388da6c28aaSamw } 1389da6c28aaSamw /* Display file timestamps and extended system attribute timestamps */ 1390da6c28aaSamw if (tmflg && alltm) { 1391da6c28aaSamw new_line(); 1392da6c28aaSamw print_time(p); 1393da6c28aaSamw new_line(); 1394da6c28aaSamw } 1395fa9e4066Sahrens if (vflg) { 1396fa9e4066Sahrens new_line(); 1397fa9e4066Sahrens if (p->aclp) { 13985a5eeccaSmarks acl_printacl(p->aclp, num_cols, Vflg); 1399fa9e4066Sahrens } 1400fa9e4066Sahrens } 1401da6c28aaSamw /* Free extended system attribute lists */ 1402da6c28aaSamw if (saflg || tmflg) 1403da6c28aaSamw free_sysattr(p); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */ 14077c478bd9Sstevel@tonic-gate static void 14087c478bd9Sstevel@tonic-gate pmode(mode_t aflag) 14097c478bd9Sstevel@tonic-gate { 14107c478bd9Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 14117c478bd9Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 14127c478bd9Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 14137c478bd9Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 14147c478bd9Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 14157c478bd9Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 14167c478bd9Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 14177c478bd9Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 14187c478bd9Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 14197c478bd9Sstevel@tonic-gate #ifdef XPG4 14207c478bd9Sstevel@tonic-gate S_ISGID, 'L', '-'}; 14217c478bd9Sstevel@tonic-gate #else 14227c478bd9Sstevel@tonic-gate S_ISGID, 'l', '-'}; 14237c478bd9Sstevel@tonic-gate #endif 14247c478bd9Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 14257c478bd9Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 14267c478bd9Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 14277c478bd9Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate int **mp; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate flags = aflag; 14347c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 14357c478bd9Sstevel@tonic-gate selection(*mp); 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate static void 14397c478bd9Sstevel@tonic-gate selection(int *pairp) 14407c478bd9Sstevel@tonic-gate { 14417c478bd9Sstevel@tonic-gate int n; 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate n = *pairp++; 14447c478bd9Sstevel@tonic-gate while (n-->0) { 14457c478bd9Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 14467c478bd9Sstevel@tonic-gate pairp++; 14477c478bd9Sstevel@tonic-gate break; 14487c478bd9Sstevel@tonic-gate } else { 14497c478bd9Sstevel@tonic-gate pairp += 2; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate (void) putchar(*pairp); 14537c478bd9Sstevel@tonic-gate curcol++; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* 14577c478bd9Sstevel@tonic-gate * column: get to the beginning of the next column. 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate static void 14607c478bd9Sstevel@tonic-gate column(void) 14617c478bd9Sstevel@tonic-gate { 14627c478bd9Sstevel@tonic-gate if (curcol == 0) 14637c478bd9Sstevel@tonic-gate return; 14647c478bd9Sstevel@tonic-gate if (mflg) { 14657c478bd9Sstevel@tonic-gate (void) putc(',', stdout); 14667c478bd9Sstevel@tonic-gate curcol++; 14677c478bd9Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 14687c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14697c478bd9Sstevel@tonic-gate curcol = 0; 14707c478bd9Sstevel@tonic-gate return; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 14737c478bd9Sstevel@tonic-gate curcol++; 14747c478bd9Sstevel@tonic-gate return; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate if (Cflg == 0) { 14777c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14787c478bd9Sstevel@tonic-gate curcol = 0; 14797c478bd9Sstevel@tonic-gate return; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 14827c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14837c478bd9Sstevel@tonic-gate curcol = 0; 14847c478bd9Sstevel@tonic-gate return; 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate do { 14877c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 14887c478bd9Sstevel@tonic-gate curcol++; 14897c478bd9Sstevel@tonic-gate } while (curcol % colwidth); 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate static void 14937c478bd9Sstevel@tonic-gate new_line(void) 14947c478bd9Sstevel@tonic-gate { 14957c478bd9Sstevel@tonic-gate if (curcol) { 14967c478bd9Sstevel@tonic-gate first = 0; 14977c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14987c478bd9Sstevel@tonic-gate curcol = 0; 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate /* 15037c478bd9Sstevel@tonic-gate * read each filename in directory dir and store its 15047c478bd9Sstevel@tonic-gate * status in flist[nfiles] 15057c478bd9Sstevel@tonic-gate * use makename() to form pathname dir/filename; 15067c478bd9Sstevel@tonic-gate */ 15077c478bd9Sstevel@tonic-gate static void 15087c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 15097c478bd9Sstevel@tonic-gate { 15107c478bd9Sstevel@tonic-gate struct dirent *dentry; 15117c478bd9Sstevel@tonic-gate DIR *dirf; 15127c478bd9Sstevel@tonic-gate int j; 15137c478bd9Sstevel@tonic-gate struct lbuf *ep; 15147c478bd9Sstevel@tonic-gate int width; 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 15177c478bd9Sstevel@tonic-gate (void) fflush(stdout); 15187c478bd9Sstevel@tonic-gate perror(dir); 15197c478bd9Sstevel@tonic-gate err = 2; 15207c478bd9Sstevel@tonic-gate return; 15217c478bd9Sstevel@tonic-gate } else { 15227c478bd9Sstevel@tonic-gate tblocks = 0; 15237c478bd9Sstevel@tonic-gate for (;;) { 15247c478bd9Sstevel@tonic-gate errno = 0; 15257c478bd9Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 15267c478bd9Sstevel@tonic-gate break; 15277c478bd9Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 15287c478bd9Sstevel@tonic-gate (Aflg == 0 || 15297c478bd9Sstevel@tonic-gate dentry->d_name[1] == '\0' || 15307c478bd9Sstevel@tonic-gate dentry->d_name[1] == '.' && 15317c478bd9Sstevel@tonic-gate dentry->d_name[2] == '\0')) 15327c478bd9Sstevel@tonic-gate /* 15337c478bd9Sstevel@tonic-gate * check for directory items '.', '..', 15347c478bd9Sstevel@tonic-gate * and items without valid inode-number; 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate continue; 15377c478bd9Sstevel@tonic-gate 1538*5e1c72e1SJason King /* skip entries ending in ~ if -B was given */ 1539*5e1c72e1SJason King if (Bflg && 1540*5e1c72e1SJason King dentry->d_name[strlen(dentry->d_name) - 1] == '~') 1541*5e1c72e1SJason King continue; 15427c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 15437c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 15447c478bd9Sstevel@tonic-gate if (width > filewidth) 15457c478bd9Sstevel@tonic-gate filewidth = width; 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 15487c478bd9Sstevel@tonic-gate if (ep == NULL) { 15497c478bd9Sstevel@tonic-gate if (nomocore) 1550da6c28aaSamw exit(2); 15517c478bd9Sstevel@tonic-gate continue; 15527c478bd9Sstevel@tonic-gate } else { 15537c478bd9Sstevel@tonic-gate ep->lnum = dentry->d_ino; 15547c478bd9Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 15557c478bd9Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 15567c478bd9Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate if (errno) { 15607c478bd9Sstevel@tonic-gate int sav_errno = errno; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 15637c478bd9Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 15647c478bd9Sstevel@tonic-gate dir, strerror(sav_errno)); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate (void) closedir(dirf); 15677c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 15737c478bd9Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 15747c478bd9Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 15757c478bd9Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 15767c478bd9Sstevel@tonic-gate * it is reported at the right time when printing the directory. 15777c478bd9Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 15787c478bd9Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 15797c478bd9Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 15807c478bd9Sstevel@tonic-gate * command line. 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate static void 15837c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 15847c478bd9Sstevel@tonic-gate int argfl, struct ditem *myparent) 15857c478bd9Sstevel@tonic-gate { 15867c478bd9Sstevel@tonic-gate size_t file_len; 15877c478bd9Sstevel@tonic-gate struct ditem *myinfo; 15887c478bd9Sstevel@tonic-gate struct ditem *tptr; 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate file_len = strlen(file); 15917c478bd9Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 15927c478bd9Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 15937c478bd9Sstevel@tonic-gate /* 15947c478bd9Sstevel@tonic-gate * Add this inode's ancestry 15957c478bd9Sstevel@tonic-gate * info and insert it into the 15967c478bd9Sstevel@tonic-gate * ancestry list by pointing 15977c478bd9Sstevel@tonic-gate * back to its parent. We save 15987c478bd9Sstevel@tonic-gate * it (in rep) with the other info 15997c478bd9Sstevel@tonic-gate * we're gathering for this inode. 16007c478bd9Sstevel@tonic-gate */ 16017c478bd9Sstevel@tonic-gate if ((myinfo = malloc( 16027c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 16037c478bd9Sstevel@tonic-gate perror("ls"); 16047c478bd9Sstevel@tonic-gate exit(2); 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 16077c478bd9Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 16087c478bd9Sstevel@tonic-gate myinfo->parent = myparent; 16097c478bd9Sstevel@tonic-gate rep->ancinfo = myinfo; 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * If this node has the same device id and 16137c478bd9Sstevel@tonic-gate * inode number of one of its ancestors, 16147c478bd9Sstevel@tonic-gate * then we've detected a cycle. 16157c478bd9Sstevel@tonic-gate */ 16167c478bd9Sstevel@tonic-gate if (myparent != NULL) { 16177c478bd9Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 16187c478bd9Sstevel@tonic-gate tptr = tptr->parent) { 16197c478bd9Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 16207c478bd9Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Cycle detected for this 16237c478bd9Sstevel@tonic-gate * directory. Record the fact 16247c478bd9Sstevel@tonic-gate * it is a cycle so we don't 16257c478bd9Sstevel@tonic-gate * try to process this 16267c478bd9Sstevel@tonic-gate * directory as we are 16277c478bd9Sstevel@tonic-gate * walking through the 16287c478bd9Sstevel@tonic-gate * list of directories. 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate rep->cycle = 1; 16317c478bd9Sstevel@tonic-gate err = 2; 16327c478bd9Sstevel@tonic-gate break; 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate /* 164064d425a7Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 164164d425a7Sny155746 * This is because, if the server's FS happens to be UFS, supporting 164264d425a7Sny155746 * POSIX ACL's, then it does a special calculation of group mode 164364d425a7Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 164464d425a7Sny155746 * 164564d425a7Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 164664d425a7Sny155746 * algorithm is used for the group mode calculation only. 164764d425a7Sny155746 * What is modified here from the algorithm is that only the 164864d425a7Sny155746 * entries with flags ACE_GROUP are considered. For each entry 164964d425a7Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 165064d425a7Sny155746 * is checked if it is allowed. 1651e2442894Sny155746 * We are not interested in perms for user and other, as they 165264d425a7Sny155746 * were taken from st_mode value. 165364d425a7Sny155746 * We are not interested in a_who field of ACE, as we need just 165464d425a7Sny155746 * unix mode bits for the group. 165564d425a7Sny155746 */ 1656e2442894Sny155746 1657e2442894Sny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 1658e2442894Sny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 1659e2442894Sny155746 166064d425a7Sny155746 int 166164d425a7Sny155746 grp_mask_to_mode(acl_t *acep) 166264d425a7Sny155746 { 166364d425a7Sny155746 int mode = 0, seen = 0; 166464d425a7Sny155746 int acecnt; 1665e2442894Sny155746 int flags; 166664d425a7Sny155746 ace_t *ap; 166764d425a7Sny155746 166864d425a7Sny155746 acecnt = acl_cnt(acep); 166964d425a7Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 1670e2442894Sny155746 1671e2442894Sny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 1672e2442894Sny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 1673e2442894Sny155746 continue; 1674e2442894Sny155746 1675e2442894Sny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 1676e2442894Sny155746 continue; 1677e2442894Sny155746 1678e2442894Sny155746 /* 1679e2442894Sny155746 * if it is first group@ or first everyone@ 1680e2442894Sny155746 * for each of read, write and execute, then 1681e2442894Sny155746 * that will be the group mode bit. 1682e2442894Sny155746 */ 1683e2442894Sny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 1684e2442894Sny155746 if (flags == OWNED_GROUP || flags == ACE_EVERYONE) { 168564d425a7Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 168664d425a7Sny155746 if (!(seen & S_IRGRP)) { 168764d425a7Sny155746 seen |= S_IRGRP; 1688e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 168964d425a7Sny155746 mode |= S_IRGRP; 169064d425a7Sny155746 } 169164d425a7Sny155746 } 169264d425a7Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 169364d425a7Sny155746 if (!(seen & S_IWGRP)) { 169464d425a7Sny155746 seen |= S_IWGRP; 1695e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 169664d425a7Sny155746 mode |= S_IWGRP; 169764d425a7Sny155746 } 169864d425a7Sny155746 } 169964d425a7Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 170064d425a7Sny155746 if (!(seen & S_IXGRP)) { 170164d425a7Sny155746 seen |= S_IXGRP; 1702e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 170364d425a7Sny155746 mode |= S_IXGRP; 170464d425a7Sny155746 } 170564d425a7Sny155746 } 170664d425a7Sny155746 } 170764d425a7Sny155746 } 170864d425a7Sny155746 return (mode); 170964d425a7Sny155746 } 171064d425a7Sny155746 171164d425a7Sny155746 /* 17127c478bd9Sstevel@tonic-gate * get status of file and recomputes tblocks; 17137c478bd9Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 17147c478bd9Sstevel@tonic-gate * for filename in a directory whose name is an 17157c478bd9Sstevel@tonic-gate * argument in the command; 17167c478bd9Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 17177c478bd9Sstevel@tonic-gate * returns that pointer; 17187c478bd9Sstevel@tonic-gate * returns NULL if failed; 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate static struct lbuf * 17217c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 17227c478bd9Sstevel@tonic-gate { 17237c478bd9Sstevel@tonic-gate struct stat statb, statb1; 17247c478bd9Sstevel@tonic-gate struct lbuf *rep; 17257c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 17267c478bd9Sstevel@tonic-gate ssize_t cc; 17277c478bd9Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 17287c478bd9Sstevel@tonic-gate int aclcnt; 1729fa9e4066Sahrens int error; 17307c478bd9Sstevel@tonic-gate aclent_t *tp; 17317c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 17327c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate if (nomocore) 17357c478bd9Sstevel@tonic-gate return (NULL); 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate if (nfiles >= maxfils) { 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 17407c478bd9Sstevel@tonic-gate * more space 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate maxfils += quantn; 17437c478bd9Sstevel@tonic-gate if (((flist = realloc(flist, 17447c478bd9Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 17457c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 17467c478bd9Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 17477c478bd9Sstevel@tonic-gate perror("ls"); 17487c478bd9Sstevel@tonic-gate nomocore = 1; 17497c478bd9Sstevel@tonic-gate return (NULL); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * nfiles is reset to nargs for each directory 17557c478bd9Sstevel@tonic-gate * that is given as an argument maxn is checked 17567c478bd9Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 17577c478bd9Sstevel@tonic-gate * that already has one assigned. 17587c478bd9Sstevel@tonic-gate */ 17597c478bd9Sstevel@tonic-gate if (nfiles >= maxn) { 17607c478bd9Sstevel@tonic-gate rep = nxtlbf++; 17617c478bd9Sstevel@tonic-gate flist[nfiles++] = rep; 17627c478bd9Sstevel@tonic-gate maxn = nfiles; 17637c478bd9Sstevel@tonic-gate } else { 17647c478bd9Sstevel@tonic-gate rep = flist[nfiles++]; 17657c478bd9Sstevel@tonic-gate } 176644f31f13Sbasabi 176744f31f13Sbasabi /* Initialize */ 176844f31f13Sbasabi 17697c478bd9Sstevel@tonic-gate rep->lflags = (mode_t)0; 17707c478bd9Sstevel@tonic-gate rep->flinkto = NULL; 17717c478bd9Sstevel@tonic-gate rep->cycle = 0; 177244f31f13Sbasabi rep->lat.tv_sec = time(NULL); 177344f31f13Sbasabi rep->lat.tv_nsec = 0; 177444f31f13Sbasabi rep->lct.tv_sec = time(NULL); 177544f31f13Sbasabi rep->lct.tv_nsec = 0; 177644f31f13Sbasabi rep->lmt.tv_sec = time(NULL); 177744f31f13Sbasabi rep->lmt.tv_nsec = 0; 177844f31f13Sbasabi rep->exttr = NULL; 177944f31f13Sbasabi rep->extm = NULL; 178044f31f13Sbasabi 17817c478bd9Sstevel@tonic-gate if (argfl || statreq) { 17827c478bd9Sstevel@tonic-gate int doacl; 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate if (lflg) 17857c478bd9Sstevel@tonic-gate doacl = 1; 17867c478bd9Sstevel@tonic-gate else 17877c478bd9Sstevel@tonic-gate doacl = 0; 178844f31f13Sbasabi 17897c478bd9Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 17907c478bd9Sstevel@tonic-gate if (argfl || errno != ENOENT || 17917c478bd9Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 17927c478bd9Sstevel@tonic-gate /* 17937c478bd9Sstevel@tonic-gate * Avoid race between readdir and lstat. 17947c478bd9Sstevel@tonic-gate * Print error message in case of dangling link. 17957c478bd9Sstevel@tonic-gate */ 17967c478bd9Sstevel@tonic-gate perror(file); 1797*5e1c72e1SJason King err = 2; 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate nfiles--; 18007c478bd9Sstevel@tonic-gate return (NULL); 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* 18047c478bd9Sstevel@tonic-gate * If -H was specified, and the file linked to was 18057c478bd9Sstevel@tonic-gate * not a directory, then we need to get the info 18067c478bd9Sstevel@tonic-gate * for the symlink itself. 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate if ((Hflg) && (argfl) && 18097c478bd9Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 18107c478bd9Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 18117c478bd9Sstevel@tonic-gate perror(file); 1812*5e1c72e1SJason King err = 2; 18137c478bd9Sstevel@tonic-gate } 18147c478bd9Sstevel@tonic-gate } 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate rep->lnum = statb.st_ino; 18177c478bd9Sstevel@tonic-gate rep->lsize = statb.st_size; 18187c478bd9Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 18197c478bd9Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 18207c478bd9Sstevel@tonic-gate case S_IFDIR: 18217c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 18227c478bd9Sstevel@tonic-gate if (Rflg) { 18237c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 18247c478bd9Sstevel@tonic-gate argfl, myparent); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate break; 18277c478bd9Sstevel@tonic-gate case S_IFBLK: 18287c478bd9Sstevel@tonic-gate rep->ltype = 'b'; 18297c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18307c478bd9Sstevel@tonic-gate break; 18317c478bd9Sstevel@tonic-gate case S_IFCHR: 18327c478bd9Sstevel@tonic-gate rep->ltype = 'c'; 18337c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18347c478bd9Sstevel@tonic-gate break; 18357c478bd9Sstevel@tonic-gate case S_IFIFO: 18367c478bd9Sstevel@tonic-gate rep->ltype = 'p'; 18377c478bd9Sstevel@tonic-gate break; 18387c478bd9Sstevel@tonic-gate case S_IFSOCK: 18397c478bd9Sstevel@tonic-gate rep->ltype = 's'; 18407c478bd9Sstevel@tonic-gate rep->lsize = 0; 18417c478bd9Sstevel@tonic-gate break; 18427c478bd9Sstevel@tonic-gate case S_IFLNK: 18437c478bd9Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 18447c478bd9Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 18457c478bd9Sstevel@tonic-gate ((Hflg) && (!argfl))) { 18467c478bd9Sstevel@tonic-gate doacl = 0; 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate rep->ltype = 'l'; 18497c478bd9Sstevel@tonic-gate if (lflg) { 18507c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 18517c478bd9Sstevel@tonic-gate if (cc >= 0) { 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate /* 18547c478bd9Sstevel@tonic-gate * follow the symbolic link 18557c478bd9Sstevel@tonic-gate * to generate the appropriate 18567c478bd9Sstevel@tonic-gate * Fflg marker for the object 18577c478bd9Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate if ((Fflg || pflg) && 18607c478bd9Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 18617c478bd9Sstevel@tonic-gate switch (statb1.st_mode & 18627c478bd9Sstevel@tonic-gate S_IFMT) { 18637c478bd9Sstevel@tonic-gate case S_IFDIR: 18647c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 18657c478bd9Sstevel@tonic-gate break; 18667c478bd9Sstevel@tonic-gate case S_IFSOCK: 18677c478bd9Sstevel@tonic-gate buf[cc++] = '='; 18687c478bd9Sstevel@tonic-gate break; 18692236845bSakaplan case S_IFDOOR: 18702236845bSakaplan buf[cc++] = '>'; 18712236845bSakaplan break; 18722236845bSakaplan case S_IFIFO: 18732236845bSakaplan buf[cc++] = '|'; 18742236845bSakaplan break; 18757c478bd9Sstevel@tonic-gate default: 18767c478bd9Sstevel@tonic-gate if ((statb1.st_mode & 18777c478bd9Sstevel@tonic-gate ~S_IFMT) & 18787c478bd9Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 18797c478bd9Sstevel@tonic-gate S_IXOTH)) 18807c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 18817c478bd9Sstevel@tonic-gate break; 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate buf[cc] = '\0'; 18857c478bd9Sstevel@tonic-gate rep->flinkto = strdup(buf); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate break; 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate /* 18917c478bd9Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 18927c478bd9Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 18937c478bd9Sstevel@tonic-gate * when explicit arguments are specified. 18947c478bd9Sstevel@tonic-gate */ 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate #ifdef XPG6 18977c478bd9Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 18987c478bd9Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 18997c478bd9Sstevel@tonic-gate (stat(file, &statb1) < 0)) 19007c478bd9Sstevel@tonic-gate #else 19017c478bd9Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 19027c478bd9Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 19037c478bd9Sstevel@tonic-gate #endif /* XPG6 */ 19047c478bd9Sstevel@tonic-gate break; 19057c478bd9Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 19067c478bd9Sstevel@tonic-gate statb = statb1; 19077c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 19087c478bd9Sstevel@tonic-gate rep->lsize = statb1.st_size; 19097c478bd9Sstevel@tonic-gate if (Rflg) { 19107c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 19117c478bd9Sstevel@tonic-gate argfl, myparent); 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate break; 19157c478bd9Sstevel@tonic-gate case S_IFDOOR: 19167c478bd9Sstevel@tonic-gate rep->ltype = 'D'; 19177c478bd9Sstevel@tonic-gate break; 19187c478bd9Sstevel@tonic-gate case S_IFREG: 19197c478bd9Sstevel@tonic-gate rep->ltype = '-'; 19207c478bd9Sstevel@tonic-gate break; 19217c478bd9Sstevel@tonic-gate case S_IFPORT: 19227c478bd9Sstevel@tonic-gate rep->ltype = 'P'; 19237c478bd9Sstevel@tonic-gate break; 19247c478bd9Sstevel@tonic-gate default: 19257c478bd9Sstevel@tonic-gate rep->ltype = '?'; 19267c478bd9Sstevel@tonic-gate break; 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 19317c478bd9Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 19327c478bd9Sstevel@tonic-gate 193344f31f13Sbasabi rep->luid = statb.st_uid; 193444f31f13Sbasabi rep->lgid = statb.st_gid; 193544f31f13Sbasabi rep->lnl = statb.st_nlink; 193644f31f13Sbasabi if (uflg || (tmflg && atm)) 193744f31f13Sbasabi rep->lmtime = statb.st_atim; 193844f31f13Sbasabi else if (cflg || (tmflg && ctm)) 193944f31f13Sbasabi rep->lmtime = statb.st_ctim; 194044f31f13Sbasabi else 194144f31f13Sbasabi rep->lmtime = statb.st_mtim; 194244f31f13Sbasabi rep->lat = statb.st_atim; 194344f31f13Sbasabi rep->lct = statb.st_ctim; 194444f31f13Sbasabi rep->lmt = statb.st_mtim; 194544f31f13Sbasabi 19467c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 19477c478bd9Sstevel@tonic-gate if (doacl) { 19487c478bd9Sstevel@tonic-gate 1949fa9e4066Sahrens error = acl_get(file, 0, &rep->aclp); 1950fa9e4066Sahrens if (error) { 1951fa9e4066Sahrens (void) fprintf(stderr, 1952fa9e4066Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1953fa9e4066Sahrens file, acl_strerror(error)); 195444f31f13Sbasabi rep->acl = ' '; 195556798e90Sbasabi acl_err++; 195644f31f13Sbasabi return (rep); 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate 1959fa9e4066Sahrens rep->acl = ' '; 1960fa9e4066Sahrens 1961fa9e4066Sahrens if (rep->aclp && 1962fa9e4066Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1963fa9e4066Sahrens rep->acl = '+'; 19647c478bd9Sstevel@tonic-gate /* 1965fa9e4066Sahrens * Special handling for ufs aka aclent_t ACL's 1966fa9e4066Sahrens */ 196764d425a7Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 1968fa9e4066Sahrens /* 1969fa9e4066Sahrens * For files with non-trivial acls, the 1970fa9e4066Sahrens * effective group permissions are the 1971fa9e4066Sahrens * intersection of the GROUP_OBJ value 1972fa9e4066Sahrens * and the CLASS_OBJ (acl mask) value. 1973fa9e4066Sahrens * Determine both the GROUP_OBJ and 1974fa9e4066Sahrens * CLASS_OBJ for this file and insert 1975fa9e4066Sahrens * the logical AND of those two values 1976fa9e4066Sahrens * in the group permissions field 1977fa9e4066Sahrens * of the lflags value for this file. 1978fa9e4066Sahrens */ 1979fa9e4066Sahrens 1980fa9e4066Sahrens /* 1981fa9e4066Sahrens * Until found in acl list, assume 1982fa9e4066Sahrens * maximum permissions for both group 1983fa9e4066Sahrens * a nd mask. (Just in case the acl 1984fa9e4066Sahrens * lacks either value for some reason.) 19857c478bd9Sstevel@tonic-gate */ 19867c478bd9Sstevel@tonic-gate groupperm = 07; 19877c478bd9Sstevel@tonic-gate mask = 07; 19887c478bd9Sstevel@tonic-gate grouppermfound = 0; 19897c478bd9Sstevel@tonic-gate maskfound = 0; 1990fa9e4066Sahrens aclcnt = acl_cnt(rep->aclp); 1991fa9e4066Sahrens for (tp = 1992fa9e4066Sahrens (aclent_t *)acl_data(rep->aclp); 1993fa9e4066Sahrens aclcnt--; tp++) { 19947c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 19957c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 19967c478bd9Sstevel@tonic-gate grouppermfound = 1; 19977c478bd9Sstevel@tonic-gate continue; 19987c478bd9Sstevel@tonic-gate } 19997c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 20007c478bd9Sstevel@tonic-gate mask = tp->a_perm; 20017c478bd9Sstevel@tonic-gate maskfound = 1; 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 20047c478bd9Sstevel@tonic-gate break; 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* reset all the group bits */ 20097c478bd9Sstevel@tonic-gate rep->lflags &= ~S_IRWXG; 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate /* 2012fa9e4066Sahrens * Now set them to the logical AND of 2013fa9e4066Sahrens * the GROUP_OBJ permissions and the 2014fa9e4066Sahrens * acl mask. 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate rep->lflags |= (groupperm & mask) << 3; 2018fa9e4066Sahrens 201964d425a7Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 202064d425a7Sny155746 int mode; 202164d425a7Sny155746 mode = grp_mask_to_mode(rep->aclp); 202264d425a7Sny155746 rep->lflags &= ~S_IRWXG; 202364d425a7Sny155746 rep->lflags |= mode; 2024fa9e4066Sahrens } 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate 20275a5eeccaSmarks if (!vflg && !Vflg && rep->aclp) { 20285a5eeccaSmarks acl_free(rep->aclp); 20295a5eeccaSmarks rep->aclp = NULL; 20305a5eeccaSmarks } 20315a5eeccaSmarks 20327c478bd9Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 20337c478bd9Sstevel@tonic-gate rep->acl = '@'; 2034da6c28aaSamw 20357c478bd9Sstevel@tonic-gate } else 20367c478bd9Sstevel@tonic-gate rep->acl = ' '; 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 20417c478bd9Sstevel@tonic-gate tblocks += rep->lblocks; 2042da6c28aaSamw 2043da6c28aaSamw /* Get extended system attributes */ 2044da6c28aaSamw 2045da6c28aaSamw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 2046da6c28aaSamw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 2047da6c28aaSamw int i; 2048da6c28aaSamw 2049da6c28aaSamw sacnt = attr_count(); 2050da6c28aaSamw /* 2051da6c28aaSamw * Allocate 'sacnt' size array to hold extended 2052da6c28aaSamw * system attribute name (verbose) or respective 2053da6c28aaSamw * symbol represenation (compact). 2054da6c28aaSamw */ 2055da6c28aaSamw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 2056da6c28aaSamw rep); 2057da6c28aaSamw 2058da6c28aaSamw /* initialize boolean attribute list */ 2059da6c28aaSamw for (i = 0; i < sacnt; i++) 2060da6c28aaSamw rep->exttr[i].name = NULL; 2061da6c28aaSamw if (get_sysxattr(file, rep) != 0) { 2062da6c28aaSamw (void) fprintf(stderr, 2063da6c28aaSamw gettext("ls:Failed to retrieve " 2064da6c28aaSamw "extended system attribute from " 2065da6c28aaSamw "%s\n"), file); 2066da6c28aaSamw rep->exttr[0].name = xmalloc(2, rep); 2067da6c28aaSamw (void) strlcpy(rep->exttr[0].name, "?", 2); 2068da6c28aaSamw } 2069da6c28aaSamw } 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate return (rep); 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* 20757c478bd9Sstevel@tonic-gate * returns pathname of the form dir/file; 20767c478bd9Sstevel@tonic-gate * dir and file are null-terminated strings. 20777c478bd9Sstevel@tonic-gate */ 20787c478bd9Sstevel@tonic-gate static char * 20797c478bd9Sstevel@tonic-gate makename(char *dir, char *file) 20807c478bd9Sstevel@tonic-gate { 20817c478bd9Sstevel@tonic-gate /* 20827c478bd9Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 20837c478bd9Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 20847c478bd9Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 20857c478bd9Sstevel@tonic-gate * and the null character at the end. 20867c478bd9Sstevel@tonic-gate * dfile is static as this is returned by makename(). 20877c478bd9Sstevel@tonic-gate */ 20887c478bd9Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 20897c478bd9Sstevel@tonic-gate char *dp, *fp; 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate dp = dfile; 20927c478bd9Sstevel@tonic-gate fp = dir; 20937c478bd9Sstevel@tonic-gate while (*fp) 20947c478bd9Sstevel@tonic-gate *dp++ = *fp++; 20957c478bd9Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 20967c478bd9Sstevel@tonic-gate *dp++ = '/'; 20977c478bd9Sstevel@tonic-gate fp = file; 20987c478bd9Sstevel@tonic-gate while (*fp) 20997c478bd9Sstevel@tonic-gate *dp++ = *fp++; 21007c478bd9Sstevel@tonic-gate *dp = '\0'; 21017c478bd9Sstevel@tonic-gate return (dfile); 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate #include <pwd.h> 21067c478bd9Sstevel@tonic-gate #include <grp.h> 21077c478bd9Sstevel@tonic-gate #include <utmpx.h> 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate struct utmpx utmp; 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 21127c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 21167c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 21177c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 21187c478bd9Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 21197c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 21207c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 21217c478bd9Sstevel@tonic-gate }; 21227c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups; 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate static struct cachenode * 21257c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val) 21267c478bd9Sstevel@tonic-gate { 21277c478bd9Sstevel@tonic-gate struct cachenode **parent = head; 21287c478bd9Sstevel@tonic-gate struct cachenode *c = *parent; 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate while (c != NULL) { 21317c478bd9Sstevel@tonic-gate if (val == c->val) { 21327c478bd9Sstevel@tonic-gate /* found it */ 21337c478bd9Sstevel@tonic-gate return (c); 21347c478bd9Sstevel@tonic-gate } else if (val < c->val) { 21357c478bd9Sstevel@tonic-gate parent = &c->lesschild; 21367c478bd9Sstevel@tonic-gate c = c->lesschild; 21377c478bd9Sstevel@tonic-gate } else { 21387c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 21397c478bd9Sstevel@tonic-gate c = c->grtrchild; 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 21447c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 21457c478bd9Sstevel@tonic-gate if (c == NULL) { 21467c478bd9Sstevel@tonic-gate perror("ls"); 21477c478bd9Sstevel@tonic-gate exit(2); 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate *parent = c; 21507c478bd9Sstevel@tonic-gate c->val = val; 21517c478bd9Sstevel@tonic-gate return (c); 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate /* 21557c478bd9Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 21567c478bd9Sstevel@tonic-gate * lastuid is set to uid. 21577c478bd9Sstevel@tonic-gate */ 21587c478bd9Sstevel@tonic-gate static char * 21597c478bd9Sstevel@tonic-gate getname(uid_t uid) 21607c478bd9Sstevel@tonic-gate { 21617c478bd9Sstevel@tonic-gate struct passwd *pwent; 21627c478bd9Sstevel@tonic-gate struct cachenode *c; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 21657c478bd9Sstevel@tonic-gate return (lastuname); 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 21687c478bd9Sstevel@tonic-gate if (c->initted == 0) { 21697c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 21707c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 21717c478bd9Sstevel@tonic-gate } else { 21727c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate c->initted = 1; 21757c478bd9Sstevel@tonic-gate } 21767c478bd9Sstevel@tonic-gate lastuid = uid; 21777c478bd9Sstevel@tonic-gate lastuname = &c->name[0]; 21787c478bd9Sstevel@tonic-gate return (lastuname); 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate /* 21827c478bd9Sstevel@tonic-gate * get name from cache, or group file for a given gid; 21837c478bd9Sstevel@tonic-gate * lastgid is set to gid. 21847c478bd9Sstevel@tonic-gate */ 21857c478bd9Sstevel@tonic-gate static char * 21867c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 21877c478bd9Sstevel@tonic-gate { 21887c478bd9Sstevel@tonic-gate struct group *grent; 21897c478bd9Sstevel@tonic-gate struct cachenode *c; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 21927c478bd9Sstevel@tonic-gate return (lastgname); 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 21957c478bd9Sstevel@tonic-gate if (c->initted == 0) { 21967c478bd9Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 21977c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 21987c478bd9Sstevel@tonic-gate } else { 21997c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate c->initted = 1; 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate lastgid = gid; 22047c478bd9Sstevel@tonic-gate lastgname = &c->name[0]; 22057c478bd9Sstevel@tonic-gate return (lastgname); 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 22097c478bd9Sstevel@tonic-gate static int 22107c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 22117c478bd9Sstevel@tonic-gate { 22127c478bd9Sstevel@tonic-gate struct lbuf *p1, *p2; 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate p1 = *pp1; 22157c478bd9Sstevel@tonic-gate p2 = *pp2; 22167c478bd9Sstevel@tonic-gate if (dflg == 0) { 22177c478bd9Sstevel@tonic-gate /* 22187c478bd9Sstevel@tonic-gate * compare two names in ls-command one of which is file 22197c478bd9Sstevel@tonic-gate * and the other is a directory; 22207c478bd9Sstevel@tonic-gate * this portion is not used for comparing files within 22217c478bd9Sstevel@tonic-gate * a directory name of ls-command; 22227c478bd9Sstevel@tonic-gate */ 22237c478bd9Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 22247c478bd9Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 22257c478bd9Sstevel@tonic-gate return (1); 22267c478bd9Sstevel@tonic-gate } else { 22277c478bd9Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 22287c478bd9Sstevel@tonic-gate return (-1); 22297c478bd9Sstevel@tonic-gate } 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate if (tflg) { 22327c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 22337c478bd9Sstevel@tonic-gate return (rflg); 22347c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 22357c478bd9Sstevel@tonic-gate return (-rflg); 22367c478bd9Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 22377c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 22387c478bd9Sstevel@tonic-gate return (rflg); 22397c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 22407c478bd9Sstevel@tonic-gate return (-rflg); 22417c478bd9Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 22427c478bd9Sstevel@tonic-gate } else if (Sflg) { 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * The size stored in lsize can be either the 22457c478bd9Sstevel@tonic-gate * size or the major minor number (in the case of 22467c478bd9Sstevel@tonic-gate * block and character special devices). If it's 22477c478bd9Sstevel@tonic-gate * a major minor number, then the size is considered 22487c478bd9Sstevel@tonic-gate * to be zero and we want to fall through and sort 22497c478bd9Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 22507c478bd9Sstevel@tonic-gate * to the size of p1 we want to fall through and 22517c478bd9Sstevel@tonic-gate * sort by name. 22527c478bd9Sstevel@tonic-gate */ 22537c478bd9Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 22547c478bd9Sstevel@tonic-gate (p1->ltype == 'c') ? 0 : p1->lsize; 22557c478bd9Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 22567c478bd9Sstevel@tonic-gate (p2->ltype == 'c') ? 0 : p2->lsize; 22577c478bd9Sstevel@tonic-gate if (p2size > p1size) { 22587c478bd9Sstevel@tonic-gate return (rflg); 22597c478bd9Sstevel@tonic-gate } else if (p2size < p1size) { 22607c478bd9Sstevel@tonic-gate return (-rflg); 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate return (rflg * strcoll( 22657c478bd9Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 22667c478bd9Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate static void 22707c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2) 22717c478bd9Sstevel@tonic-gate { 22727c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 22737c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate static void 22777c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s) 22787c478bd9Sstevel@tonic-gate { 22797c478bd9Sstevel@tonic-gate unsigned char *cp; 22807c478bd9Sstevel@tonic-gate char c; 22817c478bd9Sstevel@tonic-gate int i; 22827c478bd9Sstevel@tonic-gate int c_len; 22837c478bd9Sstevel@tonic-gate int p_col; 22847c478bd9Sstevel@tonic-gate wchar_t pcode; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate if (!qflg && !bflg) { 22877c478bd9Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 22887c478bd9Sstevel@tonic-gate (void) putchar(*cp); 22897c478bd9Sstevel@tonic-gate curcol++; 22907c478bd9Sstevel@tonic-gate } 22917c478bd9Sstevel@tonic-gate return; 22927c478bd9Sstevel@tonic-gate } 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate for (cp = s; *cp; ) { 22957c478bd9Sstevel@tonic-gate if (isascii(c = *cp)) { 22967c478bd9Sstevel@tonic-gate if (!isprint(c)) { 22977c478bd9Sstevel@tonic-gate if (qflg) { 22987c478bd9Sstevel@tonic-gate c = '?'; 22997c478bd9Sstevel@tonic-gate } else { 23007c478bd9Sstevel@tonic-gate curcol += 3; 23017c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 23027c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23037c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23047c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23057c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23067c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 23077c478bd9Sstevel@tonic-gate } 23087c478bd9Sstevel@tonic-gate } 23097c478bd9Sstevel@tonic-gate curcol++; 23107c478bd9Sstevel@tonic-gate cp++; 23117c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23127c478bd9Sstevel@tonic-gate continue; 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 23167c478bd9Sstevel@tonic-gate c_len = 1; 23177c478bd9Sstevel@tonic-gate goto not_print; 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 23217c478bd9Sstevel@tonic-gate (void) putwchar(pcode); 23227c478bd9Sstevel@tonic-gate cp += c_len; 23237c478bd9Sstevel@tonic-gate curcol += p_col; 23247c478bd9Sstevel@tonic-gate continue; 23257c478bd9Sstevel@tonic-gate } 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate not_print: 23287c478bd9Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 23297c478bd9Sstevel@tonic-gate if (qflg) { 23307c478bd9Sstevel@tonic-gate c = '?'; 23317c478bd9Sstevel@tonic-gate } else { 23327c478bd9Sstevel@tonic-gate curcol += 3; 23337c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 23347c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23357c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23367c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23377c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23387c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 23397c478bd9Sstevel@tonic-gate } 23407c478bd9Sstevel@tonic-gate curcol++; 23417c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23427c478bd9Sstevel@tonic-gate cp++; 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate } 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate static int 23487c478bd9Sstevel@tonic-gate strcol(unsigned char *s1) 23497c478bd9Sstevel@tonic-gate { 23507c478bd9Sstevel@tonic-gate int w; 23517c478bd9Sstevel@tonic-gate int w_col; 23527c478bd9Sstevel@tonic-gate int len; 23537c478bd9Sstevel@tonic-gate wchar_t wc; 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate w = 0; 23567c478bd9Sstevel@tonic-gate while (*s1) { 23577c478bd9Sstevel@tonic-gate if (isascii(*s1)) { 23587c478bd9Sstevel@tonic-gate w++; 23597c478bd9Sstevel@tonic-gate s1++; 23607c478bd9Sstevel@tonic-gate continue; 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 23647c478bd9Sstevel@tonic-gate w++; 23657c478bd9Sstevel@tonic-gate s1++; 23667c478bd9Sstevel@tonic-gate continue; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 23707c478bd9Sstevel@tonic-gate w_col = len; 23717c478bd9Sstevel@tonic-gate s1 += len; 23727c478bd9Sstevel@tonic-gate w += w_col; 23737c478bd9Sstevel@tonic-gate } 23747c478bd9Sstevel@tonic-gate return (w); 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate /* 23787c478bd9Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 23797c478bd9Sstevel@tonic-gate * result in the caller-supplied buffer. 23807c478bd9Sstevel@tonic-gate * 23817c478bd9Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 23827c478bd9Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 23837c478bd9Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 23847c478bd9Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 23857c478bd9Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 23867c478bd9Sstevel@tonic-gate * the final number has only a single significant digit, we compute 23877c478bd9Sstevel@tonic-gate * tenths of units to provide a second significant digit. 23887c478bd9Sstevel@tonic-gate * 23897c478bd9Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 23907c478bd9Sstevel@tonic-gate * converted to "-1". 23917c478bd9Sstevel@tonic-gate * 23927c478bd9Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 23937c478bd9Sstevel@tonic-gate */ 23947c478bd9Sstevel@tonic-gate static char * 23957c478bd9Sstevel@tonic-gate number_to_scaled_string( 23967c478bd9Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 23977c478bd9Sstevel@tonic-gate unsigned long long number, /* convert this number */ 23987c478bd9Sstevel@tonic-gate long scale) 23997c478bd9Sstevel@tonic-gate { 24007c478bd9Sstevel@tonic-gate unsigned long long save; 24017c478bd9Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 24027c478bd9Sstevel@tonic-gate char *uom = "KMGTPE"; 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate if ((long long)number == (long long)-1) { 24057c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 24067c478bd9Sstevel@tonic-gate return (buf); 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate save = number; 24107c478bd9Sstevel@tonic-gate number = number / scale; 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * Now we have number as a count of scale units. 24147c478bd9Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 24157c478bd9Sstevel@tonic-gate * 24167c478bd9Sstevel@tonic-gate * The largest value number could have had entering the routine is 24177c478bd9Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 24187c478bd9Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 24197c478bd9Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 24207c478bd9Sstevel@tonic-gate */ 24217c478bd9Sstevel@tonic-gate if (number < (unsigned long long)scale) { 24227c478bd9Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 24237c478bd9Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 24247c478bd9Sstevel@tonic-gate uom++; 24257c478bd9Sstevel@tonic-gate number = 1; 24267c478bd9Sstevel@tonic-gate } 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate } else { 24297c478bd9Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 24307c478bd9Sstevel@tonic-gate uom++; /* next unit of measurement */ 24317c478bd9Sstevel@tonic-gate save = number; 24327c478bd9Sstevel@tonic-gate /* 24337c478bd9Sstevel@tonic-gate * If we're over half way to the next unit of 24347c478bd9Sstevel@tonic-gate * 'scale' bytes (which means we should round 24357c478bd9Sstevel@tonic-gate * up), then adding half of 'scale' prior to 24367c478bd9Sstevel@tonic-gate * the division will push us into that next 24377c478bd9Sstevel@tonic-gate * unit of scale when we perform the division 24387c478bd9Sstevel@tonic-gate */ 24397c478bd9Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 24407c478bd9Sstevel@tonic-gate } 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 24447c478bd9Sstevel@tonic-gate if ((save / scale) < 10) { 24457c478bd9Sstevel@tonic-gate /* snprintf() will round for us */ 24467c478bd9Sstevel@tonic-gate float fnum = (float)save / scale; 24477c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 24487c478bd9Sstevel@tonic-gate fnum, *uom); 24497c478bd9Sstevel@tonic-gate } else { 24507c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 24517c478bd9Sstevel@tonic-gate number, *uom); 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate return (buf); 24547c478bd9Sstevel@tonic-gate } 2455da6c28aaSamw 2456da6c28aaSamw /* Get extended system attributes and set the display */ 2457da6c28aaSamw 2458da6c28aaSamw int 2459da6c28aaSamw get_sysxattr(char *fname, struct lbuf *rep) 2460da6c28aaSamw { 2461da6c28aaSamw boolean_t value; 2462da6c28aaSamw data_type_t type; 2463da6c28aaSamw int error; 2464da6c28aaSamw char *name; 2465da6c28aaSamw int i; 2466da6c28aaSamw 2467da6c28aaSamw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 2468da6c28aaSamw &response)) != 0) { 2469da6c28aaSamw perror("ls:getattrat"); 2470da6c28aaSamw return (error); 2471da6c28aaSamw } 2472da6c28aaSamw 2473da6c28aaSamw /* 2474da6c28aaSamw * Allocate 'sacnt' size array to hold extended timestamp 2475da6c28aaSamw * system attributes and initialize the array. 2476da6c28aaSamw */ 2477da6c28aaSamw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 2478da6c28aaSamw for (i = 0; i < sacnt; i++) { 2479da6c28aaSamw rep->extm[i].stm = 0; 2480da6c28aaSamw rep->extm[i].nstm = 0; 2481da6c28aaSamw rep->extm[i].name = NULL; 2482da6c28aaSamw } 2483da6c28aaSamw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 2484da6c28aaSamw name = nvpair_name(pair); 2485da6c28aaSamw type = nvpair_type(pair); 2486da6c28aaSamw if (type == DATA_TYPE_BOOLEAN_VALUE) { 2487da6c28aaSamw error = nvpair_value_boolean_value(pair, &value); 2488da6c28aaSamw if (error) { 2489da6c28aaSamw (void) fprintf(stderr, 2490da6c28aaSamw gettext("nvpair_value_boolean_value " 2491da6c28aaSamw "failed: error = %d\n"), error); 2492da6c28aaSamw continue; 2493da6c28aaSamw } 2494da6c28aaSamw if (name != NULL) 2495da6c28aaSamw set_sysattrb_display(name, value, rep); 2496da6c28aaSamw continue; 2497da6c28aaSamw } else if (type == DATA_TYPE_UINT64_ARRAY) { 2498da6c28aaSamw if (name != NULL) 2499da6c28aaSamw set_sysattrtm_display(name, rep); 2500da6c28aaSamw continue; 2501da6c28aaSamw } 2502da6c28aaSamw } 2503da6c28aaSamw nvlist_free(response); 2504da6c28aaSamw return (0); 2505da6c28aaSamw } 2506da6c28aaSamw 2507da6c28aaSamw /* Set extended system attribute boolean display */ 2508da6c28aaSamw 2509da6c28aaSamw void 2510da6c28aaSamw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 2511da6c28aaSamw { 2512da6c28aaSamw f_attr_t fattr; 2513da6c28aaSamw const char *opt; 2514da6c28aaSamw size_t len; 2515da6c28aaSamw 2516da6c28aaSamw fattr = name_to_attr(name); 2517da6c28aaSamw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 2518da6c28aaSamw if (vopt) { 2519da6c28aaSamw len = strlen(name); 2520da6c28aaSamw if (val) { 2521da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2522da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, name, 2523da6c28aaSamw len + 1); 2524da6c28aaSamw } else { 2525da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 3, rep); 2526da6c28aaSamw (void) snprintf(rep->exttr[fattr].name, len + 3, 2527da6c28aaSamw "no%s", name); 2528da6c28aaSamw } 2529da6c28aaSamw } else { 2530da6c28aaSamw opt = attr_to_option(fattr); 2531da6c28aaSamw if (opt != NULL) { 2532da6c28aaSamw len = strlen(opt); 2533da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2534da6c28aaSamw if (val) 2535da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2536da6c28aaSamw opt, len + 1); 2537da6c28aaSamw else 2538da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2539da6c28aaSamw "-", len + 1); 2540da6c28aaSamw } 2541da6c28aaSamw } 2542da6c28aaSamw } 2543da6c28aaSamw } 2544da6c28aaSamw 2545da6c28aaSamw /* Set extended system attribute timestamp display */ 2546da6c28aaSamw 2547da6c28aaSamw void 2548da6c28aaSamw set_sysattrtm_display(char *name, struct lbuf *rep) 2549da6c28aaSamw { 2550da6c28aaSamw uint_t nelem; 2551da6c28aaSamw uint64_t *value; 2552da6c28aaSamw int i; 2553da6c28aaSamw size_t len; 2554da6c28aaSamw 2555da6c28aaSamw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 2556da6c28aaSamw if (*value != NULL) { 2557da6c28aaSamw len = strlen(name); 2558da6c28aaSamw i = 0; 2559da6c28aaSamw while (rep->extm[i].stm != 0 && i < sacnt) 2560da6c28aaSamw i++; 2561da6c28aaSamw rep->extm[i].stm = value[0]; 2562da6c28aaSamw rep->extm[i].nstm = value[1]; 2563da6c28aaSamw rep->extm[i].name = xmalloc(len + 1, rep); 2564da6c28aaSamw (void) strlcpy(rep->extm[i].name, name, len + 1); 2565da6c28aaSamw } 2566da6c28aaSamw } 2567da6c28aaSamw } 2568da6c28aaSamw 2569da6c28aaSamw void 2570*5e1c72e1SJason King format_time(time_t sec, time_t nsec) 2571da6c28aaSamw { 2572*5e1c72e1SJason King const char *fstr = time_fmt_new; 2573da6c28aaSamw char fmt_buf[FMTSIZE]; 2574da6c28aaSamw 2575*5e1c72e1SJason King if (Eflg) { 2576*5e1c72e1SJason King (void) snprintf(fmt_buf, FMTSIZE, fstr, nsec); 2577*5e1c72e1SJason King (void) strftime(time_buf, sizeof (time_buf), fmt_buf, 2578*5e1c72e1SJason King localtime(&sec)); 2579*5e1c72e1SJason King return; 2580da6c28aaSamw } 2581da6c28aaSamw 2582*5e1c72e1SJason King if (sec < year || sec > now) 2583*5e1c72e1SJason King fstr = time_fmt_old; 2584*5e1c72e1SJason King 2585*5e1c72e1SJason King /* if a custom time was specified, shouldn't be localized */ 2586*5e1c72e1SJason King (void) strftime(time_buf, sizeof (time_buf), 2587*5e1c72e1SJason King (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr, 2588*5e1c72e1SJason King localtime(&sec)); 2589*5e1c72e1SJason King } 2590da6c28aaSamw 2591da6c28aaSamw void 2592da6c28aaSamw format_attrtime(struct lbuf *p) 2593da6c28aaSamw { 2594da6c28aaSamw int tmattr = 0; 2595da6c28aaSamw int i; 2596da6c28aaSamw 2597da6c28aaSamw if (p->extm != NULL) { 2598da6c28aaSamw for (i = 0; i < sacnt; i++) { 2599da6c28aaSamw if (p->extm[i].name != NULL) { 2600da6c28aaSamw tmattr = 1; 2601da6c28aaSamw break; 2602da6c28aaSamw } 2603da6c28aaSamw } 2604da6c28aaSamw } 2605*5e1c72e1SJason King 2606da6c28aaSamw if (tmattr) { 2607*5e1c72e1SJason King const char *old_save = time_fmt_old; 2608*5e1c72e1SJason King const char *new_save = time_fmt_new; 2609*5e1c72e1SJason King 2610*5e1c72e1SJason King /* Eflg always sets format to FORMAT_ISO_FULL */ 2611*5e1c72e1SJason King if (!Eflg && !time_custom) { 2612*5e1c72e1SJason King time_fmt_old = FORMAT_OLD; 2613*5e1c72e1SJason King time_fmt_new = FORMAT_NEW; 2614da6c28aaSamw } 2615*5e1c72e1SJason King 2616*5e1c72e1SJason King format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm); 2617*5e1c72e1SJason King 2618*5e1c72e1SJason King time_fmt_old = old_save; 2619*5e1c72e1SJason King time_fmt_new = new_save; 2620da6c28aaSamw } 2621da6c28aaSamw } 2622da6c28aaSamw 2623da6c28aaSamw void 2624da6c28aaSamw print_time(struct lbuf *p) 2625da6c28aaSamw { 2626*5e1c72e1SJason King const char *old_save = time_fmt_old; 2627*5e1c72e1SJason King const char *new_save = time_fmt_new; 2628*5e1c72e1SJason King 2629da6c28aaSamw int i = 0; 2630da6c28aaSamw 2631*5e1c72e1SJason King if (!Eflg) { 2632*5e1c72e1SJason King time_fmt_old = FORMAT_LONG; 2633*5e1c72e1SJason King time_fmt_new = FORMAT_LONG; 2634*5e1c72e1SJason King } 2635*5e1c72e1SJason King 2636da6c28aaSamw new_line(); 2637*5e1c72e1SJason King format_time(p->lat.tv_sec, p->lat.tv_nsec); 2638*5e1c72e1SJason King (void) printf(" timestamp: atime %s\n", time_buf); 2639*5e1c72e1SJason King format_time(p->lct.tv_sec, p->lct.tv_nsec); 2640*5e1c72e1SJason King (void) printf(" timestamp: ctime %s\n", time_buf); 2641*5e1c72e1SJason King format_time(p->lmt.tv_sec, p->lmt.tv_nsec); 2642*5e1c72e1SJason King (void) printf(" timestamp: mtime %s\n", time_buf); 2643da6c28aaSamw if (p->extm != NULL) { 2644da6c28aaSamw while (p->extm[i].nstm != 0 && i < sacnt) { 2645*5e1c72e1SJason King format_time(p->extm[i].stm, p->extm[i].nstm); 2646da6c28aaSamw if (p->extm[i].name != NULL) { 2647da6c28aaSamw (void) printf(" timestamp:" 2648da6c28aaSamw " %s %s\n", 2649da6c28aaSamw p->extm[i].name, time_buf); 2650da6c28aaSamw } 2651da6c28aaSamw i++; 2652da6c28aaSamw } 2653da6c28aaSamw } 2654*5e1c72e1SJason King 2655*5e1c72e1SJason King time_fmt_old = old_save; 2656*5e1c72e1SJason King time_fmt_new = new_save; 2657*5e1c72e1SJason King } 2658*5e1c72e1SJason King 2659*5e1c72e1SJason King /* 2660*5e1c72e1SJason King * Check if color definition applies to entry, returns 1 if yes, 0 if no 2661*5e1c72e1SJason King */ 2662*5e1c72e1SJason King static int 2663*5e1c72e1SJason King color_match(struct lbuf *entry, ls_color_t *color) 2664*5e1c72e1SJason King { 2665*5e1c72e1SJason King switch (color->ftype) { 2666*5e1c72e1SJason King case LS_PAT: 2667*5e1c72e1SJason King { 2668*5e1c72e1SJason King char *fname; 2669*5e1c72e1SJason King size_t fname_len, sfx_len; 2670*5e1c72e1SJason King 2671*5e1c72e1SJason King if (entry->lflags & ISARG) 2672*5e1c72e1SJason King fname = entry->ln.namep; 2673*5e1c72e1SJason King else 2674*5e1c72e1SJason King fname = entry->ln.lname; 2675*5e1c72e1SJason King 2676*5e1c72e1SJason King fname_len = strlen(fname); 2677*5e1c72e1SJason King sfx_len = strlen(color->sfx); 2678*5e1c72e1SJason King if (sfx_len > fname_len) 2679*5e1c72e1SJason King return (0); 2680*5e1c72e1SJason King 2681*5e1c72e1SJason King if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0) 2682*5e1c72e1SJason King return (1); 2683*5e1c72e1SJason King else 2684*5e1c72e1SJason King return (0); 2685*5e1c72e1SJason King } 2686*5e1c72e1SJason King 2687*5e1c72e1SJason King case LS_NORMAL: 2688*5e1c72e1SJason King return (1); 2689*5e1c72e1SJason King 2690*5e1c72e1SJason King case LS_FILE: 2691*5e1c72e1SJason King return ((entry->ltype == '-')); 2692*5e1c72e1SJason King 2693*5e1c72e1SJason King case LS_DIR: 2694*5e1c72e1SJason King return ((entry->ltype == 'd')); 2695*5e1c72e1SJason King 2696*5e1c72e1SJason King case LS_LINK: 2697*5e1c72e1SJason King return ((entry->ltype == 'l')); 2698*5e1c72e1SJason King 2699*5e1c72e1SJason King case LS_FIFO: 2700*5e1c72e1SJason King return ((entry->ltype == 'p')); 2701*5e1c72e1SJason King 2702*5e1c72e1SJason King case LS_SOCK: 2703*5e1c72e1SJason King return ((entry->ltype == 's')); 2704*5e1c72e1SJason King 2705*5e1c72e1SJason King case LS_DOOR: 2706*5e1c72e1SJason King return ((entry->ltype == 'D')); 2707*5e1c72e1SJason King 2708*5e1c72e1SJason King case LS_BLK: 2709*5e1c72e1SJason King return ((entry->ltype == 'b')); 2710*5e1c72e1SJason King 2711*5e1c72e1SJason King case LS_CHR: 2712*5e1c72e1SJason King return ((entry->ltype == 'c')); 2713*5e1c72e1SJason King 2714*5e1c72e1SJason King case LS_PORT: 2715*5e1c72e1SJason King return ((entry->ltype == 'P')); 2716*5e1c72e1SJason King 2717*5e1c72e1SJason King case LS_ORPHAN: 2718*5e1c72e1SJason King { 2719*5e1c72e1SJason King struct stat st; 2720*5e1c72e1SJason King int rc; 2721*5e1c72e1SJason King 2722*5e1c72e1SJason King if (entry->ltype != 'l') 2723*5e1c72e1SJason King return (0); 2724*5e1c72e1SJason King if (entry->flinkto == NULL) 2725*5e1c72e1SJason King return (1); 2726*5e1c72e1SJason King 2727*5e1c72e1SJason King if (entry->lflags & ISARG) 2728*5e1c72e1SJason King rc = stat(entry->ln.namep, &st); 2729*5e1c72e1SJason King else 2730*5e1c72e1SJason King rc = stat(entry->ln.lname, &st); 2731*5e1c72e1SJason King 2732*5e1c72e1SJason King if (rc == -1 && errno == ENOENT) 2733*5e1c72e1SJason King return (1); 2734*5e1c72e1SJason King 2735*5e1c72e1SJason King return (0); 2736*5e1c72e1SJason King } 2737*5e1c72e1SJason King 2738*5e1c72e1SJason King case LS_SETUID: 2739*5e1c72e1SJason King return (entry->ltype != 'l' && (entry->lflags & (S_ISUID))); 2740*5e1c72e1SJason King 2741*5e1c72e1SJason King case LS_SETGID: 2742*5e1c72e1SJason King return (entry->ltype != 'l' && (entry->lflags & (S_ISGID))); 2743*5e1c72e1SJason King 2744*5e1c72e1SJason King case LS_STICKY_OTHER_WRITABLE: 2745*5e1c72e1SJason King return (entry->ltype != 'l' && 2746*5e1c72e1SJason King (entry->lflags & (S_IWOTH|S_ISVTX))); 2747*5e1c72e1SJason King 2748*5e1c72e1SJason King case LS_OTHER_WRITABLE: 2749*5e1c72e1SJason King return (entry->ltype != 'l' && (entry->lflags & (S_IWOTH))); 2750*5e1c72e1SJason King 2751*5e1c72e1SJason King case LS_STICKY: 2752*5e1c72e1SJason King return (entry->ltype != 'l' && (entry->lflags & (S_ISVTX))); 2753*5e1c72e1SJason King 2754*5e1c72e1SJason King case LS_EXEC: 2755*5e1c72e1SJason King return (entry->ltype != 'l' && 2756*5e1c72e1SJason King (entry->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))); 2757*5e1c72e1SJason King } 2758*5e1c72e1SJason King 2759*5e1c72e1SJason King return (0); 2760*5e1c72e1SJason King } 2761*5e1c72e1SJason King 2762*5e1c72e1SJason King static void 2763*5e1c72e1SJason King dump_color(ls_color_t *c) 2764*5e1c72e1SJason King { 2765*5e1c72e1SJason King if (c == NULL) 2766*5e1c72e1SJason King return; 2767*5e1c72e1SJason King 2768*5e1c72e1SJason King (void) printf("\n\ttype: "); 2769*5e1c72e1SJason King switch (c->ftype) { 2770*5e1c72e1SJason King case LS_NORMAL: 2771*5e1c72e1SJason King (void) printf("LS_NORMAL"); 2772*5e1c72e1SJason King break; 2773*5e1c72e1SJason King case LS_FILE: 2774*5e1c72e1SJason King (void) printf("LS_FILE"); 2775*5e1c72e1SJason King break; 2776*5e1c72e1SJason King case LS_EXEC: 2777*5e1c72e1SJason King (void) printf("LS_EXEC"); 2778*5e1c72e1SJason King break; 2779*5e1c72e1SJason King case LS_DIR: 2780*5e1c72e1SJason King (void) printf("LS_DIR"); 2781*5e1c72e1SJason King break; 2782*5e1c72e1SJason King case LS_LINK: 2783*5e1c72e1SJason King (void) printf("LS_LINK"); 2784*5e1c72e1SJason King break; 2785*5e1c72e1SJason King 2786*5e1c72e1SJason King case LS_FIFO: 2787*5e1c72e1SJason King (void) printf("LS_FIFO"); 2788*5e1c72e1SJason King break; 2789*5e1c72e1SJason King 2790*5e1c72e1SJason King case LS_SOCK: 2791*5e1c72e1SJason King (void) printf("LS_SOCK"); 2792*5e1c72e1SJason King break; 2793*5e1c72e1SJason King 2794*5e1c72e1SJason King case LS_DOOR: 2795*5e1c72e1SJason King (void) printf("LS_DOOR"); 2796*5e1c72e1SJason King break; 2797*5e1c72e1SJason King 2798*5e1c72e1SJason King case LS_BLK: 2799*5e1c72e1SJason King (void) printf("LS_BLK"); 2800*5e1c72e1SJason King break; 2801*5e1c72e1SJason King 2802*5e1c72e1SJason King case LS_CHR: 2803*5e1c72e1SJason King (void) printf("LS_CHR"); 2804*5e1c72e1SJason King break; 2805*5e1c72e1SJason King 2806*5e1c72e1SJason King case LS_PORT: 2807*5e1c72e1SJason King (void) printf("LS_PORT"); 2808*5e1c72e1SJason King break; 2809*5e1c72e1SJason King 2810*5e1c72e1SJason King case LS_STICKY: 2811*5e1c72e1SJason King (void) printf("LS_STICKY"); 2812*5e1c72e1SJason King break; 2813*5e1c72e1SJason King 2814*5e1c72e1SJason King case LS_ORPHAN: 2815*5e1c72e1SJason King (void) printf("LS_ORPHAN"); 2816*5e1c72e1SJason King break; 2817*5e1c72e1SJason King 2818*5e1c72e1SJason King case LS_SETGID: 2819*5e1c72e1SJason King (void) printf("LS_SETGID"); 2820*5e1c72e1SJason King break; 2821*5e1c72e1SJason King 2822*5e1c72e1SJason King case LS_SETUID: 2823*5e1c72e1SJason King (void) printf("LS_SETUID"); 2824*5e1c72e1SJason King break; 2825*5e1c72e1SJason King 2826*5e1c72e1SJason King case LS_OTHER_WRITABLE: 2827*5e1c72e1SJason King (void) printf("LS_OTHER_WRITABLE"); 2828*5e1c72e1SJason King break; 2829*5e1c72e1SJason King 2830*5e1c72e1SJason King case LS_STICKY_OTHER_WRITABLE: 2831*5e1c72e1SJason King (void) printf("LS_STICKY_OTHER_WRITABLE"); 2832*5e1c72e1SJason King break; 2833*5e1c72e1SJason King 2834*5e1c72e1SJason King case LS_PAT: 2835*5e1c72e1SJason King (void) printf("LS_PAT\n"); 2836*5e1c72e1SJason King (void) printf("\tpattern: %s", c->sfx); 2837*5e1c72e1SJason King break; 2838*5e1c72e1SJason King } 2839*5e1c72e1SJason King (void) printf("\n"); 2840*5e1c72e1SJason King (void) printf("\tattr: %d\n", c->attr); 2841*5e1c72e1SJason King (void) printf("\tfg: %d\n", c->fg); 2842*5e1c72e1SJason King (void) printf("\tbg: %d\n", c->bg); 2843*5e1c72e1SJason King (void) printf("\t"); 2844*5e1c72e1SJason King } 2845*5e1c72e1SJason King 2846*5e1c72e1SJason King static ls_color_t * 2847*5e1c72e1SJason King get_color_attr(struct lbuf *l) 2848*5e1c72e1SJason King { 2849*5e1c72e1SJason King int i; 2850*5e1c72e1SJason King 2851*5e1c72e1SJason King /* 2852*5e1c72e1SJason King * Colors are sorted from most general lsc_colors[0] to most specific 2853*5e1c72e1SJason King * lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with 2854*5e1c72e1SJason King * most specific color rule and work towards most general. 2855*5e1c72e1SJason King */ 2856*5e1c72e1SJason King for (i = lsc_ncolors - 1; i >= 0; --i) 2857*5e1c72e1SJason King if (color_match(l, &lsc_colors[i])) 2858*5e1c72e1SJason King return (&lsc_colors[i]); 2859*5e1c72e1SJason King 2860*5e1c72e1SJason King return (NULL); 2861*5e1c72e1SJason King } 2862*5e1c72e1SJason King 2863*5e1c72e1SJason King static void 2864*5e1c72e1SJason King ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4, 2865*5e1c72e1SJason King long int p5, long int p6, long int p7, long int p8, long int p9) 2866*5e1c72e1SJason King { 2867*5e1c72e1SJason King char *s; 2868*5e1c72e1SJason King 2869*5e1c72e1SJason King if (str == NULL) 2870*5e1c72e1SJason King return; 2871*5e1c72e1SJason King 2872*5e1c72e1SJason King s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); 2873*5e1c72e1SJason King 2874*5e1c72e1SJason King if (s != NULL) 2875*5e1c72e1SJason King (void) putp(s); 2876*5e1c72e1SJason King } 2877*5e1c72e1SJason King 2878*5e1c72e1SJason King static void 2879*5e1c72e1SJason King ls_start_color(struct lbuf *l) 2880*5e1c72e1SJason King { 2881*5e1c72e1SJason King ls_color_t *c = get_color_attr(l); 2882*5e1c72e1SJason King 2883*5e1c72e1SJason King if (c == NULL) 2884*5e1c72e1SJason King return; 2885*5e1c72e1SJason King 2886*5e1c72e1SJason King if (lsc_debug) 2887*5e1c72e1SJason King lsc_match = c; 2888*5e1c72e1SJason King 2889*5e1c72e1SJason King if (c->attr & LSA_BOLD) 2890*5e1c72e1SJason King ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2891*5e1c72e1SJason King if (c->attr & LSA_UNDERSCORE) 2892*5e1c72e1SJason King ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2893*5e1c72e1SJason King if (c->attr & LSA_BLINK) 2894*5e1c72e1SJason King ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2895*5e1c72e1SJason King if (c->attr & LSA_REVERSE) 2896*5e1c72e1SJason King ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2897*5e1c72e1SJason King if (c->attr & LSA_CONCEALED) 2898*5e1c72e1SJason King ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2899*5e1c72e1SJason King if (c->attr == LSA_NONE) 2900*5e1c72e1SJason King ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2901*5e1c72e1SJason King 2902*5e1c72e1SJason King if (c->fg != -1) 2903*5e1c72e1SJason King ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0); 2904*5e1c72e1SJason King if (c->bg != -1) 2905*5e1c72e1SJason King ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0); 2906*5e1c72e1SJason King } 2907*5e1c72e1SJason King 2908*5e1c72e1SJason King static void 2909*5e1c72e1SJason King ls_end_color() 2910*5e1c72e1SJason King { 2911*5e1c72e1SJason King ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2912*5e1c72e1SJason King if (lsc_debug) 2913*5e1c72e1SJason King dump_color(lsc_match); 2914*5e1c72e1SJason King } 2915*5e1c72e1SJason King 2916*5e1c72e1SJason King static void 2917*5e1c72e1SJason King new_color_entry(char *colorstr) 2918*5e1c72e1SJason King { 2919*5e1c72e1SJason King static const struct { 2920*5e1c72e1SJason King const char *s; 2921*5e1c72e1SJason King ls_cftype_t stype; 2922*5e1c72e1SJason King } type_map[] = { 2923*5e1c72e1SJason King { "no", LS_NORMAL }, 2924*5e1c72e1SJason King { "fi", LS_FILE }, 2925*5e1c72e1SJason King { "di", LS_DIR }, 2926*5e1c72e1SJason King { "ln", LS_LINK }, 2927*5e1c72e1SJason King { "pi", LS_FIFO }, 2928*5e1c72e1SJason King { "so", LS_SOCK }, 2929*5e1c72e1SJason King { "do", LS_DOOR }, 2930*5e1c72e1SJason King { "bd", LS_BLK }, 2931*5e1c72e1SJason King { "cd", LS_CHR }, 2932*5e1c72e1SJason King { "or", LS_ORPHAN }, 2933*5e1c72e1SJason King { "su", LS_SETUID }, 2934*5e1c72e1SJason King { "sg", LS_SETGID }, 2935*5e1c72e1SJason King { "tw", LS_STICKY_OTHER_WRITABLE }, 2936*5e1c72e1SJason King { "ow", LS_OTHER_WRITABLE }, 2937*5e1c72e1SJason King { "st", LS_STICKY }, 2938*5e1c72e1SJason King { "ex", LS_EXEC }, 2939*5e1c72e1SJason King { "po", LS_PORT }, 2940*5e1c72e1SJason King { NULL, LS_NORMAL } 2941*5e1c72e1SJason King }; 2942*5e1c72e1SJason King 2943*5e1c72e1SJason King char *p, *lasts; 2944*5e1c72e1SJason King int i; 2945*5e1c72e1SJason King int color, attr; 2946*5e1c72e1SJason King 2947*5e1c72e1SJason King p = strtok_r(colorstr, "=", &lasts); 2948*5e1c72e1SJason King if (p == NULL) { 2949*5e1c72e1SJason King colorflg = 0; 2950*5e1c72e1SJason King return; 2951*5e1c72e1SJason King } 2952*5e1c72e1SJason King 2953*5e1c72e1SJason King if (p[0] == '*') { 2954*5e1c72e1SJason King lsc_colors[lsc_ncolors].ftype = LS_PAT; 2955*5e1c72e1SJason King /* don't include the * in the suffix */ 2956*5e1c72e1SJason King if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) { 2957*5e1c72e1SJason King colorflg = 0; 2958*5e1c72e1SJason King return; 2959*5e1c72e1SJason King } 2960da6c28aaSamw } else { 2961*5e1c72e1SJason King lsc_colors[lsc_ncolors].sfx = NULL; 2962*5e1c72e1SJason King 2963*5e1c72e1SJason King for (i = 0; type_map[i].s != NULL; ++i) { 2964*5e1c72e1SJason King if (strncmp(type_map[i].s, p, 2) == 0) 2965*5e1c72e1SJason King break; 2966da6c28aaSamw } 2967*5e1c72e1SJason King 2968*5e1c72e1SJason King /* ignore unknown file types */ 2969*5e1c72e1SJason King if (type_map[i].s == NULL) 2970*5e1c72e1SJason King return; 2971*5e1c72e1SJason King 2972*5e1c72e1SJason King lsc_colors[lsc_ncolors].ftype = type_map[i].stype; 2973*5e1c72e1SJason King } 2974*5e1c72e1SJason King 2975*5e1c72e1SJason King attr = LSA_NONE; 2976*5e1c72e1SJason King lsc_colors[lsc_ncolors].fg = -1; 2977*5e1c72e1SJason King lsc_colors[lsc_ncolors].bg = -1; 2978*5e1c72e1SJason King for (p = strtok_r(NULL, ";", &lasts); p != NULL; 2979*5e1c72e1SJason King p = strtok_r(NULL, ";", &lasts)) { 2980*5e1c72e1SJason King color = strtol(p, NULL, 10); 2981*5e1c72e1SJason King 2982*5e1c72e1SJason King if (color < 10) { 2983*5e1c72e1SJason King switch (color) { 2984*5e1c72e1SJason King case 0: 2985*5e1c72e1SJason King attr = LSA_NONE; 2986*5e1c72e1SJason King continue; 2987*5e1c72e1SJason King case 1: 2988*5e1c72e1SJason King attr |= LSA_BOLD; 2989*5e1c72e1SJason King continue; 2990*5e1c72e1SJason King case 4: 2991*5e1c72e1SJason King attr |= LSA_UNDERSCORE; 2992*5e1c72e1SJason King continue; 2993*5e1c72e1SJason King case 5: 2994*5e1c72e1SJason King attr |= LSA_BLINK; 2995*5e1c72e1SJason King continue; 2996*5e1c72e1SJason King case 7: 2997*5e1c72e1SJason King attr |= LSA_REVERSE; 2998*5e1c72e1SJason King continue; 2999*5e1c72e1SJason King case 8: 3000*5e1c72e1SJason King attr |= LSA_CONCEALED; 3001*5e1c72e1SJason King continue; 3002*5e1c72e1SJason King default: 3003*5e1c72e1SJason King continue; 3004da6c28aaSamw } 3005da6c28aaSamw } 3006*5e1c72e1SJason King 3007*5e1c72e1SJason King if (color < 40) 3008*5e1c72e1SJason King lsc_colors[lsc_ncolors].fg = color - 30; 3009*5e1c72e1SJason King else 3010*5e1c72e1SJason King lsc_colors[lsc_ncolors].bg = color - 40; 3011*5e1c72e1SJason King } 3012*5e1c72e1SJason King 3013*5e1c72e1SJason King lsc_colors[lsc_ncolors].attr = attr; 3014*5e1c72e1SJason King ++lsc_ncolors; 3015*5e1c72e1SJason King } 3016*5e1c72e1SJason King 3017*5e1c72e1SJason King static int 3018*5e1c72e1SJason King ls_color_compare(const void *p1, const void *p2) 3019*5e1c72e1SJason King { 3020*5e1c72e1SJason King const ls_color_t *c1 = (const ls_color_t *)p1; 3021*5e1c72e1SJason King const ls_color_t *c2 = (const ls_color_t *)p2; 3022*5e1c72e1SJason King 3023*5e1c72e1SJason King int ret = c1->ftype - c2->ftype; 3024*5e1c72e1SJason King 3025*5e1c72e1SJason King if (ret != 0) 3026*5e1c72e1SJason King return (ret); 3027*5e1c72e1SJason King 3028*5e1c72e1SJason King if (c1->ftype != LS_PAT) 3029*5e1c72e1SJason King return (ret); 3030*5e1c72e1SJason King 3031*5e1c72e1SJason King return (strcmp(c1->sfx, c2->sfx)); 3032*5e1c72e1SJason King } 3033*5e1c72e1SJason King 3034*5e1c72e1SJason King static void 3035*5e1c72e1SJason King ls_color_init() 3036*5e1c72e1SJason King { 3037*5e1c72e1SJason King static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35" 3038*5e1c72e1SJason King ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01" 3039*5e1c72e1SJason King ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31" 3040*5e1c72e1SJason King ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31" 3041*5e1c72e1SJason King ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31" 3042*5e1c72e1SJason King ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35" 3043*5e1c72e1SJason King ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35" 3044*5e1c72e1SJason King ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35" 3045*5e1c72e1SJason King ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35" 3046*5e1c72e1SJason King ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35" 3047*5e1c72e1SJason King ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35"; 3048*5e1c72e1SJason King 3049*5e1c72e1SJason King char *colorstr; 3050*5e1c72e1SJason King char *p, *lasts; 3051*5e1c72e1SJason King size_t color_sz; 3052*5e1c72e1SJason King int termret; 3053*5e1c72e1SJason King 3054*5e1c72e1SJason King (void) setupterm(NULL, 1, &termret); 3055*5e1c72e1SJason King if (termret != 1) 3056*5e1c72e1SJason King return; 3057*5e1c72e1SJason King 3058*5e1c72e1SJason King if ((colorstr = getenv("LS_COLORS")) == NULL) 3059*5e1c72e1SJason King colorstr = default_colorstr; 3060*5e1c72e1SJason King 3061*5e1c72e1SJason King color_sz = 0; 3062*5e1c72e1SJason King for (p = strchr(colorstr, ':'); p != NULL && *p != '\0'; 3063*5e1c72e1SJason King p = strchr(++p, ':')) 3064*5e1c72e1SJason King ++color_sz; 3065*5e1c72e1SJason King 3066*5e1c72e1SJason King lsc_colors = calloc(color_sz, sizeof (ls_color_t)); 3067*5e1c72e1SJason King if (lsc_colors == NULL) { 3068*5e1c72e1SJason King free(colorstr); 3069*5e1c72e1SJason King return; 3070*5e1c72e1SJason King } 3071*5e1c72e1SJason King 3072*5e1c72e1SJason King for (p = strtok_r(colorstr, ":", &lasts); 3073*5e1c72e1SJason King p != NULL && lsc_ncolors < color_sz; 3074*5e1c72e1SJason King p = strtok_r(NULL, ":", &lasts)) 3075*5e1c72e1SJason King new_color_entry(p); 3076*5e1c72e1SJason King 3077*5e1c72e1SJason King qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t), 3078*5e1c72e1SJason King ls_color_compare); 3079*5e1c72e1SJason King 3080*5e1c72e1SJason King if ((lsc_bold = tigetstr("bold")) == (char *)-1) 3081*5e1c72e1SJason King lsc_bold = NULL; 3082*5e1c72e1SJason King 3083*5e1c72e1SJason King if ((lsc_underline = tigetstr("smul")) == (char *)-1) 3084*5e1c72e1SJason King lsc_underline = NULL; 3085*5e1c72e1SJason King 3086*5e1c72e1SJason King if ((lsc_blink = tigetstr("blink")) == (char *)-1) 3087*5e1c72e1SJason King lsc_blink = NULL; 3088*5e1c72e1SJason King 3089*5e1c72e1SJason King if ((lsc_reverse = tigetstr("rev")) == (char *)-1) 3090*5e1c72e1SJason King lsc_reverse = NULL; 3091*5e1c72e1SJason King 3092*5e1c72e1SJason King if ((lsc_concealed = tigetstr("prot")) == (char *)-1) 3093*5e1c72e1SJason King lsc_concealed = NULL; 3094*5e1c72e1SJason King 3095*5e1c72e1SJason King if ((lsc_none = tigetstr("sgr0")) == (char *)-1) 3096*5e1c72e1SJason King lsc_none = NULL; 3097*5e1c72e1SJason King 3098*5e1c72e1SJason King if ((lsc_setfg = tigetstr("setaf")) == (char *)-1) 3099*5e1c72e1SJason King lsc_setfg = NULL; 3100*5e1c72e1SJason King 3101*5e1c72e1SJason King if ((lsc_setbg = tigetstr("setab")) == (char *)-1) 3102*5e1c72e1SJason King lsc_setbg = NULL; 3103*5e1c72e1SJason King 3104*5e1c72e1SJason King if (getenv("_LS_COLOR_DEBUG") != NULL) { 3105*5e1c72e1SJason King int i; 3106*5e1c72e1SJason King 3107*5e1c72e1SJason King lsc_debug = 1; 3108*5e1c72e1SJason King for (i = 0; i < lsc_ncolors; ++i) 3109*5e1c72e1SJason King dump_color(&lsc_colors[i]); 3110da6c28aaSamw } 3111da6c28aaSamw } 3112da6c28aaSamw 3113da6c28aaSamw /* Free extended system attribute lists */ 3114da6c28aaSamw 3115da6c28aaSamw void 3116da6c28aaSamw free_sysattr(struct lbuf *p) 3117da6c28aaSamw { 3118da6c28aaSamw int i; 3119da6c28aaSamw 3120da6c28aaSamw if (p->exttr != NULL) { 3121da6c28aaSamw for (i = 0; i < sacnt; i++) { 3122da6c28aaSamw if (p->exttr[i].name != NULL) 3123da6c28aaSamw free(p->exttr[i].name); 3124da6c28aaSamw } 3125da6c28aaSamw free(p->exttr); 3126da6c28aaSamw } 3127da6c28aaSamw if (p->extm != NULL) { 3128da6c28aaSamw for (i = 0; i < sacnt; i++) { 3129da6c28aaSamw if (p->extm[i].name != NULL) 3130da6c28aaSamw free(p->extm[i].name); 3131da6c28aaSamw } 3132da6c28aaSamw free(p->extm); 3133da6c28aaSamw } 3134da6c28aaSamw } 3135da6c28aaSamw 3136da6c28aaSamw /* Allocate extended system attribute list */ 3137da6c28aaSamw 3138da6c28aaSamw void * 3139da6c28aaSamw xmalloc(size_t size, struct lbuf *p) 3140da6c28aaSamw { 3141da6c28aaSamw if ((p = malloc(size)) == NULL) { 3142da6c28aaSamw perror("ls"); 3143da6c28aaSamw free_sysattr(p); 3144da6c28aaSamw nvlist_free(response); 3145da6c28aaSamw exit(2); 3146da6c28aaSamw } 3147da6c28aaSamw return (p); 3148da6c28aaSamw } 3149