10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51447Sakaplan * Common Development and Distribution License (the "License"). 61447Sakaplan * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*9664Sjason@ansipunx.net 220Sstevel@tonic-gate /* 23*9664Sjason@ansipunx.net * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*9664Sjason@ansipunx.net * Use is subject to license terms. 25*9664Sjason@ansipunx.net */ 26*9664Sjason@ansipunx.net 27*9664Sjason@ansipunx.net /* 28*9664Sjason@ansipunx.net * Copyright 2009 Jason King. All rights reserved. 290Sstevel@tonic-gate * Use is subject to license terms. 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 330Sstevel@tonic-gate /* All Rights Reserved */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 360Sstevel@tonic-gate /* All Rights Reserved */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate /* 390Sstevel@tonic-gate * List files or directories 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <sys/param.h> 430Sstevel@tonic-gate #include <sys/types.h> 440Sstevel@tonic-gate #include <sys/mkdev.h> 450Sstevel@tonic-gate #include <sys/stat.h> 460Sstevel@tonic-gate #include <sys/acl.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include <wchar.h> 490Sstevel@tonic-gate #include <stdio.h> 500Sstevel@tonic-gate #include <ctype.h> 510Sstevel@tonic-gate #include <dirent.h> 520Sstevel@tonic-gate #include <string.h> 530Sstevel@tonic-gate #include <locale.h> 540Sstevel@tonic-gate #include <curses.h> 55*9664Sjason@ansipunx.net #include <term.h> 560Sstevel@tonic-gate #include <termios.h> 570Sstevel@tonic-gate #include <stdlib.h> 580Sstevel@tonic-gate #include <widec.h> 590Sstevel@tonic-gate #include <locale.h> 600Sstevel@tonic-gate #include <wctype.h> 610Sstevel@tonic-gate #include <pwd.h> 620Sstevel@tonic-gate #include <grp.h> 630Sstevel@tonic-gate #include <limits.h> 640Sstevel@tonic-gate #include <fcntl.h> 650Sstevel@tonic-gate #include <unistd.h> 660Sstevel@tonic-gate #include <libgen.h> 670Sstevel@tonic-gate #include <errno.h> 68789Sahrens #include <aclutils.h> 695331Samw #include <libnvpair.h> 705331Samw #include <libcmdutils.h> 715331Samw #include <attr.h> 72*9664Sjason@ansipunx.net #include <getopt.h> 73*9664Sjason@ansipunx.net #include <inttypes.h> 740Sstevel@tonic-gate 750Sstevel@tonic-gate #ifndef STANDALONE 760Sstevel@tonic-gate #define TERMINFO 770Sstevel@tonic-gate #endif 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 810Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 825331Samw * the terminfo feature(pre 6.0 systems ?). 830Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 840Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 850Sstevel@tonic-gate */ 860Sstevel@tonic-gate #ifdef NOTERMINFO 870Sstevel@tonic-gate #undef TERMINFO 880Sstevel@tonic-gate #endif 890Sstevel@tonic-gate 900Sstevel@tonic-gate #include <term.h> 910Sstevel@tonic-gate 920Sstevel@tonic-gate #define BFSIZE 16 930Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 940Sstevel@tonic-gate #define ISARG 0100000 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 980Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate #define LS_NOTREG 010000 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * Date and time formats 1050Sstevel@tonic-gate * 1060Sstevel@tonic-gate * b --- abbreviated month name 1070Sstevel@tonic-gate * e --- day number 1080Sstevel@tonic-gate * Y --- year in the form ccyy 1090Sstevel@tonic-gate * H --- hour(24-hour version) 1100Sstevel@tonic-gate * M --- minute 1110Sstevel@tonic-gate * F --- yyyy-mm-dd 1120Sstevel@tonic-gate * T --- hh:mm:ss 1130Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1140Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1150Sstevel@tonic-gate * not present in older C libraries 1160Sstevel@tonic-gate */ 117*9664Sjason@ansipunx.net #define FORMAT_OLD " %b %e %Y " 118*9664Sjason@ansipunx.net #define FORMAT_NEW " %b %e %H:%M " 119*9664Sjason@ansipunx.net #define FORMAT_LONG " %b %e %T %Y " 120*9664Sjason@ansipunx.net #define FORMAT_ISO_FULL " %%F %%T.%.09ld %%z " 121*9664Sjason@ansipunx.net #define FORMAT_ISO_LONG " %F %R " 122*9664Sjason@ansipunx.net #define FORMAT_ISO_NEW " %m-%d %H:%M " 123*9664Sjason@ansipunx.net #define FORMAT_ISO_OLD " %F " 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate #undef BUFSIZ 1260Sstevel@tonic-gate #define BUFSIZ 4096 1270Sstevel@tonic-gate #define NUMBER_WIDTH 40 1280Sstevel@tonic-gate #define FMTSIZE 50 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate struct ditem { 1310Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1320Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1330Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1340Sstevel@tonic-gate }; 1355331Samw /* Holds boolean extended system attributes */ 1365331Samw struct attrb { 1375331Samw char *name; 1385331Samw }; 1395331Samw /* Holds timestamp extended system attributes */ 1405331Samw struct attrtm { 1415331Samw char *name; 1425331Samw uint64_t stm; 1435331Samw uint64_t nstm; 1445331Samw }; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate struct lbuf { 1470Sstevel@tonic-gate union { 1480Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 1490Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 1500Sstevel@tonic-gate } ln; 1510Sstevel@tonic-gate char ltype; /* filetype */ 1520Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 1530Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1540Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 1550Sstevel@tonic-gate uid_t luid; 1560Sstevel@tonic-gate gid_t lgid; 1570Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 1580Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 1590Sstevel@tonic-gate timestruc_t lmtime; 1605331Samw timestruc_t lat; 1615331Samw timestruc_t lct; 1625331Samw timestruc_t lmt; 1630Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 1640Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 1650Sstevel@tonic-gate int cycle; /* cycle detected flag */ 1660Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 167789Sahrens acl_t *aclp; /* ACL if present */ 1685331Samw struct attrb *exttr; /* boolean extended system attributes */ 1695331Samw struct attrtm *extm; /* timestamp extended system attributes */ 1700Sstevel@tonic-gate }; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate struct dchain { 1730Sstevel@tonic-gate char *dc_name; /* path name */ 1740Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 1750Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 1760Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 1770Sstevel@tonic-gate }; 1780Sstevel@tonic-gate 179*9664Sjason@ansipunx.net #define LSA_NONE (0) 180*9664Sjason@ansipunx.net #define LSA_BOLD (1L << 0) 181*9664Sjason@ansipunx.net #define LSA_UNDERSCORE (1L << 1) 182*9664Sjason@ansipunx.net #define LSA_BLINK (1L << 2) 183*9664Sjason@ansipunx.net #define LSA_REVERSE (1L << 3) 184*9664Sjason@ansipunx.net #define LSA_CONCEALED (1L << 4) 185*9664Sjason@ansipunx.net 186*9664Sjason@ansipunx.net /* these should be ordered most general to most specific */ 187*9664Sjason@ansipunx.net typedef enum LS_CFTYPE { 188*9664Sjason@ansipunx.net LS_NORMAL, 189*9664Sjason@ansipunx.net LS_FILE, 190*9664Sjason@ansipunx.net LS_EXEC, 191*9664Sjason@ansipunx.net LS_DIR, 192*9664Sjason@ansipunx.net LS_LINK, 193*9664Sjason@ansipunx.net LS_FIFO, 194*9664Sjason@ansipunx.net LS_SOCK, 195*9664Sjason@ansipunx.net LS_DOOR, 196*9664Sjason@ansipunx.net LS_BLK, 197*9664Sjason@ansipunx.net LS_CHR, 198*9664Sjason@ansipunx.net LS_PORT, 199*9664Sjason@ansipunx.net LS_STICKY, 200*9664Sjason@ansipunx.net LS_ORPHAN, 201*9664Sjason@ansipunx.net LS_SETGID, 202*9664Sjason@ansipunx.net LS_SETUID, 203*9664Sjason@ansipunx.net LS_OTHER_WRITABLE, 204*9664Sjason@ansipunx.net LS_STICKY_OTHER_WRITABLE, 205*9664Sjason@ansipunx.net LS_PAT 206*9664Sjason@ansipunx.net } ls_cftype_t; 207*9664Sjason@ansipunx.net 208*9664Sjason@ansipunx.net typedef struct ls_color { 209*9664Sjason@ansipunx.net char *sfx; 210*9664Sjason@ansipunx.net ls_cftype_t ftype; 211*9664Sjason@ansipunx.net int attr; 212*9664Sjason@ansipunx.net int fg; 213*9664Sjason@ansipunx.net int bg; 214*9664Sjason@ansipunx.net } ls_color_t; 215*9664Sjason@ansipunx.net 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 2220Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 2230Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 2240Sstevel@tonic-gate static char *curdir; /* the current directory */ 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 2270Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 2280Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 2290Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 2300Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 2310Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 2340Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 2350Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 2360Sstevel@tonic-gate static char *getname(uid_t); 2370Sstevel@tonic-gate static char *getgroup(gid_t); 2380Sstevel@tonic-gate static char *makename(char *, char *); 2390Sstevel@tonic-gate static void pentry(struct lbuf *); 2400Sstevel@tonic-gate static void column(void); 2410Sstevel@tonic-gate static void pmode(mode_t aflag); 2420Sstevel@tonic-gate static void selection(int *); 2430Sstevel@tonic-gate static void new_line(void); 2440Sstevel@tonic-gate static void rddir(char *, struct ditem *); 2450Sstevel@tonic-gate static int strcol(unsigned char *); 2460Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2470Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2480Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2490Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2500Sstevel@tonic-gate static void pprintf(char *, char *); 2510Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2520Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2530Sstevel@tonic-gate unsigned long long number, 2540Sstevel@tonic-gate long scale); 2550Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2560Sstevel@tonic-gate int, struct ditem *); 257*9664Sjason@ansipunx.net static void ls_color_init(void); 258*9664Sjason@ansipunx.net static void ls_start_color(struct lbuf *); 259*9664Sjason@ansipunx.net static void ls_end_color(void); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate static int aflg; 2620Sstevel@tonic-gate static int atflg; 2630Sstevel@tonic-gate static int bflg; 2640Sstevel@tonic-gate static int cflg; 2650Sstevel@tonic-gate static int dflg; 2660Sstevel@tonic-gate static int eflg; 2670Sstevel@tonic-gate static int fflg; 2680Sstevel@tonic-gate static int gflg; 2690Sstevel@tonic-gate static int hflg; 2700Sstevel@tonic-gate static int iflg; 2710Sstevel@tonic-gate static int lflg; 2720Sstevel@tonic-gate static int mflg; 2730Sstevel@tonic-gate static int nflg; 2740Sstevel@tonic-gate static int oflg; 2750Sstevel@tonic-gate static int pflg; 2760Sstevel@tonic-gate static int qflg; 2770Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2780Sstevel@tonic-gate static int sflg; 2790Sstevel@tonic-gate static int tflg; 2800Sstevel@tonic-gate static int uflg; 281*9664Sjason@ansipunx.net static int Uflg; 282*9664Sjason@ansipunx.net static int wflg; 2830Sstevel@tonic-gate static int xflg; 2840Sstevel@tonic-gate static int Aflg; 285*9664Sjason@ansipunx.net static int Bflg; 2860Sstevel@tonic-gate static int Cflg; 2870Sstevel@tonic-gate static int Eflg; 2880Sstevel@tonic-gate static int Fflg; 2890Sstevel@tonic-gate static int Hflg; 2900Sstevel@tonic-gate static int Lflg; 2910Sstevel@tonic-gate static int Rflg; 2920Sstevel@tonic-gate static int Sflg; 293789Sahrens static int vflg; 2941420Smarks static int Vflg; 2955331Samw static int saflg; /* boolean extended system attr. */ 2965331Samw static int sacnt; /* number of extended system attr. */ 2975331Samw static int copt; 2985331Samw static int vopt; 2995331Samw static int tmflg; /* create time ext. system attr. */ 3005331Samw static int ctm; 3015331Samw static int atm; 3025331Samw static int mtm; 3035331Samw static int crtm; 3045331Samw static int alltm; 3050Sstevel@tonic-gate static long hscale; 3060Sstevel@tonic-gate static mode_t flags; 3070Sstevel@tonic-gate static int err = 0; /* Contains return code */ 308*9664Sjason@ansipunx.net static int colorflg; 309*9664Sjason@ansipunx.net static int file_typeflg; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 3120Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 3130Sstevel@tonic-gate static char *lastuname = NULL; 3140Sstevel@tonic-gate static char *lastgname = NULL; 3150Sstevel@tonic-gate 316*9664Sjason@ansipunx.net /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */ 3170Sstevel@tonic-gate static int statreq; 3180Sstevel@tonic-gate 319*9664Sjason@ansipunx.net static uint64_t block_size = 1; 3200Sstevel@tonic-gate static char *dotp = "."; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 3230Sstevel@tonic-gate static time_t year, now; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate static int num_cols = 80; 3260Sstevel@tonic-gate static int colwidth; 3270Sstevel@tonic-gate static int filewidth; 3280Sstevel@tonic-gate static int fixedwidth; 3290Sstevel@tonic-gate static int nomocore; 3300Sstevel@tonic-gate static int curcol; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate static struct winsize win; 3330Sstevel@tonic-gate 334*9664Sjason@ansipunx.net /* if time_fmt_new is left NULL, time_fmt_old is used for all times */ 335*9664Sjason@ansipunx.net static const char *time_fmt_old = FORMAT_OLD; /* non-recent files */ 336*9664Sjason@ansipunx.net static const char *time_fmt_new = FORMAT_NEW; /* recent files */ 337*9664Sjason@ansipunx.net static int time_custom; /* != 0 if a custom format */ 3385331Samw static char time_buf[FMTSIZE]; /* array to hold day and time */ 3390Sstevel@tonic-gate 340*9664Sjason@ansipunx.net static int lsc_debug; 341*9664Sjason@ansipunx.net static ls_color_t *lsc_match; 342*9664Sjason@ansipunx.net static ls_color_t *lsc_colors; 343*9664Sjason@ansipunx.net static size_t lsc_ncolors; 344*9664Sjason@ansipunx.net static char *lsc_bold; 345*9664Sjason@ansipunx.net static char *lsc_underline; 346*9664Sjason@ansipunx.net static char *lsc_blink; 347*9664Sjason@ansipunx.net static char *lsc_reverse; 348*9664Sjason@ansipunx.net static char *lsc_concealed; 349*9664Sjason@ansipunx.net static char *lsc_none; 350*9664Sjason@ansipunx.net static char *lsc_setfg; 351*9664Sjason@ansipunx.net static char *lsc_setbg; 352*9664Sjason@ansipunx.net 3530Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 3540Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 3570Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 3585331Samw /* Extended system attributes support */ 3595331Samw static int get_sysxattr(char *, struct lbuf *); 3605331Samw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 3615331Samw static void set_sysattrtm_display(char *, struct lbuf *); 362*9664Sjason@ansipunx.net static void format_time(time_t, time_t); 3635331Samw static void print_time(struct lbuf *); 3645331Samw static void format_attrtime(struct lbuf *); 3655331Samw static void *xmalloc(size_t, struct lbuf *); 3665331Samw static void free_sysattr(struct lbuf *); 3675331Samw static nvpair_t *pair; 3685331Samw static nvlist_t *response; 3696866Sbasabi static int acl_err; 3700Sstevel@tonic-gate 371*9664Sjason@ansipunx.net const struct option long_options[] = { 372*9664Sjason@ansipunx.net { "all", no_argument, NULL, 'a' }, 373*9664Sjason@ansipunx.net { "almost-all", no_argument, NULL, 'A' }, 374*9664Sjason@ansipunx.net { "escape", no_argument, NULL, 'b' }, 375*9664Sjason@ansipunx.net { "classify", no_argument, NULL, 'F' }, 376*9664Sjason@ansipunx.net { "human-readable", no_argument, NULL, 'h' }, 377*9664Sjason@ansipunx.net { "dereference", no_argument, NULL, 'L' }, 378*9664Sjason@ansipunx.net { "dereference-command-line", no_argument, NULL, 'H' }, 379*9664Sjason@ansipunx.net { "ignore-backups", no_argument, NULL, 'B' }, 380*9664Sjason@ansipunx.net { "inode", no_argument, NULL, 'i' }, 381*9664Sjason@ansipunx.net { "numeric-uid-gid", no_argument, NULL, 'n' }, 382*9664Sjason@ansipunx.net { "no-group", no_argument, NULL, 'o' }, 383*9664Sjason@ansipunx.net { "hide-control-chars", no_argument, NULL, 'q' }, 384*9664Sjason@ansipunx.net { "reverse", no_argument, NULL, 'r' }, 385*9664Sjason@ansipunx.net { "recursive", no_argument, NULL, 'R' }, 386*9664Sjason@ansipunx.net { "size", no_argument, NULL, 's' }, 387*9664Sjason@ansipunx.net { "width", required_argument, NULL, 'w' }, 388*9664Sjason@ansipunx.net 389*9664Sjason@ansipunx.net /* no short options for these */ 390*9664Sjason@ansipunx.net { "block-size", required_argument, NULL, 0 }, 391*9664Sjason@ansipunx.net { "full-time", no_argument, NULL, 0 }, 392*9664Sjason@ansipunx.net { "si", no_argument, NULL, 0 }, 393*9664Sjason@ansipunx.net { "color", optional_argument, NULL, 0 }, 394*9664Sjason@ansipunx.net { "colour", optional_argument, NULL, 0}, 395*9664Sjason@ansipunx.net { "file-type", no_argument, NULL, 0 }, 396*9664Sjason@ansipunx.net { "time-style", required_argument, NULL, 0 }, 397*9664Sjason@ansipunx.net 398*9664Sjason@ansipunx.net {0, 0, 0, 0} 399*9664Sjason@ansipunx.net }; 400*9664Sjason@ansipunx.net 4010Sstevel@tonic-gate int 4020Sstevel@tonic-gate main(int argc, char *argv[]) 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate int c; 4050Sstevel@tonic-gate int i; 4060Sstevel@tonic-gate int width; 4070Sstevel@tonic-gate int amino = 0; 4080Sstevel@tonic-gate int opterr = 0; 409*9664Sjason@ansipunx.net int option_index = 0; 4100Sstevel@tonic-gate struct lbuf *ep; 4110Sstevel@tonic-gate struct lbuf lb; 4120Sstevel@tonic-gate struct ditem *myinfo; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4150Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 4160Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 4170Sstevel@tonic-gate #endif 4180Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4190Sstevel@tonic-gate #ifdef STANDALONE 4200Sstevel@tonic-gate if (argv[0][0] == '\0') 4210Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 4220Sstevel@tonic-gate #endif 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 4250Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 4260Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 4270Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 4280Sstevel@tonic-gate if (isatty(1)) { 4290Sstevel@tonic-gate Cflg = 1; 4300Sstevel@tonic-gate mflg = 0; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 433*9664Sjason@ansipunx.net while ((c = getopt_long(argc, argv, 434*9664Sjason@ansipunx.net "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options, 435*9664Sjason@ansipunx.net &option_index)) != -1) 4360Sstevel@tonic-gate switch (c) { 437*9664Sjason@ansipunx.net case 0: 438*9664Sjason@ansipunx.net /* non-short options */ 439*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 440*9664Sjason@ansipunx.net "color") == 0 || 441*9664Sjason@ansipunx.net strcmp(long_options[option_index].name, 442*9664Sjason@ansipunx.net "colour") == 0) { 443*9664Sjason@ansipunx.net if (optarg == NULL || 444*9664Sjason@ansipunx.net strcmp(optarg, "always") == 0 || 445*9664Sjason@ansipunx.net strcmp(optarg, "yes") == 0 || 446*9664Sjason@ansipunx.net strcmp(optarg, "force") == 0) { 447*9664Sjason@ansipunx.net colorflg++; 448*9664Sjason@ansipunx.net statreq++; 449*9664Sjason@ansipunx.net continue; 450*9664Sjason@ansipunx.net } 451*9664Sjason@ansipunx.net 452*9664Sjason@ansipunx.net if ((strcmp(optarg, "auto") == 0 || 453*9664Sjason@ansipunx.net strcmp(optarg, "tty") == 0 || 454*9664Sjason@ansipunx.net strcmp(optarg, "if-tty") == 0) && 455*9664Sjason@ansipunx.net isatty(1) == 1) { 456*9664Sjason@ansipunx.net colorflg++; 457*9664Sjason@ansipunx.net statreq++; 458*9664Sjason@ansipunx.net continue; 459*9664Sjason@ansipunx.net } 460*9664Sjason@ansipunx.net 461*9664Sjason@ansipunx.net if (strcmp(optarg, "never") == 0 || 462*9664Sjason@ansipunx.net strcmp(optarg, "no") == 0 || 463*9664Sjason@ansipunx.net strcmp(optarg, "none") == 0) { 464*9664Sjason@ansipunx.net colorflg = 0; 465*9664Sjason@ansipunx.net continue; 466*9664Sjason@ansipunx.net } 467*9664Sjason@ansipunx.net (void) fprintf(stderr, 468*9664Sjason@ansipunx.net gettext("Invalid argument '%s' for " 469*9664Sjason@ansipunx.net "--color\n"), optarg); 470*9664Sjason@ansipunx.net ++opterr; 471*9664Sjason@ansipunx.net continue; 472*9664Sjason@ansipunx.net } 473*9664Sjason@ansipunx.net 474*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 475*9664Sjason@ansipunx.net "si") == 0) { 476*9664Sjason@ansipunx.net hflg++; 477*9664Sjason@ansipunx.net hscale = 1000; 478*9664Sjason@ansipunx.net continue; 479*9664Sjason@ansipunx.net } 480*9664Sjason@ansipunx.net 481*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 482*9664Sjason@ansipunx.net "block-size") == 0) { 483*9664Sjason@ansipunx.net size_t scale_len = strlen(optarg); 484*9664Sjason@ansipunx.net uint64_t scale = 1; 485*9664Sjason@ansipunx.net uint64_t kilo = 1024; 486*9664Sjason@ansipunx.net char scale_c; 487*9664Sjason@ansipunx.net 488*9664Sjason@ansipunx.net if (scale_len == 0) { 489*9664Sjason@ansipunx.net (void) fprintf(stderr, gettext( 490*9664Sjason@ansipunx.net "Invalid block size \'%s\'\n"), 491*9664Sjason@ansipunx.net optarg); 492*9664Sjason@ansipunx.net exit(1); 493*9664Sjason@ansipunx.net } 494*9664Sjason@ansipunx.net 495*9664Sjason@ansipunx.net scale_c = optarg[scale_len - 1]; 496*9664Sjason@ansipunx.net if (scale_c == 'B') { 497*9664Sjason@ansipunx.net /* need at least digit, scale, B */ 498*9664Sjason@ansipunx.net if (scale_len < 3) { 499*9664Sjason@ansipunx.net (void) fprintf(stderr, gettext( 500*9664Sjason@ansipunx.net "Invalid block size " 501*9664Sjason@ansipunx.net "\'%s\'\n"), optarg); 502*9664Sjason@ansipunx.net exit(1); 503*9664Sjason@ansipunx.net } 504*9664Sjason@ansipunx.net kilo = 1000; 505*9664Sjason@ansipunx.net scale_c = optarg[scale_len - 2]; 506*9664Sjason@ansipunx.net if (isdigit(scale_c)) { 507*9664Sjason@ansipunx.net (void) fprintf(stderr, 508*9664Sjason@ansipunx.net gettext("Invalid block size" 509*9664Sjason@ansipunx.net " \'%s\'\n"), optarg); 510*9664Sjason@ansipunx.net exit(1); 511*9664Sjason@ansipunx.net } 512*9664Sjason@ansipunx.net /* 513*9664Sjason@ansipunx.net * make optarg[scale_len - 1] point to 514*9664Sjason@ansipunx.net * the scale factor 515*9664Sjason@ansipunx.net */ 516*9664Sjason@ansipunx.net --scale_len; 517*9664Sjason@ansipunx.net } 518*9664Sjason@ansipunx.net 519*9664Sjason@ansipunx.net switch (scale_c) { 520*9664Sjason@ansipunx.net case 'y': 521*9664Sjason@ansipunx.net case 'Y': 522*9664Sjason@ansipunx.net scale *= kilo; 523*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 524*9664Sjason@ansipunx.net case 'Z': 525*9664Sjason@ansipunx.net case 'z': 526*9664Sjason@ansipunx.net scale *= kilo; 527*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 528*9664Sjason@ansipunx.net case 'E': 529*9664Sjason@ansipunx.net case 'e': 530*9664Sjason@ansipunx.net scale *= kilo; 531*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 532*9664Sjason@ansipunx.net case 'P': 533*9664Sjason@ansipunx.net case 'p': 534*9664Sjason@ansipunx.net scale *= kilo; 535*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 536*9664Sjason@ansipunx.net case 'T': 537*9664Sjason@ansipunx.net case 't': 538*9664Sjason@ansipunx.net scale *= kilo; 539*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 540*9664Sjason@ansipunx.net case 'G': 541*9664Sjason@ansipunx.net case 'g': 542*9664Sjason@ansipunx.net scale *= kilo; 543*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 544*9664Sjason@ansipunx.net case 'M': 545*9664Sjason@ansipunx.net case 'm': 546*9664Sjason@ansipunx.net scale *= kilo; 547*9664Sjason@ansipunx.net /*FALLTHROUGH*/ 548*9664Sjason@ansipunx.net case 'K': 549*9664Sjason@ansipunx.net case 'k': 550*9664Sjason@ansipunx.net scale *= kilo; 551*9664Sjason@ansipunx.net break; 552*9664Sjason@ansipunx.net default: 553*9664Sjason@ansipunx.net if (!isdigit(scale_c)) { 554*9664Sjason@ansipunx.net (void) fprintf(stderr, 555*9664Sjason@ansipunx.net gettext("Invalid character " 556*9664Sjason@ansipunx.net "following block size in " 557*9664Sjason@ansipunx.net "\'%s\'\n"), optarg); 558*9664Sjason@ansipunx.net exit(1); 559*9664Sjason@ansipunx.net } 560*9664Sjason@ansipunx.net } 561*9664Sjason@ansipunx.net 562*9664Sjason@ansipunx.net /* NULL out scale constant if present */ 563*9664Sjason@ansipunx.net if (scale > 1 && !isdigit(scale_c)) 564*9664Sjason@ansipunx.net optarg[scale_len - 1] = '\0'; 565*9664Sjason@ansipunx.net 566*9664Sjason@ansipunx.net /* Based on testing, this is what GNU ls does */ 567*9664Sjason@ansipunx.net block_size = strtoll(optarg, NULL, 0) * scale; 568*9664Sjason@ansipunx.net if (block_size < 1) { 569*9664Sjason@ansipunx.net (void) fprintf(stderr, 570*9664Sjason@ansipunx.net gettext("Invalid block size " 571*9664Sjason@ansipunx.net "\'%s\'\n"), optarg); 572*9664Sjason@ansipunx.net exit(1); 573*9664Sjason@ansipunx.net } 574*9664Sjason@ansipunx.net continue; 575*9664Sjason@ansipunx.net } 576*9664Sjason@ansipunx.net 577*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 578*9664Sjason@ansipunx.net "file-type") == 0) { 579*9664Sjason@ansipunx.net file_typeflg++; 580*9664Sjason@ansipunx.net Fflg++; 581*9664Sjason@ansipunx.net statreq++; 582*9664Sjason@ansipunx.net continue; 583*9664Sjason@ansipunx.net } 584*9664Sjason@ansipunx.net 585*9664Sjason@ansipunx.net 586*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 587*9664Sjason@ansipunx.net "full-time") == 0) { 588*9664Sjason@ansipunx.net Eflg++; 589*9664Sjason@ansipunx.net statreq++; 590*9664Sjason@ansipunx.net eflg = 0; 591*9664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 592*9664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 593*9664Sjason@ansipunx.net continue; 594*9664Sjason@ansipunx.net } 595*9664Sjason@ansipunx.net 596*9664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 597*9664Sjason@ansipunx.net "time-style") == 0) { 598*9664Sjason@ansipunx.net /* like -E, but doesn't imply -l */ 599*9664Sjason@ansipunx.net if (strcmp(optarg, "full-iso") == 0) { 600*9664Sjason@ansipunx.net Eflg++; 601*9664Sjason@ansipunx.net statreq++; 602*9664Sjason@ansipunx.net eflg = 0; 603*9664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 604*9664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 605*9664Sjason@ansipunx.net continue; 606*9664Sjason@ansipunx.net } 607*9664Sjason@ansipunx.net if (strcmp(optarg, "long-iso") == 0) { 608*9664Sjason@ansipunx.net statreq++; 609*9664Sjason@ansipunx.net Eflg = 0; 610*9664Sjason@ansipunx.net eflg = 0; 611*9664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_LONG; 612*9664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_LONG; 613*9664Sjason@ansipunx.net continue; 614*9664Sjason@ansipunx.net } 615*9664Sjason@ansipunx.net if (strcmp(optarg, "iso") == 0) { 616*9664Sjason@ansipunx.net statreq++; 617*9664Sjason@ansipunx.net Eflg = 0; 618*9664Sjason@ansipunx.net eflg = 0; 619*9664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_OLD; 620*9664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_NEW; 621*9664Sjason@ansipunx.net continue; 622*9664Sjason@ansipunx.net } 623*9664Sjason@ansipunx.net /* should be the default */ 624*9664Sjason@ansipunx.net if (strcmp(optarg, "locale") == 0) { 625*9664Sjason@ansipunx.net time_fmt_old = FORMAT_OLD; 626*9664Sjason@ansipunx.net time_fmt_new = FORMAT_NEW; 627*9664Sjason@ansipunx.net continue; 628*9664Sjason@ansipunx.net } 629*9664Sjason@ansipunx.net if (optarg[0] == '+') { 630*9664Sjason@ansipunx.net char *told, *tnew; 631*9664Sjason@ansipunx.net char *p; 632*9664Sjason@ansipunx.net size_t timelen = strlen(optarg); 633*9664Sjason@ansipunx.net 634*9664Sjason@ansipunx.net p = strchr(optarg, '\n'); 635*9664Sjason@ansipunx.net if (p != NULL) 636*9664Sjason@ansipunx.net *p++ = '\0'; 637*9664Sjason@ansipunx.net 638*9664Sjason@ansipunx.net /* 639*9664Sjason@ansipunx.net * Time format requires a leading and 640*9664Sjason@ansipunx.net * trailing space 641*9664Sjason@ansipunx.net * Add room for 3 spaces + 2 nulls 642*9664Sjason@ansipunx.net * The + in optarg is replaced with 643*9664Sjason@ansipunx.net * a space. 644*9664Sjason@ansipunx.net */ 645*9664Sjason@ansipunx.net timelen += 2 + 3; 646*9664Sjason@ansipunx.net told = malloc(timelen); 647*9664Sjason@ansipunx.net if (told == NULL) { 648*9664Sjason@ansipunx.net perror("Out of memory"); 649*9664Sjason@ansipunx.net exit(1); 650*9664Sjason@ansipunx.net } 651*9664Sjason@ansipunx.net 652*9664Sjason@ansipunx.net (void) memset(told, 0, timelen); 653*9664Sjason@ansipunx.net told[0] = ' '; 654*9664Sjason@ansipunx.net (void) strlcat(told, &optarg[1], 655*9664Sjason@ansipunx.net timelen); 656*9664Sjason@ansipunx.net (void) strlcat(told, " ", timelen); 657*9664Sjason@ansipunx.net 658*9664Sjason@ansipunx.net if (p != NULL) { 659*9664Sjason@ansipunx.net size_t tnew_len; 660*9664Sjason@ansipunx.net 661*9664Sjason@ansipunx.net tnew = told + strlen(told) + 1; 662*9664Sjason@ansipunx.net tnew_len = timelen - 663*9664Sjason@ansipunx.net strlen(told) - 1; 664*9664Sjason@ansipunx.net 665*9664Sjason@ansipunx.net tnew[0] = ' '; 666*9664Sjason@ansipunx.net (void) strlcat(tnew, p, 667*9664Sjason@ansipunx.net tnew_len); 668*9664Sjason@ansipunx.net (void) strlcat(tnew, " ", 669*9664Sjason@ansipunx.net tnew_len); 670*9664Sjason@ansipunx.net time_fmt_new = 671*9664Sjason@ansipunx.net (const char *)tnew; 672*9664Sjason@ansipunx.net } else { 673*9664Sjason@ansipunx.net time_fmt_new = 674*9664Sjason@ansipunx.net (const char *)told; 675*9664Sjason@ansipunx.net } 676*9664Sjason@ansipunx.net 677*9664Sjason@ansipunx.net time_fmt_old = (const char *)told; 678*9664Sjason@ansipunx.net time_custom = 1; 679*9664Sjason@ansipunx.net continue; 680*9664Sjason@ansipunx.net } 681*9664Sjason@ansipunx.net continue; 682*9664Sjason@ansipunx.net } 683*9664Sjason@ansipunx.net 684*9664Sjason@ansipunx.net continue; 685*9664Sjason@ansipunx.net 6860Sstevel@tonic-gate case 'a': 6870Sstevel@tonic-gate aflg++; 6880Sstevel@tonic-gate continue; 6890Sstevel@tonic-gate case 'A': 6900Sstevel@tonic-gate Aflg++; 6910Sstevel@tonic-gate continue; 6920Sstevel@tonic-gate case 'b': 6930Sstevel@tonic-gate bflg = 1; 6940Sstevel@tonic-gate qflg = 0; 6950Sstevel@tonic-gate continue; 696*9664Sjason@ansipunx.net case 'B': 697*9664Sjason@ansipunx.net Bflg = 1; 698*9664Sjason@ansipunx.net continue; 6990Sstevel@tonic-gate case 'c': 7000Sstevel@tonic-gate uflg = 0; 7015331Samw atm = 0; 7025331Samw ctm = 0; 7035331Samw mtm = 0; 7045331Samw crtm = 0; 7050Sstevel@tonic-gate cflg++; 7060Sstevel@tonic-gate continue; 7070Sstevel@tonic-gate case 'C': 7080Sstevel@tonic-gate Cflg = 1; 7090Sstevel@tonic-gate mflg = 0; 7100Sstevel@tonic-gate #ifdef XPG4 7110Sstevel@tonic-gate lflg = 0; 7120Sstevel@tonic-gate #endif 7130Sstevel@tonic-gate continue; 7140Sstevel@tonic-gate case 'd': 7150Sstevel@tonic-gate dflg++; 7160Sstevel@tonic-gate continue; 7170Sstevel@tonic-gate case 'e': 7180Sstevel@tonic-gate eflg++; 7190Sstevel@tonic-gate lflg++; 7200Sstevel@tonic-gate statreq++; 7210Sstevel@tonic-gate Eflg = 0; 722*9664Sjason@ansipunx.net time_fmt_old = FORMAT_LONG; 723*9664Sjason@ansipunx.net time_fmt_new = FORMAT_LONG; 7240Sstevel@tonic-gate continue; 7250Sstevel@tonic-gate case 'E': 7260Sstevel@tonic-gate Eflg++; 7270Sstevel@tonic-gate lflg++; 7280Sstevel@tonic-gate statreq++; 7290Sstevel@tonic-gate eflg = 0; 730*9664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 731*9664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 7320Sstevel@tonic-gate continue; 7330Sstevel@tonic-gate case 'f': 7340Sstevel@tonic-gate fflg++; 7350Sstevel@tonic-gate continue; 7360Sstevel@tonic-gate case 'F': 7370Sstevel@tonic-gate Fflg++; 7380Sstevel@tonic-gate statreq++; 7390Sstevel@tonic-gate continue; 7400Sstevel@tonic-gate case 'g': 7410Sstevel@tonic-gate gflg++; 7420Sstevel@tonic-gate lflg++; 7430Sstevel@tonic-gate statreq++; 7440Sstevel@tonic-gate continue; 7450Sstevel@tonic-gate case 'h': 7460Sstevel@tonic-gate hflg++; 7470Sstevel@tonic-gate hscale = 1024; 7480Sstevel@tonic-gate continue; 7490Sstevel@tonic-gate case 'H': 7500Sstevel@tonic-gate Hflg++; 7510Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7520Sstevel@tonic-gate Lflg = 0; 7530Sstevel@tonic-gate continue; 7540Sstevel@tonic-gate case 'i': 7550Sstevel@tonic-gate iflg++; 7560Sstevel@tonic-gate continue; 757*9664Sjason@ansipunx.net case 'k': 758*9664Sjason@ansipunx.net block_size = 1024; 759*9664Sjason@ansipunx.net continue; 7600Sstevel@tonic-gate case 'l': 7610Sstevel@tonic-gate lflg++; 7620Sstevel@tonic-gate statreq++; 7630Sstevel@tonic-gate Cflg = 0; 7640Sstevel@tonic-gate xflg = 0; 7650Sstevel@tonic-gate mflg = 0; 7660Sstevel@tonic-gate atflg = 0; 7670Sstevel@tonic-gate continue; 7680Sstevel@tonic-gate case 'L': 7690Sstevel@tonic-gate Lflg++; 7700Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7710Sstevel@tonic-gate Hflg = 0; 7720Sstevel@tonic-gate continue; 7730Sstevel@tonic-gate case 'm': 7740Sstevel@tonic-gate Cflg = 0; 7750Sstevel@tonic-gate mflg = 1; 7760Sstevel@tonic-gate #ifdef XPG4 7770Sstevel@tonic-gate lflg = 0; 7780Sstevel@tonic-gate #endif 7790Sstevel@tonic-gate continue; 7800Sstevel@tonic-gate case 'n': 7810Sstevel@tonic-gate nflg++; 7820Sstevel@tonic-gate lflg++; 7830Sstevel@tonic-gate statreq++; 7840Sstevel@tonic-gate Cflg = 0; 7850Sstevel@tonic-gate xflg = 0; 7860Sstevel@tonic-gate mflg = 0; 7870Sstevel@tonic-gate atflg = 0; 7880Sstevel@tonic-gate continue; 7890Sstevel@tonic-gate case 'o': 7900Sstevel@tonic-gate oflg++; 7910Sstevel@tonic-gate lflg++; 7920Sstevel@tonic-gate statreq++; 7930Sstevel@tonic-gate continue; 7940Sstevel@tonic-gate case 'p': 7950Sstevel@tonic-gate pflg++; 7960Sstevel@tonic-gate statreq++; 7970Sstevel@tonic-gate continue; 7980Sstevel@tonic-gate case 'q': 7990Sstevel@tonic-gate qflg = 1; 8000Sstevel@tonic-gate bflg = 0; 8010Sstevel@tonic-gate continue; 8020Sstevel@tonic-gate case 'r': 8030Sstevel@tonic-gate rflg = -1; 8040Sstevel@tonic-gate continue; 8050Sstevel@tonic-gate case 'R': 8060Sstevel@tonic-gate Rflg++; 8070Sstevel@tonic-gate statreq++; 8080Sstevel@tonic-gate continue; 8090Sstevel@tonic-gate case 's': 8100Sstevel@tonic-gate sflg++; 8110Sstevel@tonic-gate statreq++; 8120Sstevel@tonic-gate continue; 8130Sstevel@tonic-gate case 'S': 8140Sstevel@tonic-gate tflg = 0; 815*9664Sjason@ansipunx.net Uflg = 0; 8160Sstevel@tonic-gate Sflg++; 8170Sstevel@tonic-gate statreq++; 8180Sstevel@tonic-gate continue; 8190Sstevel@tonic-gate case 't': 8200Sstevel@tonic-gate Sflg = 0; 821*9664Sjason@ansipunx.net Uflg = 0; 8220Sstevel@tonic-gate tflg++; 8230Sstevel@tonic-gate statreq++; 8240Sstevel@tonic-gate continue; 825*9664Sjason@ansipunx.net case 'U': 826*9664Sjason@ansipunx.net Sflg = 0; 827*9664Sjason@ansipunx.net tflg = 0; 828*9664Sjason@ansipunx.net Uflg++; 829*9664Sjason@ansipunx.net continue; 8300Sstevel@tonic-gate case 'u': 8310Sstevel@tonic-gate cflg = 0; 8325331Samw atm = 0; 8335331Samw ctm = 0; 8345331Samw mtm = 0; 8355331Samw crtm = 0; 8360Sstevel@tonic-gate uflg++; 8370Sstevel@tonic-gate continue; 8381420Smarks case 'V': 8391420Smarks Vflg++; 8401420Smarks /*FALLTHROUGH*/ 841789Sahrens case 'v': 842789Sahrens vflg++; 843789Sahrens #if !defined(XPG4) 844789Sahrens if (lflg) 845789Sahrens continue; 846789Sahrens #endif 847789Sahrens lflg++; 848789Sahrens statreq++; 849789Sahrens Cflg = 0; 850789Sahrens xflg = 0; 851789Sahrens mflg = 0; 852789Sahrens continue; 853*9664Sjason@ansipunx.net case 'w': 854*9664Sjason@ansipunx.net wflg++; 855*9664Sjason@ansipunx.net num_cols = atoi(optarg); 856*9664Sjason@ansipunx.net continue; 8570Sstevel@tonic-gate case 'x': 8580Sstevel@tonic-gate xflg = 1; 8590Sstevel@tonic-gate Cflg = 1; 8600Sstevel@tonic-gate mflg = 0; 8610Sstevel@tonic-gate #ifdef XPG4 8620Sstevel@tonic-gate lflg = 0; 8630Sstevel@tonic-gate #endif 8640Sstevel@tonic-gate continue; 8650Sstevel@tonic-gate case '1': 8660Sstevel@tonic-gate Cflg = 0; 8670Sstevel@tonic-gate continue; 8680Sstevel@tonic-gate case '@': 8690Sstevel@tonic-gate #if !defined(XPG4) 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * -l has precedence over -@ 8720Sstevel@tonic-gate */ 8730Sstevel@tonic-gate if (lflg) 8740Sstevel@tonic-gate continue; 8750Sstevel@tonic-gate #endif 8760Sstevel@tonic-gate atflg++; 8770Sstevel@tonic-gate lflg++; 8780Sstevel@tonic-gate statreq++; 8790Sstevel@tonic-gate Cflg = 0; 8800Sstevel@tonic-gate xflg = 0; 8810Sstevel@tonic-gate mflg = 0; 8820Sstevel@tonic-gate continue; 8835331Samw case '/': 8845331Samw saflg++; 8855331Samw if (optarg != NULL) { 8865331Samw if (strcmp(optarg, "c") == 0) { 8875331Samw copt++; 8885331Samw vopt = 0; 8895331Samw } else if (strcmp(optarg, "v") == 0) { 8905331Samw vopt++; 8915331Samw copt = 0; 8925331Samw } else 8935331Samw opterr++; 8945331Samw } else 8955331Samw opterr++; 8965331Samw lflg++; 8975331Samw statreq++; 8985331Samw Cflg = 0; 8995331Samw xflg = 0; 9005331Samw mflg = 0; 9015331Samw continue; 9025331Samw case '%': 9035331Samw tmflg++; 9045331Samw if (optarg != NULL) { 9055331Samw if (strcmp(optarg, "ctime") == 0) { 9065331Samw ctm++; 9075331Samw atm = 0; 9085331Samw mtm = 0; 9095331Samw crtm = 0; 9105331Samw } else if (strcmp(optarg, "atime") == 0) { 9115331Samw atm++; 9125331Samw ctm = 0; 9135331Samw mtm = 0; 9145331Samw crtm = 0; 9155331Samw uflg = 0; 9165331Samw cflg = 0; 9175331Samw } else if (strcmp(optarg, "mtime") == 0) { 9185331Samw mtm++; 9195331Samw atm = 0; 9205331Samw ctm = 0; 9215331Samw crtm = 0; 9225331Samw uflg = 0; 9235331Samw cflg = 0; 9245331Samw } else if (strcmp(optarg, "crtime") == 0) { 9255331Samw crtm++; 9265331Samw atm = 0; 9275331Samw ctm = 0; 9285331Samw mtm = 0; 9295331Samw uflg = 0; 9305331Samw cflg = 0; 9315331Samw } else if (strcmp(optarg, "all") == 0) { 9325331Samw alltm++; 9335331Samw atm = 0; 9345331Samw ctm = 0; 9355331Samw mtm = 0; 9365331Samw crtm = 0; 9375331Samw } else 9385331Samw opterr++; 9395331Samw } else 9405331Samw opterr++; 9415331Samw 9425331Samw Sflg = 0; 9435331Samw statreq++; 9445331Samw mflg = 0; 9455331Samw continue; 9460Sstevel@tonic-gate case '?': 9470Sstevel@tonic-gate opterr++; 9480Sstevel@tonic-gate continue; 9490Sstevel@tonic-gate } 950*9664Sjason@ansipunx.net 9510Sstevel@tonic-gate if (opterr) { 9520Sstevel@tonic-gate (void) fprintf(stderr, gettext( 953*9664Sjason@ansipunx.net "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]" 9545331Samw "%%[atime | crtime | ctime | mtime | all]" 9555331Samw " [files]\n")); 9560Sstevel@tonic-gate exit(2); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate if (fflg) { 9600Sstevel@tonic-gate aflg++; 9610Sstevel@tonic-gate lflg = 0; 9620Sstevel@tonic-gate sflg = 0; 9630Sstevel@tonic-gate tflg = 0; 9640Sstevel@tonic-gate Sflg = 0; 9650Sstevel@tonic-gate statreq = 0; 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate fixedwidth = 2; 9690Sstevel@tonic-gate if (pflg || Fflg) 9700Sstevel@tonic-gate fixedwidth++; 9710Sstevel@tonic-gate if (iflg) 9720Sstevel@tonic-gate fixedwidth += 11; 9730Sstevel@tonic-gate if (sflg) 9740Sstevel@tonic-gate fixedwidth += 5; 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate if (lflg) { 9770Sstevel@tonic-gate if (!gflg && !oflg) 9780Sstevel@tonic-gate gflg = oflg = 1; 9790Sstevel@tonic-gate else 9800Sstevel@tonic-gate if (gflg && oflg) 9810Sstevel@tonic-gate gflg = oflg = 0; 9820Sstevel@tonic-gate Cflg = mflg = 0; 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate 985*9664Sjason@ansipunx.net if (!wflg && (Cflg || mflg)) { 9860Sstevel@tonic-gate char *clptr; 9870Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 9880Sstevel@tonic-gate num_cols = atoi(clptr); 9890Sstevel@tonic-gate #ifdef TERMINFO 9900Sstevel@tonic-gate else { 9910Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 9920Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate #endif 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 997*9664Sjason@ansipunx.net if (num_cols < 20 || num_cols > 1000) 998*9664Sjason@ansipunx.net /* assume it is an error */ 999*9664Sjason@ansipunx.net num_cols = 80; 1000*9664Sjason@ansipunx.net 10010Sstevel@tonic-gate /* allocate space for flist and the associated */ 10020Sstevel@tonic-gate /* data structures (lbufs) */ 10030Sstevel@tonic-gate maxfils = quantn; 10040Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 10050Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 10060Sstevel@tonic-gate perror("ls"); 10070Sstevel@tonic-gate exit(2); 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 10100Sstevel@tonic-gate /* 10110Sstevel@tonic-gate * case when no names are given 10120Sstevel@tonic-gate * in ls-command and current 10130Sstevel@tonic-gate * directory is to be used 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate argv[optind] = dotp; 10160Sstevel@tonic-gate } 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate /* 10210Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 10220Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 10230Sstevel@tonic-gate * (actually, just the directories) visited, we 10240Sstevel@tonic-gate * maintain a directory ancestry list for a file 10250Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 10260Sstevel@tonic-gate * a parent directory passes its directory list 10270Sstevel@tonic-gate * info (device id, inode number, and a pointer to 10280Sstevel@tonic-gate * its parent) to each of its children. As we 10290Sstevel@tonic-gate * process a child that is a directory, we save 10300Sstevel@tonic-gate * its own personal directory list info. We then 10310Sstevel@tonic-gate * check to see if the child has already been 10320Sstevel@tonic-gate * processed by comparing its device id and inode 10330Sstevel@tonic-gate * number from its own personal directory list info 10340Sstevel@tonic-gate * to that of each of its ancestors. If there is a 10350Sstevel@tonic-gate * match, then we know we've detected a cycle. 10360Sstevel@tonic-gate */ 10370Sstevel@tonic-gate if (Rflg) { 10380Sstevel@tonic-gate /* 10390Sstevel@tonic-gate * This is the first parent in this lineage 10400Sstevel@tonic-gate * (first in a directory hierarchy), so 10410Sstevel@tonic-gate * this parent's parent doesn't exist. We 10420Sstevel@tonic-gate * only initialize myinfo when we are 10430Sstevel@tonic-gate * recursing, otherwise it's not used. 10440Sstevel@tonic-gate */ 10450Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 10460Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 10470Sstevel@tonic-gate perror("ls"); 10480Sstevel@tonic-gate exit(2); 10490Sstevel@tonic-gate } else { 10500Sstevel@tonic-gate myinfo->dev = 0; 10510Sstevel@tonic-gate myinfo->ino = 0; 10520Sstevel@tonic-gate myinfo->parent = NULL; 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate if (Cflg || mflg) { 10570Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 10580Sstevel@tonic-gate if (width > filewidth) 10590Sstevel@tonic-gate filewidth = width; 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 10620Sstevel@tonic-gate 1, myinfo)) == NULL) { 10630Sstevel@tonic-gate if (nomocore) 10640Sstevel@tonic-gate exit(2); 10650Sstevel@tonic-gate err = 2; 10660Sstevel@tonic-gate optind++; 10670Sstevel@tonic-gate continue; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 10700Sstevel@tonic-gate ep->lflags |= ISARG; 10710Sstevel@tonic-gate optind++; 10720Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 10736866Sbasabi if (acl_err) 10746866Sbasabi err = 2; 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 1077*9664Sjason@ansipunx.net if (!Uflg) 1078*9664Sjason@ansipunx.net qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 1079*9664Sjason@ansipunx.net (int (*)(const void *, const void *))compar); 10800Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 10810Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 10820Sstevel@tonic-gate break; 10830Sstevel@tonic-gate } 1084*9664Sjason@ansipunx.net 1085*9664Sjason@ansipunx.net if (colorflg) 1086*9664Sjason@ansipunx.net ls_color_init(); 1087*9664Sjason@ansipunx.net 10880Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 10890Sstevel@tonic-gate for (; i < nargs; i++) { 10900Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 10910Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 10920Sstevel@tonic-gate if (nomocore) 10930Sstevel@tonic-gate exit(2); 10940Sstevel@tonic-gate /* -R: print subdirectories found */ 10950Sstevel@tonic-gate while (dfirst || cdfirst) { 10960Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 10970Sstevel@tonic-gate while (cdfirst) { 10980Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 10990Sstevel@tonic-gate dtemp = cdfirst; 11000Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 11010Sstevel@tonic-gate dtemp -> dc_next = dfirst; 11020Sstevel@tonic-gate dfirst = dtemp; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 11050Sstevel@tonic-gate dtemp = dfirst; 11060Sstevel@tonic-gate dfirst = dfirst->dc_next; 11070Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 11080Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 11090Sstevel@tonic-gate if (nomocore) 11100Sstevel@tonic-gate exit(2); 11110Sstevel@tonic-gate free(dtemp->dc_name); 11120Sstevel@tonic-gate free(dtemp); 11130Sstevel@tonic-gate } 11140Sstevel@tonic-gate } 1115*9664Sjason@ansipunx.net 11160Sstevel@tonic-gate return (err); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate /* 11200Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 11210Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 11220Sstevel@tonic-gate */ 11230Sstevel@tonic-gate static void 11240Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 11250Sstevel@tonic-gate { 11260Sstevel@tonic-gate struct dchain *dp; 11270Sstevel@tonic-gate struct lbuf *ap; 11280Sstevel@tonic-gate char *pname; 11290Sstevel@tonic-gate int j; 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate filewidth = 0; 11320Sstevel@tonic-gate curdir = name; 11330Sstevel@tonic-gate if (title) { 11340Sstevel@tonic-gate if (!first) 11350Sstevel@tonic-gate (void) putc('\n', stdout); 11360Sstevel@tonic-gate pprintf(name, ":"); 11370Sstevel@tonic-gate new_line(); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 11410Sstevel@tonic-gate * further. 11420Sstevel@tonic-gate */ 11430Sstevel@tonic-gate if (cdetect) { 11440Sstevel@tonic-gate if (lflg || sflg) { 11450Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 11460Sstevel@tonic-gate new_line(); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11490Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 11500Sstevel@tonic-gate return; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate nfiles = lp; 11540Sstevel@tonic-gate rddir(name, myinfo); 11550Sstevel@tonic-gate if (nomocore) 11560Sstevel@tonic-gate return; 1157*9664Sjason@ansipunx.net if (fflg == 0 && Uflg == 0) 11580Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 11590Sstevel@tonic-gate sizeof (struct lbuf *), 11600Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 11610Sstevel@tonic-gate if (Rflg) { 11620Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 11630Sstevel@tonic-gate ap = flist[j]; 11640Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 11650Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 11660Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 11670Sstevel@tonic-gate if (dp == NULL) { 11680Sstevel@tonic-gate perror("ls"); 11690Sstevel@tonic-gate exit(2); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 11720Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 11730Sstevel@tonic-gate perror("ls"); 11740Sstevel@tonic-gate exit(2); 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 11770Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 11780Sstevel@tonic-gate dp->dc_next = dfirst; 11790Sstevel@tonic-gate dfirst = dp; 11800Sstevel@tonic-gate } 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate if (lflg || sflg) { 11840Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 11850Sstevel@tonic-gate new_line(); 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 11910Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 11920Sstevel@tonic-gate * by slp and lp. 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate static void 11950Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 11960Sstevel@tonic-gate { 11970Sstevel@tonic-gate long row, nrows, i; 11980Sstevel@tonic-gate int col, ncols; 11990Sstevel@tonic-gate struct lbuf **ep; 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate if (Cflg || mflg) { 12020Sstevel@tonic-gate if (colwidth > num_cols) { 12030Sstevel@tonic-gate ncols = 1; 12040Sstevel@tonic-gate } else { 12050Sstevel@tonic-gate ncols = num_cols / colwidth; 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 12100Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 12110Sstevel@tonic-gate pentry(*ep); 12120Sstevel@tonic-gate new_line(); 12130Sstevel@tonic-gate return; 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate /* otherwise print -C columns */ 12160Sstevel@tonic-gate if (tot_flag) { 12170Sstevel@tonic-gate slp--; 12180Sstevel@tonic-gate row = 1; 12190Sstevel@tonic-gate } 12200Sstevel@tonic-gate else 12210Sstevel@tonic-gate row = 0; 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 12240Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 12250Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 12260Sstevel@tonic-gate ep = slp + (nrows * col) + row; 12270Sstevel@tonic-gate if (ep < lp) 12280Sstevel@tonic-gate pentry(*ep); 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate new_line(); 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate /* 12350Sstevel@tonic-gate * print one output entry; 12360Sstevel@tonic-gate * if uid/gid is not found in the appropriate 12370Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 12380Sstevel@tonic-gate * user/group name; 12390Sstevel@tonic-gate */ 12400Sstevel@tonic-gate static void 12410Sstevel@tonic-gate pentry(struct lbuf *ap) 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate struct lbuf *p; 12440Sstevel@tonic-gate numbuf_t hbuf; 12450Sstevel@tonic-gate char buf[BUFSIZ]; 12460Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 12470Sstevel@tonic-gate char *cp; 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate p = ap; 12500Sstevel@tonic-gate column(); 12510Sstevel@tonic-gate if (iflg) 12520Sstevel@tonic-gate if (mflg && !lflg) 12530Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 12540Sstevel@tonic-gate else 12550Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 12560Sstevel@tonic-gate if (sflg) 12570Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 12585331Samw (p->lblocks < 10000) ? "%4lld " : "%lld ", 12595331Samw (p->ltype != 'b' && p->ltype != 'c') ? 12605331Samw p->lblocks : 0LL); 12610Sstevel@tonic-gate if (lflg) { 12620Sstevel@tonic-gate (void) putchar(p->ltype); 12630Sstevel@tonic-gate curcol++; 12640Sstevel@tonic-gate pmode(p->lflags); 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate /* ACL: additional access mode flag */ 12670Sstevel@tonic-gate (void) putchar(p->acl); 12680Sstevel@tonic-gate curcol++; 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 12710Sstevel@tonic-gate if (oflg) 12720Sstevel@tonic-gate if (!nflg) { 12730Sstevel@tonic-gate cp = getname(p->luid); 12740Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12750Sstevel@tonic-gate } else 12760Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 12770Sstevel@tonic-gate if (gflg) 12780Sstevel@tonic-gate if (!nflg) { 12790Sstevel@tonic-gate cp = getgroup(p->lgid); 12800Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12810Sstevel@tonic-gate } else 12820Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 12830Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 12840Sstevel@tonic-gate curcol += printf("%3u, %2u", 12850Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 12860Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 12870Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 12880Sstevel@tonic-gate curcol += printf("%7s", 12890Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 12900Sstevel@tonic-gate } else { 1291*9664Sjason@ansipunx.net uint64_t bsize = p->lsize / block_size; 1292*9664Sjason@ansipunx.net 1293*9664Sjason@ansipunx.net /* 1294*9664Sjason@ansipunx.net * Round up only when using blocks > 1 byte, otherwise 1295*9664Sjason@ansipunx.net * 'normal' sizes display 1 byte too large. 1296*9664Sjason@ansipunx.net */ 1297*9664Sjason@ansipunx.net if (p->lsize % block_size != 0) 1298*9664Sjason@ansipunx.net bsize++; 1299*9664Sjason@ansipunx.net 1300*9664Sjason@ansipunx.net curcol += printf("%7" PRIu64, bsize); 13010Sstevel@tonic-gate } 1302*9664Sjason@ansipunx.net format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec); 13035331Samw /* format extended system attribute time */ 13045331Samw if (tmflg && crtm) 13055331Samw format_attrtime(p); 13065331Samw 13070Sstevel@tonic-gate curcol += printf("%s", time_buf); 13085331Samw 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * prevent both "->" and trailing marks 13120Sstevel@tonic-gate * from appearing 13130Sstevel@tonic-gate */ 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate if (pflg && p->ltype == 'd') 13160Sstevel@tonic-gate dmark = "/"; 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 13190Sstevel@tonic-gate if (p->ltype == 'd') 13200Sstevel@tonic-gate dmark = "/"; 13210Sstevel@tonic-gate else if (p->ltype == 'D') 13220Sstevel@tonic-gate dmark = ">"; 13230Sstevel@tonic-gate else if (p->ltype == 'p') 13240Sstevel@tonic-gate dmark = "|"; 13250Sstevel@tonic-gate else if (p->ltype == 'l') 13260Sstevel@tonic-gate dmark = "@"; 13270Sstevel@tonic-gate else if (p->ltype == 's') 13280Sstevel@tonic-gate dmark = "="; 1329*9664Sjason@ansipunx.net else if (!file_typeflg && 1330*9664Sjason@ansipunx.net (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))) 13310Sstevel@tonic-gate dmark = "*"; 13320Sstevel@tonic-gate else 13330Sstevel@tonic-gate dmark = ""; 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate if (lflg && p->flinkto) { 13370Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 13380Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 13390Sstevel@tonic-gate dmark = buf; 13400Sstevel@tonic-gate } 1341*9664Sjason@ansipunx.net 1342*9664Sjason@ansipunx.net if (colorflg) 1343*9664Sjason@ansipunx.net ls_start_color(p); 1344*9664Sjason@ansipunx.net 13450Sstevel@tonic-gate if (p->lflags & ISARG) { 13460Sstevel@tonic-gate if (qflg || bflg) 13470Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 13480Sstevel@tonic-gate else { 13490Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 13500Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 13510Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate } else { 13540Sstevel@tonic-gate if (qflg || bflg) 13550Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 13560Sstevel@tonic-gate else { 13570Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 13580Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 13590Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate } 1362789Sahrens 1363*9664Sjason@ansipunx.net if (colorflg) 1364*9664Sjason@ansipunx.net ls_end_color(); 1365*9664Sjason@ansipunx.net 13665331Samw /* Display extended system attributes */ 13675331Samw if (saflg) { 13685331Samw int i; 13695331Samw 13705331Samw new_line(); 13715331Samw (void) printf(" \t{"); 13725331Samw if (p->exttr != NULL) { 13735331Samw int k = 0; 13745331Samw for (i = 0; i < sacnt; i++) { 13755331Samw if (p->exttr[i].name != NULL) 13765331Samw k++; 13775331Samw } 13785331Samw for (i = 0; i < sacnt; i++) { 13795331Samw if (p->exttr[i].name != NULL) { 13805331Samw (void) printf("%s", p->exttr[i].name); 13815331Samw k--; 13825331Samw if (vopt && (k != 0)) 13835331Samw (void) printf(","); 13845331Samw } 13855331Samw } 13865331Samw } 13875331Samw (void) printf("}\n"); 13885331Samw } 13895331Samw /* Display file timestamps and extended system attribute timestamps */ 13905331Samw if (tmflg && alltm) { 13915331Samw new_line(); 13925331Samw print_time(p); 13935331Samw new_line(); 13945331Samw } 1395789Sahrens if (vflg) { 1396789Sahrens new_line(); 1397789Sahrens if (p->aclp) { 13981420Smarks acl_printacl(p->aclp, num_cols, Vflg); 1399789Sahrens } 1400789Sahrens } 14015331Samw /* Free extended system attribute lists */ 14025331Samw if (saflg || tmflg) 14035331Samw free_sysattr(p); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate /* print various r,w,x permissions */ 14070Sstevel@tonic-gate static void 14080Sstevel@tonic-gate pmode(mode_t aflag) 14090Sstevel@tonic-gate { 14100Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 14110Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 14120Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 14130Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 14140Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 14150Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 14160Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 14170Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 14180Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 14190Sstevel@tonic-gate #ifdef XPG4 14200Sstevel@tonic-gate S_ISGID, 'L', '-'}; 14210Sstevel@tonic-gate #else 14220Sstevel@tonic-gate S_ISGID, 'l', '-'}; 14230Sstevel@tonic-gate #endif 14240Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 14250Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 14260Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 14270Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate int **mp; 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate flags = aflag; 14340Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 14350Sstevel@tonic-gate selection(*mp); 14360Sstevel@tonic-gate } 14370Sstevel@tonic-gate 14380Sstevel@tonic-gate static void 14390Sstevel@tonic-gate selection(int *pairp) 14400Sstevel@tonic-gate { 14410Sstevel@tonic-gate int n; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate n = *pairp++; 14440Sstevel@tonic-gate while (n-->0) { 14450Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 14460Sstevel@tonic-gate pairp++; 14470Sstevel@tonic-gate break; 14480Sstevel@tonic-gate } else { 14490Sstevel@tonic-gate pairp += 2; 14500Sstevel@tonic-gate } 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate (void) putchar(*pairp); 14530Sstevel@tonic-gate curcol++; 14540Sstevel@tonic-gate } 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate /* 14570Sstevel@tonic-gate * column: get to the beginning of the next column. 14580Sstevel@tonic-gate */ 14590Sstevel@tonic-gate static void 14600Sstevel@tonic-gate column(void) 14610Sstevel@tonic-gate { 14620Sstevel@tonic-gate if (curcol == 0) 14630Sstevel@tonic-gate return; 14640Sstevel@tonic-gate if (mflg) { 14650Sstevel@tonic-gate (void) putc(',', stdout); 14660Sstevel@tonic-gate curcol++; 14670Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 14680Sstevel@tonic-gate (void) putc('\n', stdout); 14690Sstevel@tonic-gate curcol = 0; 14700Sstevel@tonic-gate return; 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate (void) putc(' ', stdout); 14730Sstevel@tonic-gate curcol++; 14740Sstevel@tonic-gate return; 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate if (Cflg == 0) { 14770Sstevel@tonic-gate (void) putc('\n', stdout); 14780Sstevel@tonic-gate curcol = 0; 14790Sstevel@tonic-gate return; 14800Sstevel@tonic-gate } 14810Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 14820Sstevel@tonic-gate (void) putc('\n', stdout); 14830Sstevel@tonic-gate curcol = 0; 14840Sstevel@tonic-gate return; 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate do { 14870Sstevel@tonic-gate (void) putc(' ', stdout); 14880Sstevel@tonic-gate curcol++; 14890Sstevel@tonic-gate } while (curcol % colwidth); 14900Sstevel@tonic-gate } 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate static void 14930Sstevel@tonic-gate new_line(void) 14940Sstevel@tonic-gate { 14950Sstevel@tonic-gate if (curcol) { 14960Sstevel@tonic-gate first = 0; 14970Sstevel@tonic-gate (void) putc('\n', stdout); 14980Sstevel@tonic-gate curcol = 0; 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate /* 15030Sstevel@tonic-gate * read each filename in directory dir and store its 15040Sstevel@tonic-gate * status in flist[nfiles] 15050Sstevel@tonic-gate * use makename() to form pathname dir/filename; 15060Sstevel@tonic-gate */ 15070Sstevel@tonic-gate static void 15080Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 15090Sstevel@tonic-gate { 15100Sstevel@tonic-gate struct dirent *dentry; 15110Sstevel@tonic-gate DIR *dirf; 15120Sstevel@tonic-gate int j; 15130Sstevel@tonic-gate struct lbuf *ep; 15140Sstevel@tonic-gate int width; 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 15170Sstevel@tonic-gate (void) fflush(stdout); 15180Sstevel@tonic-gate perror(dir); 15190Sstevel@tonic-gate err = 2; 15200Sstevel@tonic-gate return; 15210Sstevel@tonic-gate } else { 15220Sstevel@tonic-gate tblocks = 0; 15230Sstevel@tonic-gate for (;;) { 15240Sstevel@tonic-gate errno = 0; 15250Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 15260Sstevel@tonic-gate break; 15270Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 15280Sstevel@tonic-gate (Aflg == 0 || 15290Sstevel@tonic-gate dentry->d_name[1] == '\0' || 15300Sstevel@tonic-gate dentry->d_name[1] == '.' && 15310Sstevel@tonic-gate dentry->d_name[2] == '\0')) 15320Sstevel@tonic-gate /* 15330Sstevel@tonic-gate * check for directory items '.', '..', 15340Sstevel@tonic-gate * and items without valid inode-number; 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate continue; 15370Sstevel@tonic-gate 1538*9664Sjason@ansipunx.net /* skip entries ending in ~ if -B was given */ 1539*9664Sjason@ansipunx.net if (Bflg && 1540*9664Sjason@ansipunx.net dentry->d_name[strlen(dentry->d_name) - 1] == '~') 1541*9664Sjason@ansipunx.net continue; 15420Sstevel@tonic-gate if (Cflg || mflg) { 15430Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 15440Sstevel@tonic-gate if (width > filewidth) 15450Sstevel@tonic-gate filewidth = width; 15460Sstevel@tonic-gate } 15470Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 15480Sstevel@tonic-gate if (ep == NULL) { 15490Sstevel@tonic-gate if (nomocore) 15505331Samw exit(2); 15510Sstevel@tonic-gate continue; 15520Sstevel@tonic-gate } else { 15530Sstevel@tonic-gate ep->lnum = dentry->d_ino; 15540Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 15550Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 15560Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 15570Sstevel@tonic-gate } 15580Sstevel@tonic-gate } 15590Sstevel@tonic-gate if (errno) { 15600Sstevel@tonic-gate int sav_errno = errno; 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate (void) fprintf(stderr, 15630Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 15640Sstevel@tonic-gate dir, strerror(sav_errno)); 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate (void) closedir(dirf); 15670Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 15680Sstevel@tonic-gate } 15690Sstevel@tonic-gate } 15700Sstevel@tonic-gate 15710Sstevel@tonic-gate /* 15720Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 15730Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 15740Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 15750Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 15760Sstevel@tonic-gate * it is reported at the right time when printing the directory. 15770Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 15780Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 15790Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 15800Sstevel@tonic-gate * command line. 15810Sstevel@tonic-gate */ 15820Sstevel@tonic-gate static void 15830Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 15840Sstevel@tonic-gate int argfl, struct ditem *myparent) 15850Sstevel@tonic-gate { 15860Sstevel@tonic-gate size_t file_len; 15870Sstevel@tonic-gate struct ditem *myinfo; 15880Sstevel@tonic-gate struct ditem *tptr; 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate file_len = strlen(file); 15910Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 15920Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 15930Sstevel@tonic-gate /* 15940Sstevel@tonic-gate * Add this inode's ancestry 15950Sstevel@tonic-gate * info and insert it into the 15960Sstevel@tonic-gate * ancestry list by pointing 15970Sstevel@tonic-gate * back to its parent. We save 15980Sstevel@tonic-gate * it (in rep) with the other info 15990Sstevel@tonic-gate * we're gathering for this inode. 16000Sstevel@tonic-gate */ 16010Sstevel@tonic-gate if ((myinfo = malloc( 16020Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 16030Sstevel@tonic-gate perror("ls"); 16040Sstevel@tonic-gate exit(2); 16050Sstevel@tonic-gate } 16060Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 16070Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 16080Sstevel@tonic-gate myinfo->parent = myparent; 16090Sstevel@tonic-gate rep->ancinfo = myinfo; 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate /* 16120Sstevel@tonic-gate * If this node has the same device id and 16130Sstevel@tonic-gate * inode number of one of its ancestors, 16140Sstevel@tonic-gate * then we've detected a cycle. 16150Sstevel@tonic-gate */ 16160Sstevel@tonic-gate if (myparent != NULL) { 16170Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 16180Sstevel@tonic-gate tptr = tptr->parent) { 16190Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 16200Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 16210Sstevel@tonic-gate /* 16220Sstevel@tonic-gate * Cycle detected for this 16230Sstevel@tonic-gate * directory. Record the fact 16240Sstevel@tonic-gate * it is a cycle so we don't 16250Sstevel@tonic-gate * try to process this 16260Sstevel@tonic-gate * directory as we are 16270Sstevel@tonic-gate * walking through the 16280Sstevel@tonic-gate * list of directories. 16290Sstevel@tonic-gate */ 16300Sstevel@tonic-gate rep->cycle = 1; 16310Sstevel@tonic-gate err = 2; 16320Sstevel@tonic-gate break; 16330Sstevel@tonic-gate } 16340Sstevel@tonic-gate } 16350Sstevel@tonic-gate } 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate /* 16406178Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 16416178Sny155746 * This is because, if the server's FS happens to be UFS, supporting 16426178Sny155746 * POSIX ACL's, then it does a special calculation of group mode 16436178Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 16446178Sny155746 * 16456178Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 16466178Sny155746 * algorithm is used for the group mode calculation only. 16476178Sny155746 * What is modified here from the algorithm is that only the 16486178Sny155746 * entries with flags ACE_GROUP are considered. For each entry 16496178Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 16506178Sny155746 * is checked if it is allowed. 16516373Sny155746 * We are not interested in perms for user and other, as they 16526178Sny155746 * were taken from st_mode value. 16536178Sny155746 * We are not interested in a_who field of ACE, as we need just 16546178Sny155746 * unix mode bits for the group. 16556178Sny155746 */ 16566373Sny155746 16576373Sny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 16586373Sny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 16596373Sny155746 16606178Sny155746 int 16616178Sny155746 grp_mask_to_mode(acl_t *acep) 16626178Sny155746 { 16636178Sny155746 int mode = 0, seen = 0; 16646178Sny155746 int acecnt; 16656373Sny155746 int flags; 16666178Sny155746 ace_t *ap; 16676178Sny155746 16686178Sny155746 acecnt = acl_cnt(acep); 16696178Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 16706373Sny155746 16716373Sny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 16726373Sny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 16736373Sny155746 continue; 16746373Sny155746 16756373Sny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 16766373Sny155746 continue; 16776373Sny155746 16786373Sny155746 /* 16796373Sny155746 * if it is first group@ or first everyone@ 16806373Sny155746 * for each of read, write and execute, then 16816373Sny155746 * that will be the group mode bit. 16826373Sny155746 */ 16836373Sny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 16846373Sny155746 if (flags == OWNED_GROUP || flags == ACE_EVERYONE) { 16856373Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 16866373Sny155746 if (!(seen & S_IRGRP)) { 16876373Sny155746 seen |= S_IRGRP; 16886373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 16896373Sny155746 mode |= S_IRGRP; 16906178Sny155746 } 16916373Sny155746 } 16926373Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 16936373Sny155746 if (!(seen & S_IWGRP)) { 16946373Sny155746 seen |= S_IWGRP; 16956373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 16966373Sny155746 mode |= S_IWGRP; 16976178Sny155746 } 16986373Sny155746 } 16996373Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 17006373Sny155746 if (!(seen & S_IXGRP)) { 17016373Sny155746 seen |= S_IXGRP; 17026373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 17036373Sny155746 mode |= S_IXGRP; 17046178Sny155746 } 17056178Sny155746 } 17066178Sny155746 } 17076178Sny155746 } 17086178Sny155746 return (mode); 17096178Sny155746 } 17106178Sny155746 17116178Sny155746 /* 17120Sstevel@tonic-gate * get status of file and recomputes tblocks; 17130Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 17140Sstevel@tonic-gate * for filename in a directory whose name is an 17150Sstevel@tonic-gate * argument in the command; 17160Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 17170Sstevel@tonic-gate * returns that pointer; 17180Sstevel@tonic-gate * returns NULL if failed; 17190Sstevel@tonic-gate */ 17200Sstevel@tonic-gate static struct lbuf * 17210Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 17220Sstevel@tonic-gate { 17230Sstevel@tonic-gate struct stat statb, statb1; 17240Sstevel@tonic-gate struct lbuf *rep; 17250Sstevel@tonic-gate char buf[BUFSIZ]; 17260Sstevel@tonic-gate ssize_t cc; 17270Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 17280Sstevel@tonic-gate int aclcnt; 1729789Sahrens int error; 17300Sstevel@tonic-gate aclent_t *tp; 17310Sstevel@tonic-gate o_mode_t groupperm, mask; 17320Sstevel@tonic-gate int grouppermfound, maskfound; 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate if (nomocore) 17350Sstevel@tonic-gate return (NULL); 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate if (nfiles >= maxfils) { 17380Sstevel@tonic-gate /* 17390Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 17400Sstevel@tonic-gate * more space 17410Sstevel@tonic-gate */ 17420Sstevel@tonic-gate maxfils += quantn; 17430Sstevel@tonic-gate if (((flist = realloc(flist, 17440Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 17450Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 17460Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 17470Sstevel@tonic-gate perror("ls"); 17480Sstevel@tonic-gate nomocore = 1; 17490Sstevel@tonic-gate return (NULL); 17500Sstevel@tonic-gate } 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate /* 17540Sstevel@tonic-gate * nfiles is reset to nargs for each directory 17550Sstevel@tonic-gate * that is given as an argument maxn is checked 17560Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 17570Sstevel@tonic-gate * that already has one assigned. 17580Sstevel@tonic-gate */ 17590Sstevel@tonic-gate if (nfiles >= maxn) { 17600Sstevel@tonic-gate rep = nxtlbf++; 17610Sstevel@tonic-gate flist[nfiles++] = rep; 17620Sstevel@tonic-gate maxn = nfiles; 17630Sstevel@tonic-gate } else { 17640Sstevel@tonic-gate rep = flist[nfiles++]; 17650Sstevel@tonic-gate } 17666792Sbasabi 17676792Sbasabi /* Initialize */ 17686792Sbasabi 17690Sstevel@tonic-gate rep->lflags = (mode_t)0; 17700Sstevel@tonic-gate rep->flinkto = NULL; 17710Sstevel@tonic-gate rep->cycle = 0; 17726792Sbasabi rep->lat.tv_sec = time(NULL); 17736792Sbasabi rep->lat.tv_nsec = 0; 17746792Sbasabi rep->lct.tv_sec = time(NULL); 17756792Sbasabi rep->lct.tv_nsec = 0; 17766792Sbasabi rep->lmt.tv_sec = time(NULL); 17776792Sbasabi rep->lmt.tv_nsec = 0; 17786792Sbasabi rep->exttr = NULL; 17796792Sbasabi rep->extm = NULL; 17806792Sbasabi 17810Sstevel@tonic-gate if (argfl || statreq) { 17820Sstevel@tonic-gate int doacl; 17830Sstevel@tonic-gate 17840Sstevel@tonic-gate if (lflg) 17850Sstevel@tonic-gate doacl = 1; 17860Sstevel@tonic-gate else 17870Sstevel@tonic-gate doacl = 0; 17886792Sbasabi 17890Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 17900Sstevel@tonic-gate if (argfl || errno != ENOENT || 17910Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 17920Sstevel@tonic-gate /* 17930Sstevel@tonic-gate * Avoid race between readdir and lstat. 17940Sstevel@tonic-gate * Print error message in case of dangling link. 17950Sstevel@tonic-gate */ 17960Sstevel@tonic-gate perror(file); 1797*9664Sjason@ansipunx.net err = 2; 17980Sstevel@tonic-gate } 17990Sstevel@tonic-gate nfiles--; 18000Sstevel@tonic-gate return (NULL); 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate /* 18040Sstevel@tonic-gate * If -H was specified, and the file linked to was 18050Sstevel@tonic-gate * not a directory, then we need to get the info 18060Sstevel@tonic-gate * for the symlink itself. 18070Sstevel@tonic-gate */ 18080Sstevel@tonic-gate if ((Hflg) && (argfl) && 18090Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 18100Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 18110Sstevel@tonic-gate perror(file); 1812*9664Sjason@ansipunx.net err = 2; 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate rep->lnum = statb.st_ino; 18170Sstevel@tonic-gate rep->lsize = statb.st_size; 18180Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 18190Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 18200Sstevel@tonic-gate case S_IFDIR: 18210Sstevel@tonic-gate rep->ltype = 'd'; 18220Sstevel@tonic-gate if (Rflg) { 18230Sstevel@tonic-gate record_ancestry(file, &statb, rep, 18240Sstevel@tonic-gate argfl, myparent); 18250Sstevel@tonic-gate } 18260Sstevel@tonic-gate break; 18270Sstevel@tonic-gate case S_IFBLK: 18280Sstevel@tonic-gate rep->ltype = 'b'; 18290Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18300Sstevel@tonic-gate break; 18310Sstevel@tonic-gate case S_IFCHR: 18320Sstevel@tonic-gate rep->ltype = 'c'; 18330Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18340Sstevel@tonic-gate break; 18350Sstevel@tonic-gate case S_IFIFO: 18360Sstevel@tonic-gate rep->ltype = 'p'; 18370Sstevel@tonic-gate break; 18380Sstevel@tonic-gate case S_IFSOCK: 18390Sstevel@tonic-gate rep->ltype = 's'; 18400Sstevel@tonic-gate rep->lsize = 0; 18410Sstevel@tonic-gate break; 18420Sstevel@tonic-gate case S_IFLNK: 18430Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 18440Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 18450Sstevel@tonic-gate ((Hflg) && (!argfl))) { 18460Sstevel@tonic-gate doacl = 0; 18470Sstevel@tonic-gate } 18480Sstevel@tonic-gate rep->ltype = 'l'; 18490Sstevel@tonic-gate if (lflg) { 18500Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 18510Sstevel@tonic-gate if (cc >= 0) { 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate /* 18540Sstevel@tonic-gate * follow the symbolic link 18550Sstevel@tonic-gate * to generate the appropriate 18560Sstevel@tonic-gate * Fflg marker for the object 18570Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 18580Sstevel@tonic-gate */ 18590Sstevel@tonic-gate if ((Fflg || pflg) && 18600Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 18610Sstevel@tonic-gate switch (statb1.st_mode & 18620Sstevel@tonic-gate S_IFMT) { 18630Sstevel@tonic-gate case S_IFDIR: 18640Sstevel@tonic-gate buf[cc++] = '/'; 18650Sstevel@tonic-gate break; 18660Sstevel@tonic-gate case S_IFSOCK: 18670Sstevel@tonic-gate buf[cc++] = '='; 18680Sstevel@tonic-gate break; 18691447Sakaplan case S_IFDOOR: 18701447Sakaplan buf[cc++] = '>'; 18711447Sakaplan break; 18721447Sakaplan case S_IFIFO: 18731447Sakaplan buf[cc++] = '|'; 18741447Sakaplan break; 18750Sstevel@tonic-gate default: 18760Sstevel@tonic-gate if ((statb1.st_mode & 18770Sstevel@tonic-gate ~S_IFMT) & 18780Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 18790Sstevel@tonic-gate S_IXOTH)) 18800Sstevel@tonic-gate buf[cc++] = '*'; 18810Sstevel@tonic-gate break; 18820Sstevel@tonic-gate } 18830Sstevel@tonic-gate } 18840Sstevel@tonic-gate buf[cc] = '\0'; 18850Sstevel@tonic-gate rep->flinkto = strdup(buf); 18860Sstevel@tonic-gate } 18870Sstevel@tonic-gate break; 18880Sstevel@tonic-gate } 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate /* 18910Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 18920Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 18930Sstevel@tonic-gate * when explicit arguments are specified. 18940Sstevel@tonic-gate */ 18950Sstevel@tonic-gate 18960Sstevel@tonic-gate #ifdef XPG6 18970Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 18980Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 18990Sstevel@tonic-gate (stat(file, &statb1) < 0)) 19000Sstevel@tonic-gate #else 19010Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 19020Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 19030Sstevel@tonic-gate #endif /* XPG6 */ 19040Sstevel@tonic-gate break; 19050Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 19060Sstevel@tonic-gate statb = statb1; 19070Sstevel@tonic-gate rep->ltype = 'd'; 19080Sstevel@tonic-gate rep->lsize = statb1.st_size; 19090Sstevel@tonic-gate if (Rflg) { 19100Sstevel@tonic-gate record_ancestry(file, &statb, rep, 19110Sstevel@tonic-gate argfl, myparent); 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate break; 19150Sstevel@tonic-gate case S_IFDOOR: 19160Sstevel@tonic-gate rep->ltype = 'D'; 19170Sstevel@tonic-gate break; 19180Sstevel@tonic-gate case S_IFREG: 19190Sstevel@tonic-gate rep->ltype = '-'; 19200Sstevel@tonic-gate break; 19210Sstevel@tonic-gate case S_IFPORT: 19220Sstevel@tonic-gate rep->ltype = 'P'; 19230Sstevel@tonic-gate break; 19240Sstevel@tonic-gate default: 19250Sstevel@tonic-gate rep->ltype = '?'; 19260Sstevel@tonic-gate break; 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 19290Sstevel@tonic-gate 19300Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 19310Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 19320Sstevel@tonic-gate 19336792Sbasabi rep->luid = statb.st_uid; 19346792Sbasabi rep->lgid = statb.st_gid; 19356792Sbasabi rep->lnl = statb.st_nlink; 19366792Sbasabi if (uflg || (tmflg && atm)) 19376792Sbasabi rep->lmtime = statb.st_atim; 19386792Sbasabi else if (cflg || (tmflg && ctm)) 19396792Sbasabi rep->lmtime = statb.st_ctim; 19406792Sbasabi else 19416792Sbasabi rep->lmtime = statb.st_mtim; 19426792Sbasabi rep->lat = statb.st_atim; 19436792Sbasabi rep->lct = statb.st_ctim; 19446792Sbasabi rep->lmt = statb.st_mtim; 19456792Sbasabi 19460Sstevel@tonic-gate /* ACL: check acl entries count */ 19470Sstevel@tonic-gate if (doacl) { 19480Sstevel@tonic-gate 1949789Sahrens error = acl_get(file, 0, &rep->aclp); 1950789Sahrens if (error) { 1951789Sahrens (void) fprintf(stderr, 1952789Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1953789Sahrens file, acl_strerror(error)); 19546792Sbasabi rep->acl = ' '; 19556866Sbasabi acl_err++; 19566792Sbasabi return (rep); 1957789Sahrens } 19580Sstevel@tonic-gate 1959789Sahrens rep->acl = ' '; 19600Sstevel@tonic-gate 1961789Sahrens if (rep->aclp && 1962789Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1963789Sahrens rep->acl = '+'; 19640Sstevel@tonic-gate /* 1965789Sahrens * Special handling for ufs aka aclent_t ACL's 19660Sstevel@tonic-gate */ 19676178Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 1968789Sahrens /* 1969789Sahrens * For files with non-trivial acls, the 1970789Sahrens * effective group permissions are the 1971789Sahrens * intersection of the GROUP_OBJ value 1972789Sahrens * and the CLASS_OBJ (acl mask) value. 1973789Sahrens * Determine both the GROUP_OBJ and 1974789Sahrens * CLASS_OBJ for this file and insert 1975789Sahrens * the logical AND of those two values 1976789Sahrens * in the group permissions field 1977789Sahrens * of the lflags value for this file. 1978789Sahrens */ 1979789Sahrens 1980789Sahrens /* 1981789Sahrens * Until found in acl list, assume 1982789Sahrens * maximum permissions for both group 1983789Sahrens * a nd mask. (Just in case the acl 1984789Sahrens * lacks either value for some reason.) 1985789Sahrens */ 1986789Sahrens groupperm = 07; 1987789Sahrens mask = 07; 1988789Sahrens grouppermfound = 0; 1989789Sahrens maskfound = 0; 1990789Sahrens aclcnt = acl_cnt(rep->aclp); 1991789Sahrens for (tp = 1992789Sahrens (aclent_t *)acl_data(rep->aclp); 1993789Sahrens aclcnt--; tp++) { 1994789Sahrens if (tp->a_type == GROUP_OBJ) { 1995789Sahrens groupperm = tp->a_perm; 1996789Sahrens grouppermfound = 1; 1997789Sahrens continue; 1998789Sahrens } 1999789Sahrens if (tp->a_type == CLASS_OBJ) { 2000789Sahrens mask = tp->a_perm; 2001789Sahrens maskfound = 1; 2002789Sahrens } 2003789Sahrens if (grouppermfound && maskfound) 2004789Sahrens break; 20050Sstevel@tonic-gate } 2006789Sahrens 20070Sstevel@tonic-gate 2008789Sahrens /* reset all the group bits */ 2009789Sahrens rep->lflags &= ~S_IRWXG; 20100Sstevel@tonic-gate 2011789Sahrens /* 2012789Sahrens * Now set them to the logical AND of 2013789Sahrens * the GROUP_OBJ permissions and the 2014789Sahrens * acl mask. 2015789Sahrens */ 20160Sstevel@tonic-gate 2017789Sahrens rep->lflags |= (groupperm & mask) << 3; 20180Sstevel@tonic-gate 20196178Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 20206178Sny155746 int mode; 20216178Sny155746 mode = grp_mask_to_mode(rep->aclp); 20226178Sny155746 rep->lflags &= ~S_IRWXG; 20236178Sny155746 rep->lflags |= mode; 2024789Sahrens } 20250Sstevel@tonic-gate } 20260Sstevel@tonic-gate 20271420Smarks if (!vflg && !Vflg && rep->aclp) { 20281420Smarks acl_free(rep->aclp); 20291420Smarks rep->aclp = NULL; 20301420Smarks } 20311420Smarks 20320Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 20330Sstevel@tonic-gate rep->acl = '@'; 20345331Samw 20350Sstevel@tonic-gate } else 20360Sstevel@tonic-gate rep->acl = ' '; 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 20410Sstevel@tonic-gate tblocks += rep->lblocks; 20425331Samw 20435331Samw /* Get extended system attributes */ 20445331Samw 20455331Samw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 20465331Samw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 20475331Samw int i; 20485331Samw 20495331Samw sacnt = attr_count(); 20505331Samw /* 20515331Samw * Allocate 'sacnt' size array to hold extended 20525331Samw * system attribute name (verbose) or respective 20535331Samw * symbol represenation (compact). 20545331Samw */ 20555331Samw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 20565331Samw rep); 20575331Samw 20585331Samw /* initialize boolean attribute list */ 20595331Samw for (i = 0; i < sacnt; i++) 20605331Samw rep->exttr[i].name = NULL; 20615331Samw if (get_sysxattr(file, rep) != 0) { 20625331Samw (void) fprintf(stderr, 20635331Samw gettext("ls:Failed to retrieve " 20645331Samw "extended system attribute from " 20655331Samw "%s\n"), file); 20665331Samw rep->exttr[0].name = xmalloc(2, rep); 20675331Samw (void) strlcpy(rep->exttr[0].name, "?", 2); 20685331Samw } 20695331Samw } 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate return (rep); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate 20740Sstevel@tonic-gate /* 20750Sstevel@tonic-gate * returns pathname of the form dir/file; 20760Sstevel@tonic-gate * dir and file are null-terminated strings. 20770Sstevel@tonic-gate */ 20780Sstevel@tonic-gate static char * 20790Sstevel@tonic-gate makename(char *dir, char *file) 20800Sstevel@tonic-gate { 20810Sstevel@tonic-gate /* 20820Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 20830Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 20840Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 20850Sstevel@tonic-gate * and the null character at the end. 20860Sstevel@tonic-gate * dfile is static as this is returned by makename(). 20870Sstevel@tonic-gate */ 20880Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 20890Sstevel@tonic-gate char *dp, *fp; 20900Sstevel@tonic-gate 20910Sstevel@tonic-gate dp = dfile; 20920Sstevel@tonic-gate fp = dir; 20930Sstevel@tonic-gate while (*fp) 20940Sstevel@tonic-gate *dp++ = *fp++; 20950Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 20960Sstevel@tonic-gate *dp++ = '/'; 20970Sstevel@tonic-gate fp = file; 20980Sstevel@tonic-gate while (*fp) 20990Sstevel@tonic-gate *dp++ = *fp++; 21000Sstevel@tonic-gate *dp = '\0'; 21010Sstevel@tonic-gate return (dfile); 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate 21050Sstevel@tonic-gate #include <pwd.h> 21060Sstevel@tonic-gate #include <grp.h> 21070Sstevel@tonic-gate #include <utmpx.h> 21080Sstevel@tonic-gate 21090Sstevel@tonic-gate struct utmpx utmp; 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 21120Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 21160Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 21170Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 21180Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 21190Sstevel@tonic-gate int initted; /* name has been filled in */ 21200Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 21210Sstevel@tonic-gate }; 21220Sstevel@tonic-gate static struct cachenode *names, *groups; 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate static struct cachenode * 21250Sstevel@tonic-gate findincache(struct cachenode **head, long val) 21260Sstevel@tonic-gate { 21270Sstevel@tonic-gate struct cachenode **parent = head; 21280Sstevel@tonic-gate struct cachenode *c = *parent; 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate while (c != NULL) { 21310Sstevel@tonic-gate if (val == c->val) { 21320Sstevel@tonic-gate /* found it */ 21330Sstevel@tonic-gate return (c); 21340Sstevel@tonic-gate } else if (val < c->val) { 21350Sstevel@tonic-gate parent = &c->lesschild; 21360Sstevel@tonic-gate c = c->lesschild; 21370Sstevel@tonic-gate } else { 21380Sstevel@tonic-gate parent = &c->grtrchild; 21390Sstevel@tonic-gate c = c->grtrchild; 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 21440Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 21450Sstevel@tonic-gate if (c == NULL) { 21460Sstevel@tonic-gate perror("ls"); 21470Sstevel@tonic-gate exit(2); 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate *parent = c; 21500Sstevel@tonic-gate c->val = val; 21510Sstevel@tonic-gate return (c); 21520Sstevel@tonic-gate } 21530Sstevel@tonic-gate 21540Sstevel@tonic-gate /* 21550Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 21560Sstevel@tonic-gate * lastuid is set to uid. 21570Sstevel@tonic-gate */ 21580Sstevel@tonic-gate static char * 21590Sstevel@tonic-gate getname(uid_t uid) 21600Sstevel@tonic-gate { 21610Sstevel@tonic-gate struct passwd *pwent; 21620Sstevel@tonic-gate struct cachenode *c; 21630Sstevel@tonic-gate 21640Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 21650Sstevel@tonic-gate return (lastuname); 21660Sstevel@tonic-gate 21670Sstevel@tonic-gate c = findincache(&names, uid); 21680Sstevel@tonic-gate if (c->initted == 0) { 21690Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 21700Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 21710Sstevel@tonic-gate } else { 21720Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 21730Sstevel@tonic-gate } 21740Sstevel@tonic-gate c->initted = 1; 21750Sstevel@tonic-gate } 21760Sstevel@tonic-gate lastuid = uid; 21770Sstevel@tonic-gate lastuname = &c->name[0]; 21780Sstevel@tonic-gate return (lastuname); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate /* 21820Sstevel@tonic-gate * get name from cache, or group file for a given gid; 21830Sstevel@tonic-gate * lastgid is set to gid. 21840Sstevel@tonic-gate */ 21850Sstevel@tonic-gate static char * 21860Sstevel@tonic-gate getgroup(gid_t gid) 21870Sstevel@tonic-gate { 21880Sstevel@tonic-gate struct group *grent; 21890Sstevel@tonic-gate struct cachenode *c; 21900Sstevel@tonic-gate 21910Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 21920Sstevel@tonic-gate return (lastgname); 21930Sstevel@tonic-gate 21940Sstevel@tonic-gate c = findincache(&groups, gid); 21950Sstevel@tonic-gate if (c->initted == 0) { 21960Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 21970Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 21980Sstevel@tonic-gate } else { 21990Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate c->initted = 1; 22020Sstevel@tonic-gate } 22030Sstevel@tonic-gate lastgid = gid; 22040Sstevel@tonic-gate lastgname = &c->name[0]; 22050Sstevel@tonic-gate return (lastgname); 22060Sstevel@tonic-gate } 22070Sstevel@tonic-gate 22080Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 22090Sstevel@tonic-gate static int 22100Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 22110Sstevel@tonic-gate { 22120Sstevel@tonic-gate struct lbuf *p1, *p2; 22130Sstevel@tonic-gate 22140Sstevel@tonic-gate p1 = *pp1; 22150Sstevel@tonic-gate p2 = *pp2; 22160Sstevel@tonic-gate if (dflg == 0) { 22170Sstevel@tonic-gate /* 22180Sstevel@tonic-gate * compare two names in ls-command one of which is file 22190Sstevel@tonic-gate * and the other is a directory; 22200Sstevel@tonic-gate * this portion is not used for comparing files within 22210Sstevel@tonic-gate * a directory name of ls-command; 22220Sstevel@tonic-gate */ 22230Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 22240Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 22250Sstevel@tonic-gate return (1); 22260Sstevel@tonic-gate } else { 22270Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 22280Sstevel@tonic-gate return (-1); 22290Sstevel@tonic-gate } 22300Sstevel@tonic-gate } 22310Sstevel@tonic-gate if (tflg) { 22320Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 22330Sstevel@tonic-gate return (rflg); 22340Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 22350Sstevel@tonic-gate return (-rflg); 22360Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 22370Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 22380Sstevel@tonic-gate return (rflg); 22390Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 22400Sstevel@tonic-gate return (-rflg); 22410Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 22420Sstevel@tonic-gate } else if (Sflg) { 22430Sstevel@tonic-gate /* 22440Sstevel@tonic-gate * The size stored in lsize can be either the 22450Sstevel@tonic-gate * size or the major minor number (in the case of 22460Sstevel@tonic-gate * block and character special devices). If it's 22470Sstevel@tonic-gate * a major minor number, then the size is considered 22480Sstevel@tonic-gate * to be zero and we want to fall through and sort 22490Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 22500Sstevel@tonic-gate * to the size of p1 we want to fall through and 22510Sstevel@tonic-gate * sort by name. 22520Sstevel@tonic-gate */ 22530Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 22545331Samw (p1->ltype == 'c') ? 0 : p1->lsize; 22550Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 22565331Samw (p2->ltype == 'c') ? 0 : p2->lsize; 22570Sstevel@tonic-gate if (p2size > p1size) { 22580Sstevel@tonic-gate return (rflg); 22590Sstevel@tonic-gate } else if (p2size < p1size) { 22600Sstevel@tonic-gate return (-rflg); 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 22630Sstevel@tonic-gate } 22640Sstevel@tonic-gate return (rflg * strcoll( 22650Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 22660Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate static void 22700Sstevel@tonic-gate pprintf(char *s1, char *s2) 22710Sstevel@tonic-gate { 22720Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 22730Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 22740Sstevel@tonic-gate } 22750Sstevel@tonic-gate 22760Sstevel@tonic-gate static void 22770Sstevel@tonic-gate csi_pprintf(unsigned char *s) 22780Sstevel@tonic-gate { 22790Sstevel@tonic-gate unsigned char *cp; 22800Sstevel@tonic-gate char c; 22810Sstevel@tonic-gate int i; 22820Sstevel@tonic-gate int c_len; 22830Sstevel@tonic-gate int p_col; 22840Sstevel@tonic-gate wchar_t pcode; 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate if (!qflg && !bflg) { 22870Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 22880Sstevel@tonic-gate (void) putchar(*cp); 22890Sstevel@tonic-gate curcol++; 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate return; 22920Sstevel@tonic-gate } 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate for (cp = s; *cp; ) { 22950Sstevel@tonic-gate if (isascii(c = *cp)) { 22960Sstevel@tonic-gate if (!isprint(c)) { 22970Sstevel@tonic-gate if (qflg) { 22980Sstevel@tonic-gate c = '?'; 22990Sstevel@tonic-gate } else { 23000Sstevel@tonic-gate curcol += 3; 23010Sstevel@tonic-gate (void) putc('\\', stdout); 23020Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23030Sstevel@tonic-gate (void) putc(c, stdout); 23040Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23050Sstevel@tonic-gate (void) putc(c, stdout); 23060Sstevel@tonic-gate c = '0' + (*cp & 07); 23070Sstevel@tonic-gate } 23080Sstevel@tonic-gate } 23090Sstevel@tonic-gate curcol++; 23100Sstevel@tonic-gate cp++; 23110Sstevel@tonic-gate (void) putc(c, stdout); 23120Sstevel@tonic-gate continue; 23130Sstevel@tonic-gate } 23140Sstevel@tonic-gate 23150Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 23160Sstevel@tonic-gate c_len = 1; 23170Sstevel@tonic-gate goto not_print; 23180Sstevel@tonic-gate } 23190Sstevel@tonic-gate 23200Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 23210Sstevel@tonic-gate (void) putwchar(pcode); 23220Sstevel@tonic-gate cp += c_len; 23230Sstevel@tonic-gate curcol += p_col; 23240Sstevel@tonic-gate continue; 23250Sstevel@tonic-gate } 23260Sstevel@tonic-gate 23270Sstevel@tonic-gate not_print: 23280Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 23290Sstevel@tonic-gate if (qflg) { 23300Sstevel@tonic-gate c = '?'; 23310Sstevel@tonic-gate } else { 23320Sstevel@tonic-gate curcol += 3; 23330Sstevel@tonic-gate (void) putc('\\', stdout); 23340Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23350Sstevel@tonic-gate (void) putc(c, stdout); 23360Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23370Sstevel@tonic-gate (void) putc(c, stdout); 23380Sstevel@tonic-gate c = '0' + (*cp & 07); 23390Sstevel@tonic-gate } 23400Sstevel@tonic-gate curcol++; 23410Sstevel@tonic-gate (void) putc(c, stdout); 23420Sstevel@tonic-gate cp++; 23430Sstevel@tonic-gate } 23440Sstevel@tonic-gate } 23450Sstevel@tonic-gate } 23460Sstevel@tonic-gate 23470Sstevel@tonic-gate static int 23480Sstevel@tonic-gate strcol(unsigned char *s1) 23490Sstevel@tonic-gate { 23500Sstevel@tonic-gate int w; 23510Sstevel@tonic-gate int w_col; 23520Sstevel@tonic-gate int len; 23530Sstevel@tonic-gate wchar_t wc; 23540Sstevel@tonic-gate 23550Sstevel@tonic-gate w = 0; 23560Sstevel@tonic-gate while (*s1) { 23570Sstevel@tonic-gate if (isascii(*s1)) { 23580Sstevel@tonic-gate w++; 23590Sstevel@tonic-gate s1++; 23600Sstevel@tonic-gate continue; 23610Sstevel@tonic-gate } 23620Sstevel@tonic-gate 23630Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 23640Sstevel@tonic-gate w++; 23650Sstevel@tonic-gate s1++; 23660Sstevel@tonic-gate continue; 23670Sstevel@tonic-gate } 23680Sstevel@tonic-gate 23690Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 23700Sstevel@tonic-gate w_col = len; 23710Sstevel@tonic-gate s1 += len; 23720Sstevel@tonic-gate w += w_col; 23730Sstevel@tonic-gate } 23740Sstevel@tonic-gate return (w); 23750Sstevel@tonic-gate } 23760Sstevel@tonic-gate 23770Sstevel@tonic-gate /* 23780Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 23790Sstevel@tonic-gate * result in the caller-supplied buffer. 23800Sstevel@tonic-gate * 23810Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 23820Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 23830Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 23840Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 23850Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 23860Sstevel@tonic-gate * the final number has only a single significant digit, we compute 23870Sstevel@tonic-gate * tenths of units to provide a second significant digit. 23880Sstevel@tonic-gate * 23890Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 23900Sstevel@tonic-gate * converted to "-1". 23910Sstevel@tonic-gate * 23920Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 23930Sstevel@tonic-gate */ 23940Sstevel@tonic-gate static char * 23950Sstevel@tonic-gate number_to_scaled_string( 23960Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 23970Sstevel@tonic-gate unsigned long long number, /* convert this number */ 23980Sstevel@tonic-gate long scale) 23990Sstevel@tonic-gate { 24000Sstevel@tonic-gate unsigned long long save; 24010Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 24020Sstevel@tonic-gate char *uom = "KMGTPE"; 24030Sstevel@tonic-gate 24040Sstevel@tonic-gate if ((long long)number == (long long)-1) { 24050Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 24060Sstevel@tonic-gate return (buf); 24070Sstevel@tonic-gate } 24080Sstevel@tonic-gate 24090Sstevel@tonic-gate save = number; 24100Sstevel@tonic-gate number = number / scale; 24110Sstevel@tonic-gate 24120Sstevel@tonic-gate /* 24130Sstevel@tonic-gate * Now we have number as a count of scale units. 24140Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 24150Sstevel@tonic-gate * 24160Sstevel@tonic-gate * The largest value number could have had entering the routine is 24170Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 24180Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 24190Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 24200Sstevel@tonic-gate */ 24210Sstevel@tonic-gate if (number < (unsigned long long)scale) { 24220Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 24230Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 24240Sstevel@tonic-gate uom++; 24250Sstevel@tonic-gate number = 1; 24260Sstevel@tonic-gate } 24270Sstevel@tonic-gate } 24280Sstevel@tonic-gate } else { 24290Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 24300Sstevel@tonic-gate uom++; /* next unit of measurement */ 24310Sstevel@tonic-gate save = number; 24320Sstevel@tonic-gate /* 24330Sstevel@tonic-gate * If we're over half way to the next unit of 24340Sstevel@tonic-gate * 'scale' bytes (which means we should round 24350Sstevel@tonic-gate * up), then adding half of 'scale' prior to 24360Sstevel@tonic-gate * the division will push us into that next 24370Sstevel@tonic-gate * unit of scale when we perform the division 24380Sstevel@tonic-gate */ 24390Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 24400Sstevel@tonic-gate } 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate 24430Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 24440Sstevel@tonic-gate if ((save / scale) < 10) { 24450Sstevel@tonic-gate /* snprintf() will round for us */ 24460Sstevel@tonic-gate float fnum = (float)save / scale; 24470Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 24480Sstevel@tonic-gate fnum, *uom); 24490Sstevel@tonic-gate } else { 24500Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 24510Sstevel@tonic-gate number, *uom); 24520Sstevel@tonic-gate } 24530Sstevel@tonic-gate return (buf); 24540Sstevel@tonic-gate } 24555331Samw 24565331Samw /* Get extended system attributes and set the display */ 24575331Samw 24585331Samw int 24595331Samw get_sysxattr(char *fname, struct lbuf *rep) 24605331Samw { 24615331Samw boolean_t value; 24625331Samw data_type_t type; 24635331Samw int error; 24645331Samw char *name; 24655331Samw int i; 24665331Samw 24675331Samw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 24685331Samw &response)) != 0) { 24695331Samw perror("ls:getattrat"); 24705331Samw return (error); 24715331Samw } 24725331Samw 24735331Samw /* 24745331Samw * Allocate 'sacnt' size array to hold extended timestamp 24755331Samw * system attributes and initialize the array. 24765331Samw */ 24775331Samw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 24785331Samw for (i = 0; i < sacnt; i++) { 24795331Samw rep->extm[i].stm = 0; 24805331Samw rep->extm[i].nstm = 0; 24815331Samw rep->extm[i].name = NULL; 24825331Samw } 24835331Samw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 24845331Samw name = nvpair_name(pair); 24855331Samw type = nvpair_type(pair); 24865331Samw if (type == DATA_TYPE_BOOLEAN_VALUE) { 24875331Samw error = nvpair_value_boolean_value(pair, &value); 24885331Samw if (error) { 24895331Samw (void) fprintf(stderr, 24905331Samw gettext("nvpair_value_boolean_value " 24915331Samw "failed: error = %d\n"), error); 24925331Samw continue; 24935331Samw } 24945331Samw if (name != NULL) 24955331Samw set_sysattrb_display(name, value, rep); 24965331Samw continue; 24975331Samw } else if (type == DATA_TYPE_UINT64_ARRAY) { 24985331Samw if (name != NULL) 24995331Samw set_sysattrtm_display(name, rep); 25005331Samw continue; 25015331Samw } 25025331Samw } 25035331Samw nvlist_free(response); 25045331Samw return (0); 25055331Samw } 25065331Samw 25075331Samw /* Set extended system attribute boolean display */ 25085331Samw 25095331Samw void 25105331Samw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 25115331Samw { 25125331Samw f_attr_t fattr; 25135331Samw const char *opt; 25145331Samw size_t len; 25155331Samw 25165331Samw fattr = name_to_attr(name); 25175331Samw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 25185331Samw if (vopt) { 25195331Samw len = strlen(name); 25205331Samw if (val) { 25215331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 25225331Samw (void) strlcpy(rep->exttr[fattr].name, name, 25235331Samw len + 1); 25245331Samw } else { 25255331Samw rep->exttr[fattr].name = xmalloc(len + 3, rep); 25265331Samw (void) snprintf(rep->exttr[fattr].name, len + 3, 25275331Samw "no%s", name); 25285331Samw } 25295331Samw } else { 25305331Samw opt = attr_to_option(fattr); 25315331Samw if (opt != NULL) { 25325331Samw len = strlen(opt); 25335331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 25345331Samw if (val) 25355331Samw (void) strlcpy(rep->exttr[fattr].name, 25365331Samw opt, len + 1); 25375331Samw else 25385331Samw (void) strlcpy(rep->exttr[fattr].name, 25395331Samw "-", len + 1); 25405331Samw } 25415331Samw } 25425331Samw } 25435331Samw } 25445331Samw 25455331Samw /* Set extended system attribute timestamp display */ 25465331Samw 25475331Samw void 25485331Samw set_sysattrtm_display(char *name, struct lbuf *rep) 25495331Samw { 25505331Samw uint_t nelem; 25515331Samw uint64_t *value; 25525331Samw int i; 25535331Samw size_t len; 25545331Samw 25555331Samw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 25565331Samw if (*value != NULL) { 25575331Samw len = strlen(name); 25585331Samw i = 0; 25595331Samw while (rep->extm[i].stm != 0 && i < sacnt) 25605331Samw i++; 25615331Samw rep->extm[i].stm = value[0]; 25625331Samw rep->extm[i].nstm = value[1]; 25635331Samw rep->extm[i].name = xmalloc(len + 1, rep); 25645331Samw (void) strlcpy(rep->extm[i].name, name, len + 1); 25655331Samw } 25665331Samw } 25675331Samw } 25685331Samw 25695331Samw void 2570*9664Sjason@ansipunx.net format_time(time_t sec, time_t nsec) 25715331Samw { 2572*9664Sjason@ansipunx.net const char *fstr = time_fmt_new; 2573*9664Sjason@ansipunx.net char fmt_buf[FMTSIZE]; 25745331Samw 2575*9664Sjason@ansipunx.net if (Eflg) { 2576*9664Sjason@ansipunx.net (void) snprintf(fmt_buf, FMTSIZE, fstr, nsec); 2577*9664Sjason@ansipunx.net (void) strftime(time_buf, sizeof (time_buf), fmt_buf, 2578*9664Sjason@ansipunx.net localtime(&sec)); 2579*9664Sjason@ansipunx.net return; 2580*9664Sjason@ansipunx.net } 2581*9664Sjason@ansipunx.net 2582*9664Sjason@ansipunx.net if (sec < year || sec > now) 2583*9664Sjason@ansipunx.net fstr = time_fmt_old; 2584*9664Sjason@ansipunx.net 2585*9664Sjason@ansipunx.net /* if a custom time was specified, shouldn't be localized */ 25865331Samw (void) strftime(time_buf, sizeof (time_buf), 2587*9664Sjason@ansipunx.net (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr, 25885331Samw localtime(&sec)); 25895331Samw } 25905331Samw 25915331Samw void 25925331Samw format_attrtime(struct lbuf *p) 25935331Samw { 2594*9664Sjason@ansipunx.net int tmattr = 0; 25955331Samw int i; 25965331Samw 25975331Samw if (p->extm != NULL) { 25985331Samw for (i = 0; i < sacnt; i++) { 25995331Samw if (p->extm[i].name != NULL) { 26005331Samw tmattr = 1; 26015331Samw break; 26025331Samw } 26035331Samw } 26045331Samw } 2605*9664Sjason@ansipunx.net 26065331Samw if (tmattr) { 2607*9664Sjason@ansipunx.net const char *old_save = time_fmt_old; 2608*9664Sjason@ansipunx.net const char *new_save = time_fmt_new; 2609*9664Sjason@ansipunx.net 2610*9664Sjason@ansipunx.net /* Eflg always sets format to FORMAT_ISO_FULL */ 2611*9664Sjason@ansipunx.net if (!Eflg && !time_custom) { 2612*9664Sjason@ansipunx.net time_fmt_old = FORMAT_OLD; 2613*9664Sjason@ansipunx.net time_fmt_new = FORMAT_NEW; 26145331Samw } 2615*9664Sjason@ansipunx.net 2616*9664Sjason@ansipunx.net format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm); 2617*9664Sjason@ansipunx.net 2618*9664Sjason@ansipunx.net time_fmt_old = old_save; 2619*9664Sjason@ansipunx.net time_fmt_new = new_save; 26205331Samw } 26215331Samw } 26225331Samw 26235331Samw void 26245331Samw print_time(struct lbuf *p) 26255331Samw { 2626*9664Sjason@ansipunx.net const char *old_save = time_fmt_old; 2627*9664Sjason@ansipunx.net const char *new_save = time_fmt_new; 2628*9664Sjason@ansipunx.net 26295331Samw int i = 0; 26305331Samw 2631*9664Sjason@ansipunx.net if (!Eflg) { 2632*9664Sjason@ansipunx.net time_fmt_old = FORMAT_LONG; 2633*9664Sjason@ansipunx.net time_fmt_new = FORMAT_LONG; 2634*9664Sjason@ansipunx.net } 2635*9664Sjason@ansipunx.net 26365331Samw new_line(); 2637*9664Sjason@ansipunx.net format_time(p->lat.tv_sec, p->lat.tv_nsec); 2638*9664Sjason@ansipunx.net (void) printf(" timestamp: atime %s\n", time_buf); 2639*9664Sjason@ansipunx.net format_time(p->lct.tv_sec, p->lct.tv_nsec); 2640*9664Sjason@ansipunx.net (void) printf(" timestamp: ctime %s\n", time_buf); 2641*9664Sjason@ansipunx.net format_time(p->lmt.tv_sec, p->lmt.tv_nsec); 2642*9664Sjason@ansipunx.net (void) printf(" timestamp: mtime %s\n", time_buf); 2643*9664Sjason@ansipunx.net if (p->extm != NULL) { 2644*9664Sjason@ansipunx.net while (p->extm[i].nstm != 0 && i < sacnt) { 2645*9664Sjason@ansipunx.net format_time(p->extm[i].stm, p->extm[i].nstm); 2646*9664Sjason@ansipunx.net if (p->extm[i].name != NULL) { 2647*9664Sjason@ansipunx.net (void) printf(" timestamp:" 2648*9664Sjason@ansipunx.net " %s %s\n", 2649*9664Sjason@ansipunx.net p->extm[i].name, time_buf); 2650*9664Sjason@ansipunx.net } 2651*9664Sjason@ansipunx.net i++; 2652*9664Sjason@ansipunx.net } 2653*9664Sjason@ansipunx.net } 2654*9664Sjason@ansipunx.net 2655*9664Sjason@ansipunx.net time_fmt_old = old_save; 2656*9664Sjason@ansipunx.net time_fmt_new = new_save; 2657*9664Sjason@ansipunx.net } 2658*9664Sjason@ansipunx.net 2659*9664Sjason@ansipunx.net /* 2660*9664Sjason@ansipunx.net * Check if color definition applies to entry, returns 1 if yes, 0 if no 2661*9664Sjason@ansipunx.net */ 2662*9664Sjason@ansipunx.net static int 2663*9664Sjason@ansipunx.net color_match(struct lbuf *entry, ls_color_t *color) 2664*9664Sjason@ansipunx.net { 2665*9664Sjason@ansipunx.net switch (color->ftype) { 2666*9664Sjason@ansipunx.net case LS_PAT: 2667*9664Sjason@ansipunx.net { 2668*9664Sjason@ansipunx.net char *fname; 2669*9664Sjason@ansipunx.net size_t fname_len, sfx_len; 2670*9664Sjason@ansipunx.net 2671*9664Sjason@ansipunx.net if (entry->lflags & ISARG) 2672*9664Sjason@ansipunx.net fname = entry->ln.namep; 2673*9664Sjason@ansipunx.net else 2674*9664Sjason@ansipunx.net fname = entry->ln.lname; 2675*9664Sjason@ansipunx.net 2676*9664Sjason@ansipunx.net fname_len = strlen(fname); 2677*9664Sjason@ansipunx.net sfx_len = strlen(color->sfx); 2678*9664Sjason@ansipunx.net if (sfx_len > fname_len) 2679*9664Sjason@ansipunx.net return (0); 2680*9664Sjason@ansipunx.net 2681*9664Sjason@ansipunx.net if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0) 2682*9664Sjason@ansipunx.net return (1); 2683*9664Sjason@ansipunx.net else 2684*9664Sjason@ansipunx.net return (0); 2685*9664Sjason@ansipunx.net } 2686*9664Sjason@ansipunx.net 2687*9664Sjason@ansipunx.net case LS_NORMAL: 2688*9664Sjason@ansipunx.net return (1); 2689*9664Sjason@ansipunx.net 2690*9664Sjason@ansipunx.net case LS_FILE: 2691*9664Sjason@ansipunx.net return ((entry->ltype == '-')); 2692*9664Sjason@ansipunx.net 2693*9664Sjason@ansipunx.net case LS_DIR: 2694*9664Sjason@ansipunx.net return ((entry->ltype == 'd')); 2695*9664Sjason@ansipunx.net 2696*9664Sjason@ansipunx.net case LS_LINK: 2697*9664Sjason@ansipunx.net return ((entry->ltype == 'l')); 2698*9664Sjason@ansipunx.net 2699*9664Sjason@ansipunx.net case LS_FIFO: 2700*9664Sjason@ansipunx.net return ((entry->ltype == 'p')); 2701*9664Sjason@ansipunx.net 2702*9664Sjason@ansipunx.net case LS_SOCK: 2703*9664Sjason@ansipunx.net return ((entry->ltype == 's')); 2704*9664Sjason@ansipunx.net 2705*9664Sjason@ansipunx.net case LS_DOOR: 2706*9664Sjason@ansipunx.net return ((entry->ltype == 'D')); 2707*9664Sjason@ansipunx.net 2708*9664Sjason@ansipunx.net case LS_BLK: 2709*9664Sjason@ansipunx.net return ((entry->ltype == 'b')); 2710*9664Sjason@ansipunx.net 2711*9664Sjason@ansipunx.net case LS_CHR: 2712*9664Sjason@ansipunx.net return ((entry->ltype == 'c')); 2713*9664Sjason@ansipunx.net 2714*9664Sjason@ansipunx.net case LS_PORT: 2715*9664Sjason@ansipunx.net return ((entry->ltype == 'P')); 2716*9664Sjason@ansipunx.net 2717*9664Sjason@ansipunx.net case LS_ORPHAN: 2718*9664Sjason@ansipunx.net { 2719*9664Sjason@ansipunx.net struct stat st; 2720*9664Sjason@ansipunx.net int rc; 2721*9664Sjason@ansipunx.net 2722*9664Sjason@ansipunx.net if (entry->ltype != 'l') 2723*9664Sjason@ansipunx.net return (0); 2724*9664Sjason@ansipunx.net if (entry->flinkto == NULL) 2725*9664Sjason@ansipunx.net return (1); 2726*9664Sjason@ansipunx.net 2727*9664Sjason@ansipunx.net if (entry->lflags & ISARG) 2728*9664Sjason@ansipunx.net rc = stat(entry->ln.namep, &st); 2729*9664Sjason@ansipunx.net else 2730*9664Sjason@ansipunx.net rc = stat(entry->ln.lname, &st); 2731*9664Sjason@ansipunx.net 2732*9664Sjason@ansipunx.net if (rc == -1 && errno == ENOENT) 2733*9664Sjason@ansipunx.net return (1); 2734*9664Sjason@ansipunx.net 2735*9664Sjason@ansipunx.net return (0); 2736*9664Sjason@ansipunx.net } 2737*9664Sjason@ansipunx.net 2738*9664Sjason@ansipunx.net case LS_SETUID: 2739*9664Sjason@ansipunx.net return (entry->ltype != 'l' && (entry->lflags & (S_ISUID))); 2740*9664Sjason@ansipunx.net 2741*9664Sjason@ansipunx.net case LS_SETGID: 2742*9664Sjason@ansipunx.net return (entry->ltype != 'l' && (entry->lflags & (S_ISGID))); 2743*9664Sjason@ansipunx.net 2744*9664Sjason@ansipunx.net case LS_STICKY_OTHER_WRITABLE: 2745*9664Sjason@ansipunx.net return (entry->ltype != 'l' && 2746*9664Sjason@ansipunx.net (entry->lflags & (S_IWOTH|S_ISVTX))); 2747*9664Sjason@ansipunx.net 2748*9664Sjason@ansipunx.net case LS_OTHER_WRITABLE: 2749*9664Sjason@ansipunx.net return (entry->ltype != 'l' && (entry->lflags & (S_IWOTH))); 2750*9664Sjason@ansipunx.net 2751*9664Sjason@ansipunx.net case LS_STICKY: 2752*9664Sjason@ansipunx.net return (entry->ltype != 'l' && (entry->lflags & (S_ISVTX))); 2753*9664Sjason@ansipunx.net 2754*9664Sjason@ansipunx.net case LS_EXEC: 2755*9664Sjason@ansipunx.net return (entry->ltype != 'l' && 2756*9664Sjason@ansipunx.net (entry->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))); 2757*9664Sjason@ansipunx.net } 2758*9664Sjason@ansipunx.net 2759*9664Sjason@ansipunx.net return (0); 2760*9664Sjason@ansipunx.net } 2761*9664Sjason@ansipunx.net 2762*9664Sjason@ansipunx.net static void 2763*9664Sjason@ansipunx.net dump_color(ls_color_t *c) 2764*9664Sjason@ansipunx.net { 2765*9664Sjason@ansipunx.net if (c == NULL) 2766*9664Sjason@ansipunx.net return; 2767*9664Sjason@ansipunx.net 2768*9664Sjason@ansipunx.net (void) printf("\n\ttype: "); 2769*9664Sjason@ansipunx.net switch (c->ftype) { 2770*9664Sjason@ansipunx.net case LS_NORMAL: 2771*9664Sjason@ansipunx.net (void) printf("LS_NORMAL"); 2772*9664Sjason@ansipunx.net break; 2773*9664Sjason@ansipunx.net case LS_FILE: 2774*9664Sjason@ansipunx.net (void) printf("LS_FILE"); 2775*9664Sjason@ansipunx.net break; 2776*9664Sjason@ansipunx.net case LS_EXEC: 2777*9664Sjason@ansipunx.net (void) printf("LS_EXEC"); 2778*9664Sjason@ansipunx.net break; 2779*9664Sjason@ansipunx.net case LS_DIR: 2780*9664Sjason@ansipunx.net (void) printf("LS_DIR"); 2781*9664Sjason@ansipunx.net break; 2782*9664Sjason@ansipunx.net case LS_LINK: 2783*9664Sjason@ansipunx.net (void) printf("LS_LINK"); 2784*9664Sjason@ansipunx.net break; 2785*9664Sjason@ansipunx.net 2786*9664Sjason@ansipunx.net case LS_FIFO: 2787*9664Sjason@ansipunx.net (void) printf("LS_FIFO"); 2788*9664Sjason@ansipunx.net break; 2789*9664Sjason@ansipunx.net 2790*9664Sjason@ansipunx.net case LS_SOCK: 2791*9664Sjason@ansipunx.net (void) printf("LS_SOCK"); 2792*9664Sjason@ansipunx.net break; 2793*9664Sjason@ansipunx.net 2794*9664Sjason@ansipunx.net case LS_DOOR: 2795*9664Sjason@ansipunx.net (void) printf("LS_DOOR"); 2796*9664Sjason@ansipunx.net break; 2797*9664Sjason@ansipunx.net 2798*9664Sjason@ansipunx.net case LS_BLK: 2799*9664Sjason@ansipunx.net (void) printf("LS_BLK"); 2800*9664Sjason@ansipunx.net break; 2801*9664Sjason@ansipunx.net 2802*9664Sjason@ansipunx.net case LS_CHR: 2803*9664Sjason@ansipunx.net (void) printf("LS_CHR"); 2804*9664Sjason@ansipunx.net break; 2805*9664Sjason@ansipunx.net 2806*9664Sjason@ansipunx.net case LS_PORT: 2807*9664Sjason@ansipunx.net (void) printf("LS_PORT"); 2808*9664Sjason@ansipunx.net break; 2809*9664Sjason@ansipunx.net 2810*9664Sjason@ansipunx.net case LS_STICKY: 2811*9664Sjason@ansipunx.net (void) printf("LS_STICKY"); 2812*9664Sjason@ansipunx.net break; 2813*9664Sjason@ansipunx.net 2814*9664Sjason@ansipunx.net case LS_ORPHAN: 2815*9664Sjason@ansipunx.net (void) printf("LS_ORPHAN"); 2816*9664Sjason@ansipunx.net break; 2817*9664Sjason@ansipunx.net 2818*9664Sjason@ansipunx.net case LS_SETGID: 2819*9664Sjason@ansipunx.net (void) printf("LS_SETGID"); 2820*9664Sjason@ansipunx.net break; 2821*9664Sjason@ansipunx.net 2822*9664Sjason@ansipunx.net case LS_SETUID: 2823*9664Sjason@ansipunx.net (void) printf("LS_SETUID"); 2824*9664Sjason@ansipunx.net break; 2825*9664Sjason@ansipunx.net 2826*9664Sjason@ansipunx.net case LS_OTHER_WRITABLE: 2827*9664Sjason@ansipunx.net (void) printf("LS_OTHER_WRITABLE"); 2828*9664Sjason@ansipunx.net break; 2829*9664Sjason@ansipunx.net 2830*9664Sjason@ansipunx.net case LS_STICKY_OTHER_WRITABLE: 2831*9664Sjason@ansipunx.net (void) printf("LS_STICKY_OTHER_WRITABLE"); 2832*9664Sjason@ansipunx.net break; 2833*9664Sjason@ansipunx.net 2834*9664Sjason@ansipunx.net case LS_PAT: 2835*9664Sjason@ansipunx.net (void) printf("LS_PAT\n"); 2836*9664Sjason@ansipunx.net (void) printf("\tpattern: %s", c->sfx); 2837*9664Sjason@ansipunx.net break; 2838*9664Sjason@ansipunx.net } 2839*9664Sjason@ansipunx.net (void) printf("\n"); 2840*9664Sjason@ansipunx.net (void) printf("\tattr: %d\n", c->attr); 2841*9664Sjason@ansipunx.net (void) printf("\tfg: %d\n", c->fg); 2842*9664Sjason@ansipunx.net (void) printf("\tbg: %d\n", c->bg); 2843*9664Sjason@ansipunx.net (void) printf("\t"); 2844*9664Sjason@ansipunx.net } 2845*9664Sjason@ansipunx.net 2846*9664Sjason@ansipunx.net static ls_color_t * 2847*9664Sjason@ansipunx.net get_color_attr(struct lbuf *l) 2848*9664Sjason@ansipunx.net { 2849*9664Sjason@ansipunx.net int i; 2850*9664Sjason@ansipunx.net 2851*9664Sjason@ansipunx.net /* 2852*9664Sjason@ansipunx.net * Colors are sorted from most general lsc_colors[0] to most specific 2853*9664Sjason@ansipunx.net * lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with 2854*9664Sjason@ansipunx.net * most specific color rule and work towards most general. 2855*9664Sjason@ansipunx.net */ 2856*9664Sjason@ansipunx.net for (i = lsc_ncolors - 1; i >= 0; --i) 2857*9664Sjason@ansipunx.net if (color_match(l, &lsc_colors[i])) 2858*9664Sjason@ansipunx.net return (&lsc_colors[i]); 2859*9664Sjason@ansipunx.net 2860*9664Sjason@ansipunx.net return (NULL); 2861*9664Sjason@ansipunx.net } 2862*9664Sjason@ansipunx.net 2863*9664Sjason@ansipunx.net static void 2864*9664Sjason@ansipunx.net ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4, 2865*9664Sjason@ansipunx.net long int p5, long int p6, long int p7, long int p8, long int p9) 2866*9664Sjason@ansipunx.net { 2867*9664Sjason@ansipunx.net char *s; 2868*9664Sjason@ansipunx.net 2869*9664Sjason@ansipunx.net if (str == NULL) 2870*9664Sjason@ansipunx.net return; 2871*9664Sjason@ansipunx.net 2872*9664Sjason@ansipunx.net s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); 2873*9664Sjason@ansipunx.net 2874*9664Sjason@ansipunx.net if (s != NULL) 2875*9664Sjason@ansipunx.net (void) putp(s); 2876*9664Sjason@ansipunx.net } 2877*9664Sjason@ansipunx.net 2878*9664Sjason@ansipunx.net static void 2879*9664Sjason@ansipunx.net ls_start_color(struct lbuf *l) 2880*9664Sjason@ansipunx.net { 2881*9664Sjason@ansipunx.net ls_color_t *c = get_color_attr(l); 2882*9664Sjason@ansipunx.net 2883*9664Sjason@ansipunx.net if (c == NULL) 2884*9664Sjason@ansipunx.net return; 2885*9664Sjason@ansipunx.net 2886*9664Sjason@ansipunx.net if (lsc_debug) 2887*9664Sjason@ansipunx.net lsc_match = c; 2888*9664Sjason@ansipunx.net 2889*9664Sjason@ansipunx.net if (c->attr & LSA_BOLD) 2890*9664Sjason@ansipunx.net ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2891*9664Sjason@ansipunx.net if (c->attr & LSA_UNDERSCORE) 2892*9664Sjason@ansipunx.net ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2893*9664Sjason@ansipunx.net if (c->attr & LSA_BLINK) 2894*9664Sjason@ansipunx.net ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2895*9664Sjason@ansipunx.net if (c->attr & LSA_REVERSE) 2896*9664Sjason@ansipunx.net ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2897*9664Sjason@ansipunx.net if (c->attr & LSA_CONCEALED) 2898*9664Sjason@ansipunx.net ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2899*9664Sjason@ansipunx.net if (c->attr == LSA_NONE) 2900*9664Sjason@ansipunx.net ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2901*9664Sjason@ansipunx.net 2902*9664Sjason@ansipunx.net if (c->fg != -1) 2903*9664Sjason@ansipunx.net ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0); 2904*9664Sjason@ansipunx.net if (c->bg != -1) 2905*9664Sjason@ansipunx.net ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0); 2906*9664Sjason@ansipunx.net } 2907*9664Sjason@ansipunx.net 2908*9664Sjason@ansipunx.net static void 2909*9664Sjason@ansipunx.net ls_end_color() 2910*9664Sjason@ansipunx.net { 2911*9664Sjason@ansipunx.net ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2912*9664Sjason@ansipunx.net if (lsc_debug) 2913*9664Sjason@ansipunx.net dump_color(lsc_match); 2914*9664Sjason@ansipunx.net } 2915*9664Sjason@ansipunx.net 2916*9664Sjason@ansipunx.net static void 2917*9664Sjason@ansipunx.net new_color_entry(char *colorstr) 2918*9664Sjason@ansipunx.net { 2919*9664Sjason@ansipunx.net static const struct { 2920*9664Sjason@ansipunx.net const char *s; 2921*9664Sjason@ansipunx.net ls_cftype_t stype; 2922*9664Sjason@ansipunx.net } type_map[] = { 2923*9664Sjason@ansipunx.net { "no", LS_NORMAL }, 2924*9664Sjason@ansipunx.net { "fi", LS_FILE }, 2925*9664Sjason@ansipunx.net { "di", LS_DIR }, 2926*9664Sjason@ansipunx.net { "ln", LS_LINK }, 2927*9664Sjason@ansipunx.net { "pi", LS_FIFO }, 2928*9664Sjason@ansipunx.net { "so", LS_SOCK }, 2929*9664Sjason@ansipunx.net { "do", LS_DOOR }, 2930*9664Sjason@ansipunx.net { "bd", LS_BLK }, 2931*9664Sjason@ansipunx.net { "cd", LS_CHR }, 2932*9664Sjason@ansipunx.net { "or", LS_ORPHAN }, 2933*9664Sjason@ansipunx.net { "su", LS_SETUID }, 2934*9664Sjason@ansipunx.net { "sg", LS_SETGID }, 2935*9664Sjason@ansipunx.net { "tw", LS_STICKY_OTHER_WRITABLE }, 2936*9664Sjason@ansipunx.net { "ow", LS_OTHER_WRITABLE }, 2937*9664Sjason@ansipunx.net { "st", LS_STICKY }, 2938*9664Sjason@ansipunx.net { "ex", LS_EXEC }, 2939*9664Sjason@ansipunx.net { "po", LS_PORT }, 2940*9664Sjason@ansipunx.net { NULL, LS_NORMAL } 2941*9664Sjason@ansipunx.net }; 2942*9664Sjason@ansipunx.net 2943*9664Sjason@ansipunx.net char *p, *lasts; 2944*9664Sjason@ansipunx.net int i; 2945*9664Sjason@ansipunx.net int color, attr; 2946*9664Sjason@ansipunx.net 2947*9664Sjason@ansipunx.net p = strtok_r(colorstr, "=", &lasts); 2948*9664Sjason@ansipunx.net if (p == NULL) { 2949*9664Sjason@ansipunx.net colorflg = 0; 2950*9664Sjason@ansipunx.net return; 2951*9664Sjason@ansipunx.net } 2952*9664Sjason@ansipunx.net 2953*9664Sjason@ansipunx.net if (p[0] == '*') { 2954*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].ftype = LS_PAT; 2955*9664Sjason@ansipunx.net /* don't include the * in the suffix */ 2956*9664Sjason@ansipunx.net if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) { 2957*9664Sjason@ansipunx.net colorflg = 0; 2958*9664Sjason@ansipunx.net return; 2959*9664Sjason@ansipunx.net } 2960*9664Sjason@ansipunx.net } else { 2961*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].sfx = NULL; 2962*9664Sjason@ansipunx.net 2963*9664Sjason@ansipunx.net for (i = 0; type_map[i].s != NULL; ++i) { 2964*9664Sjason@ansipunx.net if (strncmp(type_map[i].s, p, 2) == 0) 2965*9664Sjason@ansipunx.net break; 2966*9664Sjason@ansipunx.net } 2967*9664Sjason@ansipunx.net 2968*9664Sjason@ansipunx.net /* ignore unknown file types */ 2969*9664Sjason@ansipunx.net if (type_map[i].s == NULL) 2970*9664Sjason@ansipunx.net return; 2971*9664Sjason@ansipunx.net 2972*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].ftype = type_map[i].stype; 2973*9664Sjason@ansipunx.net } 2974*9664Sjason@ansipunx.net 2975*9664Sjason@ansipunx.net attr = LSA_NONE; 2976*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].fg = -1; 2977*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].bg = -1; 2978*9664Sjason@ansipunx.net for (p = strtok_r(NULL, ";", &lasts); p != NULL; 2979*9664Sjason@ansipunx.net p = strtok_r(NULL, ";", &lasts)) { 2980*9664Sjason@ansipunx.net color = strtol(p, NULL, 10); 2981*9664Sjason@ansipunx.net 2982*9664Sjason@ansipunx.net if (color < 10) { 2983*9664Sjason@ansipunx.net switch (color) { 2984*9664Sjason@ansipunx.net case 0: 2985*9664Sjason@ansipunx.net attr = LSA_NONE; 2986*9664Sjason@ansipunx.net continue; 2987*9664Sjason@ansipunx.net case 1: 2988*9664Sjason@ansipunx.net attr |= LSA_BOLD; 2989*9664Sjason@ansipunx.net continue; 2990*9664Sjason@ansipunx.net case 4: 2991*9664Sjason@ansipunx.net attr |= LSA_UNDERSCORE; 2992*9664Sjason@ansipunx.net continue; 2993*9664Sjason@ansipunx.net case 5: 2994*9664Sjason@ansipunx.net attr |= LSA_BLINK; 2995*9664Sjason@ansipunx.net continue; 2996*9664Sjason@ansipunx.net case 7: 2997*9664Sjason@ansipunx.net attr |= LSA_REVERSE; 2998*9664Sjason@ansipunx.net continue; 2999*9664Sjason@ansipunx.net case 8: 3000*9664Sjason@ansipunx.net attr |= LSA_CONCEALED; 3001*9664Sjason@ansipunx.net continue; 3002*9664Sjason@ansipunx.net default: 3003*9664Sjason@ansipunx.net continue; 30045331Samw } 30055331Samw } 3006*9664Sjason@ansipunx.net 3007*9664Sjason@ansipunx.net if (color < 40) 3008*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].fg = color - 30; 3009*9664Sjason@ansipunx.net else 3010*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].bg = color - 40; 3011*9664Sjason@ansipunx.net } 3012*9664Sjason@ansipunx.net 3013*9664Sjason@ansipunx.net lsc_colors[lsc_ncolors].attr = attr; 3014*9664Sjason@ansipunx.net ++lsc_ncolors; 3015*9664Sjason@ansipunx.net } 3016*9664Sjason@ansipunx.net 3017*9664Sjason@ansipunx.net static int 3018*9664Sjason@ansipunx.net ls_color_compare(const void *p1, const void *p2) 3019*9664Sjason@ansipunx.net { 3020*9664Sjason@ansipunx.net const ls_color_t *c1 = (const ls_color_t *)p1; 3021*9664Sjason@ansipunx.net const ls_color_t *c2 = (const ls_color_t *)p2; 3022*9664Sjason@ansipunx.net 3023*9664Sjason@ansipunx.net int ret = c1->ftype - c2->ftype; 3024*9664Sjason@ansipunx.net 3025*9664Sjason@ansipunx.net if (ret != 0) 3026*9664Sjason@ansipunx.net return (ret); 3027*9664Sjason@ansipunx.net 3028*9664Sjason@ansipunx.net if (c1->ftype != LS_PAT) 3029*9664Sjason@ansipunx.net return (ret); 3030*9664Sjason@ansipunx.net 3031*9664Sjason@ansipunx.net return (strcmp(c1->sfx, c2->sfx)); 3032*9664Sjason@ansipunx.net } 3033*9664Sjason@ansipunx.net 3034*9664Sjason@ansipunx.net static void 3035*9664Sjason@ansipunx.net ls_color_init() 3036*9664Sjason@ansipunx.net { 3037*9664Sjason@ansipunx.net static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35" 3038*9664Sjason@ansipunx.net ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01" 3039*9664Sjason@ansipunx.net ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31" 3040*9664Sjason@ansipunx.net ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31" 3041*9664Sjason@ansipunx.net ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31" 3042*9664Sjason@ansipunx.net ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35" 3043*9664Sjason@ansipunx.net ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35" 3044*9664Sjason@ansipunx.net ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35" 3045*9664Sjason@ansipunx.net ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35" 3046*9664Sjason@ansipunx.net ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35" 3047*9664Sjason@ansipunx.net ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35"; 3048*9664Sjason@ansipunx.net 3049*9664Sjason@ansipunx.net char *colorstr; 3050*9664Sjason@ansipunx.net char *p, *lasts; 3051*9664Sjason@ansipunx.net size_t color_sz; 3052*9664Sjason@ansipunx.net int termret; 3053*9664Sjason@ansipunx.net 3054*9664Sjason@ansipunx.net (void) setupterm(NULL, 1, &termret); 3055*9664Sjason@ansipunx.net if (termret != 1) 3056*9664Sjason@ansipunx.net return; 3057*9664Sjason@ansipunx.net 3058*9664Sjason@ansipunx.net if ((colorstr = getenv("LS_COLORS")) == NULL) 3059*9664Sjason@ansipunx.net colorstr = default_colorstr; 3060*9664Sjason@ansipunx.net 3061*9664Sjason@ansipunx.net color_sz = 0; 3062*9664Sjason@ansipunx.net for (p = strchr(colorstr, ':'); p != NULL && *p != '\0'; 3063*9664Sjason@ansipunx.net p = strchr(++p, ':')) 3064*9664Sjason@ansipunx.net ++color_sz; 3065*9664Sjason@ansipunx.net 3066*9664Sjason@ansipunx.net lsc_colors = calloc(color_sz, sizeof (ls_color_t)); 3067*9664Sjason@ansipunx.net if (lsc_colors == NULL) { 3068*9664Sjason@ansipunx.net free(colorstr); 3069*9664Sjason@ansipunx.net return; 3070*9664Sjason@ansipunx.net } 3071*9664Sjason@ansipunx.net 3072*9664Sjason@ansipunx.net for (p = strtok_r(colorstr, ":", &lasts); 3073*9664Sjason@ansipunx.net p != NULL && lsc_ncolors < color_sz; 3074*9664Sjason@ansipunx.net p = strtok_r(NULL, ":", &lasts)) 3075*9664Sjason@ansipunx.net new_color_entry(p); 3076*9664Sjason@ansipunx.net 3077*9664Sjason@ansipunx.net qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t), 3078*9664Sjason@ansipunx.net ls_color_compare); 3079*9664Sjason@ansipunx.net 3080*9664Sjason@ansipunx.net if ((lsc_bold = tigetstr("bold")) == (char *)-1) 3081*9664Sjason@ansipunx.net lsc_bold = NULL; 3082*9664Sjason@ansipunx.net 3083*9664Sjason@ansipunx.net if ((lsc_underline = tigetstr("smul")) == (char *)-1) 3084*9664Sjason@ansipunx.net lsc_underline = NULL; 3085*9664Sjason@ansipunx.net 3086*9664Sjason@ansipunx.net if ((lsc_blink = tigetstr("blink")) == (char *)-1) 3087*9664Sjason@ansipunx.net lsc_blink = NULL; 3088*9664Sjason@ansipunx.net 3089*9664Sjason@ansipunx.net if ((lsc_reverse = tigetstr("rev")) == (char *)-1) 3090*9664Sjason@ansipunx.net lsc_reverse = NULL; 3091*9664Sjason@ansipunx.net 3092*9664Sjason@ansipunx.net if ((lsc_concealed = tigetstr("prot")) == (char *)-1) 3093*9664Sjason@ansipunx.net lsc_concealed = NULL; 3094*9664Sjason@ansipunx.net 3095*9664Sjason@ansipunx.net if ((lsc_none = tigetstr("sgr0")) == (char *)-1) 3096*9664Sjason@ansipunx.net lsc_none = NULL; 3097*9664Sjason@ansipunx.net 3098*9664Sjason@ansipunx.net if ((lsc_setfg = tigetstr("setaf")) == (char *)-1) 3099*9664Sjason@ansipunx.net lsc_setfg = NULL; 3100*9664Sjason@ansipunx.net 3101*9664Sjason@ansipunx.net if ((lsc_setbg = tigetstr("setab")) == (char *)-1) 3102*9664Sjason@ansipunx.net lsc_setbg = NULL; 3103*9664Sjason@ansipunx.net 3104*9664Sjason@ansipunx.net if (getenv("_LS_COLOR_DEBUG") != NULL) { 3105*9664Sjason@ansipunx.net int i; 3106*9664Sjason@ansipunx.net 3107*9664Sjason@ansipunx.net lsc_debug = 1; 3108*9664Sjason@ansipunx.net for (i = 0; i < lsc_ncolors; ++i) 3109*9664Sjason@ansipunx.net dump_color(&lsc_colors[i]); 31105331Samw } 31115331Samw } 31125331Samw 31135331Samw /* Free extended system attribute lists */ 31145331Samw 31155331Samw void 31165331Samw free_sysattr(struct lbuf *p) 31175331Samw { 31185331Samw int i; 31195331Samw 31205331Samw if (p->exttr != NULL) { 31215331Samw for (i = 0; i < sacnt; i++) { 31225331Samw if (p->exttr[i].name != NULL) 31235331Samw free(p->exttr[i].name); 31245331Samw } 31255331Samw free(p->exttr); 31265331Samw } 31275331Samw if (p->extm != NULL) { 31285331Samw for (i = 0; i < sacnt; i++) { 31295331Samw if (p->extm[i].name != NULL) 31305331Samw free(p->extm[i].name); 31315331Samw } 31325331Samw free(p->extm); 31335331Samw } 31345331Samw } 31355331Samw 31365331Samw /* Allocate extended system attribute list */ 31375331Samw 31385331Samw void * 31395331Samw xmalloc(size_t size, struct lbuf *p) 31405331Samw { 31415331Samw if ((p = malloc(size)) == NULL) { 31425331Samw perror("ls"); 31435331Samw free_sysattr(p); 31445331Samw nvlist_free(response); 31455331Samw exit(2); 31465331Samw } 31475331Samw return (p); 31485331Samw } 3149