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 */ 215e1c72e1SJason King 227c478bd9Sstevel@tonic-gate /* 2327dd1e87SMark Shellenbaum * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 245e1c72e1SJason King */ 255e1c72e1SJason King 265e1c72e1SJason King /* 275e1c72e1SJason King * Copyright 2009 Jason King. All rights reserved. 287c478bd9Sstevel@tonic-gate * Use is subject to license terms. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 327c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 357c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * List files or directories 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/param.h> 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 447c478bd9Sstevel@tonic-gate #include <sys/stat.h> 457c478bd9Sstevel@tonic-gate #include <sys/acl.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <wchar.h> 487c478bd9Sstevel@tonic-gate #include <stdio.h> 497c478bd9Sstevel@tonic-gate #include <ctype.h> 507c478bd9Sstevel@tonic-gate #include <dirent.h> 517c478bd9Sstevel@tonic-gate #include <string.h> 527c478bd9Sstevel@tonic-gate #include <locale.h> 537c478bd9Sstevel@tonic-gate #include <curses.h> 545e1c72e1SJason King #include <term.h> 557c478bd9Sstevel@tonic-gate #include <termios.h> 567c478bd9Sstevel@tonic-gate #include <stdlib.h> 577c478bd9Sstevel@tonic-gate #include <widec.h> 587c478bd9Sstevel@tonic-gate #include <locale.h> 597c478bd9Sstevel@tonic-gate #include <wctype.h> 607c478bd9Sstevel@tonic-gate #include <pwd.h> 617c478bd9Sstevel@tonic-gate #include <grp.h> 627c478bd9Sstevel@tonic-gate #include <limits.h> 637c478bd9Sstevel@tonic-gate #include <fcntl.h> 647c478bd9Sstevel@tonic-gate #include <unistd.h> 657c478bd9Sstevel@tonic-gate #include <libgen.h> 667c478bd9Sstevel@tonic-gate #include <errno.h> 67fa9e4066Sahrens #include <aclutils.h> 68da6c28aaSamw #include <libnvpair.h> 69da6c28aaSamw #include <libcmdutils.h> 70da6c28aaSamw #include <attr.h> 715e1c72e1SJason King #include <getopt.h> 725e1c72e1SJason King #include <inttypes.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #ifndef STANDALONE 757c478bd9Sstevel@tonic-gate #define TERMINFO 767c478bd9Sstevel@tonic-gate #endif 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 807c478bd9Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 81da6c28aaSamw * the terminfo feature(pre 6.0 systems ?). 827c478bd9Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 837c478bd9Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO 867c478bd9Sstevel@tonic-gate #undef TERMINFO 877c478bd9Sstevel@tonic-gate #endif 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #include <term.h> 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate #define BFSIZE 16 927c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 937c478bd9Sstevel@tonic-gate #define ISARG 0100000 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 977c478bd9Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate #define LS_NOTREG 010000 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Date and time formats 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * b --- abbreviated month name 1067c478bd9Sstevel@tonic-gate * e --- day number 1077c478bd9Sstevel@tonic-gate * Y --- year in the form ccyy 1087c478bd9Sstevel@tonic-gate * H --- hour(24-hour version) 1097c478bd9Sstevel@tonic-gate * M --- minute 1107c478bd9Sstevel@tonic-gate * F --- yyyy-mm-dd 1117c478bd9Sstevel@tonic-gate * T --- hh:mm:ss 1127c478bd9Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1137c478bd9Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1147c478bd9Sstevel@tonic-gate * not present in older C libraries 1157c478bd9Sstevel@tonic-gate */ 1165e1c72e1SJason King #define FORMAT_OLD " %b %e %Y " 1175e1c72e1SJason King #define FORMAT_NEW " %b %e %H:%M " 1185e1c72e1SJason King #define FORMAT_LONG " %b %e %T %Y " 1195e1c72e1SJason King #define FORMAT_ISO_FULL " %%F %%T.%.09ld %%z " 1205e1c72e1SJason King #define FORMAT_ISO_LONG " %F %R " 1215e1c72e1SJason King #define FORMAT_ISO_NEW " %m-%d %H:%M " 1225e1c72e1SJason King #define FORMAT_ISO_OLD " %F " 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #undef BUFSIZ 1257c478bd9Sstevel@tonic-gate #define BUFSIZ 4096 1267c478bd9Sstevel@tonic-gate #define NUMBER_WIDTH 40 1277c478bd9Sstevel@tonic-gate #define FMTSIZE 50 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate struct ditem { 1307c478bd9Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1317c478bd9Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1327c478bd9Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1337c478bd9Sstevel@tonic-gate }; 134da6c28aaSamw /* Holds boolean extended system attributes */ 135da6c28aaSamw struct attrb { 136da6c28aaSamw char *name; 137da6c28aaSamw }; 138da6c28aaSamw /* Holds timestamp extended system attributes */ 139da6c28aaSamw struct attrtm { 140da6c28aaSamw char *name; 141da6c28aaSamw uint64_t stm; 142da6c28aaSamw uint64_t nstm; 143da6c28aaSamw }; 1447c478bd9Sstevel@tonic-gate 1455e1c72e1SJason King #define LSA_NONE (0) 1465e1c72e1SJason King #define LSA_BOLD (1L << 0) 1475e1c72e1SJason King #define LSA_UNDERSCORE (1L << 1) 1485e1c72e1SJason King #define LSA_BLINK (1L << 2) 1495e1c72e1SJason King #define LSA_REVERSE (1L << 3) 1505e1c72e1SJason King #define LSA_CONCEALED (1L << 4) 1515e1c72e1SJason King 1525e1c72e1SJason King /* these should be ordered most general to most specific */ 1535e1c72e1SJason King typedef enum LS_CFTYPE { 1545e1c72e1SJason King LS_NORMAL, 1555e1c72e1SJason King LS_FILE, 1565e1c72e1SJason King LS_EXEC, 1575e1c72e1SJason King LS_DIR, 1585e1c72e1SJason King LS_LINK, 1595e1c72e1SJason King LS_FIFO, 1605e1c72e1SJason King LS_SOCK, 1615e1c72e1SJason King LS_DOOR, 1625e1c72e1SJason King LS_BLK, 1635e1c72e1SJason King LS_CHR, 1645e1c72e1SJason King LS_PORT, 1655e1c72e1SJason King LS_STICKY, 1665e1c72e1SJason King LS_ORPHAN, 1675e1c72e1SJason King LS_SETGID, 1685e1c72e1SJason King LS_SETUID, 1695e1c72e1SJason King LS_OTHER_WRITABLE, 1705e1c72e1SJason King LS_STICKY_OTHER_WRITABLE, 1715e1c72e1SJason King LS_PAT 1725e1c72e1SJason King } ls_cftype_t; 1735e1c72e1SJason King 1741b628248SJason King typedef struct { 1755e1c72e1SJason King char *sfx; 1765e1c72e1SJason King ls_cftype_t ftype; 1775e1c72e1SJason King int attr; 1785e1c72e1SJason King int fg; 1795e1c72e1SJason King int bg; 1805e1c72e1SJason King } ls_color_t; 1815e1c72e1SJason King 1821b628248SJason King struct lbuf { 1831b628248SJason King union { 1841b628248SJason King char lname[MAXNAMLEN]; /* used for filename in a directory */ 1851b628248SJason King char *namep; /* for name in ls-command; */ 1861b628248SJason King } ln; 1871b628248SJason King char ltype; /* filetype */ 1881b628248SJason King ino_t lnum; /* inode number of file */ 1891b628248SJason King mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1901b628248SJason King nlink_t lnl; /* number of links to file */ 1911b628248SJason King uid_t luid; 1921b628248SJason King gid_t lgid; 1931b628248SJason King off_t lsize; /* filesize or major/minor dev numbers */ 1941b628248SJason King blkcnt_t lblocks; /* number of file blocks */ 1951b628248SJason King timestruc_t lmtime; 1961b628248SJason King timestruc_t lat; 1971b628248SJason King timestruc_t lct; 1981b628248SJason King timestruc_t lmt; 1991b628248SJason King char *flinkto; /* symbolic link contents */ 2001b628248SJason King char acl; /* indicate there are additional acl entries */ 2011b628248SJason King int cycle; /* cycle detected flag */ 2021b628248SJason King struct ditem *ancinfo; /* maintains ancestor info */ 2031b628248SJason King acl_t *aclp; /* ACL if present */ 2041b628248SJason King struct attrb *exttr; /* boolean extended system attributes */ 2051b628248SJason King struct attrtm *extm; /* timestamp extended system attributes */ 2061b628248SJason King ls_color_t *color; /* color for entry */ 2071b628248SJason King ls_color_t *link_color; /* color for symlink */ 2081b628248SJason King }; 2091b628248SJason King 2101b628248SJason King struct dchain { 2111b628248SJason King char *dc_name; /* path name */ 2121b628248SJason King int cycle_detected; /* cycle detected visiting this directory */ 2131b628248SJason King struct ditem *myancinfo; /* this directory's ancestry info */ 2141b628248SJason King struct dchain *dc_next; /* next directory in the chain */ 2151b628248SJason King }; 2161b628248SJason King 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 2237c478bd9Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 2247c478bd9Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 2257c478bd9Sstevel@tonic-gate static char *curdir; /* the current directory */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 2287c478bd9Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 2297c478bd9Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 2307c478bd9Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 2317c478bd9Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 2327c478bd9Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 2357c478bd9Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 2367c478bd9Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 2377c478bd9Sstevel@tonic-gate static char *getname(uid_t); 2387c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 2397c478bd9Sstevel@tonic-gate static char *makename(char *, char *); 2407c478bd9Sstevel@tonic-gate static void pentry(struct lbuf *); 2417c478bd9Sstevel@tonic-gate static void column(void); 2427c478bd9Sstevel@tonic-gate static void pmode(mode_t aflag); 2437c478bd9Sstevel@tonic-gate static void selection(int *); 2447c478bd9Sstevel@tonic-gate static void new_line(void); 2457c478bd9Sstevel@tonic-gate static void rddir(char *, struct ditem *); 2467c478bd9Sstevel@tonic-gate static int strcol(unsigned char *); 2477c478bd9Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2487c478bd9Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2497c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2507c478bd9Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2517c478bd9Sstevel@tonic-gate static void pprintf(char *, char *); 2527c478bd9Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2537c478bd9Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2547c478bd9Sstevel@tonic-gate unsigned long long number, 2557c478bd9Sstevel@tonic-gate long scale); 2567c478bd9Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2577c478bd9Sstevel@tonic-gate int, struct ditem *); 2585e1c72e1SJason King static void ls_color_init(void); 2591b628248SJason King static ls_color_t *ls_color_find(const char *, mode_t); 2601b628248SJason King static void ls_start_color(ls_color_t *); 2615e1c72e1SJason King static void ls_end_color(void); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static int aflg; 2647c478bd9Sstevel@tonic-gate static int atflg; 2657c478bd9Sstevel@tonic-gate static int bflg; 2667c478bd9Sstevel@tonic-gate static int cflg; 2677c478bd9Sstevel@tonic-gate static int dflg; 2687c478bd9Sstevel@tonic-gate static int eflg; 2697c478bd9Sstevel@tonic-gate static int fflg; 2707c478bd9Sstevel@tonic-gate static int gflg; 2717c478bd9Sstevel@tonic-gate static int hflg; 2727c478bd9Sstevel@tonic-gate static int iflg; 2737c478bd9Sstevel@tonic-gate static int lflg; 2747c478bd9Sstevel@tonic-gate static int mflg; 2757c478bd9Sstevel@tonic-gate static int nflg; 2767c478bd9Sstevel@tonic-gate static int oflg; 2777c478bd9Sstevel@tonic-gate static int pflg; 2787c478bd9Sstevel@tonic-gate static int qflg; 2797c478bd9Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2807c478bd9Sstevel@tonic-gate static int sflg; 2817c478bd9Sstevel@tonic-gate static int tflg; 2827c478bd9Sstevel@tonic-gate static int uflg; 2835e1c72e1SJason King static int Uflg; 2845e1c72e1SJason King static int wflg; 2857c478bd9Sstevel@tonic-gate static int xflg; 2867c478bd9Sstevel@tonic-gate static int Aflg; 2875e1c72e1SJason King static int Bflg; 2887c478bd9Sstevel@tonic-gate static int Cflg; 2897c478bd9Sstevel@tonic-gate static int Eflg; 2907c478bd9Sstevel@tonic-gate static int Fflg; 2917c478bd9Sstevel@tonic-gate static int Hflg; 2927c478bd9Sstevel@tonic-gate static int Lflg; 2937c478bd9Sstevel@tonic-gate static int Rflg; 2947c478bd9Sstevel@tonic-gate static int Sflg; 295fa9e4066Sahrens static int vflg; 2965a5eeccaSmarks static int Vflg; 297da6c28aaSamw static int saflg; /* boolean extended system attr. */ 298da6c28aaSamw static int sacnt; /* number of extended system attr. */ 299da6c28aaSamw static int copt; 300da6c28aaSamw static int vopt; 301da6c28aaSamw static int tmflg; /* create time ext. system attr. */ 302da6c28aaSamw static int ctm; 303da6c28aaSamw static int atm; 304da6c28aaSamw static int mtm; 305da6c28aaSamw static int crtm; 306da6c28aaSamw static int alltm; 3077c478bd9Sstevel@tonic-gate static long hscale; 3087c478bd9Sstevel@tonic-gate static mode_t flags; 3097c478bd9Sstevel@tonic-gate static int err = 0; /* Contains return code */ 3105e1c72e1SJason King static int colorflg; 3115e1c72e1SJason King static int file_typeflg; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 3147c478bd9Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 3157c478bd9Sstevel@tonic-gate static char *lastuname = NULL; 3167c478bd9Sstevel@tonic-gate static char *lastgname = NULL; 3177c478bd9Sstevel@tonic-gate 3185e1c72e1SJason King /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */ 3197c478bd9Sstevel@tonic-gate static int statreq; 3207c478bd9Sstevel@tonic-gate 3215e1c72e1SJason King static uint64_t block_size = 1; 3227c478bd9Sstevel@tonic-gate static char *dotp = "."; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 3257c478bd9Sstevel@tonic-gate static time_t year, now; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate static int num_cols = 80; 3287c478bd9Sstevel@tonic-gate static int colwidth; 3297c478bd9Sstevel@tonic-gate static int filewidth; 3307c478bd9Sstevel@tonic-gate static int fixedwidth; 3317c478bd9Sstevel@tonic-gate static int nomocore; 3327c478bd9Sstevel@tonic-gate static int curcol; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate static struct winsize win; 3357c478bd9Sstevel@tonic-gate 3365e1c72e1SJason King /* if time_fmt_new is left NULL, time_fmt_old is used for all times */ 3375e1c72e1SJason King static const char *time_fmt_old = FORMAT_OLD; /* non-recent files */ 3385e1c72e1SJason King static const char *time_fmt_new = FORMAT_NEW; /* recent files */ 3395e1c72e1SJason King static int time_custom; /* != 0 if a custom format */ 340da6c28aaSamw static char time_buf[FMTSIZE]; /* array to hold day and time */ 3417c478bd9Sstevel@tonic-gate 3425e1c72e1SJason King static int lsc_debug; 3435e1c72e1SJason King static ls_color_t *lsc_match; 3445e1c72e1SJason King static ls_color_t *lsc_colors; 3455e1c72e1SJason King static size_t lsc_ncolors; 3465e1c72e1SJason King static char *lsc_bold; 3475e1c72e1SJason King static char *lsc_underline; 3485e1c72e1SJason King static char *lsc_blink; 3495e1c72e1SJason King static char *lsc_reverse; 3505e1c72e1SJason King static char *lsc_concealed; 3515e1c72e1SJason King static char *lsc_none; 3525e1c72e1SJason King static char *lsc_setfg; 3535e1c72e1SJason King static char *lsc_setbg; 3541b628248SJason King static ls_color_t *lsc_orphan; 3555e1c72e1SJason King 3567c478bd9Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 3577c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 3607c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 361da6c28aaSamw /* Extended system attributes support */ 362da6c28aaSamw static int get_sysxattr(char *, struct lbuf *); 363da6c28aaSamw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 364da6c28aaSamw static void set_sysattrtm_display(char *, struct lbuf *); 3655e1c72e1SJason King static void format_time(time_t, time_t); 366da6c28aaSamw static void print_time(struct lbuf *); 367da6c28aaSamw static void format_attrtime(struct lbuf *); 368da6c28aaSamw static void *xmalloc(size_t, struct lbuf *); 369da6c28aaSamw static void free_sysattr(struct lbuf *); 370da6c28aaSamw static nvpair_t *pair; 371da6c28aaSamw static nvlist_t *response; 37256798e90Sbasabi static int acl_err; 3737c478bd9Sstevel@tonic-gate 3745e1c72e1SJason King const struct option long_options[] = { 3755e1c72e1SJason King { "all", no_argument, NULL, 'a' }, 3765e1c72e1SJason King { "almost-all", no_argument, NULL, 'A' }, 3775e1c72e1SJason King { "escape", no_argument, NULL, 'b' }, 3785e1c72e1SJason King { "classify", no_argument, NULL, 'F' }, 3795e1c72e1SJason King { "human-readable", no_argument, NULL, 'h' }, 3805e1c72e1SJason King { "dereference", no_argument, NULL, 'L' }, 3815e1c72e1SJason King { "dereference-command-line", no_argument, NULL, 'H' }, 3825e1c72e1SJason King { "ignore-backups", no_argument, NULL, 'B' }, 3835e1c72e1SJason King { "inode", no_argument, NULL, 'i' }, 3845e1c72e1SJason King { "numeric-uid-gid", no_argument, NULL, 'n' }, 3855e1c72e1SJason King { "no-group", no_argument, NULL, 'o' }, 3865e1c72e1SJason King { "hide-control-chars", no_argument, NULL, 'q' }, 3875e1c72e1SJason King { "reverse", no_argument, NULL, 'r' }, 3885e1c72e1SJason King { "recursive", no_argument, NULL, 'R' }, 3895e1c72e1SJason King { "size", no_argument, NULL, 's' }, 3905e1c72e1SJason King { "width", required_argument, NULL, 'w' }, 3915e1c72e1SJason King 3925e1c72e1SJason King /* no short options for these */ 3935e1c72e1SJason King { "block-size", required_argument, NULL, 0 }, 3945e1c72e1SJason King { "full-time", no_argument, NULL, 0 }, 3955e1c72e1SJason King { "si", no_argument, NULL, 0 }, 3965e1c72e1SJason King { "color", optional_argument, NULL, 0 }, 3975e1c72e1SJason King { "colour", optional_argument, NULL, 0}, 3985e1c72e1SJason King { "file-type", no_argument, NULL, 0 }, 3995e1c72e1SJason King { "time-style", required_argument, NULL, 0 }, 4005e1c72e1SJason King 4015e1c72e1SJason King {0, 0, 0, 0} 4025e1c72e1SJason King }; 4035e1c72e1SJason King 4047c478bd9Sstevel@tonic-gate int 4057c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate int c; 4087c478bd9Sstevel@tonic-gate int i; 4097c478bd9Sstevel@tonic-gate int width; 4107c478bd9Sstevel@tonic-gate int amino = 0; 4117c478bd9Sstevel@tonic-gate int opterr = 0; 4125e1c72e1SJason King int option_index = 0; 4137c478bd9Sstevel@tonic-gate struct lbuf *ep; 4147c478bd9Sstevel@tonic-gate struct lbuf lb; 4157c478bd9Sstevel@tonic-gate struct ditem *myinfo; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4187c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 4197c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 4207c478bd9Sstevel@tonic-gate #endif 4217c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4227c478bd9Sstevel@tonic-gate #ifdef STANDALONE 4237c478bd9Sstevel@tonic-gate if (argv[0][0] == '\0') 4247c478bd9Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 4257c478bd9Sstevel@tonic-gate #endif 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 4287c478bd9Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 4297c478bd9Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 4307c478bd9Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 4317c478bd9Sstevel@tonic-gate if (isatty(1)) { 4327c478bd9Sstevel@tonic-gate Cflg = 1; 4337c478bd9Sstevel@tonic-gate mflg = 0; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4365e1c72e1SJason King while ((c = getopt_long(argc, argv, 4375e1c72e1SJason King "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options, 4385e1c72e1SJason King &option_index)) != -1) 4397c478bd9Sstevel@tonic-gate switch (c) { 4405e1c72e1SJason King case 0: 4415e1c72e1SJason King /* non-short options */ 4425e1c72e1SJason King if (strcmp(long_options[option_index].name, 4435e1c72e1SJason King "color") == 0 || 4445e1c72e1SJason King strcmp(long_options[option_index].name, 4455e1c72e1SJason King "colour") == 0) { 4465e1c72e1SJason King if (optarg == NULL || 4475e1c72e1SJason King strcmp(optarg, "always") == 0 || 4485e1c72e1SJason King strcmp(optarg, "yes") == 0 || 4495e1c72e1SJason King strcmp(optarg, "force") == 0) { 4505e1c72e1SJason King colorflg++; 4515e1c72e1SJason King statreq++; 4525e1c72e1SJason King continue; 4535e1c72e1SJason King } 4545e1c72e1SJason King 455c7a7d03cSJason King if (strcmp(optarg, "auto") == 0 || 4565e1c72e1SJason King strcmp(optarg, "tty") == 0 || 457c7a7d03cSJason King strcmp(optarg, "if-tty") == 0) { 458c7a7d03cSJason King if (isatty(1) == 1) { 4595e1c72e1SJason King colorflg++; 4605e1c72e1SJason King statreq++; 461c7a7d03cSJason King } 4625e1c72e1SJason King continue; 4635e1c72e1SJason King } 4645e1c72e1SJason King 4655e1c72e1SJason King if (strcmp(optarg, "never") == 0 || 4665e1c72e1SJason King strcmp(optarg, "no") == 0 || 4675e1c72e1SJason King strcmp(optarg, "none") == 0) { 4685e1c72e1SJason King colorflg = 0; 4695e1c72e1SJason King continue; 4705e1c72e1SJason King } 4715e1c72e1SJason King (void) fprintf(stderr, 4725e1c72e1SJason King gettext("Invalid argument '%s' for " 4735e1c72e1SJason King "--color\n"), optarg); 4745e1c72e1SJason King ++opterr; 4755e1c72e1SJason King continue; 4765e1c72e1SJason King } 4775e1c72e1SJason King 4785e1c72e1SJason King if (strcmp(long_options[option_index].name, 4795e1c72e1SJason King "si") == 0) { 4805e1c72e1SJason King hflg++; 4815e1c72e1SJason King hscale = 1000; 4825e1c72e1SJason King continue; 4835e1c72e1SJason King } 4845e1c72e1SJason King 4855e1c72e1SJason King if (strcmp(long_options[option_index].name, 4865e1c72e1SJason King "block-size") == 0) { 4875e1c72e1SJason King size_t scale_len = strlen(optarg); 4885e1c72e1SJason King uint64_t scale = 1; 4895e1c72e1SJason King uint64_t kilo = 1024; 4905e1c72e1SJason King char scale_c; 4915e1c72e1SJason King 4925e1c72e1SJason King if (scale_len == 0) { 4935e1c72e1SJason King (void) fprintf(stderr, gettext( 4945e1c72e1SJason King "Invalid block size \'%s\'\n"), 4955e1c72e1SJason King optarg); 4965e1c72e1SJason King exit(1); 4975e1c72e1SJason King } 4985e1c72e1SJason King 4995e1c72e1SJason King scale_c = optarg[scale_len - 1]; 5005e1c72e1SJason King if (scale_c == 'B') { 5015e1c72e1SJason King /* need at least digit, scale, B */ 5025e1c72e1SJason King if (scale_len < 3) { 5035e1c72e1SJason King (void) fprintf(stderr, gettext( 5045e1c72e1SJason King "Invalid block size " 5055e1c72e1SJason King "\'%s\'\n"), optarg); 5065e1c72e1SJason King exit(1); 5075e1c72e1SJason King } 5085e1c72e1SJason King kilo = 1000; 5095e1c72e1SJason King scale_c = optarg[scale_len - 2]; 5105e1c72e1SJason King if (isdigit(scale_c)) { 5115e1c72e1SJason King (void) fprintf(stderr, 5125e1c72e1SJason King gettext("Invalid block size" 5135e1c72e1SJason King " \'%s\'\n"), optarg); 5145e1c72e1SJason King exit(1); 5155e1c72e1SJason King } 5165e1c72e1SJason King /* 5175e1c72e1SJason King * make optarg[scale_len - 1] point to 5185e1c72e1SJason King * the scale factor 5195e1c72e1SJason King */ 5205e1c72e1SJason King --scale_len; 5215e1c72e1SJason King } 5225e1c72e1SJason King 5235e1c72e1SJason King switch (scale_c) { 5245e1c72e1SJason King case 'y': 5255e1c72e1SJason King case 'Y': 5265e1c72e1SJason King scale *= kilo; 5275e1c72e1SJason King /*FALLTHROUGH*/ 5285e1c72e1SJason King case 'Z': 5295e1c72e1SJason King case 'z': 5305e1c72e1SJason King scale *= kilo; 5315e1c72e1SJason King /*FALLTHROUGH*/ 5325e1c72e1SJason King case 'E': 5335e1c72e1SJason King case 'e': 5345e1c72e1SJason King scale *= kilo; 5355e1c72e1SJason King /*FALLTHROUGH*/ 5365e1c72e1SJason King case 'P': 5375e1c72e1SJason King case 'p': 5385e1c72e1SJason King scale *= kilo; 5395e1c72e1SJason King /*FALLTHROUGH*/ 5405e1c72e1SJason King case 'T': 5415e1c72e1SJason King case 't': 5425e1c72e1SJason King scale *= kilo; 5435e1c72e1SJason King /*FALLTHROUGH*/ 5445e1c72e1SJason King case 'G': 5455e1c72e1SJason King case 'g': 5465e1c72e1SJason King scale *= kilo; 5475e1c72e1SJason King /*FALLTHROUGH*/ 5485e1c72e1SJason King case 'M': 5495e1c72e1SJason King case 'm': 5505e1c72e1SJason King scale *= kilo; 5515e1c72e1SJason King /*FALLTHROUGH*/ 5525e1c72e1SJason King case 'K': 5535e1c72e1SJason King case 'k': 5545e1c72e1SJason King scale *= kilo; 5555e1c72e1SJason King break; 5565e1c72e1SJason King default: 5575e1c72e1SJason King if (!isdigit(scale_c)) { 5585e1c72e1SJason King (void) fprintf(stderr, 5595e1c72e1SJason King gettext("Invalid character " 5605e1c72e1SJason King "following block size in " 5615e1c72e1SJason King "\'%s\'\n"), optarg); 5625e1c72e1SJason King exit(1); 5635e1c72e1SJason King } 5645e1c72e1SJason King } 5655e1c72e1SJason King 5665e1c72e1SJason King /* NULL out scale constant if present */ 5675e1c72e1SJason King if (scale > 1 && !isdigit(scale_c)) 5685e1c72e1SJason King optarg[scale_len - 1] = '\0'; 5695e1c72e1SJason King 5705e1c72e1SJason King /* Based on testing, this is what GNU ls does */ 5715e1c72e1SJason King block_size = strtoll(optarg, NULL, 0) * scale; 5725e1c72e1SJason King if (block_size < 1) { 5735e1c72e1SJason King (void) fprintf(stderr, 5745e1c72e1SJason King gettext("Invalid block size " 5755e1c72e1SJason King "\'%s\'\n"), optarg); 5765e1c72e1SJason King exit(1); 5775e1c72e1SJason King } 5785e1c72e1SJason King continue; 5795e1c72e1SJason King } 5805e1c72e1SJason King 5815e1c72e1SJason King if (strcmp(long_options[option_index].name, 5825e1c72e1SJason King "file-type") == 0) { 5835e1c72e1SJason King file_typeflg++; 5845e1c72e1SJason King Fflg++; 5855e1c72e1SJason King statreq++; 5865e1c72e1SJason King continue; 5875e1c72e1SJason King } 5885e1c72e1SJason King 5895e1c72e1SJason King 5905e1c72e1SJason King if (strcmp(long_options[option_index].name, 5915e1c72e1SJason King "full-time") == 0) { 5925e1c72e1SJason King Eflg++; 5935e1c72e1SJason King statreq++; 5945e1c72e1SJason King eflg = 0; 5955e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 5965e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 5975e1c72e1SJason King continue; 5985e1c72e1SJason King } 5995e1c72e1SJason King 6005e1c72e1SJason King if (strcmp(long_options[option_index].name, 6015e1c72e1SJason King "time-style") == 0) { 6025e1c72e1SJason King /* like -E, but doesn't imply -l */ 6035e1c72e1SJason King if (strcmp(optarg, "full-iso") == 0) { 6045e1c72e1SJason King Eflg++; 6055e1c72e1SJason King statreq++; 6065e1c72e1SJason King eflg = 0; 6075e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 6085e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 6095e1c72e1SJason King continue; 6105e1c72e1SJason King } 6115e1c72e1SJason King if (strcmp(optarg, "long-iso") == 0) { 6125e1c72e1SJason King statreq++; 6135e1c72e1SJason King Eflg = 0; 6145e1c72e1SJason King eflg = 0; 6155e1c72e1SJason King time_fmt_old = FORMAT_ISO_LONG; 6165e1c72e1SJason King time_fmt_new = FORMAT_ISO_LONG; 6175e1c72e1SJason King continue; 6185e1c72e1SJason King } 6195e1c72e1SJason King if (strcmp(optarg, "iso") == 0) { 6205e1c72e1SJason King statreq++; 6215e1c72e1SJason King Eflg = 0; 6225e1c72e1SJason King eflg = 0; 6235e1c72e1SJason King time_fmt_old = FORMAT_ISO_OLD; 6245e1c72e1SJason King time_fmt_new = FORMAT_ISO_NEW; 6255e1c72e1SJason King continue; 6265e1c72e1SJason King } 6275e1c72e1SJason King /* should be the default */ 6285e1c72e1SJason King if (strcmp(optarg, "locale") == 0) { 6295e1c72e1SJason King time_fmt_old = FORMAT_OLD; 6305e1c72e1SJason King time_fmt_new = FORMAT_NEW; 6315e1c72e1SJason King continue; 6325e1c72e1SJason King } 6335e1c72e1SJason King if (optarg[0] == '+') { 6345e1c72e1SJason King char *told, *tnew; 6355e1c72e1SJason King char *p; 6365e1c72e1SJason King size_t timelen = strlen(optarg); 6375e1c72e1SJason King 6385e1c72e1SJason King p = strchr(optarg, '\n'); 6395e1c72e1SJason King if (p != NULL) 6405e1c72e1SJason King *p++ = '\0'; 6415e1c72e1SJason King 6425e1c72e1SJason King /* 6435e1c72e1SJason King * Time format requires a leading and 6445e1c72e1SJason King * trailing space 6455e1c72e1SJason King * Add room for 3 spaces + 2 nulls 6465e1c72e1SJason King * The + in optarg is replaced with 6475e1c72e1SJason King * a space. 6485e1c72e1SJason King */ 6495e1c72e1SJason King timelen += 2 + 3; 6505e1c72e1SJason King told = malloc(timelen); 6515e1c72e1SJason King if (told == NULL) { 652*38f2a414SAlbert Lee perror("ls"); 653*38f2a414SAlbert Lee exit(2); 6545e1c72e1SJason King } 6555e1c72e1SJason King 6565e1c72e1SJason King (void) memset(told, 0, timelen); 6575e1c72e1SJason King told[0] = ' '; 6585e1c72e1SJason King (void) strlcat(told, &optarg[1], 6595e1c72e1SJason King timelen); 6605e1c72e1SJason King (void) strlcat(told, " ", timelen); 6615e1c72e1SJason King 6625e1c72e1SJason King if (p != NULL) { 6635e1c72e1SJason King size_t tnew_len; 6645e1c72e1SJason King 6655e1c72e1SJason King tnew = told + strlen(told) + 1; 6665e1c72e1SJason King tnew_len = timelen - 6675e1c72e1SJason King strlen(told) - 1; 6685e1c72e1SJason King 6695e1c72e1SJason King tnew[0] = ' '; 6705e1c72e1SJason King (void) strlcat(tnew, p, 6715e1c72e1SJason King tnew_len); 6725e1c72e1SJason King (void) strlcat(tnew, " ", 6735e1c72e1SJason King tnew_len); 6745e1c72e1SJason King time_fmt_new = 6755e1c72e1SJason King (const char *)tnew; 6765e1c72e1SJason King } else { 6775e1c72e1SJason King time_fmt_new = 6785e1c72e1SJason King (const char *)told; 6795e1c72e1SJason King } 6805e1c72e1SJason King 6815e1c72e1SJason King time_fmt_old = (const char *)told; 6825e1c72e1SJason King time_custom = 1; 6835e1c72e1SJason King continue; 6845e1c72e1SJason King } 6855e1c72e1SJason King continue; 6865e1c72e1SJason King } 6875e1c72e1SJason King 6885e1c72e1SJason King continue; 6895e1c72e1SJason King 6907c478bd9Sstevel@tonic-gate case 'a': 6917c478bd9Sstevel@tonic-gate aflg++; 6927c478bd9Sstevel@tonic-gate continue; 6937c478bd9Sstevel@tonic-gate case 'A': 6947c478bd9Sstevel@tonic-gate Aflg++; 6957c478bd9Sstevel@tonic-gate continue; 6967c478bd9Sstevel@tonic-gate case 'b': 6977c478bd9Sstevel@tonic-gate bflg = 1; 6987c478bd9Sstevel@tonic-gate qflg = 0; 6997c478bd9Sstevel@tonic-gate continue; 7005e1c72e1SJason King case 'B': 7015e1c72e1SJason King Bflg = 1; 7025e1c72e1SJason King continue; 7037c478bd9Sstevel@tonic-gate case 'c': 7047c478bd9Sstevel@tonic-gate uflg = 0; 705da6c28aaSamw atm = 0; 706da6c28aaSamw ctm = 0; 707da6c28aaSamw mtm = 0; 708da6c28aaSamw crtm = 0; 7097c478bd9Sstevel@tonic-gate cflg++; 7107c478bd9Sstevel@tonic-gate continue; 7117c478bd9Sstevel@tonic-gate case 'C': 7127c478bd9Sstevel@tonic-gate Cflg = 1; 7137c478bd9Sstevel@tonic-gate mflg = 0; 7147c478bd9Sstevel@tonic-gate #ifdef XPG4 7157c478bd9Sstevel@tonic-gate lflg = 0; 7167c478bd9Sstevel@tonic-gate #endif 7177c478bd9Sstevel@tonic-gate continue; 7187c478bd9Sstevel@tonic-gate case 'd': 7197c478bd9Sstevel@tonic-gate dflg++; 7207c478bd9Sstevel@tonic-gate continue; 7217c478bd9Sstevel@tonic-gate case 'e': 7227c478bd9Sstevel@tonic-gate eflg++; 7237c478bd9Sstevel@tonic-gate lflg++; 7247c478bd9Sstevel@tonic-gate statreq++; 7257c478bd9Sstevel@tonic-gate Eflg = 0; 7265e1c72e1SJason King time_fmt_old = FORMAT_LONG; 7275e1c72e1SJason King time_fmt_new = FORMAT_LONG; 7287c478bd9Sstevel@tonic-gate continue; 7297c478bd9Sstevel@tonic-gate case 'E': 7307c478bd9Sstevel@tonic-gate Eflg++; 7317c478bd9Sstevel@tonic-gate lflg++; 7327c478bd9Sstevel@tonic-gate statreq++; 7337c478bd9Sstevel@tonic-gate eflg = 0; 7345e1c72e1SJason King time_fmt_old = FORMAT_ISO_FULL; 7355e1c72e1SJason King time_fmt_new = FORMAT_ISO_FULL; 7367c478bd9Sstevel@tonic-gate continue; 7377c478bd9Sstevel@tonic-gate case 'f': 7387c478bd9Sstevel@tonic-gate fflg++; 7397c478bd9Sstevel@tonic-gate continue; 7407c478bd9Sstevel@tonic-gate case 'F': 7417c478bd9Sstevel@tonic-gate Fflg++; 7427c478bd9Sstevel@tonic-gate statreq++; 7437c478bd9Sstevel@tonic-gate continue; 7447c478bd9Sstevel@tonic-gate case 'g': 7457c478bd9Sstevel@tonic-gate gflg++; 7467c478bd9Sstevel@tonic-gate lflg++; 7477c478bd9Sstevel@tonic-gate statreq++; 7487c478bd9Sstevel@tonic-gate continue; 7497c478bd9Sstevel@tonic-gate case 'h': 7507c478bd9Sstevel@tonic-gate hflg++; 7517c478bd9Sstevel@tonic-gate hscale = 1024; 7527c478bd9Sstevel@tonic-gate continue; 7537c478bd9Sstevel@tonic-gate case 'H': 7547c478bd9Sstevel@tonic-gate Hflg++; 7557c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7567c478bd9Sstevel@tonic-gate Lflg = 0; 7577c478bd9Sstevel@tonic-gate continue; 7587c478bd9Sstevel@tonic-gate case 'i': 7597c478bd9Sstevel@tonic-gate iflg++; 7607c478bd9Sstevel@tonic-gate continue; 7615e1c72e1SJason King case 'k': 7625e1c72e1SJason King block_size = 1024; 7635e1c72e1SJason King continue; 7647c478bd9Sstevel@tonic-gate case 'l': 7657c478bd9Sstevel@tonic-gate lflg++; 7667c478bd9Sstevel@tonic-gate statreq++; 7677c478bd9Sstevel@tonic-gate Cflg = 0; 7687c478bd9Sstevel@tonic-gate xflg = 0; 7697c478bd9Sstevel@tonic-gate mflg = 0; 7707c478bd9Sstevel@tonic-gate atflg = 0; 7717c478bd9Sstevel@tonic-gate continue; 7727c478bd9Sstevel@tonic-gate case 'L': 7737c478bd9Sstevel@tonic-gate Lflg++; 7747c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7757c478bd9Sstevel@tonic-gate Hflg = 0; 7767c478bd9Sstevel@tonic-gate continue; 7777c478bd9Sstevel@tonic-gate case 'm': 7787c478bd9Sstevel@tonic-gate Cflg = 0; 7797c478bd9Sstevel@tonic-gate mflg = 1; 7807c478bd9Sstevel@tonic-gate #ifdef XPG4 7817c478bd9Sstevel@tonic-gate lflg = 0; 7827c478bd9Sstevel@tonic-gate #endif 7837c478bd9Sstevel@tonic-gate continue; 7847c478bd9Sstevel@tonic-gate case 'n': 7857c478bd9Sstevel@tonic-gate nflg++; 7867c478bd9Sstevel@tonic-gate lflg++; 7877c478bd9Sstevel@tonic-gate statreq++; 7887c478bd9Sstevel@tonic-gate Cflg = 0; 7897c478bd9Sstevel@tonic-gate xflg = 0; 7907c478bd9Sstevel@tonic-gate mflg = 0; 7917c478bd9Sstevel@tonic-gate atflg = 0; 7927c478bd9Sstevel@tonic-gate continue; 7937c478bd9Sstevel@tonic-gate case 'o': 7947c478bd9Sstevel@tonic-gate oflg++; 7957c478bd9Sstevel@tonic-gate lflg++; 7967c478bd9Sstevel@tonic-gate statreq++; 7977c478bd9Sstevel@tonic-gate continue; 7987c478bd9Sstevel@tonic-gate case 'p': 7997c478bd9Sstevel@tonic-gate pflg++; 8007c478bd9Sstevel@tonic-gate statreq++; 8017c478bd9Sstevel@tonic-gate continue; 8027c478bd9Sstevel@tonic-gate case 'q': 8037c478bd9Sstevel@tonic-gate qflg = 1; 8047c478bd9Sstevel@tonic-gate bflg = 0; 8057c478bd9Sstevel@tonic-gate continue; 8067c478bd9Sstevel@tonic-gate case 'r': 8077c478bd9Sstevel@tonic-gate rflg = -1; 8087c478bd9Sstevel@tonic-gate continue; 8097c478bd9Sstevel@tonic-gate case 'R': 8107c478bd9Sstevel@tonic-gate Rflg++; 8117c478bd9Sstevel@tonic-gate statreq++; 8127c478bd9Sstevel@tonic-gate continue; 8137c478bd9Sstevel@tonic-gate case 's': 8147c478bd9Sstevel@tonic-gate sflg++; 8157c478bd9Sstevel@tonic-gate statreq++; 8167c478bd9Sstevel@tonic-gate continue; 8177c478bd9Sstevel@tonic-gate case 'S': 8187c478bd9Sstevel@tonic-gate tflg = 0; 8195e1c72e1SJason King Uflg = 0; 8207c478bd9Sstevel@tonic-gate Sflg++; 8217c478bd9Sstevel@tonic-gate statreq++; 8227c478bd9Sstevel@tonic-gate continue; 8237c478bd9Sstevel@tonic-gate case 't': 8247c478bd9Sstevel@tonic-gate Sflg = 0; 8255e1c72e1SJason King Uflg = 0; 8267c478bd9Sstevel@tonic-gate tflg++; 8277c478bd9Sstevel@tonic-gate statreq++; 8287c478bd9Sstevel@tonic-gate continue; 8295e1c72e1SJason King case 'U': 8305e1c72e1SJason King Sflg = 0; 8315e1c72e1SJason King tflg = 0; 8325e1c72e1SJason King Uflg++; 8335e1c72e1SJason King continue; 8347c478bd9Sstevel@tonic-gate case 'u': 8357c478bd9Sstevel@tonic-gate cflg = 0; 836da6c28aaSamw atm = 0; 837da6c28aaSamw ctm = 0; 838da6c28aaSamw mtm = 0; 839da6c28aaSamw crtm = 0; 8407c478bd9Sstevel@tonic-gate uflg++; 8417c478bd9Sstevel@tonic-gate continue; 8425a5eeccaSmarks case 'V': 8435a5eeccaSmarks Vflg++; 8445a5eeccaSmarks /*FALLTHROUGH*/ 845fa9e4066Sahrens case 'v': 846fa9e4066Sahrens vflg++; 847fa9e4066Sahrens #if !defined(XPG4) 848fa9e4066Sahrens if (lflg) 849fa9e4066Sahrens continue; 850fa9e4066Sahrens #endif 851fa9e4066Sahrens lflg++; 852fa9e4066Sahrens statreq++; 853fa9e4066Sahrens Cflg = 0; 854fa9e4066Sahrens xflg = 0; 855fa9e4066Sahrens mflg = 0; 856fa9e4066Sahrens continue; 8575e1c72e1SJason King case 'w': 8585e1c72e1SJason King wflg++; 8595e1c72e1SJason King num_cols = atoi(optarg); 8605e1c72e1SJason King continue; 8617c478bd9Sstevel@tonic-gate case 'x': 8627c478bd9Sstevel@tonic-gate xflg = 1; 8637c478bd9Sstevel@tonic-gate Cflg = 1; 8647c478bd9Sstevel@tonic-gate mflg = 0; 8657c478bd9Sstevel@tonic-gate #ifdef XPG4 8667c478bd9Sstevel@tonic-gate lflg = 0; 8677c478bd9Sstevel@tonic-gate #endif 8687c478bd9Sstevel@tonic-gate continue; 8697c478bd9Sstevel@tonic-gate case '1': 8707c478bd9Sstevel@tonic-gate Cflg = 0; 8717c478bd9Sstevel@tonic-gate continue; 8727c478bd9Sstevel@tonic-gate case '@': 8737c478bd9Sstevel@tonic-gate #if !defined(XPG4) 8747c478bd9Sstevel@tonic-gate /* 8757c478bd9Sstevel@tonic-gate * -l has precedence over -@ 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate if (lflg) 8787c478bd9Sstevel@tonic-gate continue; 8797c478bd9Sstevel@tonic-gate #endif 8807c478bd9Sstevel@tonic-gate atflg++; 8817c478bd9Sstevel@tonic-gate lflg++; 8827c478bd9Sstevel@tonic-gate statreq++; 8837c478bd9Sstevel@tonic-gate Cflg = 0; 8847c478bd9Sstevel@tonic-gate xflg = 0; 8857c478bd9Sstevel@tonic-gate mflg = 0; 8867c478bd9Sstevel@tonic-gate continue; 887da6c28aaSamw case '/': 888da6c28aaSamw saflg++; 889da6c28aaSamw if (optarg != NULL) { 890da6c28aaSamw if (strcmp(optarg, "c") == 0) { 891da6c28aaSamw copt++; 892da6c28aaSamw vopt = 0; 893da6c28aaSamw } else if (strcmp(optarg, "v") == 0) { 894da6c28aaSamw vopt++; 895da6c28aaSamw copt = 0; 896da6c28aaSamw } else 897da6c28aaSamw opterr++; 898da6c28aaSamw } else 899da6c28aaSamw opterr++; 900da6c28aaSamw lflg++; 901da6c28aaSamw statreq++; 902da6c28aaSamw Cflg = 0; 903da6c28aaSamw xflg = 0; 904da6c28aaSamw mflg = 0; 905da6c28aaSamw continue; 906da6c28aaSamw case '%': 907da6c28aaSamw tmflg++; 908da6c28aaSamw if (optarg != NULL) { 909da6c28aaSamw if (strcmp(optarg, "ctime") == 0) { 910da6c28aaSamw ctm++; 911da6c28aaSamw atm = 0; 912da6c28aaSamw mtm = 0; 913da6c28aaSamw crtm = 0; 914da6c28aaSamw } else if (strcmp(optarg, "atime") == 0) { 915da6c28aaSamw atm++; 916da6c28aaSamw ctm = 0; 917da6c28aaSamw mtm = 0; 918da6c28aaSamw crtm = 0; 919da6c28aaSamw uflg = 0; 920da6c28aaSamw cflg = 0; 921da6c28aaSamw } else if (strcmp(optarg, "mtime") == 0) { 922da6c28aaSamw mtm++; 923da6c28aaSamw atm = 0; 924da6c28aaSamw ctm = 0; 925da6c28aaSamw crtm = 0; 926da6c28aaSamw uflg = 0; 927da6c28aaSamw cflg = 0; 928da6c28aaSamw } else if (strcmp(optarg, "crtime") == 0) { 929da6c28aaSamw crtm++; 930da6c28aaSamw atm = 0; 931da6c28aaSamw ctm = 0; 932da6c28aaSamw mtm = 0; 933da6c28aaSamw uflg = 0; 934da6c28aaSamw cflg = 0; 935da6c28aaSamw } else if (strcmp(optarg, "all") == 0) { 936da6c28aaSamw alltm++; 937da6c28aaSamw atm = 0; 938da6c28aaSamw ctm = 0; 939da6c28aaSamw mtm = 0; 940da6c28aaSamw crtm = 0; 941da6c28aaSamw } else 942da6c28aaSamw opterr++; 943da6c28aaSamw } else 944da6c28aaSamw opterr++; 945da6c28aaSamw 946da6c28aaSamw Sflg = 0; 947da6c28aaSamw statreq++; 948da6c28aaSamw mflg = 0; 949da6c28aaSamw continue; 9507c478bd9Sstevel@tonic-gate case '?': 9517c478bd9Sstevel@tonic-gate opterr++; 9527c478bd9Sstevel@tonic-gate continue; 9537c478bd9Sstevel@tonic-gate } 9545e1c72e1SJason King 9557c478bd9Sstevel@tonic-gate if (opterr) { 9567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 9575e1c72e1SJason King "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]" 958da6c28aaSamw "%%[atime | crtime | ctime | mtime | all]" 959da6c28aaSamw " [files]\n")); 9607c478bd9Sstevel@tonic-gate exit(2); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate if (fflg) { 9647c478bd9Sstevel@tonic-gate aflg++; 9657c478bd9Sstevel@tonic-gate lflg = 0; 9667c478bd9Sstevel@tonic-gate sflg = 0; 9677c478bd9Sstevel@tonic-gate tflg = 0; 9687c478bd9Sstevel@tonic-gate Sflg = 0; 9697c478bd9Sstevel@tonic-gate statreq = 0; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate fixedwidth = 2; 9737c478bd9Sstevel@tonic-gate if (pflg || Fflg) 9747c478bd9Sstevel@tonic-gate fixedwidth++; 9757c478bd9Sstevel@tonic-gate if (iflg) 9767c478bd9Sstevel@tonic-gate fixedwidth += 11; 9777c478bd9Sstevel@tonic-gate if (sflg) 9787c478bd9Sstevel@tonic-gate fixedwidth += 5; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate if (lflg) { 9817c478bd9Sstevel@tonic-gate if (!gflg && !oflg) 9827c478bd9Sstevel@tonic-gate gflg = oflg = 1; 9837c478bd9Sstevel@tonic-gate else 9847c478bd9Sstevel@tonic-gate if (gflg && oflg) 9857c478bd9Sstevel@tonic-gate gflg = oflg = 0; 9867c478bd9Sstevel@tonic-gate Cflg = mflg = 0; 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9895e1c72e1SJason King if (!wflg && (Cflg || mflg)) { 9907c478bd9Sstevel@tonic-gate char *clptr; 9917c478bd9Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 9927c478bd9Sstevel@tonic-gate num_cols = atoi(clptr); 9937c478bd9Sstevel@tonic-gate #ifdef TERMINFO 9947c478bd9Sstevel@tonic-gate else { 9957c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 9967c478bd9Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate #endif 9995e1c72e1SJason King } 10005e1c72e1SJason King 10017c478bd9Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 10027c478bd9Sstevel@tonic-gate /* assume it is an error */ 10037c478bd9Sstevel@tonic-gate num_cols = 80; 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* allocate space for flist and the associated */ 10067c478bd9Sstevel@tonic-gate /* data structures (lbufs) */ 10077c478bd9Sstevel@tonic-gate maxfils = quantn; 10087c478bd9Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 10097c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 10107c478bd9Sstevel@tonic-gate perror("ls"); 10117c478bd9Sstevel@tonic-gate exit(2); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 10147c478bd9Sstevel@tonic-gate /* 10157c478bd9Sstevel@tonic-gate * case when no names are given 10167c478bd9Sstevel@tonic-gate * in ls-command and current 10177c478bd9Sstevel@tonic-gate * directory is to be used 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate argv[optind] = dotp; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate /* 10257c478bd9Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 10267c478bd9Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 10277c478bd9Sstevel@tonic-gate * (actually, just the directories) visited, we 10287c478bd9Sstevel@tonic-gate * maintain a directory ancestry list for a file 10297c478bd9Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 10307c478bd9Sstevel@tonic-gate * a parent directory passes its directory list 10317c478bd9Sstevel@tonic-gate * info (device id, inode number, and a pointer to 10327c478bd9Sstevel@tonic-gate * its parent) to each of its children. As we 10337c478bd9Sstevel@tonic-gate * process a child that is a directory, we save 10347c478bd9Sstevel@tonic-gate * its own personal directory list info. We then 10357c478bd9Sstevel@tonic-gate * check to see if the child has already been 10367c478bd9Sstevel@tonic-gate * processed by comparing its device id and inode 10377c478bd9Sstevel@tonic-gate * number from its own personal directory list info 10387c478bd9Sstevel@tonic-gate * to that of each of its ancestors. If there is a 10397c478bd9Sstevel@tonic-gate * match, then we know we've detected a cycle. 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate if (Rflg) { 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * This is the first parent in this lineage 10447c478bd9Sstevel@tonic-gate * (first in a directory hierarchy), so 10457c478bd9Sstevel@tonic-gate * this parent's parent doesn't exist. We 10467c478bd9Sstevel@tonic-gate * only initialize myinfo when we are 10477c478bd9Sstevel@tonic-gate * recursing, otherwise it's not used. 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 10507c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 10517c478bd9Sstevel@tonic-gate perror("ls"); 10527c478bd9Sstevel@tonic-gate exit(2); 10537c478bd9Sstevel@tonic-gate } else { 10547c478bd9Sstevel@tonic-gate myinfo->dev = 0; 10557c478bd9Sstevel@tonic-gate myinfo->ino = 0; 10567c478bd9Sstevel@tonic-gate myinfo->parent = NULL; 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 10617c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 10627c478bd9Sstevel@tonic-gate if (width > filewidth) 10637c478bd9Sstevel@tonic-gate filewidth = width; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 10667c478bd9Sstevel@tonic-gate 1, myinfo)) == NULL) { 10677c478bd9Sstevel@tonic-gate if (nomocore) 10687c478bd9Sstevel@tonic-gate exit(2); 10697c478bd9Sstevel@tonic-gate err = 2; 10707c478bd9Sstevel@tonic-gate optind++; 10717c478bd9Sstevel@tonic-gate continue; 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 10747c478bd9Sstevel@tonic-gate ep->lflags |= ISARG; 10757c478bd9Sstevel@tonic-gate optind++; 10767c478bd9Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 107756798e90Sbasabi if (acl_err) 107856798e90Sbasabi err = 2; 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 10815e1c72e1SJason King if (!Uflg) 10827c478bd9Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 10837c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 10847c478bd9Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 10857c478bd9Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 10867c478bd9Sstevel@tonic-gate break; 10877c478bd9Sstevel@tonic-gate } 10885e1c72e1SJason King 10895e1c72e1SJason King if (colorflg) 10905e1c72e1SJason King ls_color_init(); 10915e1c72e1SJason King 10927c478bd9Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 10937c478bd9Sstevel@tonic-gate for (; i < nargs; i++) { 10947c478bd9Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 10957c478bd9Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 10967c478bd9Sstevel@tonic-gate if (nomocore) 10977c478bd9Sstevel@tonic-gate exit(2); 10987c478bd9Sstevel@tonic-gate /* -R: print subdirectories found */ 10997c478bd9Sstevel@tonic-gate while (dfirst || cdfirst) { 11007c478bd9Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 11017c478bd9Sstevel@tonic-gate while (cdfirst) { 11027c478bd9Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 11037c478bd9Sstevel@tonic-gate dtemp = cdfirst; 11047c478bd9Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 11057c478bd9Sstevel@tonic-gate dtemp -> dc_next = dfirst; 11067c478bd9Sstevel@tonic-gate dfirst = dtemp; 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 11097c478bd9Sstevel@tonic-gate dtemp = dfirst; 11107c478bd9Sstevel@tonic-gate dfirst = dfirst->dc_next; 11117c478bd9Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 11127c478bd9Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 11137c478bd9Sstevel@tonic-gate if (nomocore) 11147c478bd9Sstevel@tonic-gate exit(2); 11157c478bd9Sstevel@tonic-gate free(dtemp->dc_name); 11167c478bd9Sstevel@tonic-gate free(dtemp); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate } 11195e1c72e1SJason King 11207c478bd9Sstevel@tonic-gate return (err); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate /* 11247c478bd9Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 11257c478bd9Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate static void 11287c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 11297c478bd9Sstevel@tonic-gate { 11307c478bd9Sstevel@tonic-gate struct dchain *dp; 11317c478bd9Sstevel@tonic-gate struct lbuf *ap; 11327c478bd9Sstevel@tonic-gate char *pname; 11337c478bd9Sstevel@tonic-gate int j; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate filewidth = 0; 11367c478bd9Sstevel@tonic-gate curdir = name; 11377c478bd9Sstevel@tonic-gate if (title) { 11387c478bd9Sstevel@tonic-gate if (!first) 11397c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 11407c478bd9Sstevel@tonic-gate pprintf(name, ":"); 11417c478bd9Sstevel@tonic-gate new_line(); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 11457c478bd9Sstevel@tonic-gate * further. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate if (cdetect) { 11487c478bd9Sstevel@tonic-gate if (lflg || sflg) { 11497c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 11507c478bd9Sstevel@tonic-gate new_line(); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11537c478bd9Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 11547c478bd9Sstevel@tonic-gate return; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate nfiles = lp; 11587c478bd9Sstevel@tonic-gate rddir(name, myinfo); 11597c478bd9Sstevel@tonic-gate if (nomocore) 11607c478bd9Sstevel@tonic-gate return; 11615e1c72e1SJason King if (fflg == 0 && Uflg == 0) 11627c478bd9Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 11637c478bd9Sstevel@tonic-gate sizeof (struct lbuf *), 11647c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 11657c478bd9Sstevel@tonic-gate if (Rflg) { 11667c478bd9Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 11677c478bd9Sstevel@tonic-gate ap = flist[j]; 11687c478bd9Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 11697c478bd9Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 11707c478bd9Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 11717c478bd9Sstevel@tonic-gate if (dp == NULL) { 11727c478bd9Sstevel@tonic-gate perror("ls"); 11737c478bd9Sstevel@tonic-gate exit(2); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 11767c478bd9Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 11777c478bd9Sstevel@tonic-gate perror("ls"); 11787c478bd9Sstevel@tonic-gate exit(2); 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 11817c478bd9Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 11827c478bd9Sstevel@tonic-gate dp->dc_next = dfirst; 11837c478bd9Sstevel@tonic-gate dfirst = dp; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate if (lflg || sflg) { 11887c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 11897c478bd9Sstevel@tonic-gate new_line(); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 11967c478bd9Sstevel@tonic-gate * by slp and lp. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate static void 11997c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 12007c478bd9Sstevel@tonic-gate { 12017c478bd9Sstevel@tonic-gate long row, nrows, i; 12027c478bd9Sstevel@tonic-gate int col, ncols; 12037c478bd9Sstevel@tonic-gate struct lbuf **ep; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 12067c478bd9Sstevel@tonic-gate if (colwidth > num_cols) { 12077c478bd9Sstevel@tonic-gate ncols = 1; 12087c478bd9Sstevel@tonic-gate } else { 12097c478bd9Sstevel@tonic-gate ncols = num_cols / colwidth; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 12147c478bd9Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 12157c478bd9Sstevel@tonic-gate pentry(*ep); 12167c478bd9Sstevel@tonic-gate new_line(); 12177c478bd9Sstevel@tonic-gate return; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate /* otherwise print -C columns */ 12207c478bd9Sstevel@tonic-gate if (tot_flag) { 12217c478bd9Sstevel@tonic-gate slp--; 12227c478bd9Sstevel@tonic-gate row = 1; 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate else 12257c478bd9Sstevel@tonic-gate row = 0; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 12287c478bd9Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 12297c478bd9Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 12307c478bd9Sstevel@tonic-gate ep = slp + (nrows * col) + row; 12317c478bd9Sstevel@tonic-gate if (ep < lp) 12327c478bd9Sstevel@tonic-gate pentry(*ep); 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate new_line(); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /* 12397c478bd9Sstevel@tonic-gate * print one output entry; 12407c478bd9Sstevel@tonic-gate * if uid/gid is not found in the appropriate 12417c478bd9Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 12427c478bd9Sstevel@tonic-gate * user/group name; 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate static void 12457c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap) 12467c478bd9Sstevel@tonic-gate { 12477c478bd9Sstevel@tonic-gate struct lbuf *p; 12487c478bd9Sstevel@tonic-gate numbuf_t hbuf; 12497c478bd9Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 12507c478bd9Sstevel@tonic-gate char *cp; 12511b628248SJason King char *str; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate p = ap; 12547c478bd9Sstevel@tonic-gate column(); 12557c478bd9Sstevel@tonic-gate if (iflg) 12567c478bd9Sstevel@tonic-gate if (mflg && !lflg) 12577c478bd9Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 12587c478bd9Sstevel@tonic-gate else 12597c478bd9Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 12607c478bd9Sstevel@tonic-gate if (sflg) 12617c478bd9Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 12627c478bd9Sstevel@tonic-gate (p->lblocks < 10000) ? "%4lld " : "%lld ", 12637c478bd9Sstevel@tonic-gate (p->ltype != 'b' && p->ltype != 'c') ? 12647c478bd9Sstevel@tonic-gate p->lblocks : 0LL); 12657c478bd9Sstevel@tonic-gate if (lflg) { 12667c478bd9Sstevel@tonic-gate (void) putchar(p->ltype); 12677c478bd9Sstevel@tonic-gate curcol++; 12687c478bd9Sstevel@tonic-gate pmode(p->lflags); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* ACL: additional access mode flag */ 12717c478bd9Sstevel@tonic-gate (void) putchar(p->acl); 12727c478bd9Sstevel@tonic-gate curcol++; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 12757c478bd9Sstevel@tonic-gate if (oflg) 12767c478bd9Sstevel@tonic-gate if (!nflg) { 12777c478bd9Sstevel@tonic-gate cp = getname(p->luid); 12787c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12797c478bd9Sstevel@tonic-gate } else 12807c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 12817c478bd9Sstevel@tonic-gate if (gflg) 12827c478bd9Sstevel@tonic-gate if (!nflg) { 12837c478bd9Sstevel@tonic-gate cp = getgroup(p->lgid); 12847c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12857c478bd9Sstevel@tonic-gate } else 12867c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 12877c478bd9Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 12887c478bd9Sstevel@tonic-gate curcol += printf("%3u, %2u", 12897c478bd9Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 12907c478bd9Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 12917c478bd9Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 12927c478bd9Sstevel@tonic-gate curcol += printf("%7s", 12937c478bd9Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 12947c478bd9Sstevel@tonic-gate } else { 12955e1c72e1SJason King uint64_t bsize = p->lsize / block_size; 12965e1c72e1SJason King 12975e1c72e1SJason King /* 12985e1c72e1SJason King * Round up only when using blocks > 1 byte, otherwise 12995e1c72e1SJason King * 'normal' sizes display 1 byte too large. 13005e1c72e1SJason King */ 13015e1c72e1SJason King if (p->lsize % block_size != 0) 13025e1c72e1SJason King bsize++; 13035e1c72e1SJason King 13045e1c72e1SJason King curcol += printf("%7" PRIu64, bsize); 13057c478bd9Sstevel@tonic-gate } 13065e1c72e1SJason King format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec); 1307da6c28aaSamw /* format extended system attribute time */ 1308da6c28aaSamw if (tmflg && crtm) 1309da6c28aaSamw format_attrtime(p); 13107c478bd9Sstevel@tonic-gate 1311da6c28aaSamw curcol += printf("%s", time_buf); 1312da6c28aaSamw 1313da6c28aaSamw } 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * prevent both "->" and trailing marks 13167c478bd9Sstevel@tonic-gate * from appearing 13177c478bd9Sstevel@tonic-gate */ 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (pflg && p->ltype == 'd') 13207c478bd9Sstevel@tonic-gate dmark = "/"; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 13237c478bd9Sstevel@tonic-gate if (p->ltype == 'd') 13247c478bd9Sstevel@tonic-gate dmark = "/"; 13257c478bd9Sstevel@tonic-gate else if (p->ltype == 'D') 13267c478bd9Sstevel@tonic-gate dmark = ">"; 13277c478bd9Sstevel@tonic-gate else if (p->ltype == 'p') 13287c478bd9Sstevel@tonic-gate dmark = "|"; 13297c478bd9Sstevel@tonic-gate else if (p->ltype == 'l') 13307c478bd9Sstevel@tonic-gate dmark = "@"; 13317c478bd9Sstevel@tonic-gate else if (p->ltype == 's') 13327c478bd9Sstevel@tonic-gate dmark = "="; 13335e1c72e1SJason King else if (!file_typeflg && 13345e1c72e1SJason King (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))) 13357c478bd9Sstevel@tonic-gate dmark = "*"; 13367c478bd9Sstevel@tonic-gate else 13377c478bd9Sstevel@tonic-gate dmark = ""; 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13405e1c72e1SJason King if (colorflg) 13411b628248SJason King ls_start_color(p->color); 13425e1c72e1SJason King 13431b628248SJason King if (p->lflags & ISARG) 13441b628248SJason King str = p->ln.namep; 13451b628248SJason King else 13461b628248SJason King str = p->ln.lname; 13471b628248SJason King 13481b628248SJason King if (qflg || bflg) { 13491b628248SJason King csi_pprintf((unsigned char *)str); 13501b628248SJason King 13511b628248SJason King if (lflg && p->flinkto) { 13521b628248SJason King if (colorflg) 13531b628248SJason King ls_end_color(); 13541b628248SJason King csi_pprintf((unsigned char *)" -> "); 13551b628248SJason King if (colorflg) 13561b628248SJason King ls_start_color(p->link_color); 13571b628248SJason King csi_pprintf((unsigned char *)p->flinkto); 13581b628248SJason King } else { 13591b628248SJason King csi_pprintf((unsigned char *)dmark); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate } else { 13621b628248SJason King (void) printf("%s", str); 13631b628248SJason King curcol += strcol((unsigned char *)str); 13641b628248SJason King 13651b628248SJason King if (lflg && p->flinkto) { 13661b628248SJason King if (colorflg) 13671b628248SJason King ls_end_color(); 13681b628248SJason King str = " -> "; 13691b628248SJason King (void) printf("%s", str); 13701b628248SJason King curcol += strcol((unsigned char *)str); 13711b628248SJason King if (colorflg) 13721b628248SJason King ls_start_color(p->link_color); 13731b628248SJason King (void) printf("%s", p->flinkto); 13741b628248SJason King curcol += strcol((unsigned char *)p->flinkto); 13751b628248SJason King } else { 13761b628248SJason King (void) printf("%s", dmark); 13777c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate } 1380fa9e4066Sahrens 13815e1c72e1SJason King if (colorflg) 13825e1c72e1SJason King ls_end_color(); 13835e1c72e1SJason King 1384da6c28aaSamw /* Display extended system attributes */ 1385da6c28aaSamw if (saflg) { 1386da6c28aaSamw int i; 1387da6c28aaSamw 1388da6c28aaSamw new_line(); 1389da6c28aaSamw (void) printf(" \t{"); 1390da6c28aaSamw if (p->exttr != NULL) { 1391da6c28aaSamw int k = 0; 1392da6c28aaSamw for (i = 0; i < sacnt; i++) { 1393da6c28aaSamw if (p->exttr[i].name != NULL) 1394da6c28aaSamw k++; 1395da6c28aaSamw } 1396da6c28aaSamw for (i = 0; i < sacnt; i++) { 1397da6c28aaSamw if (p->exttr[i].name != NULL) { 1398da6c28aaSamw (void) printf("%s", p->exttr[i].name); 1399da6c28aaSamw k--; 1400da6c28aaSamw if (vopt && (k != 0)) 1401da6c28aaSamw (void) printf(","); 1402da6c28aaSamw } 1403da6c28aaSamw } 1404da6c28aaSamw } 1405da6c28aaSamw (void) printf("}\n"); 1406da6c28aaSamw } 1407da6c28aaSamw /* Display file timestamps and extended system attribute timestamps */ 1408da6c28aaSamw if (tmflg && alltm) { 1409da6c28aaSamw new_line(); 1410da6c28aaSamw print_time(p); 1411da6c28aaSamw new_line(); 1412da6c28aaSamw } 1413fa9e4066Sahrens if (vflg) { 1414fa9e4066Sahrens new_line(); 1415fa9e4066Sahrens if (p->aclp) { 14165a5eeccaSmarks acl_printacl(p->aclp, num_cols, Vflg); 1417fa9e4066Sahrens } 1418fa9e4066Sahrens } 1419da6c28aaSamw /* Free extended system attribute lists */ 1420da6c28aaSamw if (saflg || tmflg) 1421da6c28aaSamw free_sysattr(p); 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */ 14257c478bd9Sstevel@tonic-gate static void 14267c478bd9Sstevel@tonic-gate pmode(mode_t aflag) 14277c478bd9Sstevel@tonic-gate { 14287c478bd9Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 14297c478bd9Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 14307c478bd9Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 14317c478bd9Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 14327c478bd9Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 14337c478bd9Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 14347c478bd9Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 14357c478bd9Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 14367c478bd9Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 14377c478bd9Sstevel@tonic-gate #ifdef XPG4 14387c478bd9Sstevel@tonic-gate S_ISGID, 'L', '-'}; 14397c478bd9Sstevel@tonic-gate #else 14407c478bd9Sstevel@tonic-gate S_ISGID, 'l', '-'}; 14417c478bd9Sstevel@tonic-gate #endif 14427c478bd9Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 14437c478bd9Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 14447c478bd9Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 14457c478bd9Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate int **mp; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate flags = aflag; 14527c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 14537c478bd9Sstevel@tonic-gate selection(*mp); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate static void 14577c478bd9Sstevel@tonic-gate selection(int *pairp) 14587c478bd9Sstevel@tonic-gate { 14597c478bd9Sstevel@tonic-gate int n; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate n = *pairp++; 14627c478bd9Sstevel@tonic-gate while (n-->0) { 14637c478bd9Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 14647c478bd9Sstevel@tonic-gate pairp++; 14657c478bd9Sstevel@tonic-gate break; 14667c478bd9Sstevel@tonic-gate } else { 14677c478bd9Sstevel@tonic-gate pairp += 2; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate (void) putchar(*pairp); 14717c478bd9Sstevel@tonic-gate curcol++; 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate /* 14757c478bd9Sstevel@tonic-gate * column: get to the beginning of the next column. 14767c478bd9Sstevel@tonic-gate */ 14777c478bd9Sstevel@tonic-gate static void 14787c478bd9Sstevel@tonic-gate column(void) 14797c478bd9Sstevel@tonic-gate { 14807c478bd9Sstevel@tonic-gate if (curcol == 0) 14817c478bd9Sstevel@tonic-gate return; 14827c478bd9Sstevel@tonic-gate if (mflg) { 14837c478bd9Sstevel@tonic-gate (void) putc(',', stdout); 14847c478bd9Sstevel@tonic-gate curcol++; 14857c478bd9Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 14867c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14877c478bd9Sstevel@tonic-gate curcol = 0; 14887c478bd9Sstevel@tonic-gate return; 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 14917c478bd9Sstevel@tonic-gate curcol++; 14927c478bd9Sstevel@tonic-gate return; 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate if (Cflg == 0) { 14957c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 14967c478bd9Sstevel@tonic-gate curcol = 0; 14977c478bd9Sstevel@tonic-gate return; 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 15007c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 15017c478bd9Sstevel@tonic-gate curcol = 0; 15027c478bd9Sstevel@tonic-gate return; 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate do { 15057c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 15067c478bd9Sstevel@tonic-gate curcol++; 15077c478bd9Sstevel@tonic-gate } while (curcol % colwidth); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate static void 15117c478bd9Sstevel@tonic-gate new_line(void) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate if (curcol) { 15147c478bd9Sstevel@tonic-gate first = 0; 15157c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 15167c478bd9Sstevel@tonic-gate curcol = 0; 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* 15217c478bd9Sstevel@tonic-gate * read each filename in directory dir and store its 15227c478bd9Sstevel@tonic-gate * status in flist[nfiles] 15237c478bd9Sstevel@tonic-gate * use makename() to form pathname dir/filename; 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate static void 15267c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 15277c478bd9Sstevel@tonic-gate { 15287c478bd9Sstevel@tonic-gate struct dirent *dentry; 15297c478bd9Sstevel@tonic-gate DIR *dirf; 15307c478bd9Sstevel@tonic-gate int j; 15317c478bd9Sstevel@tonic-gate struct lbuf *ep; 15327c478bd9Sstevel@tonic-gate int width; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 15357c478bd9Sstevel@tonic-gate (void) fflush(stdout); 15367c478bd9Sstevel@tonic-gate perror(dir); 15377c478bd9Sstevel@tonic-gate err = 2; 15387c478bd9Sstevel@tonic-gate return; 15397c478bd9Sstevel@tonic-gate } else { 15407c478bd9Sstevel@tonic-gate tblocks = 0; 15417c478bd9Sstevel@tonic-gate for (;;) { 15427c478bd9Sstevel@tonic-gate errno = 0; 15437c478bd9Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 15447c478bd9Sstevel@tonic-gate break; 15457c478bd9Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 15467c478bd9Sstevel@tonic-gate (Aflg == 0 || 15477c478bd9Sstevel@tonic-gate dentry->d_name[1] == '\0' || 15487c478bd9Sstevel@tonic-gate dentry->d_name[1] == '.' && 15497c478bd9Sstevel@tonic-gate dentry->d_name[2] == '\0')) 15507c478bd9Sstevel@tonic-gate /* 15517c478bd9Sstevel@tonic-gate * check for directory items '.', '..', 15527c478bd9Sstevel@tonic-gate * and items without valid inode-number; 15537c478bd9Sstevel@tonic-gate */ 15547c478bd9Sstevel@tonic-gate continue; 15557c478bd9Sstevel@tonic-gate 15565e1c72e1SJason King /* skip entries ending in ~ if -B was given */ 15575e1c72e1SJason King if (Bflg && 15585e1c72e1SJason King dentry->d_name[strlen(dentry->d_name) - 1] == '~') 15595e1c72e1SJason King continue; 15607c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 15617c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 15627c478bd9Sstevel@tonic-gate if (width > filewidth) 15637c478bd9Sstevel@tonic-gate filewidth = width; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 15667c478bd9Sstevel@tonic-gate if (ep == NULL) { 15677c478bd9Sstevel@tonic-gate if (nomocore) 1568da6c28aaSamw exit(2); 15697c478bd9Sstevel@tonic-gate continue; 15707c478bd9Sstevel@tonic-gate } else { 15717c478bd9Sstevel@tonic-gate ep->lnum = dentry->d_ino; 15727c478bd9Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 15737c478bd9Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 15747c478bd9Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate if (errno) { 15787c478bd9Sstevel@tonic-gate int sav_errno = errno; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 15817c478bd9Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 15827c478bd9Sstevel@tonic-gate dir, strerror(sav_errno)); 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate (void) closedir(dirf); 15857c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 15917c478bd9Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 15927c478bd9Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 15937c478bd9Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 15947c478bd9Sstevel@tonic-gate * it is reported at the right time when printing the directory. 15957c478bd9Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 15967c478bd9Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 15977c478bd9Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 15987c478bd9Sstevel@tonic-gate * command line. 15997c478bd9Sstevel@tonic-gate */ 16007c478bd9Sstevel@tonic-gate static void 16017c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 16027c478bd9Sstevel@tonic-gate int argfl, struct ditem *myparent) 16037c478bd9Sstevel@tonic-gate { 16047c478bd9Sstevel@tonic-gate size_t file_len; 16057c478bd9Sstevel@tonic-gate struct ditem *myinfo; 16067c478bd9Sstevel@tonic-gate struct ditem *tptr; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate file_len = strlen(file); 16097c478bd9Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 16107c478bd9Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * Add this inode's ancestry 16137c478bd9Sstevel@tonic-gate * info and insert it into the 16147c478bd9Sstevel@tonic-gate * ancestry list by pointing 16157c478bd9Sstevel@tonic-gate * back to its parent. We save 16167c478bd9Sstevel@tonic-gate * it (in rep) with the other info 16177c478bd9Sstevel@tonic-gate * we're gathering for this inode. 16187c478bd9Sstevel@tonic-gate */ 16197c478bd9Sstevel@tonic-gate if ((myinfo = malloc( 16207c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 16217c478bd9Sstevel@tonic-gate perror("ls"); 16227c478bd9Sstevel@tonic-gate exit(2); 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 16257c478bd9Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 16267c478bd9Sstevel@tonic-gate myinfo->parent = myparent; 16277c478bd9Sstevel@tonic-gate rep->ancinfo = myinfo; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * If this node has the same device id and 16317c478bd9Sstevel@tonic-gate * inode number of one of its ancestors, 16327c478bd9Sstevel@tonic-gate * then we've detected a cycle. 16337c478bd9Sstevel@tonic-gate */ 16347c478bd9Sstevel@tonic-gate if (myparent != NULL) { 16357c478bd9Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 16367c478bd9Sstevel@tonic-gate tptr = tptr->parent) { 16377c478bd9Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 16387c478bd9Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 16397c478bd9Sstevel@tonic-gate /* 16407c478bd9Sstevel@tonic-gate * Cycle detected for this 16417c478bd9Sstevel@tonic-gate * directory. Record the fact 16427c478bd9Sstevel@tonic-gate * it is a cycle so we don't 16437c478bd9Sstevel@tonic-gate * try to process this 16447c478bd9Sstevel@tonic-gate * directory as we are 16457c478bd9Sstevel@tonic-gate * walking through the 16467c478bd9Sstevel@tonic-gate * list of directories. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate rep->cycle = 1; 16497c478bd9Sstevel@tonic-gate err = 2; 16507c478bd9Sstevel@tonic-gate break; 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate /* 165864d425a7Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 165964d425a7Sny155746 * This is because, if the server's FS happens to be UFS, supporting 166064d425a7Sny155746 * POSIX ACL's, then it does a special calculation of group mode 166164d425a7Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 166264d425a7Sny155746 * 166364d425a7Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 166464d425a7Sny155746 * algorithm is used for the group mode calculation only. 166564d425a7Sny155746 * What is modified here from the algorithm is that only the 166664d425a7Sny155746 * entries with flags ACE_GROUP are considered. For each entry 166764d425a7Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 166864d425a7Sny155746 * is checked if it is allowed. 1669e2442894Sny155746 * We are not interested in perms for user and other, as they 167064d425a7Sny155746 * were taken from st_mode value. 167164d425a7Sny155746 * We are not interested in a_who field of ACE, as we need just 167264d425a7Sny155746 * unix mode bits for the group. 167364d425a7Sny155746 */ 1674e2442894Sny155746 1675e2442894Sny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 1676e2442894Sny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 1677e2442894Sny155746 167864d425a7Sny155746 int 167927dd1e87SMark Shellenbaum grp_mask_to_mode(struct lbuf *p) 168064d425a7Sny155746 { 168164d425a7Sny155746 int mode = 0, seen = 0; 168264d425a7Sny155746 int acecnt; 1683e2442894Sny155746 int flags; 168464d425a7Sny155746 ace_t *ap; 168527dd1e87SMark Shellenbaum acl_t *acep = p->aclp; 168664d425a7Sny155746 168764d425a7Sny155746 acecnt = acl_cnt(acep); 168864d425a7Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 1689e2442894Sny155746 1690e2442894Sny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 1691e2442894Sny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 1692e2442894Sny155746 continue; 1693e2442894Sny155746 1694e2442894Sny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 1695e2442894Sny155746 continue; 1696e2442894Sny155746 1697e2442894Sny155746 /* 1698e2442894Sny155746 * if it is first group@ or first everyone@ 1699e2442894Sny155746 * for each of read, write and execute, then 1700e2442894Sny155746 * that will be the group mode bit. 1701e2442894Sny155746 */ 1702e2442894Sny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 170327dd1e87SMark Shellenbaum if (flags == OWNED_GROUP || (flags == ACE_IDENTIFIER_GROUP && 170427dd1e87SMark Shellenbaum ap->a_who == p->lgid) || flags == ACE_EVERYONE) { 170564d425a7Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 170664d425a7Sny155746 if (!(seen & S_IRGRP)) { 170764d425a7Sny155746 seen |= S_IRGRP; 1708e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 170964d425a7Sny155746 mode |= S_IRGRP; 171064d425a7Sny155746 } 171164d425a7Sny155746 } 171264d425a7Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 171364d425a7Sny155746 if (!(seen & S_IWGRP)) { 171464d425a7Sny155746 seen |= S_IWGRP; 1715e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 171664d425a7Sny155746 mode |= S_IWGRP; 171764d425a7Sny155746 } 171864d425a7Sny155746 } 171964d425a7Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 172064d425a7Sny155746 if (!(seen & S_IXGRP)) { 172164d425a7Sny155746 seen |= S_IXGRP; 1722e2442894Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 172364d425a7Sny155746 mode |= S_IXGRP; 172464d425a7Sny155746 } 172564d425a7Sny155746 } 172664d425a7Sny155746 } 172764d425a7Sny155746 } 172864d425a7Sny155746 return (mode); 172964d425a7Sny155746 } 173064d425a7Sny155746 173164d425a7Sny155746 /* 17327c478bd9Sstevel@tonic-gate * get status of file and recomputes tblocks; 17337c478bd9Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 17347c478bd9Sstevel@tonic-gate * for filename in a directory whose name is an 17357c478bd9Sstevel@tonic-gate * argument in the command; 17367c478bd9Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 17377c478bd9Sstevel@tonic-gate * returns that pointer; 17387c478bd9Sstevel@tonic-gate * returns NULL if failed; 17397c478bd9Sstevel@tonic-gate */ 17407c478bd9Sstevel@tonic-gate static struct lbuf * 17417c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate struct stat statb, statb1; 17447c478bd9Sstevel@tonic-gate struct lbuf *rep; 17457c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 17467c478bd9Sstevel@tonic-gate ssize_t cc; 17477c478bd9Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 17487c478bd9Sstevel@tonic-gate int aclcnt; 1749fa9e4066Sahrens int error; 17507c478bd9Sstevel@tonic-gate aclent_t *tp; 17517c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 17527c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate if (nomocore) 17557c478bd9Sstevel@tonic-gate return (NULL); 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate if (nfiles >= maxfils) { 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 17607c478bd9Sstevel@tonic-gate * more space 17617c478bd9Sstevel@tonic-gate */ 17627c478bd9Sstevel@tonic-gate maxfils += quantn; 17637c478bd9Sstevel@tonic-gate if (((flist = realloc(flist, 17647c478bd9Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 17657c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 17667c478bd9Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 17677c478bd9Sstevel@tonic-gate perror("ls"); 17687c478bd9Sstevel@tonic-gate nomocore = 1; 17697c478bd9Sstevel@tonic-gate return (NULL); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate /* 17747c478bd9Sstevel@tonic-gate * nfiles is reset to nargs for each directory 17757c478bd9Sstevel@tonic-gate * that is given as an argument maxn is checked 17767c478bd9Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 17777c478bd9Sstevel@tonic-gate * that already has one assigned. 17787c478bd9Sstevel@tonic-gate */ 17797c478bd9Sstevel@tonic-gate if (nfiles >= maxn) { 17807c478bd9Sstevel@tonic-gate rep = nxtlbf++; 17817c478bd9Sstevel@tonic-gate flist[nfiles++] = rep; 17827c478bd9Sstevel@tonic-gate maxn = nfiles; 17837c478bd9Sstevel@tonic-gate } else { 17847c478bd9Sstevel@tonic-gate rep = flist[nfiles++]; 17857c478bd9Sstevel@tonic-gate } 178644f31f13Sbasabi 178744f31f13Sbasabi /* Initialize */ 178844f31f13Sbasabi 17897c478bd9Sstevel@tonic-gate rep->lflags = (mode_t)0; 17907c478bd9Sstevel@tonic-gate rep->flinkto = NULL; 17917c478bd9Sstevel@tonic-gate rep->cycle = 0; 179244f31f13Sbasabi rep->lat.tv_sec = time(NULL); 179344f31f13Sbasabi rep->lat.tv_nsec = 0; 179444f31f13Sbasabi rep->lct.tv_sec = time(NULL); 179544f31f13Sbasabi rep->lct.tv_nsec = 0; 179644f31f13Sbasabi rep->lmt.tv_sec = time(NULL); 179744f31f13Sbasabi rep->lmt.tv_nsec = 0; 179844f31f13Sbasabi rep->exttr = NULL; 179944f31f13Sbasabi rep->extm = NULL; 18001b628248SJason King rep->color = NULL; 18011b628248SJason King rep->link_color = NULL; 180244f31f13Sbasabi 18037c478bd9Sstevel@tonic-gate if (argfl || statreq) { 18047c478bd9Sstevel@tonic-gate int doacl; 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate if (lflg) 18077c478bd9Sstevel@tonic-gate doacl = 1; 18087c478bd9Sstevel@tonic-gate else 18097c478bd9Sstevel@tonic-gate doacl = 0; 181044f31f13Sbasabi 18117c478bd9Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 18127c478bd9Sstevel@tonic-gate if (argfl || errno != ENOENT || 18137c478bd9Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 18147c478bd9Sstevel@tonic-gate /* 18157c478bd9Sstevel@tonic-gate * Avoid race between readdir and lstat. 18167c478bd9Sstevel@tonic-gate * Print error message in case of dangling link. 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate perror(file); 18195e1c72e1SJason King err = 2; 18207c478bd9Sstevel@tonic-gate } 18217c478bd9Sstevel@tonic-gate nfiles--; 18227c478bd9Sstevel@tonic-gate return (NULL); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate /* 18267c478bd9Sstevel@tonic-gate * If -H was specified, and the file linked to was 18277c478bd9Sstevel@tonic-gate * not a directory, then we need to get the info 18287c478bd9Sstevel@tonic-gate * for the symlink itself. 18297c478bd9Sstevel@tonic-gate */ 18307c478bd9Sstevel@tonic-gate if ((Hflg) && (argfl) && 18317c478bd9Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 18327c478bd9Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 18337c478bd9Sstevel@tonic-gate perror(file); 18345e1c72e1SJason King err = 2; 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate rep->lnum = statb.st_ino; 18397c478bd9Sstevel@tonic-gate rep->lsize = statb.st_size; 18407c478bd9Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 18411b628248SJason King if (colorflg) 18421b628248SJason King rep->color = ls_color_find(file, statb.st_mode); 18431b628248SJason King 18447c478bd9Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 18457c478bd9Sstevel@tonic-gate case S_IFDIR: 18467c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 18477c478bd9Sstevel@tonic-gate if (Rflg) { 18487c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 18497c478bd9Sstevel@tonic-gate argfl, myparent); 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate break; 18527c478bd9Sstevel@tonic-gate case S_IFBLK: 18537c478bd9Sstevel@tonic-gate rep->ltype = 'b'; 18547c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18557c478bd9Sstevel@tonic-gate break; 18567c478bd9Sstevel@tonic-gate case S_IFCHR: 18577c478bd9Sstevel@tonic-gate rep->ltype = 'c'; 18587c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18597c478bd9Sstevel@tonic-gate break; 18607c478bd9Sstevel@tonic-gate case S_IFIFO: 18617c478bd9Sstevel@tonic-gate rep->ltype = 'p'; 18627c478bd9Sstevel@tonic-gate break; 18637c478bd9Sstevel@tonic-gate case S_IFSOCK: 18647c478bd9Sstevel@tonic-gate rep->ltype = 's'; 18657c478bd9Sstevel@tonic-gate rep->lsize = 0; 18667c478bd9Sstevel@tonic-gate break; 18677c478bd9Sstevel@tonic-gate case S_IFLNK: 18687c478bd9Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 18697c478bd9Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 18707c478bd9Sstevel@tonic-gate ((Hflg) && (!argfl))) { 18717c478bd9Sstevel@tonic-gate doacl = 0; 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate rep->ltype = 'l'; 18741b628248SJason King if (lflg || colorflg) { 18757c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 18761b628248SJason King if (cc < 0) 18771b628248SJason King break; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* 18807c478bd9Sstevel@tonic-gate * follow the symbolic link 18817c478bd9Sstevel@tonic-gate * to generate the appropriate 18827c478bd9Sstevel@tonic-gate * Fflg marker for the object 18837c478bd9Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 18847c478bd9Sstevel@tonic-gate */ 18851b628248SJason King error = 0; 18861b628248SJason King if (Fflg || pflg || colorflg) 18871b628248SJason King error = stat(file, &statb1); 18881b628248SJason King 18891b628248SJason King if (colorflg) { 18901b628248SJason King if (error >= 0) 18911b628248SJason King rep->link_color = 18921b628248SJason King ls_color_find(file, 18931b628248SJason King statb1.st_mode); 18941b628248SJason King else 18951b628248SJason King rep->link_color = 18961b628248SJason King lsc_orphan; 18971b628248SJason King } 18981b628248SJason King 18991b628248SJason King if ((Fflg || pflg) && error >= 0) { 19001b628248SJason King switch (statb1.st_mode & S_IFMT) { 19017c478bd9Sstevel@tonic-gate case S_IFDIR: 19027c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 19037c478bd9Sstevel@tonic-gate break; 19047c478bd9Sstevel@tonic-gate case S_IFSOCK: 19057c478bd9Sstevel@tonic-gate buf[cc++] = '='; 19067c478bd9Sstevel@tonic-gate break; 19072236845bSakaplan case S_IFDOOR: 19082236845bSakaplan buf[cc++] = '>'; 19092236845bSakaplan break; 19102236845bSakaplan case S_IFIFO: 19112236845bSakaplan buf[cc++] = '|'; 19122236845bSakaplan break; 19137c478bd9Sstevel@tonic-gate default: 19141b628248SJason King if ((statb1.st_mode & ~S_IFMT) & 19151b628248SJason King (S_IXUSR|S_IXGRP| S_IXOTH)) 19167c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 19177c478bd9Sstevel@tonic-gate break; 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate buf[cc] = '\0'; 19217c478bd9Sstevel@tonic-gate rep->flinkto = strdup(buf); 1922*38f2a414SAlbert Lee if (rep->flinkto == NULL) { 1923*38f2a414SAlbert Lee perror("ls"); 1924*38f2a414SAlbert Lee nomocore = 1; 1925*38f2a414SAlbert Lee return (NULL); 1926*38f2a414SAlbert Lee } 19277c478bd9Sstevel@tonic-gate break; 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 19327c478bd9Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 19337c478bd9Sstevel@tonic-gate * when explicit arguments are specified. 19347c478bd9Sstevel@tonic-gate */ 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate #ifdef XPG6 19377c478bd9Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 19387c478bd9Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 19397c478bd9Sstevel@tonic-gate (stat(file, &statb1) < 0)) 19407c478bd9Sstevel@tonic-gate #else 19417c478bd9Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 19427c478bd9Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 19437c478bd9Sstevel@tonic-gate #endif /* XPG6 */ 19447c478bd9Sstevel@tonic-gate break; 19457c478bd9Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 19467c478bd9Sstevel@tonic-gate statb = statb1; 19477c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 19487c478bd9Sstevel@tonic-gate rep->lsize = statb1.st_size; 19497c478bd9Sstevel@tonic-gate if (Rflg) { 19507c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 19517c478bd9Sstevel@tonic-gate argfl, myparent); 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate break; 19557c478bd9Sstevel@tonic-gate case S_IFDOOR: 19567c478bd9Sstevel@tonic-gate rep->ltype = 'D'; 19577c478bd9Sstevel@tonic-gate break; 19587c478bd9Sstevel@tonic-gate case S_IFREG: 19597c478bd9Sstevel@tonic-gate rep->ltype = '-'; 19607c478bd9Sstevel@tonic-gate break; 19617c478bd9Sstevel@tonic-gate case S_IFPORT: 19627c478bd9Sstevel@tonic-gate rep->ltype = 'P'; 19637c478bd9Sstevel@tonic-gate break; 19647c478bd9Sstevel@tonic-gate default: 19657c478bd9Sstevel@tonic-gate rep->ltype = '?'; 19667c478bd9Sstevel@tonic-gate break; 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 19717c478bd9Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 19727c478bd9Sstevel@tonic-gate 197344f31f13Sbasabi rep->luid = statb.st_uid; 197444f31f13Sbasabi rep->lgid = statb.st_gid; 197544f31f13Sbasabi rep->lnl = statb.st_nlink; 197644f31f13Sbasabi if (uflg || (tmflg && atm)) 197744f31f13Sbasabi rep->lmtime = statb.st_atim; 197844f31f13Sbasabi else if (cflg || (tmflg && ctm)) 197944f31f13Sbasabi rep->lmtime = statb.st_ctim; 198044f31f13Sbasabi else 198144f31f13Sbasabi rep->lmtime = statb.st_mtim; 198244f31f13Sbasabi rep->lat = statb.st_atim; 198344f31f13Sbasabi rep->lct = statb.st_ctim; 198444f31f13Sbasabi rep->lmt = statb.st_mtim; 198544f31f13Sbasabi 19867c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 19877c478bd9Sstevel@tonic-gate if (doacl) { 19887c478bd9Sstevel@tonic-gate 1989fa9e4066Sahrens error = acl_get(file, 0, &rep->aclp); 1990fa9e4066Sahrens if (error) { 1991fa9e4066Sahrens (void) fprintf(stderr, 1992fa9e4066Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1993fa9e4066Sahrens file, acl_strerror(error)); 199444f31f13Sbasabi rep->acl = ' '; 199556798e90Sbasabi acl_err++; 199644f31f13Sbasabi return (rep); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate 1999fa9e4066Sahrens rep->acl = ' '; 2000fa9e4066Sahrens 2001fa9e4066Sahrens if (rep->aclp && 2002fa9e4066Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 2003fa9e4066Sahrens rep->acl = '+'; 20047c478bd9Sstevel@tonic-gate /* 2005fa9e4066Sahrens * Special handling for ufs aka aclent_t ACL's 2006fa9e4066Sahrens */ 200764d425a7Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 2008fa9e4066Sahrens /* 2009fa9e4066Sahrens * For files with non-trivial acls, the 2010fa9e4066Sahrens * effective group permissions are the 2011fa9e4066Sahrens * intersection of the GROUP_OBJ value 2012fa9e4066Sahrens * and the CLASS_OBJ (acl mask) value. 2013fa9e4066Sahrens * Determine both the GROUP_OBJ and 2014fa9e4066Sahrens * CLASS_OBJ for this file and insert 2015fa9e4066Sahrens * the logical AND of those two values 2016fa9e4066Sahrens * in the group permissions field 2017fa9e4066Sahrens * of the lflags value for this file. 2018fa9e4066Sahrens */ 2019fa9e4066Sahrens 2020fa9e4066Sahrens /* 2021fa9e4066Sahrens * Until found in acl list, assume 2022fa9e4066Sahrens * maximum permissions for both group 2023fa9e4066Sahrens * a nd mask. (Just in case the acl 2024fa9e4066Sahrens * lacks either value for some reason.) 20257c478bd9Sstevel@tonic-gate */ 20267c478bd9Sstevel@tonic-gate groupperm = 07; 20277c478bd9Sstevel@tonic-gate mask = 07; 20287c478bd9Sstevel@tonic-gate grouppermfound = 0; 20297c478bd9Sstevel@tonic-gate maskfound = 0; 2030fa9e4066Sahrens aclcnt = acl_cnt(rep->aclp); 2031fa9e4066Sahrens for (tp = 2032fa9e4066Sahrens (aclent_t *)acl_data(rep->aclp); 2033fa9e4066Sahrens aclcnt--; tp++) { 20347c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 20357c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 20367c478bd9Sstevel@tonic-gate grouppermfound = 1; 20377c478bd9Sstevel@tonic-gate continue; 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 20407c478bd9Sstevel@tonic-gate mask = tp->a_perm; 20417c478bd9Sstevel@tonic-gate maskfound = 1; 20427c478bd9Sstevel@tonic-gate } 20437c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 20447c478bd9Sstevel@tonic-gate break; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* reset all the group bits */ 20497c478bd9Sstevel@tonic-gate rep->lflags &= ~S_IRWXG; 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate /* 2052fa9e4066Sahrens * Now set them to the logical AND of 2053fa9e4066Sahrens * the GROUP_OBJ permissions and the 2054fa9e4066Sahrens * acl mask. 20557c478bd9Sstevel@tonic-gate */ 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate rep->lflags |= (groupperm & mask) << 3; 2058fa9e4066Sahrens 205964d425a7Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 206064d425a7Sny155746 int mode; 206127dd1e87SMark Shellenbaum mode = grp_mask_to_mode(rep); 206264d425a7Sny155746 rep->lflags &= ~S_IRWXG; 206364d425a7Sny155746 rep->lflags |= mode; 2064fa9e4066Sahrens } 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20675a5eeccaSmarks if (!vflg && !Vflg && rep->aclp) { 20685a5eeccaSmarks acl_free(rep->aclp); 20695a5eeccaSmarks rep->aclp = NULL; 20705a5eeccaSmarks } 20715a5eeccaSmarks 20727c478bd9Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 20737c478bd9Sstevel@tonic-gate rep->acl = '@'; 2074da6c28aaSamw 20757c478bd9Sstevel@tonic-gate } else 20767c478bd9Sstevel@tonic-gate rep->acl = ' '; 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 20817c478bd9Sstevel@tonic-gate tblocks += rep->lblocks; 2082da6c28aaSamw 2083da6c28aaSamw /* Get extended system attributes */ 2084da6c28aaSamw 2085da6c28aaSamw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 2086da6c28aaSamw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 2087da6c28aaSamw int i; 2088da6c28aaSamw 2089da6c28aaSamw sacnt = attr_count(); 2090da6c28aaSamw /* 2091da6c28aaSamw * Allocate 'sacnt' size array to hold extended 2092da6c28aaSamw * system attribute name (verbose) or respective 2093da6c28aaSamw * symbol represenation (compact). 2094da6c28aaSamw */ 2095da6c28aaSamw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 2096da6c28aaSamw rep); 2097da6c28aaSamw 2098da6c28aaSamw /* initialize boolean attribute list */ 2099da6c28aaSamw for (i = 0; i < sacnt; i++) 2100da6c28aaSamw rep->exttr[i].name = NULL; 2101da6c28aaSamw if (get_sysxattr(file, rep) != 0) { 2102da6c28aaSamw (void) fprintf(stderr, 2103da6c28aaSamw gettext("ls:Failed to retrieve " 2104da6c28aaSamw "extended system attribute from " 2105da6c28aaSamw "%s\n"), file); 2106da6c28aaSamw rep->exttr[0].name = xmalloc(2, rep); 2107da6c28aaSamw (void) strlcpy(rep->exttr[0].name, "?", 2); 2108da6c28aaSamw } 2109da6c28aaSamw } 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate return (rep); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate /* 21157c478bd9Sstevel@tonic-gate * returns pathname of the form dir/file; 21167c478bd9Sstevel@tonic-gate * dir and file are null-terminated strings. 21177c478bd9Sstevel@tonic-gate */ 21187c478bd9Sstevel@tonic-gate static char * 21197c478bd9Sstevel@tonic-gate makename(char *dir, char *file) 21207c478bd9Sstevel@tonic-gate { 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 21237c478bd9Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 21247c478bd9Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 21257c478bd9Sstevel@tonic-gate * and the null character at the end. 21267c478bd9Sstevel@tonic-gate * dfile is static as this is returned by makename(). 21277c478bd9Sstevel@tonic-gate */ 21287c478bd9Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 21297c478bd9Sstevel@tonic-gate char *dp, *fp; 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate dp = dfile; 21327c478bd9Sstevel@tonic-gate fp = dir; 21337c478bd9Sstevel@tonic-gate while (*fp) 21347c478bd9Sstevel@tonic-gate *dp++ = *fp++; 21357c478bd9Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 21367c478bd9Sstevel@tonic-gate *dp++ = '/'; 21377c478bd9Sstevel@tonic-gate fp = file; 21387c478bd9Sstevel@tonic-gate while (*fp) 21397c478bd9Sstevel@tonic-gate *dp++ = *fp++; 21407c478bd9Sstevel@tonic-gate *dp = '\0'; 21417c478bd9Sstevel@tonic-gate return (dfile); 21427c478bd9Sstevel@tonic-gate } 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate #include <pwd.h> 21467c478bd9Sstevel@tonic-gate #include <grp.h> 21477c478bd9Sstevel@tonic-gate #include <utmpx.h> 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate struct utmpx utmp; 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 21527c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 21567c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 21577c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 21587c478bd9Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 21597c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 21607c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 21617c478bd9Sstevel@tonic-gate }; 21627c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate static struct cachenode * 21657c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val) 21667c478bd9Sstevel@tonic-gate { 21677c478bd9Sstevel@tonic-gate struct cachenode **parent = head; 21687c478bd9Sstevel@tonic-gate struct cachenode *c = *parent; 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate while (c != NULL) { 21717c478bd9Sstevel@tonic-gate if (val == c->val) { 21727c478bd9Sstevel@tonic-gate /* found it */ 21737c478bd9Sstevel@tonic-gate return (c); 21747c478bd9Sstevel@tonic-gate } else if (val < c->val) { 21757c478bd9Sstevel@tonic-gate parent = &c->lesschild; 21767c478bd9Sstevel@tonic-gate c = c->lesschild; 21777c478bd9Sstevel@tonic-gate } else { 21787c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 21797c478bd9Sstevel@tonic-gate c = c->grtrchild; 21807c478bd9Sstevel@tonic-gate } 21817c478bd9Sstevel@tonic-gate } 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 21847c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 21857c478bd9Sstevel@tonic-gate if (c == NULL) { 21867c478bd9Sstevel@tonic-gate perror("ls"); 21877c478bd9Sstevel@tonic-gate exit(2); 21887c478bd9Sstevel@tonic-gate } 21897c478bd9Sstevel@tonic-gate *parent = c; 21907c478bd9Sstevel@tonic-gate c->val = val; 21917c478bd9Sstevel@tonic-gate return (c); 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate /* 21957c478bd9Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 21967c478bd9Sstevel@tonic-gate * lastuid is set to uid. 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate static char * 21997c478bd9Sstevel@tonic-gate getname(uid_t uid) 22007c478bd9Sstevel@tonic-gate { 22017c478bd9Sstevel@tonic-gate struct passwd *pwent; 22027c478bd9Sstevel@tonic-gate struct cachenode *c; 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 22057c478bd9Sstevel@tonic-gate return (lastuname); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 22087c478bd9Sstevel@tonic-gate if (c->initted == 0) { 22097c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 22107c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 22117c478bd9Sstevel@tonic-gate } else { 22127c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate c->initted = 1; 22157c478bd9Sstevel@tonic-gate } 22167c478bd9Sstevel@tonic-gate lastuid = uid; 22177c478bd9Sstevel@tonic-gate lastuname = &c->name[0]; 22187c478bd9Sstevel@tonic-gate return (lastuname); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate /* 22227c478bd9Sstevel@tonic-gate * get name from cache, or group file for a given gid; 22237c478bd9Sstevel@tonic-gate * lastgid is set to gid. 22247c478bd9Sstevel@tonic-gate */ 22257c478bd9Sstevel@tonic-gate static char * 22267c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 22277c478bd9Sstevel@tonic-gate { 22287c478bd9Sstevel@tonic-gate struct group *grent; 22297c478bd9Sstevel@tonic-gate struct cachenode *c; 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 22327c478bd9Sstevel@tonic-gate return (lastgname); 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 22357c478bd9Sstevel@tonic-gate if (c->initted == 0) { 22367c478bd9Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 22377c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 22387c478bd9Sstevel@tonic-gate } else { 22397c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate c->initted = 1; 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate lastgid = gid; 22447c478bd9Sstevel@tonic-gate lastgname = &c->name[0]; 22457c478bd9Sstevel@tonic-gate return (lastgname); 22467c478bd9Sstevel@tonic-gate } 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 22497c478bd9Sstevel@tonic-gate static int 22507c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 22517c478bd9Sstevel@tonic-gate { 22527c478bd9Sstevel@tonic-gate struct lbuf *p1, *p2; 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate p1 = *pp1; 22557c478bd9Sstevel@tonic-gate p2 = *pp2; 22567c478bd9Sstevel@tonic-gate if (dflg == 0) { 22577c478bd9Sstevel@tonic-gate /* 22587c478bd9Sstevel@tonic-gate * compare two names in ls-command one of which is file 22597c478bd9Sstevel@tonic-gate * and the other is a directory; 22607c478bd9Sstevel@tonic-gate * this portion is not used for comparing files within 22617c478bd9Sstevel@tonic-gate * a directory name of ls-command; 22627c478bd9Sstevel@tonic-gate */ 22637c478bd9Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 22647c478bd9Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 22657c478bd9Sstevel@tonic-gate return (1); 22667c478bd9Sstevel@tonic-gate } else { 22677c478bd9Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 22687c478bd9Sstevel@tonic-gate return (-1); 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate if (tflg) { 22727c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 22737c478bd9Sstevel@tonic-gate return (rflg); 22747c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 22757c478bd9Sstevel@tonic-gate return (-rflg); 22767c478bd9Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 22777c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 22787c478bd9Sstevel@tonic-gate return (rflg); 22797c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 22807c478bd9Sstevel@tonic-gate return (-rflg); 22817c478bd9Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 22827c478bd9Sstevel@tonic-gate } else if (Sflg) { 22837c478bd9Sstevel@tonic-gate /* 22847c478bd9Sstevel@tonic-gate * The size stored in lsize can be either the 22857c478bd9Sstevel@tonic-gate * size or the major minor number (in the case of 22867c478bd9Sstevel@tonic-gate * block and character special devices). If it's 22877c478bd9Sstevel@tonic-gate * a major minor number, then the size is considered 22887c478bd9Sstevel@tonic-gate * to be zero and we want to fall through and sort 22897c478bd9Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 22907c478bd9Sstevel@tonic-gate * to the size of p1 we want to fall through and 22917c478bd9Sstevel@tonic-gate * sort by name. 22927c478bd9Sstevel@tonic-gate */ 22937c478bd9Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 22947c478bd9Sstevel@tonic-gate (p1->ltype == 'c') ? 0 : p1->lsize; 22957c478bd9Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 22967c478bd9Sstevel@tonic-gate (p2->ltype == 'c') ? 0 : p2->lsize; 22977c478bd9Sstevel@tonic-gate if (p2size > p1size) { 22987c478bd9Sstevel@tonic-gate return (rflg); 22997c478bd9Sstevel@tonic-gate } else if (p2size < p1size) { 23007c478bd9Sstevel@tonic-gate return (-rflg); 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate return (rflg * strcoll( 23057c478bd9Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 23067c478bd9Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 23077c478bd9Sstevel@tonic-gate } 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate static void 23107c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2) 23117c478bd9Sstevel@tonic-gate { 23127c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 23137c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 23147c478bd9Sstevel@tonic-gate } 23157c478bd9Sstevel@tonic-gate 23167c478bd9Sstevel@tonic-gate static void 23177c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s) 23187c478bd9Sstevel@tonic-gate { 23197c478bd9Sstevel@tonic-gate unsigned char *cp; 23207c478bd9Sstevel@tonic-gate char c; 23217c478bd9Sstevel@tonic-gate int i; 23227c478bd9Sstevel@tonic-gate int c_len; 23237c478bd9Sstevel@tonic-gate int p_col; 23247c478bd9Sstevel@tonic-gate wchar_t pcode; 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate if (!qflg && !bflg) { 23277c478bd9Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 23287c478bd9Sstevel@tonic-gate (void) putchar(*cp); 23297c478bd9Sstevel@tonic-gate curcol++; 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate return; 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate for (cp = s; *cp; ) { 23357c478bd9Sstevel@tonic-gate if (isascii(c = *cp)) { 23367c478bd9Sstevel@tonic-gate if (!isprint(c)) { 23377c478bd9Sstevel@tonic-gate if (qflg) { 23387c478bd9Sstevel@tonic-gate c = '?'; 23397c478bd9Sstevel@tonic-gate } else { 23407c478bd9Sstevel@tonic-gate curcol += 3; 23417c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 23427c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23437c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23447c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23457c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23467c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 23477c478bd9Sstevel@tonic-gate } 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate curcol++; 23507c478bd9Sstevel@tonic-gate cp++; 23517c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23527c478bd9Sstevel@tonic-gate continue; 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 23567c478bd9Sstevel@tonic-gate c_len = 1; 23577c478bd9Sstevel@tonic-gate goto not_print; 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 23617c478bd9Sstevel@tonic-gate (void) putwchar(pcode); 23627c478bd9Sstevel@tonic-gate cp += c_len; 23637c478bd9Sstevel@tonic-gate curcol += p_col; 23647c478bd9Sstevel@tonic-gate continue; 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate not_print: 23687c478bd9Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 23697c478bd9Sstevel@tonic-gate if (qflg) { 23707c478bd9Sstevel@tonic-gate c = '?'; 23717c478bd9Sstevel@tonic-gate } else { 23727c478bd9Sstevel@tonic-gate curcol += 3; 23737c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 23747c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23757c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23767c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23777c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23787c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate curcol++; 23817c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 23827c478bd9Sstevel@tonic-gate cp++; 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate } 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate static int 23887c478bd9Sstevel@tonic-gate strcol(unsigned char *s1) 23897c478bd9Sstevel@tonic-gate { 23907c478bd9Sstevel@tonic-gate int w; 23917c478bd9Sstevel@tonic-gate int w_col; 23927c478bd9Sstevel@tonic-gate int len; 23937c478bd9Sstevel@tonic-gate wchar_t wc; 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate w = 0; 23967c478bd9Sstevel@tonic-gate while (*s1) { 23977c478bd9Sstevel@tonic-gate if (isascii(*s1)) { 23987c478bd9Sstevel@tonic-gate w++; 23997c478bd9Sstevel@tonic-gate s1++; 24007c478bd9Sstevel@tonic-gate continue; 24017c478bd9Sstevel@tonic-gate } 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 24047c478bd9Sstevel@tonic-gate w++; 24057c478bd9Sstevel@tonic-gate s1++; 24067c478bd9Sstevel@tonic-gate continue; 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 24107c478bd9Sstevel@tonic-gate w_col = len; 24117c478bd9Sstevel@tonic-gate s1 += len; 24127c478bd9Sstevel@tonic-gate w += w_col; 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate return (w); 24157c478bd9Sstevel@tonic-gate } 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate /* 24187c478bd9Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 24197c478bd9Sstevel@tonic-gate * result in the caller-supplied buffer. 24207c478bd9Sstevel@tonic-gate * 24217c478bd9Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 24227c478bd9Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 24237c478bd9Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 24247c478bd9Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 24257c478bd9Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 24267c478bd9Sstevel@tonic-gate * the final number has only a single significant digit, we compute 24277c478bd9Sstevel@tonic-gate * tenths of units to provide a second significant digit. 24287c478bd9Sstevel@tonic-gate * 24297c478bd9Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 24307c478bd9Sstevel@tonic-gate * converted to "-1". 24317c478bd9Sstevel@tonic-gate * 24327c478bd9Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 24337c478bd9Sstevel@tonic-gate */ 24347c478bd9Sstevel@tonic-gate static char * 24357c478bd9Sstevel@tonic-gate number_to_scaled_string( 24367c478bd9Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 24377c478bd9Sstevel@tonic-gate unsigned long long number, /* convert this number */ 24387c478bd9Sstevel@tonic-gate long scale) 24397c478bd9Sstevel@tonic-gate { 24407c478bd9Sstevel@tonic-gate unsigned long long save; 24417c478bd9Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 24427c478bd9Sstevel@tonic-gate char *uom = "KMGTPE"; 24437c478bd9Sstevel@tonic-gate 24447c478bd9Sstevel@tonic-gate if ((long long)number == (long long)-1) { 24457c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 24467c478bd9Sstevel@tonic-gate return (buf); 24477c478bd9Sstevel@tonic-gate } 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate save = number; 24507c478bd9Sstevel@tonic-gate number = number / scale; 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate /* 24537c478bd9Sstevel@tonic-gate * Now we have number as a count of scale units. 24547c478bd9Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 24557c478bd9Sstevel@tonic-gate * 24567c478bd9Sstevel@tonic-gate * The largest value number could have had entering the routine is 24577c478bd9Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 24587c478bd9Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 24597c478bd9Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 24607c478bd9Sstevel@tonic-gate */ 24617c478bd9Sstevel@tonic-gate if (number < (unsigned long long)scale) { 24627c478bd9Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 24637c478bd9Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 24647c478bd9Sstevel@tonic-gate uom++; 24657c478bd9Sstevel@tonic-gate number = 1; 24667c478bd9Sstevel@tonic-gate } 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate } else { 24697c478bd9Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 24707c478bd9Sstevel@tonic-gate uom++; /* next unit of measurement */ 24717c478bd9Sstevel@tonic-gate save = number; 24727c478bd9Sstevel@tonic-gate /* 24737c478bd9Sstevel@tonic-gate * If we're over half way to the next unit of 24747c478bd9Sstevel@tonic-gate * 'scale' bytes (which means we should round 24757c478bd9Sstevel@tonic-gate * up), then adding half of 'scale' prior to 24767c478bd9Sstevel@tonic-gate * the division will push us into that next 24777c478bd9Sstevel@tonic-gate * unit of scale when we perform the division 24787c478bd9Sstevel@tonic-gate */ 24797c478bd9Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 24807c478bd9Sstevel@tonic-gate } 24817c478bd9Sstevel@tonic-gate } 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 24847c478bd9Sstevel@tonic-gate if ((save / scale) < 10) { 24857c478bd9Sstevel@tonic-gate /* snprintf() will round for us */ 24867c478bd9Sstevel@tonic-gate float fnum = (float)save / scale; 24877c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 24887c478bd9Sstevel@tonic-gate fnum, *uom); 24897c478bd9Sstevel@tonic-gate } else { 24907c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 24917c478bd9Sstevel@tonic-gate number, *uom); 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate return (buf); 24947c478bd9Sstevel@tonic-gate } 2495da6c28aaSamw 2496da6c28aaSamw /* Get extended system attributes and set the display */ 2497da6c28aaSamw 2498da6c28aaSamw int 2499da6c28aaSamw get_sysxattr(char *fname, struct lbuf *rep) 2500da6c28aaSamw { 2501da6c28aaSamw boolean_t value; 2502da6c28aaSamw data_type_t type; 2503da6c28aaSamw int error; 2504da6c28aaSamw char *name; 2505da6c28aaSamw int i; 2506da6c28aaSamw 2507da6c28aaSamw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 2508da6c28aaSamw &response)) != 0) { 2509da6c28aaSamw perror("ls:getattrat"); 2510da6c28aaSamw return (error); 2511da6c28aaSamw } 2512da6c28aaSamw 2513da6c28aaSamw /* 2514da6c28aaSamw * Allocate 'sacnt' size array to hold extended timestamp 2515da6c28aaSamw * system attributes and initialize the array. 2516da6c28aaSamw */ 2517da6c28aaSamw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 2518da6c28aaSamw for (i = 0; i < sacnt; i++) { 2519da6c28aaSamw rep->extm[i].stm = 0; 2520da6c28aaSamw rep->extm[i].nstm = 0; 2521da6c28aaSamw rep->extm[i].name = NULL; 2522da6c28aaSamw } 2523da6c28aaSamw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 2524da6c28aaSamw name = nvpair_name(pair); 2525da6c28aaSamw type = nvpair_type(pair); 2526da6c28aaSamw if (type == DATA_TYPE_BOOLEAN_VALUE) { 2527da6c28aaSamw error = nvpair_value_boolean_value(pair, &value); 2528da6c28aaSamw if (error) { 2529da6c28aaSamw (void) fprintf(stderr, 2530da6c28aaSamw gettext("nvpair_value_boolean_value " 2531da6c28aaSamw "failed: error = %d\n"), error); 2532da6c28aaSamw continue; 2533da6c28aaSamw } 2534da6c28aaSamw if (name != NULL) 2535da6c28aaSamw set_sysattrb_display(name, value, rep); 2536da6c28aaSamw continue; 2537da6c28aaSamw } else if (type == DATA_TYPE_UINT64_ARRAY) { 2538da6c28aaSamw if (name != NULL) 2539da6c28aaSamw set_sysattrtm_display(name, rep); 2540da6c28aaSamw continue; 2541da6c28aaSamw } 2542da6c28aaSamw } 2543da6c28aaSamw nvlist_free(response); 2544da6c28aaSamw return (0); 2545da6c28aaSamw } 2546da6c28aaSamw 2547da6c28aaSamw /* Set extended system attribute boolean display */ 2548da6c28aaSamw 2549da6c28aaSamw void 2550da6c28aaSamw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 2551da6c28aaSamw { 2552da6c28aaSamw f_attr_t fattr; 2553da6c28aaSamw const char *opt; 2554da6c28aaSamw size_t len; 2555da6c28aaSamw 2556da6c28aaSamw fattr = name_to_attr(name); 2557da6c28aaSamw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 2558da6c28aaSamw if (vopt) { 2559da6c28aaSamw len = strlen(name); 2560da6c28aaSamw if (val) { 2561da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2562da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, name, 2563da6c28aaSamw len + 1); 2564da6c28aaSamw } else { 2565da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 3, rep); 2566da6c28aaSamw (void) snprintf(rep->exttr[fattr].name, len + 3, 2567da6c28aaSamw "no%s", name); 2568da6c28aaSamw } 2569da6c28aaSamw } else { 2570da6c28aaSamw opt = attr_to_option(fattr); 2571da6c28aaSamw if (opt != NULL) { 2572da6c28aaSamw len = strlen(opt); 2573da6c28aaSamw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2574da6c28aaSamw if (val) 2575da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2576da6c28aaSamw opt, len + 1); 2577da6c28aaSamw else 2578da6c28aaSamw (void) strlcpy(rep->exttr[fattr].name, 2579da6c28aaSamw "-", len + 1); 2580da6c28aaSamw } 2581da6c28aaSamw } 2582da6c28aaSamw } 2583da6c28aaSamw } 2584da6c28aaSamw 2585da6c28aaSamw /* Set extended system attribute timestamp display */ 2586da6c28aaSamw 2587da6c28aaSamw void 2588da6c28aaSamw set_sysattrtm_display(char *name, struct lbuf *rep) 2589da6c28aaSamw { 2590da6c28aaSamw uint_t nelem; 2591da6c28aaSamw uint64_t *value; 2592da6c28aaSamw int i; 2593da6c28aaSamw size_t len; 2594da6c28aaSamw 2595da6c28aaSamw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 2596da6c28aaSamw if (*value != NULL) { 2597da6c28aaSamw len = strlen(name); 2598da6c28aaSamw i = 0; 2599da6c28aaSamw while (rep->extm[i].stm != 0 && i < sacnt) 2600da6c28aaSamw i++; 2601da6c28aaSamw rep->extm[i].stm = value[0]; 2602da6c28aaSamw rep->extm[i].nstm = value[1]; 2603da6c28aaSamw rep->extm[i].name = xmalloc(len + 1, rep); 2604da6c28aaSamw (void) strlcpy(rep->extm[i].name, name, len + 1); 2605da6c28aaSamw } 2606da6c28aaSamw } 2607da6c28aaSamw } 2608da6c28aaSamw 2609da6c28aaSamw void 26105e1c72e1SJason King format_time(time_t sec, time_t nsec) 2611da6c28aaSamw { 26125e1c72e1SJason King const char *fstr = time_fmt_new; 2613da6c28aaSamw char fmt_buf[FMTSIZE]; 2614da6c28aaSamw 26155e1c72e1SJason King if (Eflg) { 26165e1c72e1SJason King (void) snprintf(fmt_buf, FMTSIZE, fstr, nsec); 26175e1c72e1SJason King (void) strftime(time_buf, sizeof (time_buf), fmt_buf, 26185e1c72e1SJason King localtime(&sec)); 26195e1c72e1SJason King return; 2620da6c28aaSamw } 2621da6c28aaSamw 26225e1c72e1SJason King if (sec < year || sec > now) 26235e1c72e1SJason King fstr = time_fmt_old; 26245e1c72e1SJason King 26255e1c72e1SJason King /* if a custom time was specified, shouldn't be localized */ 26265e1c72e1SJason King (void) strftime(time_buf, sizeof (time_buf), 26275e1c72e1SJason King (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr, 26285e1c72e1SJason King localtime(&sec)); 26295e1c72e1SJason King } 2630da6c28aaSamw 2631da6c28aaSamw void 2632da6c28aaSamw format_attrtime(struct lbuf *p) 2633da6c28aaSamw { 2634da6c28aaSamw int tmattr = 0; 2635da6c28aaSamw int i; 2636da6c28aaSamw 2637da6c28aaSamw if (p->extm != NULL) { 2638da6c28aaSamw for (i = 0; i < sacnt; i++) { 2639da6c28aaSamw if (p->extm[i].name != NULL) { 2640da6c28aaSamw tmattr = 1; 2641da6c28aaSamw break; 2642da6c28aaSamw } 2643da6c28aaSamw } 2644da6c28aaSamw } 26455e1c72e1SJason King 2646da6c28aaSamw if (tmattr) { 26475e1c72e1SJason King const char *old_save = time_fmt_old; 26485e1c72e1SJason King const char *new_save = time_fmt_new; 26495e1c72e1SJason King 26505e1c72e1SJason King /* Eflg always sets format to FORMAT_ISO_FULL */ 26515e1c72e1SJason King if (!Eflg && !time_custom) { 26525e1c72e1SJason King time_fmt_old = FORMAT_OLD; 26535e1c72e1SJason King time_fmt_new = FORMAT_NEW; 2654da6c28aaSamw } 26555e1c72e1SJason King 26565e1c72e1SJason King format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm); 26575e1c72e1SJason King 26585e1c72e1SJason King time_fmt_old = old_save; 26595e1c72e1SJason King time_fmt_new = new_save; 2660da6c28aaSamw } 2661da6c28aaSamw } 2662da6c28aaSamw 2663da6c28aaSamw void 2664da6c28aaSamw print_time(struct lbuf *p) 2665da6c28aaSamw { 26665e1c72e1SJason King const char *old_save = time_fmt_old; 26675e1c72e1SJason King const char *new_save = time_fmt_new; 26685e1c72e1SJason King 2669da6c28aaSamw int i = 0; 2670da6c28aaSamw 26715e1c72e1SJason King if (!Eflg) { 26725e1c72e1SJason King time_fmt_old = FORMAT_LONG; 26735e1c72e1SJason King time_fmt_new = FORMAT_LONG; 26745e1c72e1SJason King } 26755e1c72e1SJason King 2676da6c28aaSamw new_line(); 26775e1c72e1SJason King format_time(p->lat.tv_sec, p->lat.tv_nsec); 26785e1c72e1SJason King (void) printf(" timestamp: atime %s\n", time_buf); 26795e1c72e1SJason King format_time(p->lct.tv_sec, p->lct.tv_nsec); 26805e1c72e1SJason King (void) printf(" timestamp: ctime %s\n", time_buf); 26815e1c72e1SJason King format_time(p->lmt.tv_sec, p->lmt.tv_nsec); 26825e1c72e1SJason King (void) printf(" timestamp: mtime %s\n", time_buf); 2683da6c28aaSamw if (p->extm != NULL) { 2684da6c28aaSamw while (p->extm[i].nstm != 0 && i < sacnt) { 26855e1c72e1SJason King format_time(p->extm[i].stm, p->extm[i].nstm); 2686da6c28aaSamw if (p->extm[i].name != NULL) { 2687da6c28aaSamw (void) printf(" timestamp:" 2688da6c28aaSamw " %s %s\n", 2689da6c28aaSamw p->extm[i].name, time_buf); 2690da6c28aaSamw } 2691da6c28aaSamw i++; 2692da6c28aaSamw } 2693da6c28aaSamw } 26945e1c72e1SJason King 26955e1c72e1SJason King time_fmt_old = old_save; 26965e1c72e1SJason King time_fmt_new = new_save; 26975e1c72e1SJason King } 26985e1c72e1SJason King 26995e1c72e1SJason King /* 27005e1c72e1SJason King * Check if color definition applies to entry, returns 1 if yes, 0 if no 27015e1c72e1SJason King */ 27025e1c72e1SJason King static int 27031b628248SJason King color_match(const char *fname, mode_t mode, ls_color_t *color) 27045e1c72e1SJason King { 27055e1c72e1SJason King switch (color->ftype) { 27065e1c72e1SJason King case LS_PAT: 27075e1c72e1SJason King { 27085e1c72e1SJason King size_t fname_len, sfx_len; 27095e1c72e1SJason King 27105e1c72e1SJason King fname_len = strlen(fname); 27115e1c72e1SJason King sfx_len = strlen(color->sfx); 27125e1c72e1SJason King if (sfx_len > fname_len) 27135e1c72e1SJason King return (0); 27145e1c72e1SJason King 27155e1c72e1SJason King if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0) 27165e1c72e1SJason King return (1); 27175e1c72e1SJason King else 27185e1c72e1SJason King return (0); 27195e1c72e1SJason King } 27205e1c72e1SJason King 27215e1c72e1SJason King case LS_NORMAL: 27225e1c72e1SJason King return (1); 27235e1c72e1SJason King 27245e1c72e1SJason King case LS_FILE: 27251b628248SJason King return (S_ISREG(mode)); 27265e1c72e1SJason King 27275e1c72e1SJason King case LS_DIR: 27281b628248SJason King return (S_ISDIR(mode)); 27295e1c72e1SJason King 27305e1c72e1SJason King case LS_LINK: 27311b628248SJason King return (S_ISLNK(mode)); 27325e1c72e1SJason King 27335e1c72e1SJason King case LS_FIFO: 27341b628248SJason King return (S_ISFIFO(mode)); 27355e1c72e1SJason King 27365e1c72e1SJason King case LS_SOCK: 27371b628248SJason King return (S_ISSOCK(mode)); 27385e1c72e1SJason King 27395e1c72e1SJason King case LS_DOOR: 27401b628248SJason King return (S_ISDOOR(mode)); 27415e1c72e1SJason King 27425e1c72e1SJason King case LS_BLK: 27431b628248SJason King return (S_ISBLK(mode)); 27445e1c72e1SJason King 27455e1c72e1SJason King case LS_CHR: 27461b628248SJason King return (S_ISCHR(mode)); 27475e1c72e1SJason King 27485e1c72e1SJason King case LS_PORT: 27491b628248SJason King return (S_ISPORT(mode)); 27505e1c72e1SJason King 27515e1c72e1SJason King case LS_ORPHAN: 27521b628248SJason King /* this is tested for by gstat */ 27535e1c72e1SJason King return (0); 27545e1c72e1SJason King 27555e1c72e1SJason King case LS_SETUID: 27561b628248SJason King return (!S_ISLNK(mode) && (mode & S_ISUID)); 27575e1c72e1SJason King 27585e1c72e1SJason King case LS_SETGID: 27591b628248SJason King return (!S_ISLNK(mode) && (mode & S_ISGID)); 27605e1c72e1SJason King 27615e1c72e1SJason King case LS_STICKY_OTHER_WRITABLE: 27621b628248SJason King return (!S_ISLNK(mode) && (mode & (S_IWOTH|S_ISVTX))); 27635e1c72e1SJason King 27645e1c72e1SJason King case LS_OTHER_WRITABLE: 27651b628248SJason King return (!S_ISLNK(mode) && (mode & S_IWOTH)); 27665e1c72e1SJason King 27675e1c72e1SJason King case LS_STICKY: 27681b628248SJason King return (!S_ISLNK(mode) && (mode & S_ISVTX)); 27695e1c72e1SJason King 27705e1c72e1SJason King case LS_EXEC: 27711b628248SJason King return (!S_ISLNK(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH))); 27725e1c72e1SJason King } 27735e1c72e1SJason King 27745e1c72e1SJason King return (0); 27755e1c72e1SJason King } 27765e1c72e1SJason King 27775e1c72e1SJason King static void 27785e1c72e1SJason King dump_color(ls_color_t *c) 27795e1c72e1SJason King { 27805e1c72e1SJason King if (c == NULL) 27815e1c72e1SJason King return; 27825e1c72e1SJason King 27835e1c72e1SJason King (void) printf("\n\ttype: "); 27845e1c72e1SJason King switch (c->ftype) { 27855e1c72e1SJason King case LS_NORMAL: 27865e1c72e1SJason King (void) printf("LS_NORMAL"); 27875e1c72e1SJason King break; 27885e1c72e1SJason King case LS_FILE: 27895e1c72e1SJason King (void) printf("LS_FILE"); 27905e1c72e1SJason King break; 27915e1c72e1SJason King case LS_EXEC: 27925e1c72e1SJason King (void) printf("LS_EXEC"); 27935e1c72e1SJason King break; 27945e1c72e1SJason King case LS_DIR: 27955e1c72e1SJason King (void) printf("LS_DIR"); 27965e1c72e1SJason King break; 27975e1c72e1SJason King case LS_LINK: 27985e1c72e1SJason King (void) printf("LS_LINK"); 27995e1c72e1SJason King break; 28005e1c72e1SJason King 28015e1c72e1SJason King case LS_FIFO: 28025e1c72e1SJason King (void) printf("LS_FIFO"); 28035e1c72e1SJason King break; 28045e1c72e1SJason King 28055e1c72e1SJason King case LS_SOCK: 28065e1c72e1SJason King (void) printf("LS_SOCK"); 28075e1c72e1SJason King break; 28085e1c72e1SJason King 28095e1c72e1SJason King case LS_DOOR: 28105e1c72e1SJason King (void) printf("LS_DOOR"); 28115e1c72e1SJason King break; 28125e1c72e1SJason King 28135e1c72e1SJason King case LS_BLK: 28145e1c72e1SJason King (void) printf("LS_BLK"); 28155e1c72e1SJason King break; 28165e1c72e1SJason King 28175e1c72e1SJason King case LS_CHR: 28185e1c72e1SJason King (void) printf("LS_CHR"); 28195e1c72e1SJason King break; 28205e1c72e1SJason King 28215e1c72e1SJason King case LS_PORT: 28225e1c72e1SJason King (void) printf("LS_PORT"); 28235e1c72e1SJason King break; 28245e1c72e1SJason King 28255e1c72e1SJason King case LS_STICKY: 28265e1c72e1SJason King (void) printf("LS_STICKY"); 28275e1c72e1SJason King break; 28285e1c72e1SJason King 28295e1c72e1SJason King case LS_ORPHAN: 28305e1c72e1SJason King (void) printf("LS_ORPHAN"); 28315e1c72e1SJason King break; 28325e1c72e1SJason King 28335e1c72e1SJason King case LS_SETGID: 28345e1c72e1SJason King (void) printf("LS_SETGID"); 28355e1c72e1SJason King break; 28365e1c72e1SJason King 28375e1c72e1SJason King case LS_SETUID: 28385e1c72e1SJason King (void) printf("LS_SETUID"); 28395e1c72e1SJason King break; 28405e1c72e1SJason King 28415e1c72e1SJason King case LS_OTHER_WRITABLE: 28425e1c72e1SJason King (void) printf("LS_OTHER_WRITABLE"); 28435e1c72e1SJason King break; 28445e1c72e1SJason King 28455e1c72e1SJason King case LS_STICKY_OTHER_WRITABLE: 28465e1c72e1SJason King (void) printf("LS_STICKY_OTHER_WRITABLE"); 28475e1c72e1SJason King break; 28485e1c72e1SJason King 28495e1c72e1SJason King case LS_PAT: 28505e1c72e1SJason King (void) printf("LS_PAT\n"); 28515e1c72e1SJason King (void) printf("\tpattern: %s", c->sfx); 28525e1c72e1SJason King break; 28535e1c72e1SJason King } 28545e1c72e1SJason King (void) printf("\n"); 28555e1c72e1SJason King (void) printf("\tattr: %d\n", c->attr); 28565e1c72e1SJason King (void) printf("\tfg: %d\n", c->fg); 28575e1c72e1SJason King (void) printf("\tbg: %d\n", c->bg); 28585e1c72e1SJason King (void) printf("\t"); 28595e1c72e1SJason King } 28605e1c72e1SJason King 28615e1c72e1SJason King static ls_color_t * 28621b628248SJason King ls_color_find(const char *fname, mode_t mode) 28635e1c72e1SJason King { 28645e1c72e1SJason King int i; 28655e1c72e1SJason King 28665e1c72e1SJason King /* 28675e1c72e1SJason King * Colors are sorted from most general lsc_colors[0] to most specific 28685e1c72e1SJason King * lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with 28695e1c72e1SJason King * most specific color rule and work towards most general. 28705e1c72e1SJason King */ 28715e1c72e1SJason King for (i = lsc_ncolors - 1; i >= 0; --i) 28721b628248SJason King if (color_match(fname, mode, &lsc_colors[i])) 28735e1c72e1SJason King return (&lsc_colors[i]); 28745e1c72e1SJason King 28755e1c72e1SJason King return (NULL); 28765e1c72e1SJason King } 28775e1c72e1SJason King 28785e1c72e1SJason King static void 28795e1c72e1SJason King ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4, 28805e1c72e1SJason King long int p5, long int p6, long int p7, long int p8, long int p9) 28815e1c72e1SJason King { 28825e1c72e1SJason King char *s; 28835e1c72e1SJason King 28845e1c72e1SJason King if (str == NULL) 28855e1c72e1SJason King return; 28865e1c72e1SJason King 28875e1c72e1SJason King s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); 28885e1c72e1SJason King 28895e1c72e1SJason King if (s != NULL) 28905e1c72e1SJason King (void) putp(s); 28915e1c72e1SJason King } 28925e1c72e1SJason King 28935e1c72e1SJason King static void 28941b628248SJason King ls_start_color(ls_color_t *c) 28955e1c72e1SJason King { 28965e1c72e1SJason King if (c == NULL) 28975e1c72e1SJason King return; 28985e1c72e1SJason King 28995e1c72e1SJason King if (lsc_debug) 29005e1c72e1SJason King lsc_match = c; 29015e1c72e1SJason King 29025e1c72e1SJason King if (c->attr & LSA_BOLD) 29035e1c72e1SJason King ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29045e1c72e1SJason King if (c->attr & LSA_UNDERSCORE) 29055e1c72e1SJason King ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29065e1c72e1SJason King if (c->attr & LSA_BLINK) 29075e1c72e1SJason King ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29085e1c72e1SJason King if (c->attr & LSA_REVERSE) 29095e1c72e1SJason King ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29105e1c72e1SJason King if (c->attr & LSA_CONCEALED) 29115e1c72e1SJason King ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29125e1c72e1SJason King if (c->attr == LSA_NONE) 29135e1c72e1SJason King ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29145e1c72e1SJason King 29155e1c72e1SJason King if (c->fg != -1) 29165e1c72e1SJason King ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0); 29175e1c72e1SJason King if (c->bg != -1) 29185e1c72e1SJason King ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0); 29195e1c72e1SJason King } 29205e1c72e1SJason King 29215e1c72e1SJason King static void 29225e1c72e1SJason King ls_end_color() 29235e1c72e1SJason King { 29245e1c72e1SJason King ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29255e1c72e1SJason King if (lsc_debug) 29265e1c72e1SJason King dump_color(lsc_match); 29275e1c72e1SJason King } 29285e1c72e1SJason King 29295e1c72e1SJason King static void 29305e1c72e1SJason King new_color_entry(char *colorstr) 29315e1c72e1SJason King { 29325e1c72e1SJason King static const struct { 29335e1c72e1SJason King const char *s; 29345e1c72e1SJason King ls_cftype_t stype; 29355e1c72e1SJason King } type_map[] = { 29365e1c72e1SJason King { "no", LS_NORMAL }, 29375e1c72e1SJason King { "fi", LS_FILE }, 29385e1c72e1SJason King { "di", LS_DIR }, 29395e1c72e1SJason King { "ln", LS_LINK }, 29405e1c72e1SJason King { "pi", LS_FIFO }, 29415e1c72e1SJason King { "so", LS_SOCK }, 29425e1c72e1SJason King { "do", LS_DOOR }, 29435e1c72e1SJason King { "bd", LS_BLK }, 29445e1c72e1SJason King { "cd", LS_CHR }, 29455e1c72e1SJason King { "or", LS_ORPHAN }, 29465e1c72e1SJason King { "su", LS_SETUID }, 29475e1c72e1SJason King { "sg", LS_SETGID }, 29485e1c72e1SJason King { "tw", LS_STICKY_OTHER_WRITABLE }, 29495e1c72e1SJason King { "ow", LS_OTHER_WRITABLE }, 29505e1c72e1SJason King { "st", LS_STICKY }, 29515e1c72e1SJason King { "ex", LS_EXEC }, 29525e1c72e1SJason King { "po", LS_PORT }, 29535e1c72e1SJason King { NULL, LS_NORMAL } 29545e1c72e1SJason King }; 29555e1c72e1SJason King 29565e1c72e1SJason King char *p, *lasts; 29575e1c72e1SJason King int i; 29585e1c72e1SJason King int color, attr; 29595e1c72e1SJason King 29605e1c72e1SJason King p = strtok_r(colorstr, "=", &lasts); 29615e1c72e1SJason King if (p == NULL) { 29625e1c72e1SJason King colorflg = 0; 29635e1c72e1SJason King return; 29645e1c72e1SJason King } 29655e1c72e1SJason King 29665e1c72e1SJason King if (p[0] == '*') { 29675e1c72e1SJason King lsc_colors[lsc_ncolors].ftype = LS_PAT; 29685e1c72e1SJason King /* don't include the * in the suffix */ 29695e1c72e1SJason King if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) { 29705e1c72e1SJason King colorflg = 0; 29715e1c72e1SJason King return; 29725e1c72e1SJason King } 2973da6c28aaSamw } else { 29745e1c72e1SJason King lsc_colors[lsc_ncolors].sfx = NULL; 29755e1c72e1SJason King 29765e1c72e1SJason King for (i = 0; type_map[i].s != NULL; ++i) { 29775e1c72e1SJason King if (strncmp(type_map[i].s, p, 2) == 0) 29785e1c72e1SJason King break; 2979da6c28aaSamw } 29805e1c72e1SJason King 29815e1c72e1SJason King /* ignore unknown file types */ 29825e1c72e1SJason King if (type_map[i].s == NULL) 29835e1c72e1SJason King return; 29845e1c72e1SJason King 29855e1c72e1SJason King lsc_colors[lsc_ncolors].ftype = type_map[i].stype; 29865e1c72e1SJason King } 29875e1c72e1SJason King 29885e1c72e1SJason King attr = LSA_NONE; 29895e1c72e1SJason King lsc_colors[lsc_ncolors].fg = -1; 29905e1c72e1SJason King lsc_colors[lsc_ncolors].bg = -1; 29915e1c72e1SJason King for (p = strtok_r(NULL, ";", &lasts); p != NULL; 29925e1c72e1SJason King p = strtok_r(NULL, ";", &lasts)) { 29935e1c72e1SJason King color = strtol(p, NULL, 10); 29945e1c72e1SJason King 29955e1c72e1SJason King if (color < 10) { 29965e1c72e1SJason King switch (color) { 29975e1c72e1SJason King case 0: 29985e1c72e1SJason King attr = LSA_NONE; 29995e1c72e1SJason King continue; 30005e1c72e1SJason King case 1: 30015e1c72e1SJason King attr |= LSA_BOLD; 30025e1c72e1SJason King continue; 30035e1c72e1SJason King case 4: 30045e1c72e1SJason King attr |= LSA_UNDERSCORE; 30055e1c72e1SJason King continue; 30065e1c72e1SJason King case 5: 30075e1c72e1SJason King attr |= LSA_BLINK; 30085e1c72e1SJason King continue; 30095e1c72e1SJason King case 7: 30105e1c72e1SJason King attr |= LSA_REVERSE; 30115e1c72e1SJason King continue; 30125e1c72e1SJason King case 8: 30135e1c72e1SJason King attr |= LSA_CONCEALED; 30145e1c72e1SJason King continue; 30155e1c72e1SJason King default: 30165e1c72e1SJason King continue; 3017da6c28aaSamw } 3018da6c28aaSamw } 30195e1c72e1SJason King 30205e1c72e1SJason King if (color < 40) 30215e1c72e1SJason King lsc_colors[lsc_ncolors].fg = color - 30; 30225e1c72e1SJason King else 30235e1c72e1SJason King lsc_colors[lsc_ncolors].bg = color - 40; 30245e1c72e1SJason King } 30255e1c72e1SJason King 30265e1c72e1SJason King lsc_colors[lsc_ncolors].attr = attr; 30275e1c72e1SJason King ++lsc_ncolors; 30285e1c72e1SJason King } 30295e1c72e1SJason King 30305e1c72e1SJason King static int 30315e1c72e1SJason King ls_color_compare(const void *p1, const void *p2) 30325e1c72e1SJason King { 30335e1c72e1SJason King const ls_color_t *c1 = (const ls_color_t *)p1; 30345e1c72e1SJason King const ls_color_t *c2 = (const ls_color_t *)p2; 30355e1c72e1SJason King 30365e1c72e1SJason King int ret = c1->ftype - c2->ftype; 30375e1c72e1SJason King 30385e1c72e1SJason King if (ret != 0) 30395e1c72e1SJason King return (ret); 30405e1c72e1SJason King 30415e1c72e1SJason King if (c1->ftype != LS_PAT) 30425e1c72e1SJason King return (ret); 30435e1c72e1SJason King 30445e1c72e1SJason King return (strcmp(c1->sfx, c2->sfx)); 30455e1c72e1SJason King } 30465e1c72e1SJason King 30475e1c72e1SJason King static void 30485e1c72e1SJason King ls_color_init() 30495e1c72e1SJason King { 30505e1c72e1SJason King static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35" 30515e1c72e1SJason King ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01" 30525e1c72e1SJason King ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31" 30535e1c72e1SJason King ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31" 30545e1c72e1SJason King ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31" 30555e1c72e1SJason King ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35" 30565e1c72e1SJason King ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35" 30575e1c72e1SJason King ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35" 30585e1c72e1SJason King ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35" 30595e1c72e1SJason King ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35" 30605e1c72e1SJason King ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35"; 30615e1c72e1SJason King 30625e1c72e1SJason King char *colorstr; 30635e1c72e1SJason King char *p, *lasts; 30645e1c72e1SJason King size_t color_sz; 30655e1c72e1SJason King int termret; 30661b628248SJason King int i; 30675e1c72e1SJason King 30685e1c72e1SJason King (void) setupterm(NULL, 1, &termret); 30695e1c72e1SJason King if (termret != 1) 30705e1c72e1SJason King return; 30715e1c72e1SJason King 3072*38f2a414SAlbert Lee if ((p = getenv("LS_COLORS")) == NULL) 3073*38f2a414SAlbert Lee p = default_colorstr; 3074*38f2a414SAlbert Lee colorstr = strdup(p); 3075*38f2a414SAlbert Lee if (colorstr == NULL) 3076*38f2a414SAlbert Lee return; 30775e1c72e1SJason King 3078f7387fb0SJason King /* 3079f7387fb0SJason King * Determine the size of lsc_colors. color_sz can be > lsc_ncolors 3080f7387fb0SJason King * if there are invalid entries passed in the string (they are ignored) 3081f7387fb0SJason King */ 3082f7387fb0SJason King color_sz = 1; 30835e1c72e1SJason King for (p = strchr(colorstr, ':'); p != NULL && *p != '\0'; 30845e1c72e1SJason King p = strchr(++p, ':')) 30855e1c72e1SJason King ++color_sz; 30865e1c72e1SJason King 30875e1c72e1SJason King lsc_colors = calloc(color_sz, sizeof (ls_color_t)); 30885e1c72e1SJason King if (lsc_colors == NULL) { 30895e1c72e1SJason King free(colorstr); 30905e1c72e1SJason King return; 30915e1c72e1SJason King } 30925e1c72e1SJason King 30935e1c72e1SJason King for (p = strtok_r(colorstr, ":", &lasts); 30945e1c72e1SJason King p != NULL && lsc_ncolors < color_sz; 30955e1c72e1SJason King p = strtok_r(NULL, ":", &lasts)) 30965e1c72e1SJason King new_color_entry(p); 30975e1c72e1SJason King 30985e1c72e1SJason King qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t), 30995e1c72e1SJason King ls_color_compare); 31005e1c72e1SJason King 31011b628248SJason King for (i = 0; i < lsc_ncolors; ++i) 31021b628248SJason King if (lsc_colors[i].ftype == LS_ORPHAN) { 31031b628248SJason King lsc_orphan = &lsc_colors[i]; 31041b628248SJason King break; 31051b628248SJason King } 31061b628248SJason King 31075e1c72e1SJason King if ((lsc_bold = tigetstr("bold")) == (char *)-1) 31085e1c72e1SJason King lsc_bold = NULL; 31095e1c72e1SJason King 31105e1c72e1SJason King if ((lsc_underline = tigetstr("smul")) == (char *)-1) 31115e1c72e1SJason King lsc_underline = NULL; 31125e1c72e1SJason King 31135e1c72e1SJason King if ((lsc_blink = tigetstr("blink")) == (char *)-1) 31145e1c72e1SJason King lsc_blink = NULL; 31155e1c72e1SJason King 31165e1c72e1SJason King if ((lsc_reverse = tigetstr("rev")) == (char *)-1) 31175e1c72e1SJason King lsc_reverse = NULL; 31185e1c72e1SJason King 31195e1c72e1SJason King if ((lsc_concealed = tigetstr("prot")) == (char *)-1) 31205e1c72e1SJason King lsc_concealed = NULL; 31215e1c72e1SJason King 31225e1c72e1SJason King if ((lsc_none = tigetstr("sgr0")) == (char *)-1) 31235e1c72e1SJason King lsc_none = NULL; 31245e1c72e1SJason King 31255e1c72e1SJason King if ((lsc_setfg = tigetstr("setaf")) == (char *)-1) 31265e1c72e1SJason King lsc_setfg = NULL; 31275e1c72e1SJason King 31285e1c72e1SJason King if ((lsc_setbg = tigetstr("setab")) == (char *)-1) 31295e1c72e1SJason King lsc_setbg = NULL; 31305e1c72e1SJason King 31315e1c72e1SJason King if (getenv("_LS_COLOR_DEBUG") != NULL) { 31325e1c72e1SJason King int i; 31335e1c72e1SJason King 31345e1c72e1SJason King lsc_debug = 1; 31355e1c72e1SJason King for (i = 0; i < lsc_ncolors; ++i) 31365e1c72e1SJason King dump_color(&lsc_colors[i]); 3137da6c28aaSamw } 3138*38f2a414SAlbert Lee 3139*38f2a414SAlbert Lee free(colorstr); 3140da6c28aaSamw } 3141da6c28aaSamw 3142da6c28aaSamw /* Free extended system attribute lists */ 3143da6c28aaSamw 3144da6c28aaSamw void 3145da6c28aaSamw free_sysattr(struct lbuf *p) 3146da6c28aaSamw { 3147da6c28aaSamw int i; 3148da6c28aaSamw 3149da6c28aaSamw if (p->exttr != NULL) { 3150da6c28aaSamw for (i = 0; i < sacnt; i++) { 3151da6c28aaSamw if (p->exttr[i].name != NULL) 3152da6c28aaSamw free(p->exttr[i].name); 3153da6c28aaSamw } 3154da6c28aaSamw free(p->exttr); 3155da6c28aaSamw } 3156da6c28aaSamw if (p->extm != NULL) { 3157da6c28aaSamw for (i = 0; i < sacnt; i++) { 3158da6c28aaSamw if (p->extm[i].name != NULL) 3159da6c28aaSamw free(p->extm[i].name); 3160da6c28aaSamw } 3161da6c28aaSamw free(p->extm); 3162da6c28aaSamw } 3163da6c28aaSamw } 3164da6c28aaSamw 3165da6c28aaSamw /* Allocate extended system attribute list */ 3166da6c28aaSamw 3167da6c28aaSamw void * 3168da6c28aaSamw xmalloc(size_t size, struct lbuf *p) 3169da6c28aaSamw { 3170da6c28aaSamw if ((p = malloc(size)) == NULL) { 3171da6c28aaSamw perror("ls"); 3172da6c28aaSamw free_sysattr(p); 3173da6c28aaSamw nvlist_free(response); 3174da6c28aaSamw exit(2); 3175da6c28aaSamw } 3176da6c28aaSamw return (p); 3177da6c28aaSamw } 3178