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 */ 219664Sjason@ansipunx.net 220Sstevel@tonic-gate /* 239664Sjason@ansipunx.net * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 249664Sjason@ansipunx.net * Use is subject to license terms. 259664Sjason@ansipunx.net */ 269664Sjason@ansipunx.net 279664Sjason@ansipunx.net /* 289664Sjason@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> 559664Sjason@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> 729664Sjason@ansipunx.net #include <getopt.h> 739664Sjason@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 */ 1179664Sjason@ansipunx.net #define FORMAT_OLD " %b %e %Y " 1189664Sjason@ansipunx.net #define FORMAT_NEW " %b %e %H:%M " 1199664Sjason@ansipunx.net #define FORMAT_LONG " %b %e %T %Y " 1209664Sjason@ansipunx.net #define FORMAT_ISO_FULL " %%F %%T.%.09ld %%z " 1219664Sjason@ansipunx.net #define FORMAT_ISO_LONG " %F %R " 1229664Sjason@ansipunx.net #define FORMAT_ISO_NEW " %m-%d %H:%M " 1239664Sjason@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 1469664Sjason@ansipunx.net #define LSA_NONE (0) 1479664Sjason@ansipunx.net #define LSA_BOLD (1L << 0) 1489664Sjason@ansipunx.net #define LSA_UNDERSCORE (1L << 1) 1499664Sjason@ansipunx.net #define LSA_BLINK (1L << 2) 1509664Sjason@ansipunx.net #define LSA_REVERSE (1L << 3) 1519664Sjason@ansipunx.net #define LSA_CONCEALED (1L << 4) 1529664Sjason@ansipunx.net 1539664Sjason@ansipunx.net /* these should be ordered most general to most specific */ 1549664Sjason@ansipunx.net typedef enum LS_CFTYPE { 1559664Sjason@ansipunx.net LS_NORMAL, 1569664Sjason@ansipunx.net LS_FILE, 1579664Sjason@ansipunx.net LS_EXEC, 1589664Sjason@ansipunx.net LS_DIR, 1599664Sjason@ansipunx.net LS_LINK, 1609664Sjason@ansipunx.net LS_FIFO, 1619664Sjason@ansipunx.net LS_SOCK, 1629664Sjason@ansipunx.net LS_DOOR, 1639664Sjason@ansipunx.net LS_BLK, 1649664Sjason@ansipunx.net LS_CHR, 1659664Sjason@ansipunx.net LS_PORT, 1669664Sjason@ansipunx.net LS_STICKY, 1679664Sjason@ansipunx.net LS_ORPHAN, 1689664Sjason@ansipunx.net LS_SETGID, 1699664Sjason@ansipunx.net LS_SETUID, 1709664Sjason@ansipunx.net LS_OTHER_WRITABLE, 1719664Sjason@ansipunx.net LS_STICKY_OTHER_WRITABLE, 1729664Sjason@ansipunx.net LS_PAT 1739664Sjason@ansipunx.net } ls_cftype_t; 1749664Sjason@ansipunx.net 175*10059Sjason@ansipunx.net typedef struct { 1769664Sjason@ansipunx.net char *sfx; 1779664Sjason@ansipunx.net ls_cftype_t ftype; 1789664Sjason@ansipunx.net int attr; 1799664Sjason@ansipunx.net int fg; 1809664Sjason@ansipunx.net int bg; 1819664Sjason@ansipunx.net } ls_color_t; 1829664Sjason@ansipunx.net 183*10059Sjason@ansipunx.net struct lbuf { 184*10059Sjason@ansipunx.net union { 185*10059Sjason@ansipunx.net char lname[MAXNAMLEN]; /* used for filename in a directory */ 186*10059Sjason@ansipunx.net char *namep; /* for name in ls-command; */ 187*10059Sjason@ansipunx.net } ln; 188*10059Sjason@ansipunx.net char ltype; /* filetype */ 189*10059Sjason@ansipunx.net ino_t lnum; /* inode number of file */ 190*10059Sjason@ansipunx.net mode_t lflags; /* 0777 bits used as r,w,x permissions */ 191*10059Sjason@ansipunx.net nlink_t lnl; /* number of links to file */ 192*10059Sjason@ansipunx.net uid_t luid; 193*10059Sjason@ansipunx.net gid_t lgid; 194*10059Sjason@ansipunx.net off_t lsize; /* filesize or major/minor dev numbers */ 195*10059Sjason@ansipunx.net blkcnt_t lblocks; /* number of file blocks */ 196*10059Sjason@ansipunx.net timestruc_t lmtime; 197*10059Sjason@ansipunx.net timestruc_t lat; 198*10059Sjason@ansipunx.net timestruc_t lct; 199*10059Sjason@ansipunx.net timestruc_t lmt; 200*10059Sjason@ansipunx.net char *flinkto; /* symbolic link contents */ 201*10059Sjason@ansipunx.net char acl; /* indicate there are additional acl entries */ 202*10059Sjason@ansipunx.net int cycle; /* cycle detected flag */ 203*10059Sjason@ansipunx.net struct ditem *ancinfo; /* maintains ancestor info */ 204*10059Sjason@ansipunx.net acl_t *aclp; /* ACL if present */ 205*10059Sjason@ansipunx.net struct attrb *exttr; /* boolean extended system attributes */ 206*10059Sjason@ansipunx.net struct attrtm *extm; /* timestamp extended system attributes */ 207*10059Sjason@ansipunx.net ls_color_t *color; /* color for entry */ 208*10059Sjason@ansipunx.net ls_color_t *link_color; /* color for symlink */ 209*10059Sjason@ansipunx.net }; 210*10059Sjason@ansipunx.net 211*10059Sjason@ansipunx.net struct dchain { 212*10059Sjason@ansipunx.net char *dc_name; /* path name */ 213*10059Sjason@ansipunx.net int cycle_detected; /* cycle detected visiting this directory */ 214*10059Sjason@ansipunx.net struct ditem *myancinfo; /* this directory's ancestry info */ 215*10059Sjason@ansipunx.net struct dchain *dc_next; /* next directory in the chain */ 216*10059Sjason@ansipunx.net }; 217*10059Sjason@ansipunx.net 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 2240Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 2250Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 2260Sstevel@tonic-gate static char *curdir; /* the current directory */ 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 2290Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 2300Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 2310Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 2320Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 2330Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 2360Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 2370Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 2380Sstevel@tonic-gate static char *getname(uid_t); 2390Sstevel@tonic-gate static char *getgroup(gid_t); 2400Sstevel@tonic-gate static char *makename(char *, char *); 2410Sstevel@tonic-gate static void pentry(struct lbuf *); 2420Sstevel@tonic-gate static void column(void); 2430Sstevel@tonic-gate static void pmode(mode_t aflag); 2440Sstevel@tonic-gate static void selection(int *); 2450Sstevel@tonic-gate static void new_line(void); 2460Sstevel@tonic-gate static void rddir(char *, struct ditem *); 2470Sstevel@tonic-gate static int strcol(unsigned char *); 2480Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 2490Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 2500Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 2510Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 2520Sstevel@tonic-gate static void pprintf(char *, char *); 2530Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 2540Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 2550Sstevel@tonic-gate unsigned long long number, 2560Sstevel@tonic-gate long scale); 2570Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 2580Sstevel@tonic-gate int, struct ditem *); 2599664Sjason@ansipunx.net static void ls_color_init(void); 260*10059Sjason@ansipunx.net static ls_color_t *ls_color_find(const char *, mode_t); 261*10059Sjason@ansipunx.net static void ls_start_color(ls_color_t *); 2629664Sjason@ansipunx.net static void ls_end_color(void); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate static int aflg; 2650Sstevel@tonic-gate static int atflg; 2660Sstevel@tonic-gate static int bflg; 2670Sstevel@tonic-gate static int cflg; 2680Sstevel@tonic-gate static int dflg; 2690Sstevel@tonic-gate static int eflg; 2700Sstevel@tonic-gate static int fflg; 2710Sstevel@tonic-gate static int gflg; 2720Sstevel@tonic-gate static int hflg; 2730Sstevel@tonic-gate static int iflg; 2740Sstevel@tonic-gate static int lflg; 2750Sstevel@tonic-gate static int mflg; 2760Sstevel@tonic-gate static int nflg; 2770Sstevel@tonic-gate static int oflg; 2780Sstevel@tonic-gate static int pflg; 2790Sstevel@tonic-gate static int qflg; 2800Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2810Sstevel@tonic-gate static int sflg; 2820Sstevel@tonic-gate static int tflg; 2830Sstevel@tonic-gate static int uflg; 2849664Sjason@ansipunx.net static int Uflg; 2859664Sjason@ansipunx.net static int wflg; 2860Sstevel@tonic-gate static int xflg; 2870Sstevel@tonic-gate static int Aflg; 2889664Sjason@ansipunx.net static int Bflg; 2890Sstevel@tonic-gate static int Cflg; 2900Sstevel@tonic-gate static int Eflg; 2910Sstevel@tonic-gate static int Fflg; 2920Sstevel@tonic-gate static int Hflg; 2930Sstevel@tonic-gate static int Lflg; 2940Sstevel@tonic-gate static int Rflg; 2950Sstevel@tonic-gate static int Sflg; 296789Sahrens static int vflg; 2971420Smarks static int Vflg; 2985331Samw static int saflg; /* boolean extended system attr. */ 2995331Samw static int sacnt; /* number of extended system attr. */ 3005331Samw static int copt; 3015331Samw static int vopt; 3025331Samw static int tmflg; /* create time ext. system attr. */ 3035331Samw static int ctm; 3045331Samw static int atm; 3055331Samw static int mtm; 3065331Samw static int crtm; 3075331Samw static int alltm; 3080Sstevel@tonic-gate static long hscale; 3090Sstevel@tonic-gate static mode_t flags; 3100Sstevel@tonic-gate static int err = 0; /* Contains return code */ 3119664Sjason@ansipunx.net static int colorflg; 3129664Sjason@ansipunx.net static int file_typeflg; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 3150Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 3160Sstevel@tonic-gate static char *lastuname = NULL; 3170Sstevel@tonic-gate static char *lastgname = NULL; 3180Sstevel@tonic-gate 3199664Sjason@ansipunx.net /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */ 3200Sstevel@tonic-gate static int statreq; 3210Sstevel@tonic-gate 3229664Sjason@ansipunx.net static uint64_t block_size = 1; 3230Sstevel@tonic-gate static char *dotp = "."; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 3260Sstevel@tonic-gate static time_t year, now; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate static int num_cols = 80; 3290Sstevel@tonic-gate static int colwidth; 3300Sstevel@tonic-gate static int filewidth; 3310Sstevel@tonic-gate static int fixedwidth; 3320Sstevel@tonic-gate static int nomocore; 3330Sstevel@tonic-gate static int curcol; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate static struct winsize win; 3360Sstevel@tonic-gate 3379664Sjason@ansipunx.net /* if time_fmt_new is left NULL, time_fmt_old is used for all times */ 3389664Sjason@ansipunx.net static const char *time_fmt_old = FORMAT_OLD; /* non-recent files */ 3399664Sjason@ansipunx.net static const char *time_fmt_new = FORMAT_NEW; /* recent files */ 3409664Sjason@ansipunx.net static int time_custom; /* != 0 if a custom format */ 3415331Samw static char time_buf[FMTSIZE]; /* array to hold day and time */ 3420Sstevel@tonic-gate 3439664Sjason@ansipunx.net static int lsc_debug; 3449664Sjason@ansipunx.net static ls_color_t *lsc_match; 3459664Sjason@ansipunx.net static ls_color_t *lsc_colors; 3469664Sjason@ansipunx.net static size_t lsc_ncolors; 3479664Sjason@ansipunx.net static char *lsc_bold; 3489664Sjason@ansipunx.net static char *lsc_underline; 3499664Sjason@ansipunx.net static char *lsc_blink; 3509664Sjason@ansipunx.net static char *lsc_reverse; 3519664Sjason@ansipunx.net static char *lsc_concealed; 3529664Sjason@ansipunx.net static char *lsc_none; 3539664Sjason@ansipunx.net static char *lsc_setfg; 3549664Sjason@ansipunx.net static char *lsc_setbg; 355*10059Sjason@ansipunx.net static ls_color_t *lsc_orphan; 3569664Sjason@ansipunx.net 3570Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 3580Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 3610Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 3625331Samw /* Extended system attributes support */ 3635331Samw static int get_sysxattr(char *, struct lbuf *); 3645331Samw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 3655331Samw static void set_sysattrtm_display(char *, struct lbuf *); 3669664Sjason@ansipunx.net static void format_time(time_t, time_t); 3675331Samw static void print_time(struct lbuf *); 3685331Samw static void format_attrtime(struct lbuf *); 3695331Samw static void *xmalloc(size_t, struct lbuf *); 3705331Samw static void free_sysattr(struct lbuf *); 3715331Samw static nvpair_t *pair; 3725331Samw static nvlist_t *response; 3736866Sbasabi static int acl_err; 3740Sstevel@tonic-gate 3759664Sjason@ansipunx.net const struct option long_options[] = { 3769664Sjason@ansipunx.net { "all", no_argument, NULL, 'a' }, 3779664Sjason@ansipunx.net { "almost-all", no_argument, NULL, 'A' }, 3789664Sjason@ansipunx.net { "escape", no_argument, NULL, 'b' }, 3799664Sjason@ansipunx.net { "classify", no_argument, NULL, 'F' }, 3809664Sjason@ansipunx.net { "human-readable", no_argument, NULL, 'h' }, 3819664Sjason@ansipunx.net { "dereference", no_argument, NULL, 'L' }, 3829664Sjason@ansipunx.net { "dereference-command-line", no_argument, NULL, 'H' }, 3839664Sjason@ansipunx.net { "ignore-backups", no_argument, NULL, 'B' }, 3849664Sjason@ansipunx.net { "inode", no_argument, NULL, 'i' }, 3859664Sjason@ansipunx.net { "numeric-uid-gid", no_argument, NULL, 'n' }, 3869664Sjason@ansipunx.net { "no-group", no_argument, NULL, 'o' }, 3879664Sjason@ansipunx.net { "hide-control-chars", no_argument, NULL, 'q' }, 3889664Sjason@ansipunx.net { "reverse", no_argument, NULL, 'r' }, 3899664Sjason@ansipunx.net { "recursive", no_argument, NULL, 'R' }, 3909664Sjason@ansipunx.net { "size", no_argument, NULL, 's' }, 3919664Sjason@ansipunx.net { "width", required_argument, NULL, 'w' }, 3929664Sjason@ansipunx.net 3939664Sjason@ansipunx.net /* no short options for these */ 3949664Sjason@ansipunx.net { "block-size", required_argument, NULL, 0 }, 3959664Sjason@ansipunx.net { "full-time", no_argument, NULL, 0 }, 3969664Sjason@ansipunx.net { "si", no_argument, NULL, 0 }, 3979664Sjason@ansipunx.net { "color", optional_argument, NULL, 0 }, 3989664Sjason@ansipunx.net { "colour", optional_argument, NULL, 0}, 3999664Sjason@ansipunx.net { "file-type", no_argument, NULL, 0 }, 4009664Sjason@ansipunx.net { "time-style", required_argument, NULL, 0 }, 4019664Sjason@ansipunx.net 4029664Sjason@ansipunx.net {0, 0, 0, 0} 4039664Sjason@ansipunx.net }; 4049664Sjason@ansipunx.net 4050Sstevel@tonic-gate int 4060Sstevel@tonic-gate main(int argc, char *argv[]) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate int c; 4090Sstevel@tonic-gate int i; 4100Sstevel@tonic-gate int width; 4110Sstevel@tonic-gate int amino = 0; 4120Sstevel@tonic-gate int opterr = 0; 4139664Sjason@ansipunx.net int option_index = 0; 4140Sstevel@tonic-gate struct lbuf *ep; 4150Sstevel@tonic-gate struct lbuf lb; 4160Sstevel@tonic-gate struct ditem *myinfo; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4190Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 4200Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 4210Sstevel@tonic-gate #endif 4220Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4230Sstevel@tonic-gate #ifdef STANDALONE 4240Sstevel@tonic-gate if (argv[0][0] == '\0') 4250Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 4260Sstevel@tonic-gate #endif 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 4290Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 4300Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 4310Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 4320Sstevel@tonic-gate if (isatty(1)) { 4330Sstevel@tonic-gate Cflg = 1; 4340Sstevel@tonic-gate mflg = 0; 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4379664Sjason@ansipunx.net while ((c = getopt_long(argc, argv, 4389664Sjason@ansipunx.net "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options, 4399664Sjason@ansipunx.net &option_index)) != -1) 4400Sstevel@tonic-gate switch (c) { 4419664Sjason@ansipunx.net case 0: 4429664Sjason@ansipunx.net /* non-short options */ 4439664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 4449664Sjason@ansipunx.net "color") == 0 || 4459664Sjason@ansipunx.net strcmp(long_options[option_index].name, 4469664Sjason@ansipunx.net "colour") == 0) { 4479664Sjason@ansipunx.net if (optarg == NULL || 4489664Sjason@ansipunx.net strcmp(optarg, "always") == 0 || 4499664Sjason@ansipunx.net strcmp(optarg, "yes") == 0 || 4509664Sjason@ansipunx.net strcmp(optarg, "force") == 0) { 4519664Sjason@ansipunx.net colorflg++; 4529664Sjason@ansipunx.net statreq++; 4539664Sjason@ansipunx.net continue; 4549664Sjason@ansipunx.net } 4559664Sjason@ansipunx.net 4569664Sjason@ansipunx.net if ((strcmp(optarg, "auto") == 0 || 4579664Sjason@ansipunx.net strcmp(optarg, "tty") == 0 || 4589664Sjason@ansipunx.net strcmp(optarg, "if-tty") == 0) && 4599664Sjason@ansipunx.net isatty(1) == 1) { 4609664Sjason@ansipunx.net colorflg++; 4619664Sjason@ansipunx.net statreq++; 4629664Sjason@ansipunx.net continue; 4639664Sjason@ansipunx.net } 4649664Sjason@ansipunx.net 4659664Sjason@ansipunx.net if (strcmp(optarg, "never") == 0 || 4669664Sjason@ansipunx.net strcmp(optarg, "no") == 0 || 4679664Sjason@ansipunx.net strcmp(optarg, "none") == 0) { 4689664Sjason@ansipunx.net colorflg = 0; 4699664Sjason@ansipunx.net continue; 4709664Sjason@ansipunx.net } 4719664Sjason@ansipunx.net (void) fprintf(stderr, 4729664Sjason@ansipunx.net gettext("Invalid argument '%s' for " 4739664Sjason@ansipunx.net "--color\n"), optarg); 4749664Sjason@ansipunx.net ++opterr; 4759664Sjason@ansipunx.net continue; 4769664Sjason@ansipunx.net } 4779664Sjason@ansipunx.net 4789664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 4799664Sjason@ansipunx.net "si") == 0) { 4809664Sjason@ansipunx.net hflg++; 4819664Sjason@ansipunx.net hscale = 1000; 4829664Sjason@ansipunx.net continue; 4839664Sjason@ansipunx.net } 4849664Sjason@ansipunx.net 4859664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 4869664Sjason@ansipunx.net "block-size") == 0) { 4879664Sjason@ansipunx.net size_t scale_len = strlen(optarg); 4889664Sjason@ansipunx.net uint64_t scale = 1; 4899664Sjason@ansipunx.net uint64_t kilo = 1024; 4909664Sjason@ansipunx.net char scale_c; 4919664Sjason@ansipunx.net 4929664Sjason@ansipunx.net if (scale_len == 0) { 4939664Sjason@ansipunx.net (void) fprintf(stderr, gettext( 4949664Sjason@ansipunx.net "Invalid block size \'%s\'\n"), 4959664Sjason@ansipunx.net optarg); 4969664Sjason@ansipunx.net exit(1); 4979664Sjason@ansipunx.net } 4989664Sjason@ansipunx.net 4999664Sjason@ansipunx.net scale_c = optarg[scale_len - 1]; 5009664Sjason@ansipunx.net if (scale_c == 'B') { 5019664Sjason@ansipunx.net /* need at least digit, scale, B */ 5029664Sjason@ansipunx.net if (scale_len < 3) { 5039664Sjason@ansipunx.net (void) fprintf(stderr, gettext( 5049664Sjason@ansipunx.net "Invalid block size " 5059664Sjason@ansipunx.net "\'%s\'\n"), optarg); 5069664Sjason@ansipunx.net exit(1); 5079664Sjason@ansipunx.net } 5089664Sjason@ansipunx.net kilo = 1000; 5099664Sjason@ansipunx.net scale_c = optarg[scale_len - 2]; 5109664Sjason@ansipunx.net if (isdigit(scale_c)) { 5119664Sjason@ansipunx.net (void) fprintf(stderr, 5129664Sjason@ansipunx.net gettext("Invalid block size" 5139664Sjason@ansipunx.net " \'%s\'\n"), optarg); 5149664Sjason@ansipunx.net exit(1); 5159664Sjason@ansipunx.net } 5169664Sjason@ansipunx.net /* 5179664Sjason@ansipunx.net * make optarg[scale_len - 1] point to 5189664Sjason@ansipunx.net * the scale factor 5199664Sjason@ansipunx.net */ 5209664Sjason@ansipunx.net --scale_len; 5219664Sjason@ansipunx.net } 5229664Sjason@ansipunx.net 5239664Sjason@ansipunx.net switch (scale_c) { 5249664Sjason@ansipunx.net case 'y': 5259664Sjason@ansipunx.net case 'Y': 5269664Sjason@ansipunx.net scale *= kilo; 5279664Sjason@ansipunx.net /*FALLTHROUGH*/ 5289664Sjason@ansipunx.net case 'Z': 5299664Sjason@ansipunx.net case 'z': 5309664Sjason@ansipunx.net scale *= kilo; 5319664Sjason@ansipunx.net /*FALLTHROUGH*/ 5329664Sjason@ansipunx.net case 'E': 5339664Sjason@ansipunx.net case 'e': 5349664Sjason@ansipunx.net scale *= kilo; 5359664Sjason@ansipunx.net /*FALLTHROUGH*/ 5369664Sjason@ansipunx.net case 'P': 5379664Sjason@ansipunx.net case 'p': 5389664Sjason@ansipunx.net scale *= kilo; 5399664Sjason@ansipunx.net /*FALLTHROUGH*/ 5409664Sjason@ansipunx.net case 'T': 5419664Sjason@ansipunx.net case 't': 5429664Sjason@ansipunx.net scale *= kilo; 5439664Sjason@ansipunx.net /*FALLTHROUGH*/ 5449664Sjason@ansipunx.net case 'G': 5459664Sjason@ansipunx.net case 'g': 5469664Sjason@ansipunx.net scale *= kilo; 5479664Sjason@ansipunx.net /*FALLTHROUGH*/ 5489664Sjason@ansipunx.net case 'M': 5499664Sjason@ansipunx.net case 'm': 5509664Sjason@ansipunx.net scale *= kilo; 5519664Sjason@ansipunx.net /*FALLTHROUGH*/ 5529664Sjason@ansipunx.net case 'K': 5539664Sjason@ansipunx.net case 'k': 5549664Sjason@ansipunx.net scale *= kilo; 5559664Sjason@ansipunx.net break; 5569664Sjason@ansipunx.net default: 5579664Sjason@ansipunx.net if (!isdigit(scale_c)) { 5589664Sjason@ansipunx.net (void) fprintf(stderr, 5599664Sjason@ansipunx.net gettext("Invalid character " 5609664Sjason@ansipunx.net "following block size in " 5619664Sjason@ansipunx.net "\'%s\'\n"), optarg); 5629664Sjason@ansipunx.net exit(1); 5639664Sjason@ansipunx.net } 5649664Sjason@ansipunx.net } 5659664Sjason@ansipunx.net 5669664Sjason@ansipunx.net /* NULL out scale constant if present */ 5679664Sjason@ansipunx.net if (scale > 1 && !isdigit(scale_c)) 5689664Sjason@ansipunx.net optarg[scale_len - 1] = '\0'; 5699664Sjason@ansipunx.net 5709664Sjason@ansipunx.net /* Based on testing, this is what GNU ls does */ 5719664Sjason@ansipunx.net block_size = strtoll(optarg, NULL, 0) * scale; 5729664Sjason@ansipunx.net if (block_size < 1) { 5739664Sjason@ansipunx.net (void) fprintf(stderr, 5749664Sjason@ansipunx.net gettext("Invalid block size " 5759664Sjason@ansipunx.net "\'%s\'\n"), optarg); 5769664Sjason@ansipunx.net exit(1); 5779664Sjason@ansipunx.net } 5789664Sjason@ansipunx.net continue; 5799664Sjason@ansipunx.net } 5809664Sjason@ansipunx.net 5819664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 5829664Sjason@ansipunx.net "file-type") == 0) { 5839664Sjason@ansipunx.net file_typeflg++; 5849664Sjason@ansipunx.net Fflg++; 5859664Sjason@ansipunx.net statreq++; 5869664Sjason@ansipunx.net continue; 5879664Sjason@ansipunx.net } 5889664Sjason@ansipunx.net 5899664Sjason@ansipunx.net 5909664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 5919664Sjason@ansipunx.net "full-time") == 0) { 5929664Sjason@ansipunx.net Eflg++; 5939664Sjason@ansipunx.net statreq++; 5949664Sjason@ansipunx.net eflg = 0; 5959664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 5969664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 5979664Sjason@ansipunx.net continue; 5989664Sjason@ansipunx.net } 5999664Sjason@ansipunx.net 6009664Sjason@ansipunx.net if (strcmp(long_options[option_index].name, 6019664Sjason@ansipunx.net "time-style") == 0) { 6029664Sjason@ansipunx.net /* like -E, but doesn't imply -l */ 6039664Sjason@ansipunx.net if (strcmp(optarg, "full-iso") == 0) { 6049664Sjason@ansipunx.net Eflg++; 6059664Sjason@ansipunx.net statreq++; 6069664Sjason@ansipunx.net eflg = 0; 6079664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 6089664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 6099664Sjason@ansipunx.net continue; 6109664Sjason@ansipunx.net } 6119664Sjason@ansipunx.net if (strcmp(optarg, "long-iso") == 0) { 6129664Sjason@ansipunx.net statreq++; 6139664Sjason@ansipunx.net Eflg = 0; 6149664Sjason@ansipunx.net eflg = 0; 6159664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_LONG; 6169664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_LONG; 6179664Sjason@ansipunx.net continue; 6189664Sjason@ansipunx.net } 6199664Sjason@ansipunx.net if (strcmp(optarg, "iso") == 0) { 6209664Sjason@ansipunx.net statreq++; 6219664Sjason@ansipunx.net Eflg = 0; 6229664Sjason@ansipunx.net eflg = 0; 6239664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_OLD; 6249664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_NEW; 6259664Sjason@ansipunx.net continue; 6269664Sjason@ansipunx.net } 6279664Sjason@ansipunx.net /* should be the default */ 6289664Sjason@ansipunx.net if (strcmp(optarg, "locale") == 0) { 6299664Sjason@ansipunx.net time_fmt_old = FORMAT_OLD; 6309664Sjason@ansipunx.net time_fmt_new = FORMAT_NEW; 6319664Sjason@ansipunx.net continue; 6329664Sjason@ansipunx.net } 6339664Sjason@ansipunx.net if (optarg[0] == '+') { 6349664Sjason@ansipunx.net char *told, *tnew; 6359664Sjason@ansipunx.net char *p; 6369664Sjason@ansipunx.net size_t timelen = strlen(optarg); 6379664Sjason@ansipunx.net 6389664Sjason@ansipunx.net p = strchr(optarg, '\n'); 6399664Sjason@ansipunx.net if (p != NULL) 6409664Sjason@ansipunx.net *p++ = '\0'; 6419664Sjason@ansipunx.net 6429664Sjason@ansipunx.net /* 6439664Sjason@ansipunx.net * Time format requires a leading and 6449664Sjason@ansipunx.net * trailing space 6459664Sjason@ansipunx.net * Add room for 3 spaces + 2 nulls 6469664Sjason@ansipunx.net * The + in optarg is replaced with 6479664Sjason@ansipunx.net * a space. 6489664Sjason@ansipunx.net */ 6499664Sjason@ansipunx.net timelen += 2 + 3; 6509664Sjason@ansipunx.net told = malloc(timelen); 6519664Sjason@ansipunx.net if (told == NULL) { 6529664Sjason@ansipunx.net perror("Out of memory"); 6539664Sjason@ansipunx.net exit(1); 6549664Sjason@ansipunx.net } 6559664Sjason@ansipunx.net 6569664Sjason@ansipunx.net (void) memset(told, 0, timelen); 6579664Sjason@ansipunx.net told[0] = ' '; 6589664Sjason@ansipunx.net (void) strlcat(told, &optarg[1], 6599664Sjason@ansipunx.net timelen); 6609664Sjason@ansipunx.net (void) strlcat(told, " ", timelen); 6619664Sjason@ansipunx.net 6629664Sjason@ansipunx.net if (p != NULL) { 6639664Sjason@ansipunx.net size_t tnew_len; 6649664Sjason@ansipunx.net 6659664Sjason@ansipunx.net tnew = told + strlen(told) + 1; 6669664Sjason@ansipunx.net tnew_len = timelen - 6679664Sjason@ansipunx.net strlen(told) - 1; 6689664Sjason@ansipunx.net 6699664Sjason@ansipunx.net tnew[0] = ' '; 6709664Sjason@ansipunx.net (void) strlcat(tnew, p, 6719664Sjason@ansipunx.net tnew_len); 6729664Sjason@ansipunx.net (void) strlcat(tnew, " ", 6739664Sjason@ansipunx.net tnew_len); 6749664Sjason@ansipunx.net time_fmt_new = 6759664Sjason@ansipunx.net (const char *)tnew; 6769664Sjason@ansipunx.net } else { 6779664Sjason@ansipunx.net time_fmt_new = 6789664Sjason@ansipunx.net (const char *)told; 6799664Sjason@ansipunx.net } 6809664Sjason@ansipunx.net 6819664Sjason@ansipunx.net time_fmt_old = (const char *)told; 6829664Sjason@ansipunx.net time_custom = 1; 6839664Sjason@ansipunx.net continue; 6849664Sjason@ansipunx.net } 6859664Sjason@ansipunx.net continue; 6869664Sjason@ansipunx.net } 6879664Sjason@ansipunx.net 6889664Sjason@ansipunx.net continue; 6899664Sjason@ansipunx.net 6900Sstevel@tonic-gate case 'a': 6910Sstevel@tonic-gate aflg++; 6920Sstevel@tonic-gate continue; 6930Sstevel@tonic-gate case 'A': 6940Sstevel@tonic-gate Aflg++; 6950Sstevel@tonic-gate continue; 6960Sstevel@tonic-gate case 'b': 6970Sstevel@tonic-gate bflg = 1; 6980Sstevel@tonic-gate qflg = 0; 6990Sstevel@tonic-gate continue; 7009664Sjason@ansipunx.net case 'B': 7019664Sjason@ansipunx.net Bflg = 1; 7029664Sjason@ansipunx.net continue; 7030Sstevel@tonic-gate case 'c': 7040Sstevel@tonic-gate uflg = 0; 7055331Samw atm = 0; 7065331Samw ctm = 0; 7075331Samw mtm = 0; 7085331Samw crtm = 0; 7090Sstevel@tonic-gate cflg++; 7100Sstevel@tonic-gate continue; 7110Sstevel@tonic-gate case 'C': 7120Sstevel@tonic-gate Cflg = 1; 7130Sstevel@tonic-gate mflg = 0; 7140Sstevel@tonic-gate #ifdef XPG4 7150Sstevel@tonic-gate lflg = 0; 7160Sstevel@tonic-gate #endif 7170Sstevel@tonic-gate continue; 7180Sstevel@tonic-gate case 'd': 7190Sstevel@tonic-gate dflg++; 7200Sstevel@tonic-gate continue; 7210Sstevel@tonic-gate case 'e': 7220Sstevel@tonic-gate eflg++; 7230Sstevel@tonic-gate lflg++; 7240Sstevel@tonic-gate statreq++; 7250Sstevel@tonic-gate Eflg = 0; 7269664Sjason@ansipunx.net time_fmt_old = FORMAT_LONG; 7279664Sjason@ansipunx.net time_fmt_new = FORMAT_LONG; 7280Sstevel@tonic-gate continue; 7290Sstevel@tonic-gate case 'E': 7300Sstevel@tonic-gate Eflg++; 7310Sstevel@tonic-gate lflg++; 7320Sstevel@tonic-gate statreq++; 7330Sstevel@tonic-gate eflg = 0; 7349664Sjason@ansipunx.net time_fmt_old = FORMAT_ISO_FULL; 7359664Sjason@ansipunx.net time_fmt_new = FORMAT_ISO_FULL; 7360Sstevel@tonic-gate continue; 7370Sstevel@tonic-gate case 'f': 7380Sstevel@tonic-gate fflg++; 7390Sstevel@tonic-gate continue; 7400Sstevel@tonic-gate case 'F': 7410Sstevel@tonic-gate Fflg++; 7420Sstevel@tonic-gate statreq++; 7430Sstevel@tonic-gate continue; 7440Sstevel@tonic-gate case 'g': 7450Sstevel@tonic-gate gflg++; 7460Sstevel@tonic-gate lflg++; 7470Sstevel@tonic-gate statreq++; 7480Sstevel@tonic-gate continue; 7490Sstevel@tonic-gate case 'h': 7500Sstevel@tonic-gate hflg++; 7510Sstevel@tonic-gate hscale = 1024; 7520Sstevel@tonic-gate continue; 7530Sstevel@tonic-gate case 'H': 7540Sstevel@tonic-gate Hflg++; 7550Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7560Sstevel@tonic-gate Lflg = 0; 7570Sstevel@tonic-gate continue; 7580Sstevel@tonic-gate case 'i': 7590Sstevel@tonic-gate iflg++; 7600Sstevel@tonic-gate continue; 7619664Sjason@ansipunx.net case 'k': 7629664Sjason@ansipunx.net block_size = 1024; 7639664Sjason@ansipunx.net continue; 7640Sstevel@tonic-gate case 'l': 7650Sstevel@tonic-gate lflg++; 7660Sstevel@tonic-gate statreq++; 7670Sstevel@tonic-gate Cflg = 0; 7680Sstevel@tonic-gate xflg = 0; 7690Sstevel@tonic-gate mflg = 0; 7700Sstevel@tonic-gate atflg = 0; 7710Sstevel@tonic-gate continue; 7720Sstevel@tonic-gate case 'L': 7730Sstevel@tonic-gate Lflg++; 7740Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 7750Sstevel@tonic-gate Hflg = 0; 7760Sstevel@tonic-gate continue; 7770Sstevel@tonic-gate case 'm': 7780Sstevel@tonic-gate Cflg = 0; 7790Sstevel@tonic-gate mflg = 1; 7800Sstevel@tonic-gate #ifdef XPG4 7810Sstevel@tonic-gate lflg = 0; 7820Sstevel@tonic-gate #endif 7830Sstevel@tonic-gate continue; 7840Sstevel@tonic-gate case 'n': 7850Sstevel@tonic-gate nflg++; 7860Sstevel@tonic-gate lflg++; 7870Sstevel@tonic-gate statreq++; 7880Sstevel@tonic-gate Cflg = 0; 7890Sstevel@tonic-gate xflg = 0; 7900Sstevel@tonic-gate mflg = 0; 7910Sstevel@tonic-gate atflg = 0; 7920Sstevel@tonic-gate continue; 7930Sstevel@tonic-gate case 'o': 7940Sstevel@tonic-gate oflg++; 7950Sstevel@tonic-gate lflg++; 7960Sstevel@tonic-gate statreq++; 7970Sstevel@tonic-gate continue; 7980Sstevel@tonic-gate case 'p': 7990Sstevel@tonic-gate pflg++; 8000Sstevel@tonic-gate statreq++; 8010Sstevel@tonic-gate continue; 8020Sstevel@tonic-gate case 'q': 8030Sstevel@tonic-gate qflg = 1; 8040Sstevel@tonic-gate bflg = 0; 8050Sstevel@tonic-gate continue; 8060Sstevel@tonic-gate case 'r': 8070Sstevel@tonic-gate rflg = -1; 8080Sstevel@tonic-gate continue; 8090Sstevel@tonic-gate case 'R': 8100Sstevel@tonic-gate Rflg++; 8110Sstevel@tonic-gate statreq++; 8120Sstevel@tonic-gate continue; 8130Sstevel@tonic-gate case 's': 8140Sstevel@tonic-gate sflg++; 8150Sstevel@tonic-gate statreq++; 8160Sstevel@tonic-gate continue; 8170Sstevel@tonic-gate case 'S': 8180Sstevel@tonic-gate tflg = 0; 8199664Sjason@ansipunx.net Uflg = 0; 8200Sstevel@tonic-gate Sflg++; 8210Sstevel@tonic-gate statreq++; 8220Sstevel@tonic-gate continue; 8230Sstevel@tonic-gate case 't': 8240Sstevel@tonic-gate Sflg = 0; 8259664Sjason@ansipunx.net Uflg = 0; 8260Sstevel@tonic-gate tflg++; 8270Sstevel@tonic-gate statreq++; 8280Sstevel@tonic-gate continue; 8299664Sjason@ansipunx.net case 'U': 8309664Sjason@ansipunx.net Sflg = 0; 8319664Sjason@ansipunx.net tflg = 0; 8329664Sjason@ansipunx.net Uflg++; 8339664Sjason@ansipunx.net continue; 8340Sstevel@tonic-gate case 'u': 8350Sstevel@tonic-gate cflg = 0; 8365331Samw atm = 0; 8375331Samw ctm = 0; 8385331Samw mtm = 0; 8395331Samw crtm = 0; 8400Sstevel@tonic-gate uflg++; 8410Sstevel@tonic-gate continue; 8421420Smarks case 'V': 8431420Smarks Vflg++; 8441420Smarks /*FALLTHROUGH*/ 845789Sahrens case 'v': 846789Sahrens vflg++; 847789Sahrens #if !defined(XPG4) 848789Sahrens if (lflg) 849789Sahrens continue; 850789Sahrens #endif 851789Sahrens lflg++; 852789Sahrens statreq++; 853789Sahrens Cflg = 0; 854789Sahrens xflg = 0; 855789Sahrens mflg = 0; 856789Sahrens continue; 8579664Sjason@ansipunx.net case 'w': 8589664Sjason@ansipunx.net wflg++; 8599664Sjason@ansipunx.net num_cols = atoi(optarg); 8609664Sjason@ansipunx.net continue; 8610Sstevel@tonic-gate case 'x': 8620Sstevel@tonic-gate xflg = 1; 8630Sstevel@tonic-gate Cflg = 1; 8640Sstevel@tonic-gate mflg = 0; 8650Sstevel@tonic-gate #ifdef XPG4 8660Sstevel@tonic-gate lflg = 0; 8670Sstevel@tonic-gate #endif 8680Sstevel@tonic-gate continue; 8690Sstevel@tonic-gate case '1': 8700Sstevel@tonic-gate Cflg = 0; 8710Sstevel@tonic-gate continue; 8720Sstevel@tonic-gate case '@': 8730Sstevel@tonic-gate #if !defined(XPG4) 8740Sstevel@tonic-gate /* 8750Sstevel@tonic-gate * -l has precedence over -@ 8760Sstevel@tonic-gate */ 8770Sstevel@tonic-gate if (lflg) 8780Sstevel@tonic-gate continue; 8790Sstevel@tonic-gate #endif 8800Sstevel@tonic-gate atflg++; 8810Sstevel@tonic-gate lflg++; 8820Sstevel@tonic-gate statreq++; 8830Sstevel@tonic-gate Cflg = 0; 8840Sstevel@tonic-gate xflg = 0; 8850Sstevel@tonic-gate mflg = 0; 8860Sstevel@tonic-gate continue; 8875331Samw case '/': 8885331Samw saflg++; 8895331Samw if (optarg != NULL) { 8905331Samw if (strcmp(optarg, "c") == 0) { 8915331Samw copt++; 8925331Samw vopt = 0; 8935331Samw } else if (strcmp(optarg, "v") == 0) { 8945331Samw vopt++; 8955331Samw copt = 0; 8965331Samw } else 8975331Samw opterr++; 8985331Samw } else 8995331Samw opterr++; 9005331Samw lflg++; 9015331Samw statreq++; 9025331Samw Cflg = 0; 9035331Samw xflg = 0; 9045331Samw mflg = 0; 9055331Samw continue; 9065331Samw case '%': 9075331Samw tmflg++; 9085331Samw if (optarg != NULL) { 9095331Samw if (strcmp(optarg, "ctime") == 0) { 9105331Samw ctm++; 9115331Samw atm = 0; 9125331Samw mtm = 0; 9135331Samw crtm = 0; 9145331Samw } else if (strcmp(optarg, "atime") == 0) { 9155331Samw atm++; 9165331Samw ctm = 0; 9175331Samw mtm = 0; 9185331Samw crtm = 0; 9195331Samw uflg = 0; 9205331Samw cflg = 0; 9215331Samw } else if (strcmp(optarg, "mtime") == 0) { 9225331Samw mtm++; 9235331Samw atm = 0; 9245331Samw ctm = 0; 9255331Samw crtm = 0; 9265331Samw uflg = 0; 9275331Samw cflg = 0; 9285331Samw } else if (strcmp(optarg, "crtime") == 0) { 9295331Samw crtm++; 9305331Samw atm = 0; 9315331Samw ctm = 0; 9325331Samw mtm = 0; 9335331Samw uflg = 0; 9345331Samw cflg = 0; 9355331Samw } else if (strcmp(optarg, "all") == 0) { 9365331Samw alltm++; 9375331Samw atm = 0; 9385331Samw ctm = 0; 9395331Samw mtm = 0; 9405331Samw crtm = 0; 9415331Samw } else 9425331Samw opterr++; 9435331Samw } else 9445331Samw opterr++; 9455331Samw 9465331Samw Sflg = 0; 9475331Samw statreq++; 9485331Samw mflg = 0; 9495331Samw continue; 9500Sstevel@tonic-gate case '?': 9510Sstevel@tonic-gate opterr++; 9520Sstevel@tonic-gate continue; 9530Sstevel@tonic-gate } 9549664Sjason@ansipunx.net 9550Sstevel@tonic-gate if (opterr) { 9560Sstevel@tonic-gate (void) fprintf(stderr, gettext( 9579664Sjason@ansipunx.net "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]" 9585331Samw "%%[atime | crtime | ctime | mtime | all]" 9595331Samw " [files]\n")); 9600Sstevel@tonic-gate exit(2); 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate if (fflg) { 9640Sstevel@tonic-gate aflg++; 9650Sstevel@tonic-gate lflg = 0; 9660Sstevel@tonic-gate sflg = 0; 9670Sstevel@tonic-gate tflg = 0; 9680Sstevel@tonic-gate Sflg = 0; 9690Sstevel@tonic-gate statreq = 0; 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate fixedwidth = 2; 9730Sstevel@tonic-gate if (pflg || Fflg) 9740Sstevel@tonic-gate fixedwidth++; 9750Sstevel@tonic-gate if (iflg) 9760Sstevel@tonic-gate fixedwidth += 11; 9770Sstevel@tonic-gate if (sflg) 9780Sstevel@tonic-gate fixedwidth += 5; 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate if (lflg) { 9810Sstevel@tonic-gate if (!gflg && !oflg) 9820Sstevel@tonic-gate gflg = oflg = 1; 9830Sstevel@tonic-gate else 9840Sstevel@tonic-gate if (gflg && oflg) 9850Sstevel@tonic-gate gflg = oflg = 0; 9860Sstevel@tonic-gate Cflg = mflg = 0; 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9899664Sjason@ansipunx.net if (!wflg && (Cflg || mflg)) { 9900Sstevel@tonic-gate char *clptr; 9910Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 9920Sstevel@tonic-gate num_cols = atoi(clptr); 9930Sstevel@tonic-gate #ifdef TERMINFO 9940Sstevel@tonic-gate else { 9950Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 9960Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate #endif 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate 10019664Sjason@ansipunx.net if (num_cols < 20 || num_cols > 1000) 10029664Sjason@ansipunx.net /* assume it is an error */ 10039664Sjason@ansipunx.net num_cols = 80; 10049664Sjason@ansipunx.net 10050Sstevel@tonic-gate /* allocate space for flist and the associated */ 10060Sstevel@tonic-gate /* data structures (lbufs) */ 10070Sstevel@tonic-gate maxfils = quantn; 10080Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 10090Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 10100Sstevel@tonic-gate perror("ls"); 10110Sstevel@tonic-gate exit(2); 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 10140Sstevel@tonic-gate /* 10150Sstevel@tonic-gate * case when no names are given 10160Sstevel@tonic-gate * in ls-command and current 10170Sstevel@tonic-gate * directory is to be used 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate argv[optind] = dotp; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 10260Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 10270Sstevel@tonic-gate * (actually, just the directories) visited, we 10280Sstevel@tonic-gate * maintain a directory ancestry list for a file 10290Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 10300Sstevel@tonic-gate * a parent directory passes its directory list 10310Sstevel@tonic-gate * info (device id, inode number, and a pointer to 10320Sstevel@tonic-gate * its parent) to each of its children. As we 10330Sstevel@tonic-gate * process a child that is a directory, we save 10340Sstevel@tonic-gate * its own personal directory list info. We then 10350Sstevel@tonic-gate * check to see if the child has already been 10360Sstevel@tonic-gate * processed by comparing its device id and inode 10370Sstevel@tonic-gate * number from its own personal directory list info 10380Sstevel@tonic-gate * to that of each of its ancestors. If there is a 10390Sstevel@tonic-gate * match, then we know we've detected a cycle. 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate if (Rflg) { 10420Sstevel@tonic-gate /* 10430Sstevel@tonic-gate * This is the first parent in this lineage 10440Sstevel@tonic-gate * (first in a directory hierarchy), so 10450Sstevel@tonic-gate * this parent's parent doesn't exist. We 10460Sstevel@tonic-gate * only initialize myinfo when we are 10470Sstevel@tonic-gate * recursing, otherwise it's not used. 10480Sstevel@tonic-gate */ 10490Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 10500Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 10510Sstevel@tonic-gate perror("ls"); 10520Sstevel@tonic-gate exit(2); 10530Sstevel@tonic-gate } else { 10540Sstevel@tonic-gate myinfo->dev = 0; 10550Sstevel@tonic-gate myinfo->ino = 0; 10560Sstevel@tonic-gate myinfo->parent = NULL; 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate if (Cflg || mflg) { 10610Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 10620Sstevel@tonic-gate if (width > filewidth) 10630Sstevel@tonic-gate filewidth = width; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 10660Sstevel@tonic-gate 1, myinfo)) == NULL) { 10670Sstevel@tonic-gate if (nomocore) 10680Sstevel@tonic-gate exit(2); 10690Sstevel@tonic-gate err = 2; 10700Sstevel@tonic-gate optind++; 10710Sstevel@tonic-gate continue; 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 10740Sstevel@tonic-gate ep->lflags |= ISARG; 10750Sstevel@tonic-gate optind++; 10760Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 10776866Sbasabi if (acl_err) 10786866Sbasabi err = 2; 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 10819664Sjason@ansipunx.net if (!Uflg) 10829664Sjason@ansipunx.net qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 10839664Sjason@ansipunx.net (int (*)(const void *, const void *))compar); 10840Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 10850Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 10860Sstevel@tonic-gate break; 10870Sstevel@tonic-gate } 10889664Sjason@ansipunx.net 10899664Sjason@ansipunx.net if (colorflg) 10909664Sjason@ansipunx.net ls_color_init(); 10919664Sjason@ansipunx.net 10920Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 10930Sstevel@tonic-gate for (; i < nargs; i++) { 10940Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 10950Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 10960Sstevel@tonic-gate if (nomocore) 10970Sstevel@tonic-gate exit(2); 10980Sstevel@tonic-gate /* -R: print subdirectories found */ 10990Sstevel@tonic-gate while (dfirst || cdfirst) { 11000Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 11010Sstevel@tonic-gate while (cdfirst) { 11020Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 11030Sstevel@tonic-gate dtemp = cdfirst; 11040Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 11050Sstevel@tonic-gate dtemp -> dc_next = dfirst; 11060Sstevel@tonic-gate dfirst = dtemp; 11070Sstevel@tonic-gate } 11080Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 11090Sstevel@tonic-gate dtemp = dfirst; 11100Sstevel@tonic-gate dfirst = dfirst->dc_next; 11110Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 11120Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 11130Sstevel@tonic-gate if (nomocore) 11140Sstevel@tonic-gate exit(2); 11150Sstevel@tonic-gate free(dtemp->dc_name); 11160Sstevel@tonic-gate free(dtemp); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate } 11199664Sjason@ansipunx.net 11200Sstevel@tonic-gate return (err); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate /* 11240Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 11250Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 11260Sstevel@tonic-gate */ 11270Sstevel@tonic-gate static void 11280Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 11290Sstevel@tonic-gate { 11300Sstevel@tonic-gate struct dchain *dp; 11310Sstevel@tonic-gate struct lbuf *ap; 11320Sstevel@tonic-gate char *pname; 11330Sstevel@tonic-gate int j; 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate filewidth = 0; 11360Sstevel@tonic-gate curdir = name; 11370Sstevel@tonic-gate if (title) { 11380Sstevel@tonic-gate if (!first) 11390Sstevel@tonic-gate (void) putc('\n', stdout); 11400Sstevel@tonic-gate pprintf(name, ":"); 11410Sstevel@tonic-gate new_line(); 11420Sstevel@tonic-gate } 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 11450Sstevel@tonic-gate * further. 11460Sstevel@tonic-gate */ 11470Sstevel@tonic-gate if (cdetect) { 11480Sstevel@tonic-gate if (lflg || sflg) { 11490Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 11500Sstevel@tonic-gate new_line(); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11530Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 11540Sstevel@tonic-gate return; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate nfiles = lp; 11580Sstevel@tonic-gate rddir(name, myinfo); 11590Sstevel@tonic-gate if (nomocore) 11600Sstevel@tonic-gate return; 11619664Sjason@ansipunx.net if (fflg == 0 && Uflg == 0) 11620Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 11630Sstevel@tonic-gate sizeof (struct lbuf *), 11640Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 11650Sstevel@tonic-gate if (Rflg) { 11660Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 11670Sstevel@tonic-gate ap = flist[j]; 11680Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 11690Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 11700Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 11710Sstevel@tonic-gate if (dp == NULL) { 11720Sstevel@tonic-gate perror("ls"); 11730Sstevel@tonic-gate exit(2); 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 11760Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 11770Sstevel@tonic-gate perror("ls"); 11780Sstevel@tonic-gate exit(2); 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 11810Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 11820Sstevel@tonic-gate dp->dc_next = dfirst; 11830Sstevel@tonic-gate dfirst = dp; 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate if (lflg || sflg) { 11880Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 11890Sstevel@tonic-gate new_line(); 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate /* 11950Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 11960Sstevel@tonic-gate * by slp and lp. 11970Sstevel@tonic-gate */ 11980Sstevel@tonic-gate static void 11990Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 12000Sstevel@tonic-gate { 12010Sstevel@tonic-gate long row, nrows, i; 12020Sstevel@tonic-gate int col, ncols; 12030Sstevel@tonic-gate struct lbuf **ep; 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate if (Cflg || mflg) { 12060Sstevel@tonic-gate if (colwidth > num_cols) { 12070Sstevel@tonic-gate ncols = 1; 12080Sstevel@tonic-gate } else { 12090Sstevel@tonic-gate ncols = num_cols / colwidth; 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate } 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 12140Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 12150Sstevel@tonic-gate pentry(*ep); 12160Sstevel@tonic-gate new_line(); 12170Sstevel@tonic-gate return; 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate /* otherwise print -C columns */ 12200Sstevel@tonic-gate if (tot_flag) { 12210Sstevel@tonic-gate slp--; 12220Sstevel@tonic-gate row = 1; 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate else 12250Sstevel@tonic-gate row = 0; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 12280Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 12290Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 12300Sstevel@tonic-gate ep = slp + (nrows * col) + row; 12310Sstevel@tonic-gate if (ep < lp) 12320Sstevel@tonic-gate pentry(*ep); 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate new_line(); 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate /* 12390Sstevel@tonic-gate * print one output entry; 12400Sstevel@tonic-gate * if uid/gid is not found in the appropriate 12410Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 12420Sstevel@tonic-gate * user/group name; 12430Sstevel@tonic-gate */ 12440Sstevel@tonic-gate static void 12450Sstevel@tonic-gate pentry(struct lbuf *ap) 12460Sstevel@tonic-gate { 12470Sstevel@tonic-gate struct lbuf *p; 12480Sstevel@tonic-gate numbuf_t hbuf; 12490Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 12500Sstevel@tonic-gate char *cp; 1251*10059Sjason@ansipunx.net char *str; 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate p = ap; 12540Sstevel@tonic-gate column(); 12550Sstevel@tonic-gate if (iflg) 12560Sstevel@tonic-gate if (mflg && !lflg) 12570Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 12580Sstevel@tonic-gate else 12590Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 12600Sstevel@tonic-gate if (sflg) 12610Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 12625331Samw (p->lblocks < 10000) ? "%4lld " : "%lld ", 12635331Samw (p->ltype != 'b' && p->ltype != 'c') ? 12645331Samw p->lblocks : 0LL); 12650Sstevel@tonic-gate if (lflg) { 12660Sstevel@tonic-gate (void) putchar(p->ltype); 12670Sstevel@tonic-gate curcol++; 12680Sstevel@tonic-gate pmode(p->lflags); 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* ACL: additional access mode flag */ 12710Sstevel@tonic-gate (void) putchar(p->acl); 12720Sstevel@tonic-gate curcol++; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 12750Sstevel@tonic-gate if (oflg) 12760Sstevel@tonic-gate if (!nflg) { 12770Sstevel@tonic-gate cp = getname(p->luid); 12780Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12790Sstevel@tonic-gate } else 12800Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 12810Sstevel@tonic-gate if (gflg) 12820Sstevel@tonic-gate if (!nflg) { 12830Sstevel@tonic-gate cp = getgroup(p->lgid); 12840Sstevel@tonic-gate curcol += printf("%-8s ", cp); 12850Sstevel@tonic-gate } else 12860Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 12870Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 12880Sstevel@tonic-gate curcol += printf("%3u, %2u", 12890Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 12900Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 12910Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 12920Sstevel@tonic-gate curcol += printf("%7s", 12930Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 12940Sstevel@tonic-gate } else { 12959664Sjason@ansipunx.net uint64_t bsize = p->lsize / block_size; 12969664Sjason@ansipunx.net 12979664Sjason@ansipunx.net /* 12989664Sjason@ansipunx.net * Round up only when using blocks > 1 byte, otherwise 12999664Sjason@ansipunx.net * 'normal' sizes display 1 byte too large. 13009664Sjason@ansipunx.net */ 13019664Sjason@ansipunx.net if (p->lsize % block_size != 0) 13029664Sjason@ansipunx.net bsize++; 13039664Sjason@ansipunx.net 13049664Sjason@ansipunx.net curcol += printf("%7" PRIu64, bsize); 13050Sstevel@tonic-gate } 13069664Sjason@ansipunx.net format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec); 13075331Samw /* format extended system attribute time */ 13085331Samw if (tmflg && crtm) 13095331Samw format_attrtime(p); 13105331Samw 13110Sstevel@tonic-gate curcol += printf("%s", time_buf); 13125331Samw 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate /* 13150Sstevel@tonic-gate * prevent both "->" and trailing marks 13160Sstevel@tonic-gate * from appearing 13170Sstevel@tonic-gate */ 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate if (pflg && p->ltype == 'd') 13200Sstevel@tonic-gate dmark = "/"; 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 13230Sstevel@tonic-gate if (p->ltype == 'd') 13240Sstevel@tonic-gate dmark = "/"; 13250Sstevel@tonic-gate else if (p->ltype == 'D') 13260Sstevel@tonic-gate dmark = ">"; 13270Sstevel@tonic-gate else if (p->ltype == 'p') 13280Sstevel@tonic-gate dmark = "|"; 13290Sstevel@tonic-gate else if (p->ltype == 'l') 13300Sstevel@tonic-gate dmark = "@"; 13310Sstevel@tonic-gate else if (p->ltype == 's') 13320Sstevel@tonic-gate dmark = "="; 13339664Sjason@ansipunx.net else if (!file_typeflg && 13349664Sjason@ansipunx.net (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))) 13350Sstevel@tonic-gate dmark = "*"; 13360Sstevel@tonic-gate else 13370Sstevel@tonic-gate dmark = ""; 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate 1340*10059Sjason@ansipunx.net if (colorflg) 1341*10059Sjason@ansipunx.net ls_start_color(p->color); 1342*10059Sjason@ansipunx.net 1343*10059Sjason@ansipunx.net if (p->lflags & ISARG) 1344*10059Sjason@ansipunx.net str = p->ln.namep; 1345*10059Sjason@ansipunx.net else 1346*10059Sjason@ansipunx.net str = p->ln.lname; 13479664Sjason@ansipunx.net 1348*10059Sjason@ansipunx.net if (qflg || bflg) { 1349*10059Sjason@ansipunx.net csi_pprintf((unsigned char *)str); 13509664Sjason@ansipunx.net 1351*10059Sjason@ansipunx.net if (lflg && p->flinkto) { 1352*10059Sjason@ansipunx.net if (colorflg) 1353*10059Sjason@ansipunx.net ls_end_color(); 1354*10059Sjason@ansipunx.net csi_pprintf((unsigned char *)" -> "); 1355*10059Sjason@ansipunx.net if (colorflg) 1356*10059Sjason@ansipunx.net ls_start_color(p->link_color); 1357*10059Sjason@ansipunx.net csi_pprintf((unsigned char *)p->flinkto); 1358*10059Sjason@ansipunx.net } else { 1359*10059Sjason@ansipunx.net csi_pprintf((unsigned char *)dmark); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate } else { 1362*10059Sjason@ansipunx.net (void) printf("%s", str); 1363*10059Sjason@ansipunx.net curcol += strcol((unsigned char *)str); 1364*10059Sjason@ansipunx.net 1365*10059Sjason@ansipunx.net if (lflg && p->flinkto) { 1366*10059Sjason@ansipunx.net if (colorflg) 1367*10059Sjason@ansipunx.net ls_end_color(); 1368*10059Sjason@ansipunx.net str = " -> "; 1369*10059Sjason@ansipunx.net (void) printf("%s", str); 1370*10059Sjason@ansipunx.net curcol += strcol((unsigned char *)str); 1371*10059Sjason@ansipunx.net if (colorflg) 1372*10059Sjason@ansipunx.net ls_start_color(p->link_color); 1373*10059Sjason@ansipunx.net (void) printf("%s", p->flinkto); 1374*10059Sjason@ansipunx.net curcol += strcol((unsigned char *)p->flinkto); 1375*10059Sjason@ansipunx.net } else { 1376*10059Sjason@ansipunx.net (void) printf("%s", dmark); 13770Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate } 1380789Sahrens 13819664Sjason@ansipunx.net if (colorflg) 13829664Sjason@ansipunx.net ls_end_color(); 13839664Sjason@ansipunx.net 13845331Samw /* Display extended system attributes */ 13855331Samw if (saflg) { 13865331Samw int i; 13875331Samw 13885331Samw new_line(); 13895331Samw (void) printf(" \t{"); 13905331Samw if (p->exttr != NULL) { 13915331Samw int k = 0; 13925331Samw for (i = 0; i < sacnt; i++) { 13935331Samw if (p->exttr[i].name != NULL) 13945331Samw k++; 13955331Samw } 13965331Samw for (i = 0; i < sacnt; i++) { 13975331Samw if (p->exttr[i].name != NULL) { 13985331Samw (void) printf("%s", p->exttr[i].name); 13995331Samw k--; 14005331Samw if (vopt && (k != 0)) 14015331Samw (void) printf(","); 14025331Samw } 14035331Samw } 14045331Samw } 14055331Samw (void) printf("}\n"); 14065331Samw } 14075331Samw /* Display file timestamps and extended system attribute timestamps */ 14085331Samw if (tmflg && alltm) { 14095331Samw new_line(); 14105331Samw print_time(p); 14115331Samw new_line(); 14125331Samw } 1413789Sahrens if (vflg) { 1414789Sahrens new_line(); 1415789Sahrens if (p->aclp) { 14161420Smarks acl_printacl(p->aclp, num_cols, Vflg); 1417789Sahrens } 1418789Sahrens } 14195331Samw /* Free extended system attribute lists */ 14205331Samw if (saflg || tmflg) 14215331Samw free_sysattr(p); 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate /* print various r,w,x permissions */ 14250Sstevel@tonic-gate static void 14260Sstevel@tonic-gate pmode(mode_t aflag) 14270Sstevel@tonic-gate { 14280Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 14290Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 14300Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 14310Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 14320Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 14330Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 14340Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 14350Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 14360Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 14370Sstevel@tonic-gate #ifdef XPG4 14380Sstevel@tonic-gate S_ISGID, 'L', '-'}; 14390Sstevel@tonic-gate #else 14400Sstevel@tonic-gate S_ISGID, 'l', '-'}; 14410Sstevel@tonic-gate #endif 14420Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 14430Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 14440Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 14450Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate int **mp; 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate flags = aflag; 14520Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 14530Sstevel@tonic-gate selection(*mp); 14540Sstevel@tonic-gate } 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate static void 14570Sstevel@tonic-gate selection(int *pairp) 14580Sstevel@tonic-gate { 14590Sstevel@tonic-gate int n; 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate n = *pairp++; 14620Sstevel@tonic-gate while (n-->0) { 14630Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 14640Sstevel@tonic-gate pairp++; 14650Sstevel@tonic-gate break; 14660Sstevel@tonic-gate } else { 14670Sstevel@tonic-gate pairp += 2; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate (void) putchar(*pairp); 14710Sstevel@tonic-gate curcol++; 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate /* 14750Sstevel@tonic-gate * column: get to the beginning of the next column. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate static void 14780Sstevel@tonic-gate column(void) 14790Sstevel@tonic-gate { 14800Sstevel@tonic-gate if (curcol == 0) 14810Sstevel@tonic-gate return; 14820Sstevel@tonic-gate if (mflg) { 14830Sstevel@tonic-gate (void) putc(',', stdout); 14840Sstevel@tonic-gate curcol++; 14850Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 14860Sstevel@tonic-gate (void) putc('\n', stdout); 14870Sstevel@tonic-gate curcol = 0; 14880Sstevel@tonic-gate return; 14890Sstevel@tonic-gate } 14900Sstevel@tonic-gate (void) putc(' ', stdout); 14910Sstevel@tonic-gate curcol++; 14920Sstevel@tonic-gate return; 14930Sstevel@tonic-gate } 14940Sstevel@tonic-gate if (Cflg == 0) { 14950Sstevel@tonic-gate (void) putc('\n', stdout); 14960Sstevel@tonic-gate curcol = 0; 14970Sstevel@tonic-gate return; 14980Sstevel@tonic-gate } 14990Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 15000Sstevel@tonic-gate (void) putc('\n', stdout); 15010Sstevel@tonic-gate curcol = 0; 15020Sstevel@tonic-gate return; 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate do { 15050Sstevel@tonic-gate (void) putc(' ', stdout); 15060Sstevel@tonic-gate curcol++; 15070Sstevel@tonic-gate } while (curcol % colwidth); 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate static void 15110Sstevel@tonic-gate new_line(void) 15120Sstevel@tonic-gate { 15130Sstevel@tonic-gate if (curcol) { 15140Sstevel@tonic-gate first = 0; 15150Sstevel@tonic-gate (void) putc('\n', stdout); 15160Sstevel@tonic-gate curcol = 0; 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate /* 15210Sstevel@tonic-gate * read each filename in directory dir and store its 15220Sstevel@tonic-gate * status in flist[nfiles] 15230Sstevel@tonic-gate * use makename() to form pathname dir/filename; 15240Sstevel@tonic-gate */ 15250Sstevel@tonic-gate static void 15260Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 15270Sstevel@tonic-gate { 15280Sstevel@tonic-gate struct dirent *dentry; 15290Sstevel@tonic-gate DIR *dirf; 15300Sstevel@tonic-gate int j; 15310Sstevel@tonic-gate struct lbuf *ep; 15320Sstevel@tonic-gate int width; 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 15350Sstevel@tonic-gate (void) fflush(stdout); 15360Sstevel@tonic-gate perror(dir); 15370Sstevel@tonic-gate err = 2; 15380Sstevel@tonic-gate return; 15390Sstevel@tonic-gate } else { 15400Sstevel@tonic-gate tblocks = 0; 15410Sstevel@tonic-gate for (;;) { 15420Sstevel@tonic-gate errno = 0; 15430Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 15440Sstevel@tonic-gate break; 15450Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 15460Sstevel@tonic-gate (Aflg == 0 || 15470Sstevel@tonic-gate dentry->d_name[1] == '\0' || 15480Sstevel@tonic-gate dentry->d_name[1] == '.' && 15490Sstevel@tonic-gate dentry->d_name[2] == '\0')) 15500Sstevel@tonic-gate /* 15510Sstevel@tonic-gate * check for directory items '.', '..', 15520Sstevel@tonic-gate * and items without valid inode-number; 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate continue; 15550Sstevel@tonic-gate 15569664Sjason@ansipunx.net /* skip entries ending in ~ if -B was given */ 15579664Sjason@ansipunx.net if (Bflg && 15589664Sjason@ansipunx.net dentry->d_name[strlen(dentry->d_name) - 1] == '~') 15599664Sjason@ansipunx.net continue; 15600Sstevel@tonic-gate if (Cflg || mflg) { 15610Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 15620Sstevel@tonic-gate if (width > filewidth) 15630Sstevel@tonic-gate filewidth = width; 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 15660Sstevel@tonic-gate if (ep == NULL) { 15670Sstevel@tonic-gate if (nomocore) 15685331Samw exit(2); 15690Sstevel@tonic-gate continue; 15700Sstevel@tonic-gate } else { 15710Sstevel@tonic-gate ep->lnum = dentry->d_ino; 15720Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 15730Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 15740Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate if (errno) { 15780Sstevel@tonic-gate int sav_errno = errno; 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate (void) fprintf(stderr, 15810Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 15820Sstevel@tonic-gate dir, strerror(sav_errno)); 15830Sstevel@tonic-gate } 15840Sstevel@tonic-gate (void) closedir(dirf); 15850Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 15860Sstevel@tonic-gate } 15870Sstevel@tonic-gate } 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate /* 15900Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 15910Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 15920Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 15930Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 15940Sstevel@tonic-gate * it is reported at the right time when printing the directory. 15950Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 15960Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 15970Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 15980Sstevel@tonic-gate * command line. 15990Sstevel@tonic-gate */ 16000Sstevel@tonic-gate static void 16010Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 16020Sstevel@tonic-gate int argfl, struct ditem *myparent) 16030Sstevel@tonic-gate { 16040Sstevel@tonic-gate size_t file_len; 16050Sstevel@tonic-gate struct ditem *myinfo; 16060Sstevel@tonic-gate struct ditem *tptr; 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate file_len = strlen(file); 16090Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 16100Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 16110Sstevel@tonic-gate /* 16120Sstevel@tonic-gate * Add this inode's ancestry 16130Sstevel@tonic-gate * info and insert it into the 16140Sstevel@tonic-gate * ancestry list by pointing 16150Sstevel@tonic-gate * back to its parent. We save 16160Sstevel@tonic-gate * it (in rep) with the other info 16170Sstevel@tonic-gate * we're gathering for this inode. 16180Sstevel@tonic-gate */ 16190Sstevel@tonic-gate if ((myinfo = malloc( 16200Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 16210Sstevel@tonic-gate perror("ls"); 16220Sstevel@tonic-gate exit(2); 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 16250Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 16260Sstevel@tonic-gate myinfo->parent = myparent; 16270Sstevel@tonic-gate rep->ancinfo = myinfo; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate /* 16300Sstevel@tonic-gate * If this node has the same device id and 16310Sstevel@tonic-gate * inode number of one of its ancestors, 16320Sstevel@tonic-gate * then we've detected a cycle. 16330Sstevel@tonic-gate */ 16340Sstevel@tonic-gate if (myparent != NULL) { 16350Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 16360Sstevel@tonic-gate tptr = tptr->parent) { 16370Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 16380Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 16390Sstevel@tonic-gate /* 16400Sstevel@tonic-gate * Cycle detected for this 16410Sstevel@tonic-gate * directory. Record the fact 16420Sstevel@tonic-gate * it is a cycle so we don't 16430Sstevel@tonic-gate * try to process this 16440Sstevel@tonic-gate * directory as we are 16450Sstevel@tonic-gate * walking through the 16460Sstevel@tonic-gate * list of directories. 16470Sstevel@tonic-gate */ 16480Sstevel@tonic-gate rep->cycle = 1; 16490Sstevel@tonic-gate err = 2; 16500Sstevel@tonic-gate break; 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate } 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate /* 16586178Sny155746 * Do re-calculate the mode for group for ACE_T type of acls. 16596178Sny155746 * This is because, if the server's FS happens to be UFS, supporting 16606178Sny155746 * POSIX ACL's, then it does a special calculation of group mode 16616178Sny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 16626178Sny155746 * 16636178Sny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 16646178Sny155746 * algorithm is used for the group mode calculation only. 16656178Sny155746 * What is modified here from the algorithm is that only the 16666178Sny155746 * entries with flags ACE_GROUP are considered. For each entry 16676178Sny155746 * with ACE_GROUP flag, the first occurance of a specific access 16686178Sny155746 * is checked if it is allowed. 16696373Sny155746 * We are not interested in perms for user and other, as they 16706178Sny155746 * were taken from st_mode value. 16716178Sny155746 * We are not interested in a_who field of ACE, as we need just 16726178Sny155746 * unix mode bits for the group. 16736178Sny155746 */ 16746373Sny155746 16756373Sny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 16766373Sny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 16776373Sny155746 16786178Sny155746 int 16796178Sny155746 grp_mask_to_mode(acl_t *acep) 16806178Sny155746 { 16816178Sny155746 int mode = 0, seen = 0; 16826178Sny155746 int acecnt; 16836373Sny155746 int flags; 16846178Sny155746 ace_t *ap; 16856178Sny155746 16866178Sny155746 acecnt = acl_cnt(acep); 16876178Sny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 16886373Sny155746 16896373Sny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 16906373Sny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 16916373Sny155746 continue; 16926373Sny155746 16936373Sny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 16946373Sny155746 continue; 16956373Sny155746 16966373Sny155746 /* 16976373Sny155746 * if it is first group@ or first everyone@ 16986373Sny155746 * for each of read, write and execute, then 16996373Sny155746 * that will be the group mode bit. 17006373Sny155746 */ 17016373Sny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 17026373Sny155746 if (flags == OWNED_GROUP || flags == ACE_EVERYONE) { 17036373Sny155746 if (ap->a_access_mask & ACE_READ_DATA) { 17046373Sny155746 if (!(seen & S_IRGRP)) { 17056373Sny155746 seen |= S_IRGRP; 17066373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 17076373Sny155746 mode |= S_IRGRP; 17086178Sny155746 } 17096373Sny155746 } 17106373Sny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 17116373Sny155746 if (!(seen & S_IWGRP)) { 17126373Sny155746 seen |= S_IWGRP; 17136373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 17146373Sny155746 mode |= S_IWGRP; 17156178Sny155746 } 17166373Sny155746 } 17176373Sny155746 if (ap->a_access_mask & ACE_EXECUTE) { 17186373Sny155746 if (!(seen & S_IXGRP)) { 17196373Sny155746 seen |= S_IXGRP; 17206373Sny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 17216373Sny155746 mode |= S_IXGRP; 17226178Sny155746 } 17236178Sny155746 } 17246178Sny155746 } 17256178Sny155746 } 17266178Sny155746 return (mode); 17276178Sny155746 } 17286178Sny155746 17296178Sny155746 /* 17300Sstevel@tonic-gate * get status of file and recomputes tblocks; 17310Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 17320Sstevel@tonic-gate * for filename in a directory whose name is an 17330Sstevel@tonic-gate * argument in the command; 17340Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 17350Sstevel@tonic-gate * returns that pointer; 17360Sstevel@tonic-gate * returns NULL if failed; 17370Sstevel@tonic-gate */ 17380Sstevel@tonic-gate static struct lbuf * 17390Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 17400Sstevel@tonic-gate { 17410Sstevel@tonic-gate struct stat statb, statb1; 17420Sstevel@tonic-gate struct lbuf *rep; 17430Sstevel@tonic-gate char buf[BUFSIZ]; 17440Sstevel@tonic-gate ssize_t cc; 17450Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 17460Sstevel@tonic-gate int aclcnt; 1747789Sahrens int error; 17480Sstevel@tonic-gate aclent_t *tp; 17490Sstevel@tonic-gate o_mode_t groupperm, mask; 17500Sstevel@tonic-gate int grouppermfound, maskfound; 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate if (nomocore) 17530Sstevel@tonic-gate return (NULL); 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate if (nfiles >= maxfils) { 17560Sstevel@tonic-gate /* 17570Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 17580Sstevel@tonic-gate * more space 17590Sstevel@tonic-gate */ 17600Sstevel@tonic-gate maxfils += quantn; 17610Sstevel@tonic-gate if (((flist = realloc(flist, 17620Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 17630Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 17640Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 17650Sstevel@tonic-gate perror("ls"); 17660Sstevel@tonic-gate nomocore = 1; 17670Sstevel@tonic-gate return (NULL); 17680Sstevel@tonic-gate } 17690Sstevel@tonic-gate } 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate /* 17720Sstevel@tonic-gate * nfiles is reset to nargs for each directory 17730Sstevel@tonic-gate * that is given as an argument maxn is checked 17740Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 17750Sstevel@tonic-gate * that already has one assigned. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate if (nfiles >= maxn) { 17780Sstevel@tonic-gate rep = nxtlbf++; 17790Sstevel@tonic-gate flist[nfiles++] = rep; 17800Sstevel@tonic-gate maxn = nfiles; 17810Sstevel@tonic-gate } else { 17820Sstevel@tonic-gate rep = flist[nfiles++]; 17830Sstevel@tonic-gate } 17846792Sbasabi 17856792Sbasabi /* Initialize */ 17866792Sbasabi 17870Sstevel@tonic-gate rep->lflags = (mode_t)0; 17880Sstevel@tonic-gate rep->flinkto = NULL; 17890Sstevel@tonic-gate rep->cycle = 0; 17906792Sbasabi rep->lat.tv_sec = time(NULL); 17916792Sbasabi rep->lat.tv_nsec = 0; 17926792Sbasabi rep->lct.tv_sec = time(NULL); 17936792Sbasabi rep->lct.tv_nsec = 0; 17946792Sbasabi rep->lmt.tv_sec = time(NULL); 17956792Sbasabi rep->lmt.tv_nsec = 0; 17966792Sbasabi rep->exttr = NULL; 17976792Sbasabi rep->extm = NULL; 1798*10059Sjason@ansipunx.net rep->color = NULL; 1799*10059Sjason@ansipunx.net rep->link_color = NULL; 18006792Sbasabi 18010Sstevel@tonic-gate if (argfl || statreq) { 18020Sstevel@tonic-gate int doacl; 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate if (lflg) 18050Sstevel@tonic-gate doacl = 1; 18060Sstevel@tonic-gate else 18070Sstevel@tonic-gate doacl = 0; 18086792Sbasabi 18090Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 18100Sstevel@tonic-gate if (argfl || errno != ENOENT || 18110Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 18120Sstevel@tonic-gate /* 18130Sstevel@tonic-gate * Avoid race between readdir and lstat. 18140Sstevel@tonic-gate * Print error message in case of dangling link. 18150Sstevel@tonic-gate */ 18160Sstevel@tonic-gate perror(file); 18179664Sjason@ansipunx.net err = 2; 18180Sstevel@tonic-gate } 18190Sstevel@tonic-gate nfiles--; 18200Sstevel@tonic-gate return (NULL); 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate 18230Sstevel@tonic-gate /* 18240Sstevel@tonic-gate * If -H was specified, and the file linked to was 18250Sstevel@tonic-gate * not a directory, then we need to get the info 18260Sstevel@tonic-gate * for the symlink itself. 18270Sstevel@tonic-gate */ 18280Sstevel@tonic-gate if ((Hflg) && (argfl) && 18290Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 18300Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 18310Sstevel@tonic-gate perror(file); 18329664Sjason@ansipunx.net err = 2; 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate rep->lnum = statb.st_ino; 18370Sstevel@tonic-gate rep->lsize = statb.st_size; 18380Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 1839*10059Sjason@ansipunx.net if (colorflg) 1840*10059Sjason@ansipunx.net rep->color = ls_color_find(file, statb.st_mode); 1841*10059Sjason@ansipunx.net 18420Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 18430Sstevel@tonic-gate case S_IFDIR: 18440Sstevel@tonic-gate rep->ltype = 'd'; 18450Sstevel@tonic-gate if (Rflg) { 18460Sstevel@tonic-gate record_ancestry(file, &statb, rep, 18470Sstevel@tonic-gate argfl, myparent); 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate break; 18500Sstevel@tonic-gate case S_IFBLK: 18510Sstevel@tonic-gate rep->ltype = 'b'; 18520Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18530Sstevel@tonic-gate break; 18540Sstevel@tonic-gate case S_IFCHR: 18550Sstevel@tonic-gate rep->ltype = 'c'; 18560Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 18570Sstevel@tonic-gate break; 18580Sstevel@tonic-gate case S_IFIFO: 18590Sstevel@tonic-gate rep->ltype = 'p'; 18600Sstevel@tonic-gate break; 18610Sstevel@tonic-gate case S_IFSOCK: 18620Sstevel@tonic-gate rep->ltype = 's'; 18630Sstevel@tonic-gate rep->lsize = 0; 18640Sstevel@tonic-gate break; 18650Sstevel@tonic-gate case S_IFLNK: 18660Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 18670Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 18680Sstevel@tonic-gate ((Hflg) && (!argfl))) { 18690Sstevel@tonic-gate doacl = 0; 18700Sstevel@tonic-gate } 18710Sstevel@tonic-gate rep->ltype = 'l'; 1872*10059Sjason@ansipunx.net if (lflg || colorflg) { 18730Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 1874*10059Sjason@ansipunx.net if (cc < 0) 1875*10059Sjason@ansipunx.net break; 1876*10059Sjason@ansipunx.net 1877*10059Sjason@ansipunx.net /* 1878*10059Sjason@ansipunx.net * follow the symbolic link 1879*10059Sjason@ansipunx.net * to generate the appropriate 1880*10059Sjason@ansipunx.net * Fflg marker for the object 1881*10059Sjason@ansipunx.net * eg, /bin -> /sym/bin/ 1882*10059Sjason@ansipunx.net */ 1883*10059Sjason@ansipunx.net error = 0; 1884*10059Sjason@ansipunx.net if (Fflg || pflg || colorflg) 1885*10059Sjason@ansipunx.net error = stat(file, &statb1); 18860Sstevel@tonic-gate 1887*10059Sjason@ansipunx.net if (colorflg) { 1888*10059Sjason@ansipunx.net if (error >= 0) 1889*10059Sjason@ansipunx.net rep->link_color = 1890*10059Sjason@ansipunx.net ls_color_find(file, 1891*10059Sjason@ansipunx.net statb1.st_mode); 1892*10059Sjason@ansipunx.net else 1893*10059Sjason@ansipunx.net rep->link_color = 1894*10059Sjason@ansipunx.net lsc_orphan; 1895*10059Sjason@ansipunx.net } 1896*10059Sjason@ansipunx.net 1897*10059Sjason@ansipunx.net if ((Fflg || pflg) && error >= 0) { 1898*10059Sjason@ansipunx.net switch (statb1.st_mode & S_IFMT) { 1899*10059Sjason@ansipunx.net case S_IFDIR: 1900*10059Sjason@ansipunx.net buf[cc++] = '/'; 1901*10059Sjason@ansipunx.net break; 1902*10059Sjason@ansipunx.net case S_IFSOCK: 1903*10059Sjason@ansipunx.net buf[cc++] = '='; 1904*10059Sjason@ansipunx.net break; 1905*10059Sjason@ansipunx.net case S_IFDOOR: 1906*10059Sjason@ansipunx.net buf[cc++] = '>'; 1907*10059Sjason@ansipunx.net break; 1908*10059Sjason@ansipunx.net case S_IFIFO: 1909*10059Sjason@ansipunx.net buf[cc++] = '|'; 1910*10059Sjason@ansipunx.net break; 1911*10059Sjason@ansipunx.net default: 1912*10059Sjason@ansipunx.net if ((statb1.st_mode & ~S_IFMT) & 1913*10059Sjason@ansipunx.net (S_IXUSR|S_IXGRP| S_IXOTH)) 1914*10059Sjason@ansipunx.net buf[cc++] = '*'; 1915*10059Sjason@ansipunx.net break; 19160Sstevel@tonic-gate } 19170Sstevel@tonic-gate } 1918*10059Sjason@ansipunx.net buf[cc] = '\0'; 1919*10059Sjason@ansipunx.net rep->flinkto = strdup(buf); 19200Sstevel@tonic-gate break; 19210Sstevel@tonic-gate } 19220Sstevel@tonic-gate 19230Sstevel@tonic-gate /* 19240Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 19250Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 19260Sstevel@tonic-gate * when explicit arguments are specified. 19270Sstevel@tonic-gate */ 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate #ifdef XPG6 19300Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 19310Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 19320Sstevel@tonic-gate (stat(file, &statb1) < 0)) 19330Sstevel@tonic-gate #else 19340Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 19350Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 19360Sstevel@tonic-gate #endif /* XPG6 */ 19370Sstevel@tonic-gate break; 19380Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 19390Sstevel@tonic-gate statb = statb1; 19400Sstevel@tonic-gate rep->ltype = 'd'; 19410Sstevel@tonic-gate rep->lsize = statb1.st_size; 19420Sstevel@tonic-gate if (Rflg) { 19430Sstevel@tonic-gate record_ancestry(file, &statb, rep, 19440Sstevel@tonic-gate argfl, myparent); 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate } 19470Sstevel@tonic-gate break; 19480Sstevel@tonic-gate case S_IFDOOR: 19490Sstevel@tonic-gate rep->ltype = 'D'; 19500Sstevel@tonic-gate break; 19510Sstevel@tonic-gate case S_IFREG: 19520Sstevel@tonic-gate rep->ltype = '-'; 19530Sstevel@tonic-gate break; 19540Sstevel@tonic-gate case S_IFPORT: 19550Sstevel@tonic-gate rep->ltype = 'P'; 19560Sstevel@tonic-gate break; 19570Sstevel@tonic-gate default: 19580Sstevel@tonic-gate rep->ltype = '?'; 19590Sstevel@tonic-gate break; 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 19620Sstevel@tonic-gate 19630Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 19640Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 19650Sstevel@tonic-gate 19666792Sbasabi rep->luid = statb.st_uid; 19676792Sbasabi rep->lgid = statb.st_gid; 19686792Sbasabi rep->lnl = statb.st_nlink; 19696792Sbasabi if (uflg || (tmflg && atm)) 19706792Sbasabi rep->lmtime = statb.st_atim; 19716792Sbasabi else if (cflg || (tmflg && ctm)) 19726792Sbasabi rep->lmtime = statb.st_ctim; 19736792Sbasabi else 19746792Sbasabi rep->lmtime = statb.st_mtim; 19756792Sbasabi rep->lat = statb.st_atim; 19766792Sbasabi rep->lct = statb.st_ctim; 19776792Sbasabi rep->lmt = statb.st_mtim; 19786792Sbasabi 19790Sstevel@tonic-gate /* ACL: check acl entries count */ 19800Sstevel@tonic-gate if (doacl) { 19810Sstevel@tonic-gate 1982789Sahrens error = acl_get(file, 0, &rep->aclp); 1983789Sahrens if (error) { 1984789Sahrens (void) fprintf(stderr, 1985789Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1986789Sahrens file, acl_strerror(error)); 19876792Sbasabi rep->acl = ' '; 19886866Sbasabi acl_err++; 19896792Sbasabi return (rep); 1990789Sahrens } 19910Sstevel@tonic-gate 1992789Sahrens rep->acl = ' '; 19930Sstevel@tonic-gate 1994789Sahrens if (rep->aclp && 1995789Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1996789Sahrens rep->acl = '+'; 19970Sstevel@tonic-gate /* 1998789Sahrens * Special handling for ufs aka aclent_t ACL's 19990Sstevel@tonic-gate */ 20006178Sny155746 if (acl_type(rep->aclp) == ACLENT_T) { 2001789Sahrens /* 2002789Sahrens * For files with non-trivial acls, the 2003789Sahrens * effective group permissions are the 2004789Sahrens * intersection of the GROUP_OBJ value 2005789Sahrens * and the CLASS_OBJ (acl mask) value. 2006789Sahrens * Determine both the GROUP_OBJ and 2007789Sahrens * CLASS_OBJ for this file and insert 2008789Sahrens * the logical AND of those two values 2009789Sahrens * in the group permissions field 2010789Sahrens * of the lflags value for this file. 2011789Sahrens */ 2012789Sahrens 2013789Sahrens /* 2014789Sahrens * Until found in acl list, assume 2015789Sahrens * maximum permissions for both group 2016789Sahrens * a nd mask. (Just in case the acl 2017789Sahrens * lacks either value for some reason.) 2018789Sahrens */ 2019789Sahrens groupperm = 07; 2020789Sahrens mask = 07; 2021789Sahrens grouppermfound = 0; 2022789Sahrens maskfound = 0; 2023789Sahrens aclcnt = acl_cnt(rep->aclp); 2024789Sahrens for (tp = 2025789Sahrens (aclent_t *)acl_data(rep->aclp); 2026789Sahrens aclcnt--; tp++) { 2027789Sahrens if (tp->a_type == GROUP_OBJ) { 2028789Sahrens groupperm = tp->a_perm; 2029789Sahrens grouppermfound = 1; 2030789Sahrens continue; 2031789Sahrens } 2032789Sahrens if (tp->a_type == CLASS_OBJ) { 2033789Sahrens mask = tp->a_perm; 2034789Sahrens maskfound = 1; 2035789Sahrens } 2036789Sahrens if (grouppermfound && maskfound) 2037789Sahrens break; 20380Sstevel@tonic-gate } 2039789Sahrens 20400Sstevel@tonic-gate 2041789Sahrens /* reset all the group bits */ 2042789Sahrens rep->lflags &= ~S_IRWXG; 20430Sstevel@tonic-gate 2044789Sahrens /* 2045789Sahrens * Now set them to the logical AND of 2046789Sahrens * the GROUP_OBJ permissions and the 2047789Sahrens * acl mask. 2048789Sahrens */ 20490Sstevel@tonic-gate 2050789Sahrens rep->lflags |= (groupperm & mask) << 3; 20510Sstevel@tonic-gate 20526178Sny155746 } else if (acl_type(rep->aclp) == ACE_T) { 20536178Sny155746 int mode; 20546178Sny155746 mode = grp_mask_to_mode(rep->aclp); 20556178Sny155746 rep->lflags &= ~S_IRWXG; 20566178Sny155746 rep->lflags |= mode; 2057789Sahrens } 20580Sstevel@tonic-gate } 20590Sstevel@tonic-gate 20601420Smarks if (!vflg && !Vflg && rep->aclp) { 20611420Smarks acl_free(rep->aclp); 20621420Smarks rep->aclp = NULL; 20631420Smarks } 20641420Smarks 20650Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 20660Sstevel@tonic-gate rep->acl = '@'; 20675331Samw 20680Sstevel@tonic-gate } else 20690Sstevel@tonic-gate rep->acl = ' '; 20700Sstevel@tonic-gate 20710Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 20740Sstevel@tonic-gate tblocks += rep->lblocks; 20755331Samw 20765331Samw /* Get extended system attributes */ 20775331Samw 20785331Samw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 20795331Samw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 20805331Samw int i; 20815331Samw 20825331Samw sacnt = attr_count(); 20835331Samw /* 20845331Samw * Allocate 'sacnt' size array to hold extended 20855331Samw * system attribute name (verbose) or respective 20865331Samw * symbol represenation (compact). 20875331Samw */ 20885331Samw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 20895331Samw rep); 20905331Samw 20915331Samw /* initialize boolean attribute list */ 20925331Samw for (i = 0; i < sacnt; i++) 20935331Samw rep->exttr[i].name = NULL; 20945331Samw if (get_sysxattr(file, rep) != 0) { 20955331Samw (void) fprintf(stderr, 20965331Samw gettext("ls:Failed to retrieve " 20975331Samw "extended system attribute from " 20985331Samw "%s\n"), file); 20995331Samw rep->exttr[0].name = xmalloc(2, rep); 21005331Samw (void) strlcpy(rep->exttr[0].name, "?", 2); 21015331Samw } 21025331Samw } 21030Sstevel@tonic-gate } 21040Sstevel@tonic-gate return (rep); 21050Sstevel@tonic-gate } 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate /* 21080Sstevel@tonic-gate * returns pathname of the form dir/file; 21090Sstevel@tonic-gate * dir and file are null-terminated strings. 21100Sstevel@tonic-gate */ 21110Sstevel@tonic-gate static char * 21120Sstevel@tonic-gate makename(char *dir, char *file) 21130Sstevel@tonic-gate { 21140Sstevel@tonic-gate /* 21150Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 21160Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 21170Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 21180Sstevel@tonic-gate * and the null character at the end. 21190Sstevel@tonic-gate * dfile is static as this is returned by makename(). 21200Sstevel@tonic-gate */ 21210Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 21220Sstevel@tonic-gate char *dp, *fp; 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate dp = dfile; 21250Sstevel@tonic-gate fp = dir; 21260Sstevel@tonic-gate while (*fp) 21270Sstevel@tonic-gate *dp++ = *fp++; 21280Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 21290Sstevel@tonic-gate *dp++ = '/'; 21300Sstevel@tonic-gate fp = file; 21310Sstevel@tonic-gate while (*fp) 21320Sstevel@tonic-gate *dp++ = *fp++; 21330Sstevel@tonic-gate *dp = '\0'; 21340Sstevel@tonic-gate return (dfile); 21350Sstevel@tonic-gate } 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate #include <pwd.h> 21390Sstevel@tonic-gate #include <grp.h> 21400Sstevel@tonic-gate #include <utmpx.h> 21410Sstevel@tonic-gate 21420Sstevel@tonic-gate struct utmpx utmp; 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 21450Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 21460Sstevel@tonic-gate 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 21490Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 21500Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 21510Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 21520Sstevel@tonic-gate int initted; /* name has been filled in */ 21530Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 21540Sstevel@tonic-gate }; 21550Sstevel@tonic-gate static struct cachenode *names, *groups; 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate static struct cachenode * 21580Sstevel@tonic-gate findincache(struct cachenode **head, long val) 21590Sstevel@tonic-gate { 21600Sstevel@tonic-gate struct cachenode **parent = head; 21610Sstevel@tonic-gate struct cachenode *c = *parent; 21620Sstevel@tonic-gate 21630Sstevel@tonic-gate while (c != NULL) { 21640Sstevel@tonic-gate if (val == c->val) { 21650Sstevel@tonic-gate /* found it */ 21660Sstevel@tonic-gate return (c); 21670Sstevel@tonic-gate } else if (val < c->val) { 21680Sstevel@tonic-gate parent = &c->lesschild; 21690Sstevel@tonic-gate c = c->lesschild; 21700Sstevel@tonic-gate } else { 21710Sstevel@tonic-gate parent = &c->grtrchild; 21720Sstevel@tonic-gate c = c->grtrchild; 21730Sstevel@tonic-gate } 21740Sstevel@tonic-gate } 21750Sstevel@tonic-gate 21760Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 21770Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 21780Sstevel@tonic-gate if (c == NULL) { 21790Sstevel@tonic-gate perror("ls"); 21800Sstevel@tonic-gate exit(2); 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate *parent = c; 21830Sstevel@tonic-gate c->val = val; 21840Sstevel@tonic-gate return (c); 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate 21870Sstevel@tonic-gate /* 21880Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 21890Sstevel@tonic-gate * lastuid is set to uid. 21900Sstevel@tonic-gate */ 21910Sstevel@tonic-gate static char * 21920Sstevel@tonic-gate getname(uid_t uid) 21930Sstevel@tonic-gate { 21940Sstevel@tonic-gate struct passwd *pwent; 21950Sstevel@tonic-gate struct cachenode *c; 21960Sstevel@tonic-gate 21970Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 21980Sstevel@tonic-gate return (lastuname); 21990Sstevel@tonic-gate 22000Sstevel@tonic-gate c = findincache(&names, uid); 22010Sstevel@tonic-gate if (c->initted == 0) { 22020Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 22030Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 22040Sstevel@tonic-gate } else { 22050Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 22060Sstevel@tonic-gate } 22070Sstevel@tonic-gate c->initted = 1; 22080Sstevel@tonic-gate } 22090Sstevel@tonic-gate lastuid = uid; 22100Sstevel@tonic-gate lastuname = &c->name[0]; 22110Sstevel@tonic-gate return (lastuname); 22120Sstevel@tonic-gate } 22130Sstevel@tonic-gate 22140Sstevel@tonic-gate /* 22150Sstevel@tonic-gate * get name from cache, or group file for a given gid; 22160Sstevel@tonic-gate * lastgid is set to gid. 22170Sstevel@tonic-gate */ 22180Sstevel@tonic-gate static char * 22190Sstevel@tonic-gate getgroup(gid_t gid) 22200Sstevel@tonic-gate { 22210Sstevel@tonic-gate struct group *grent; 22220Sstevel@tonic-gate struct cachenode *c; 22230Sstevel@tonic-gate 22240Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 22250Sstevel@tonic-gate return (lastgname); 22260Sstevel@tonic-gate 22270Sstevel@tonic-gate c = findincache(&groups, gid); 22280Sstevel@tonic-gate if (c->initted == 0) { 22290Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 22300Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 22310Sstevel@tonic-gate } else { 22320Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 22330Sstevel@tonic-gate } 22340Sstevel@tonic-gate c->initted = 1; 22350Sstevel@tonic-gate } 22360Sstevel@tonic-gate lastgid = gid; 22370Sstevel@tonic-gate lastgname = &c->name[0]; 22380Sstevel@tonic-gate return (lastgname); 22390Sstevel@tonic-gate } 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 22420Sstevel@tonic-gate static int 22430Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 22440Sstevel@tonic-gate { 22450Sstevel@tonic-gate struct lbuf *p1, *p2; 22460Sstevel@tonic-gate 22470Sstevel@tonic-gate p1 = *pp1; 22480Sstevel@tonic-gate p2 = *pp2; 22490Sstevel@tonic-gate if (dflg == 0) { 22500Sstevel@tonic-gate /* 22510Sstevel@tonic-gate * compare two names in ls-command one of which is file 22520Sstevel@tonic-gate * and the other is a directory; 22530Sstevel@tonic-gate * this portion is not used for comparing files within 22540Sstevel@tonic-gate * a directory name of ls-command; 22550Sstevel@tonic-gate */ 22560Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 22570Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 22580Sstevel@tonic-gate return (1); 22590Sstevel@tonic-gate } else { 22600Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 22610Sstevel@tonic-gate return (-1); 22620Sstevel@tonic-gate } 22630Sstevel@tonic-gate } 22640Sstevel@tonic-gate if (tflg) { 22650Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 22660Sstevel@tonic-gate return (rflg); 22670Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 22680Sstevel@tonic-gate return (-rflg); 22690Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 22700Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 22710Sstevel@tonic-gate return (rflg); 22720Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 22730Sstevel@tonic-gate return (-rflg); 22740Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 22750Sstevel@tonic-gate } else if (Sflg) { 22760Sstevel@tonic-gate /* 22770Sstevel@tonic-gate * The size stored in lsize can be either the 22780Sstevel@tonic-gate * size or the major minor number (in the case of 22790Sstevel@tonic-gate * block and character special devices). If it's 22800Sstevel@tonic-gate * a major minor number, then the size is considered 22810Sstevel@tonic-gate * to be zero and we want to fall through and sort 22820Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 22830Sstevel@tonic-gate * to the size of p1 we want to fall through and 22840Sstevel@tonic-gate * sort by name. 22850Sstevel@tonic-gate */ 22860Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 22875331Samw (p1->ltype == 'c') ? 0 : p1->lsize; 22880Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 22895331Samw (p2->ltype == 'c') ? 0 : p2->lsize; 22900Sstevel@tonic-gate if (p2size > p1size) { 22910Sstevel@tonic-gate return (rflg); 22920Sstevel@tonic-gate } else if (p2size < p1size) { 22930Sstevel@tonic-gate return (-rflg); 22940Sstevel@tonic-gate } 22950Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 22960Sstevel@tonic-gate } 22970Sstevel@tonic-gate return (rflg * strcoll( 22980Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 22990Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 23000Sstevel@tonic-gate } 23010Sstevel@tonic-gate 23020Sstevel@tonic-gate static void 23030Sstevel@tonic-gate pprintf(char *s1, char *s2) 23040Sstevel@tonic-gate { 23050Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 23060Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 23070Sstevel@tonic-gate } 23080Sstevel@tonic-gate 23090Sstevel@tonic-gate static void 23100Sstevel@tonic-gate csi_pprintf(unsigned char *s) 23110Sstevel@tonic-gate { 23120Sstevel@tonic-gate unsigned char *cp; 23130Sstevel@tonic-gate char c; 23140Sstevel@tonic-gate int i; 23150Sstevel@tonic-gate int c_len; 23160Sstevel@tonic-gate int p_col; 23170Sstevel@tonic-gate wchar_t pcode; 23180Sstevel@tonic-gate 23190Sstevel@tonic-gate if (!qflg && !bflg) { 23200Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 23210Sstevel@tonic-gate (void) putchar(*cp); 23220Sstevel@tonic-gate curcol++; 23230Sstevel@tonic-gate } 23240Sstevel@tonic-gate return; 23250Sstevel@tonic-gate } 23260Sstevel@tonic-gate 23270Sstevel@tonic-gate for (cp = s; *cp; ) { 23280Sstevel@tonic-gate if (isascii(c = *cp)) { 23290Sstevel@tonic-gate if (!isprint(c)) { 23300Sstevel@tonic-gate if (qflg) { 23310Sstevel@tonic-gate c = '?'; 23320Sstevel@tonic-gate } else { 23330Sstevel@tonic-gate curcol += 3; 23340Sstevel@tonic-gate (void) putc('\\', stdout); 23350Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23360Sstevel@tonic-gate (void) putc(c, stdout); 23370Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23380Sstevel@tonic-gate (void) putc(c, stdout); 23390Sstevel@tonic-gate c = '0' + (*cp & 07); 23400Sstevel@tonic-gate } 23410Sstevel@tonic-gate } 23420Sstevel@tonic-gate curcol++; 23430Sstevel@tonic-gate cp++; 23440Sstevel@tonic-gate (void) putc(c, stdout); 23450Sstevel@tonic-gate continue; 23460Sstevel@tonic-gate } 23470Sstevel@tonic-gate 23480Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 23490Sstevel@tonic-gate c_len = 1; 23500Sstevel@tonic-gate goto not_print; 23510Sstevel@tonic-gate } 23520Sstevel@tonic-gate 23530Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 23540Sstevel@tonic-gate (void) putwchar(pcode); 23550Sstevel@tonic-gate cp += c_len; 23560Sstevel@tonic-gate curcol += p_col; 23570Sstevel@tonic-gate continue; 23580Sstevel@tonic-gate } 23590Sstevel@tonic-gate 23600Sstevel@tonic-gate not_print: 23610Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 23620Sstevel@tonic-gate if (qflg) { 23630Sstevel@tonic-gate c = '?'; 23640Sstevel@tonic-gate } else { 23650Sstevel@tonic-gate curcol += 3; 23660Sstevel@tonic-gate (void) putc('\\', stdout); 23670Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 23680Sstevel@tonic-gate (void) putc(c, stdout); 23690Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 23700Sstevel@tonic-gate (void) putc(c, stdout); 23710Sstevel@tonic-gate c = '0' + (*cp & 07); 23720Sstevel@tonic-gate } 23730Sstevel@tonic-gate curcol++; 23740Sstevel@tonic-gate (void) putc(c, stdout); 23750Sstevel@tonic-gate cp++; 23760Sstevel@tonic-gate } 23770Sstevel@tonic-gate } 23780Sstevel@tonic-gate } 23790Sstevel@tonic-gate 23800Sstevel@tonic-gate static int 23810Sstevel@tonic-gate strcol(unsigned char *s1) 23820Sstevel@tonic-gate { 23830Sstevel@tonic-gate int w; 23840Sstevel@tonic-gate int w_col; 23850Sstevel@tonic-gate int len; 23860Sstevel@tonic-gate wchar_t wc; 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate w = 0; 23890Sstevel@tonic-gate while (*s1) { 23900Sstevel@tonic-gate if (isascii(*s1)) { 23910Sstevel@tonic-gate w++; 23920Sstevel@tonic-gate s1++; 23930Sstevel@tonic-gate continue; 23940Sstevel@tonic-gate } 23950Sstevel@tonic-gate 23960Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 23970Sstevel@tonic-gate w++; 23980Sstevel@tonic-gate s1++; 23990Sstevel@tonic-gate continue; 24000Sstevel@tonic-gate } 24010Sstevel@tonic-gate 24020Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 24030Sstevel@tonic-gate w_col = len; 24040Sstevel@tonic-gate s1 += len; 24050Sstevel@tonic-gate w += w_col; 24060Sstevel@tonic-gate } 24070Sstevel@tonic-gate return (w); 24080Sstevel@tonic-gate } 24090Sstevel@tonic-gate 24100Sstevel@tonic-gate /* 24110Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 24120Sstevel@tonic-gate * result in the caller-supplied buffer. 24130Sstevel@tonic-gate * 24140Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 24150Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 24160Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 24170Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 24180Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 24190Sstevel@tonic-gate * the final number has only a single significant digit, we compute 24200Sstevel@tonic-gate * tenths of units to provide a second significant digit. 24210Sstevel@tonic-gate * 24220Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 24230Sstevel@tonic-gate * converted to "-1". 24240Sstevel@tonic-gate * 24250Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 24260Sstevel@tonic-gate */ 24270Sstevel@tonic-gate static char * 24280Sstevel@tonic-gate number_to_scaled_string( 24290Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 24300Sstevel@tonic-gate unsigned long long number, /* convert this number */ 24310Sstevel@tonic-gate long scale) 24320Sstevel@tonic-gate { 24330Sstevel@tonic-gate unsigned long long save; 24340Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 24350Sstevel@tonic-gate char *uom = "KMGTPE"; 24360Sstevel@tonic-gate 24370Sstevel@tonic-gate if ((long long)number == (long long)-1) { 24380Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 24390Sstevel@tonic-gate return (buf); 24400Sstevel@tonic-gate } 24410Sstevel@tonic-gate 24420Sstevel@tonic-gate save = number; 24430Sstevel@tonic-gate number = number / scale; 24440Sstevel@tonic-gate 24450Sstevel@tonic-gate /* 24460Sstevel@tonic-gate * Now we have number as a count of scale units. 24470Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 24480Sstevel@tonic-gate * 24490Sstevel@tonic-gate * The largest value number could have had entering the routine is 24500Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 24510Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 24520Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 24530Sstevel@tonic-gate */ 24540Sstevel@tonic-gate if (number < (unsigned long long)scale) { 24550Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 24560Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 24570Sstevel@tonic-gate uom++; 24580Sstevel@tonic-gate number = 1; 24590Sstevel@tonic-gate } 24600Sstevel@tonic-gate } 24610Sstevel@tonic-gate } else { 24620Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 24630Sstevel@tonic-gate uom++; /* next unit of measurement */ 24640Sstevel@tonic-gate save = number; 24650Sstevel@tonic-gate /* 24660Sstevel@tonic-gate * If we're over half way to the next unit of 24670Sstevel@tonic-gate * 'scale' bytes (which means we should round 24680Sstevel@tonic-gate * up), then adding half of 'scale' prior to 24690Sstevel@tonic-gate * the division will push us into that next 24700Sstevel@tonic-gate * unit of scale when we perform the division 24710Sstevel@tonic-gate */ 24720Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 24730Sstevel@tonic-gate } 24740Sstevel@tonic-gate } 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 24770Sstevel@tonic-gate if ((save / scale) < 10) { 24780Sstevel@tonic-gate /* snprintf() will round for us */ 24790Sstevel@tonic-gate float fnum = (float)save / scale; 24800Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 24810Sstevel@tonic-gate fnum, *uom); 24820Sstevel@tonic-gate } else { 24830Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 24840Sstevel@tonic-gate number, *uom); 24850Sstevel@tonic-gate } 24860Sstevel@tonic-gate return (buf); 24870Sstevel@tonic-gate } 24885331Samw 24895331Samw /* Get extended system attributes and set the display */ 24905331Samw 24915331Samw int 24925331Samw get_sysxattr(char *fname, struct lbuf *rep) 24935331Samw { 24945331Samw boolean_t value; 24955331Samw data_type_t type; 24965331Samw int error; 24975331Samw char *name; 24985331Samw int i; 24995331Samw 25005331Samw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 25015331Samw &response)) != 0) { 25025331Samw perror("ls:getattrat"); 25035331Samw return (error); 25045331Samw } 25055331Samw 25065331Samw /* 25075331Samw * Allocate 'sacnt' size array to hold extended timestamp 25085331Samw * system attributes and initialize the array. 25095331Samw */ 25105331Samw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 25115331Samw for (i = 0; i < sacnt; i++) { 25125331Samw rep->extm[i].stm = 0; 25135331Samw rep->extm[i].nstm = 0; 25145331Samw rep->extm[i].name = NULL; 25155331Samw } 25165331Samw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 25175331Samw name = nvpair_name(pair); 25185331Samw type = nvpair_type(pair); 25195331Samw if (type == DATA_TYPE_BOOLEAN_VALUE) { 25205331Samw error = nvpair_value_boolean_value(pair, &value); 25215331Samw if (error) { 25225331Samw (void) fprintf(stderr, 25235331Samw gettext("nvpair_value_boolean_value " 25245331Samw "failed: error = %d\n"), error); 25255331Samw continue; 25265331Samw } 25275331Samw if (name != NULL) 25285331Samw set_sysattrb_display(name, value, rep); 25295331Samw continue; 25305331Samw } else if (type == DATA_TYPE_UINT64_ARRAY) { 25315331Samw if (name != NULL) 25325331Samw set_sysattrtm_display(name, rep); 25335331Samw continue; 25345331Samw } 25355331Samw } 25365331Samw nvlist_free(response); 25375331Samw return (0); 25385331Samw } 25395331Samw 25405331Samw /* Set extended system attribute boolean display */ 25415331Samw 25425331Samw void 25435331Samw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 25445331Samw { 25455331Samw f_attr_t fattr; 25465331Samw const char *opt; 25475331Samw size_t len; 25485331Samw 25495331Samw fattr = name_to_attr(name); 25505331Samw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 25515331Samw if (vopt) { 25525331Samw len = strlen(name); 25535331Samw if (val) { 25545331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 25555331Samw (void) strlcpy(rep->exttr[fattr].name, name, 25565331Samw len + 1); 25575331Samw } else { 25585331Samw rep->exttr[fattr].name = xmalloc(len + 3, rep); 25595331Samw (void) snprintf(rep->exttr[fattr].name, len + 3, 25605331Samw "no%s", name); 25615331Samw } 25625331Samw } else { 25635331Samw opt = attr_to_option(fattr); 25645331Samw if (opt != NULL) { 25655331Samw len = strlen(opt); 25665331Samw rep->exttr[fattr].name = xmalloc(len + 1, rep); 25675331Samw if (val) 25685331Samw (void) strlcpy(rep->exttr[fattr].name, 25695331Samw opt, len + 1); 25705331Samw else 25715331Samw (void) strlcpy(rep->exttr[fattr].name, 25725331Samw "-", len + 1); 25735331Samw } 25745331Samw } 25755331Samw } 25765331Samw } 25775331Samw 25785331Samw /* Set extended system attribute timestamp display */ 25795331Samw 25805331Samw void 25815331Samw set_sysattrtm_display(char *name, struct lbuf *rep) 25825331Samw { 25835331Samw uint_t nelem; 25845331Samw uint64_t *value; 25855331Samw int i; 25865331Samw size_t len; 25875331Samw 25885331Samw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 25895331Samw if (*value != NULL) { 25905331Samw len = strlen(name); 25915331Samw i = 0; 25925331Samw while (rep->extm[i].stm != 0 && i < sacnt) 25935331Samw i++; 25945331Samw rep->extm[i].stm = value[0]; 25955331Samw rep->extm[i].nstm = value[1]; 25965331Samw rep->extm[i].name = xmalloc(len + 1, rep); 25975331Samw (void) strlcpy(rep->extm[i].name, name, len + 1); 25985331Samw } 25995331Samw } 26005331Samw } 26015331Samw 26025331Samw void 26039664Sjason@ansipunx.net format_time(time_t sec, time_t nsec) 26045331Samw { 26059664Sjason@ansipunx.net const char *fstr = time_fmt_new; 26069664Sjason@ansipunx.net char fmt_buf[FMTSIZE]; 26075331Samw 26089664Sjason@ansipunx.net if (Eflg) { 26099664Sjason@ansipunx.net (void) snprintf(fmt_buf, FMTSIZE, fstr, nsec); 26109664Sjason@ansipunx.net (void) strftime(time_buf, sizeof (time_buf), fmt_buf, 26119664Sjason@ansipunx.net localtime(&sec)); 26129664Sjason@ansipunx.net return; 26139664Sjason@ansipunx.net } 26149664Sjason@ansipunx.net 26159664Sjason@ansipunx.net if (sec < year || sec > now) 26169664Sjason@ansipunx.net fstr = time_fmt_old; 26179664Sjason@ansipunx.net 26189664Sjason@ansipunx.net /* if a custom time was specified, shouldn't be localized */ 26195331Samw (void) strftime(time_buf, sizeof (time_buf), 26209664Sjason@ansipunx.net (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr, 26215331Samw localtime(&sec)); 26225331Samw } 26235331Samw 26245331Samw void 26255331Samw format_attrtime(struct lbuf *p) 26265331Samw { 26279664Sjason@ansipunx.net int tmattr = 0; 26285331Samw int i; 26295331Samw 26305331Samw if (p->extm != NULL) { 26315331Samw for (i = 0; i < sacnt; i++) { 26325331Samw if (p->extm[i].name != NULL) { 26335331Samw tmattr = 1; 26345331Samw break; 26355331Samw } 26365331Samw } 26375331Samw } 26389664Sjason@ansipunx.net 26395331Samw if (tmattr) { 26409664Sjason@ansipunx.net const char *old_save = time_fmt_old; 26419664Sjason@ansipunx.net const char *new_save = time_fmt_new; 26429664Sjason@ansipunx.net 26439664Sjason@ansipunx.net /* Eflg always sets format to FORMAT_ISO_FULL */ 26449664Sjason@ansipunx.net if (!Eflg && !time_custom) { 26459664Sjason@ansipunx.net time_fmt_old = FORMAT_OLD; 26469664Sjason@ansipunx.net time_fmt_new = FORMAT_NEW; 26475331Samw } 26489664Sjason@ansipunx.net 26499664Sjason@ansipunx.net format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm); 26509664Sjason@ansipunx.net 26519664Sjason@ansipunx.net time_fmt_old = old_save; 26529664Sjason@ansipunx.net time_fmt_new = new_save; 26535331Samw } 26545331Samw } 26555331Samw 26565331Samw void 26575331Samw print_time(struct lbuf *p) 26585331Samw { 26599664Sjason@ansipunx.net const char *old_save = time_fmt_old; 26609664Sjason@ansipunx.net const char *new_save = time_fmt_new; 26619664Sjason@ansipunx.net 26625331Samw int i = 0; 26635331Samw 26649664Sjason@ansipunx.net if (!Eflg) { 26659664Sjason@ansipunx.net time_fmt_old = FORMAT_LONG; 26669664Sjason@ansipunx.net time_fmt_new = FORMAT_LONG; 26679664Sjason@ansipunx.net } 26689664Sjason@ansipunx.net 26695331Samw new_line(); 26709664Sjason@ansipunx.net format_time(p->lat.tv_sec, p->lat.tv_nsec); 26719664Sjason@ansipunx.net (void) printf(" timestamp: atime %s\n", time_buf); 26729664Sjason@ansipunx.net format_time(p->lct.tv_sec, p->lct.tv_nsec); 26739664Sjason@ansipunx.net (void) printf(" timestamp: ctime %s\n", time_buf); 26749664Sjason@ansipunx.net format_time(p->lmt.tv_sec, p->lmt.tv_nsec); 26759664Sjason@ansipunx.net (void) printf(" timestamp: mtime %s\n", time_buf); 26769664Sjason@ansipunx.net if (p->extm != NULL) { 26779664Sjason@ansipunx.net while (p->extm[i].nstm != 0 && i < sacnt) { 26789664Sjason@ansipunx.net format_time(p->extm[i].stm, p->extm[i].nstm); 26799664Sjason@ansipunx.net if (p->extm[i].name != NULL) { 26809664Sjason@ansipunx.net (void) printf(" timestamp:" 26819664Sjason@ansipunx.net " %s %s\n", 26829664Sjason@ansipunx.net p->extm[i].name, time_buf); 26839664Sjason@ansipunx.net } 26849664Sjason@ansipunx.net i++; 26859664Sjason@ansipunx.net } 26869664Sjason@ansipunx.net } 26879664Sjason@ansipunx.net 26889664Sjason@ansipunx.net time_fmt_old = old_save; 26899664Sjason@ansipunx.net time_fmt_new = new_save; 26909664Sjason@ansipunx.net } 26919664Sjason@ansipunx.net 26929664Sjason@ansipunx.net /* 26939664Sjason@ansipunx.net * Check if color definition applies to entry, returns 1 if yes, 0 if no 26949664Sjason@ansipunx.net */ 26959664Sjason@ansipunx.net static int 2696*10059Sjason@ansipunx.net color_match(const char *fname, mode_t mode, ls_color_t *color) 26979664Sjason@ansipunx.net { 26989664Sjason@ansipunx.net switch (color->ftype) { 26999664Sjason@ansipunx.net case LS_PAT: 27009664Sjason@ansipunx.net { 27019664Sjason@ansipunx.net size_t fname_len, sfx_len; 27029664Sjason@ansipunx.net 27039664Sjason@ansipunx.net fname_len = strlen(fname); 27049664Sjason@ansipunx.net sfx_len = strlen(color->sfx); 27059664Sjason@ansipunx.net if (sfx_len > fname_len) 27069664Sjason@ansipunx.net return (0); 27079664Sjason@ansipunx.net 27089664Sjason@ansipunx.net if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0) 27099664Sjason@ansipunx.net return (1); 27109664Sjason@ansipunx.net else 27119664Sjason@ansipunx.net return (0); 27129664Sjason@ansipunx.net } 27139664Sjason@ansipunx.net 27149664Sjason@ansipunx.net case LS_NORMAL: 27159664Sjason@ansipunx.net return (1); 27169664Sjason@ansipunx.net 27179664Sjason@ansipunx.net case LS_FILE: 2718*10059Sjason@ansipunx.net return (S_ISREG(mode)); 27199664Sjason@ansipunx.net 27209664Sjason@ansipunx.net case LS_DIR: 2721*10059Sjason@ansipunx.net return (S_ISDIR(mode)); 27229664Sjason@ansipunx.net 27239664Sjason@ansipunx.net case LS_LINK: 2724*10059Sjason@ansipunx.net return (S_ISLNK(mode)); 27259664Sjason@ansipunx.net 27269664Sjason@ansipunx.net case LS_FIFO: 2727*10059Sjason@ansipunx.net return (S_ISFIFO(mode)); 27289664Sjason@ansipunx.net 27299664Sjason@ansipunx.net case LS_SOCK: 2730*10059Sjason@ansipunx.net return (S_ISSOCK(mode)); 27319664Sjason@ansipunx.net 27329664Sjason@ansipunx.net case LS_DOOR: 2733*10059Sjason@ansipunx.net return (S_ISDOOR(mode)); 27349664Sjason@ansipunx.net 27359664Sjason@ansipunx.net case LS_BLK: 2736*10059Sjason@ansipunx.net return (S_ISBLK(mode)); 27379664Sjason@ansipunx.net 27389664Sjason@ansipunx.net case LS_CHR: 2739*10059Sjason@ansipunx.net return (S_ISCHR(mode)); 27409664Sjason@ansipunx.net 27419664Sjason@ansipunx.net case LS_PORT: 2742*10059Sjason@ansipunx.net return (S_ISPORT(mode)); 27439664Sjason@ansipunx.net 27449664Sjason@ansipunx.net case LS_ORPHAN: 2745*10059Sjason@ansipunx.net /* this is tested for by gstat */ 27469664Sjason@ansipunx.net return (0); 27479664Sjason@ansipunx.net 27489664Sjason@ansipunx.net case LS_SETUID: 2749*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & S_ISUID)); 27509664Sjason@ansipunx.net 27519664Sjason@ansipunx.net case LS_SETGID: 2752*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & S_ISGID)); 27539664Sjason@ansipunx.net 27549664Sjason@ansipunx.net case LS_STICKY_OTHER_WRITABLE: 2755*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & (S_IWOTH|S_ISVTX))); 27569664Sjason@ansipunx.net 27579664Sjason@ansipunx.net case LS_OTHER_WRITABLE: 2758*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & S_IWOTH)); 27599664Sjason@ansipunx.net 27609664Sjason@ansipunx.net case LS_STICKY: 2761*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & S_ISVTX)); 27629664Sjason@ansipunx.net 27639664Sjason@ansipunx.net case LS_EXEC: 2764*10059Sjason@ansipunx.net return (!S_ISLNK(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH))); 27659664Sjason@ansipunx.net } 27669664Sjason@ansipunx.net 27679664Sjason@ansipunx.net return (0); 27689664Sjason@ansipunx.net } 27699664Sjason@ansipunx.net 27709664Sjason@ansipunx.net static void 27719664Sjason@ansipunx.net dump_color(ls_color_t *c) 27729664Sjason@ansipunx.net { 27739664Sjason@ansipunx.net if (c == NULL) 27749664Sjason@ansipunx.net return; 27759664Sjason@ansipunx.net 27769664Sjason@ansipunx.net (void) printf("\n\ttype: "); 27779664Sjason@ansipunx.net switch (c->ftype) { 27789664Sjason@ansipunx.net case LS_NORMAL: 27799664Sjason@ansipunx.net (void) printf("LS_NORMAL"); 27809664Sjason@ansipunx.net break; 27819664Sjason@ansipunx.net case LS_FILE: 27829664Sjason@ansipunx.net (void) printf("LS_FILE"); 27839664Sjason@ansipunx.net break; 27849664Sjason@ansipunx.net case LS_EXEC: 27859664Sjason@ansipunx.net (void) printf("LS_EXEC"); 27869664Sjason@ansipunx.net break; 27879664Sjason@ansipunx.net case LS_DIR: 27889664Sjason@ansipunx.net (void) printf("LS_DIR"); 27899664Sjason@ansipunx.net break; 27909664Sjason@ansipunx.net case LS_LINK: 27919664Sjason@ansipunx.net (void) printf("LS_LINK"); 27929664Sjason@ansipunx.net break; 27939664Sjason@ansipunx.net 27949664Sjason@ansipunx.net case LS_FIFO: 27959664Sjason@ansipunx.net (void) printf("LS_FIFO"); 27969664Sjason@ansipunx.net break; 27979664Sjason@ansipunx.net 27989664Sjason@ansipunx.net case LS_SOCK: 27999664Sjason@ansipunx.net (void) printf("LS_SOCK"); 28009664Sjason@ansipunx.net break; 28019664Sjason@ansipunx.net 28029664Sjason@ansipunx.net case LS_DOOR: 28039664Sjason@ansipunx.net (void) printf("LS_DOOR"); 28049664Sjason@ansipunx.net break; 28059664Sjason@ansipunx.net 28069664Sjason@ansipunx.net case LS_BLK: 28079664Sjason@ansipunx.net (void) printf("LS_BLK"); 28089664Sjason@ansipunx.net break; 28099664Sjason@ansipunx.net 28109664Sjason@ansipunx.net case LS_CHR: 28119664Sjason@ansipunx.net (void) printf("LS_CHR"); 28129664Sjason@ansipunx.net break; 28139664Sjason@ansipunx.net 28149664Sjason@ansipunx.net case LS_PORT: 28159664Sjason@ansipunx.net (void) printf("LS_PORT"); 28169664Sjason@ansipunx.net break; 28179664Sjason@ansipunx.net 28189664Sjason@ansipunx.net case LS_STICKY: 28199664Sjason@ansipunx.net (void) printf("LS_STICKY"); 28209664Sjason@ansipunx.net break; 28219664Sjason@ansipunx.net 28229664Sjason@ansipunx.net case LS_ORPHAN: 28239664Sjason@ansipunx.net (void) printf("LS_ORPHAN"); 28249664Sjason@ansipunx.net break; 28259664Sjason@ansipunx.net 28269664Sjason@ansipunx.net case LS_SETGID: 28279664Sjason@ansipunx.net (void) printf("LS_SETGID"); 28289664Sjason@ansipunx.net break; 28299664Sjason@ansipunx.net 28309664Sjason@ansipunx.net case LS_SETUID: 28319664Sjason@ansipunx.net (void) printf("LS_SETUID"); 28329664Sjason@ansipunx.net break; 28339664Sjason@ansipunx.net 28349664Sjason@ansipunx.net case LS_OTHER_WRITABLE: 28359664Sjason@ansipunx.net (void) printf("LS_OTHER_WRITABLE"); 28369664Sjason@ansipunx.net break; 28379664Sjason@ansipunx.net 28389664Sjason@ansipunx.net case LS_STICKY_OTHER_WRITABLE: 28399664Sjason@ansipunx.net (void) printf("LS_STICKY_OTHER_WRITABLE"); 28409664Sjason@ansipunx.net break; 28419664Sjason@ansipunx.net 28429664Sjason@ansipunx.net case LS_PAT: 28439664Sjason@ansipunx.net (void) printf("LS_PAT\n"); 28449664Sjason@ansipunx.net (void) printf("\tpattern: %s", c->sfx); 28459664Sjason@ansipunx.net break; 28469664Sjason@ansipunx.net } 28479664Sjason@ansipunx.net (void) printf("\n"); 28489664Sjason@ansipunx.net (void) printf("\tattr: %d\n", c->attr); 28499664Sjason@ansipunx.net (void) printf("\tfg: %d\n", c->fg); 28509664Sjason@ansipunx.net (void) printf("\tbg: %d\n", c->bg); 28519664Sjason@ansipunx.net (void) printf("\t"); 28529664Sjason@ansipunx.net } 28539664Sjason@ansipunx.net 28549664Sjason@ansipunx.net static ls_color_t * 2855*10059Sjason@ansipunx.net ls_color_find(const char *fname, mode_t mode) 28569664Sjason@ansipunx.net { 28579664Sjason@ansipunx.net int i; 28589664Sjason@ansipunx.net 28599664Sjason@ansipunx.net /* 28609664Sjason@ansipunx.net * Colors are sorted from most general lsc_colors[0] to most specific 28619664Sjason@ansipunx.net * lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with 28629664Sjason@ansipunx.net * most specific color rule and work towards most general. 28639664Sjason@ansipunx.net */ 28649664Sjason@ansipunx.net for (i = lsc_ncolors - 1; i >= 0; --i) 2865*10059Sjason@ansipunx.net if (color_match(fname, mode, &lsc_colors[i])) 28669664Sjason@ansipunx.net return (&lsc_colors[i]); 28679664Sjason@ansipunx.net 28689664Sjason@ansipunx.net return (NULL); 28699664Sjason@ansipunx.net } 28709664Sjason@ansipunx.net 28719664Sjason@ansipunx.net static void 28729664Sjason@ansipunx.net ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4, 28739664Sjason@ansipunx.net long int p5, long int p6, long int p7, long int p8, long int p9) 28749664Sjason@ansipunx.net { 28759664Sjason@ansipunx.net char *s; 28769664Sjason@ansipunx.net 28779664Sjason@ansipunx.net if (str == NULL) 28789664Sjason@ansipunx.net return; 28799664Sjason@ansipunx.net 28809664Sjason@ansipunx.net s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); 28819664Sjason@ansipunx.net 28829664Sjason@ansipunx.net if (s != NULL) 28839664Sjason@ansipunx.net (void) putp(s); 28849664Sjason@ansipunx.net } 28859664Sjason@ansipunx.net 28869664Sjason@ansipunx.net static void 2887*10059Sjason@ansipunx.net ls_start_color(ls_color_t *c) 28889664Sjason@ansipunx.net { 28899664Sjason@ansipunx.net if (c == NULL) 28909664Sjason@ansipunx.net return; 28919664Sjason@ansipunx.net 28929664Sjason@ansipunx.net if (lsc_debug) 28939664Sjason@ansipunx.net lsc_match = c; 28949664Sjason@ansipunx.net 28959664Sjason@ansipunx.net if (c->attr & LSA_BOLD) 28969664Sjason@ansipunx.net ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0); 28979664Sjason@ansipunx.net if (c->attr & LSA_UNDERSCORE) 28989664Sjason@ansipunx.net ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0); 28999664Sjason@ansipunx.net if (c->attr & LSA_BLINK) 29009664Sjason@ansipunx.net ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29019664Sjason@ansipunx.net if (c->attr & LSA_REVERSE) 29029664Sjason@ansipunx.net ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29039664Sjason@ansipunx.net if (c->attr & LSA_CONCEALED) 29049664Sjason@ansipunx.net ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29059664Sjason@ansipunx.net if (c->attr == LSA_NONE) 29069664Sjason@ansipunx.net ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29079664Sjason@ansipunx.net 29089664Sjason@ansipunx.net if (c->fg != -1) 29099664Sjason@ansipunx.net ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0); 29109664Sjason@ansipunx.net if (c->bg != -1) 29119664Sjason@ansipunx.net ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0); 29129664Sjason@ansipunx.net } 29139664Sjason@ansipunx.net 29149664Sjason@ansipunx.net static void 29159664Sjason@ansipunx.net ls_end_color() 29169664Sjason@ansipunx.net { 29179664Sjason@ansipunx.net ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 29189664Sjason@ansipunx.net if (lsc_debug) 29199664Sjason@ansipunx.net dump_color(lsc_match); 29209664Sjason@ansipunx.net } 29219664Sjason@ansipunx.net 29229664Sjason@ansipunx.net static void 29239664Sjason@ansipunx.net new_color_entry(char *colorstr) 29249664Sjason@ansipunx.net { 29259664Sjason@ansipunx.net static const struct { 29269664Sjason@ansipunx.net const char *s; 29279664Sjason@ansipunx.net ls_cftype_t stype; 29289664Sjason@ansipunx.net } type_map[] = { 29299664Sjason@ansipunx.net { "no", LS_NORMAL }, 29309664Sjason@ansipunx.net { "fi", LS_FILE }, 29319664Sjason@ansipunx.net { "di", LS_DIR }, 29329664Sjason@ansipunx.net { "ln", LS_LINK }, 29339664Sjason@ansipunx.net { "pi", LS_FIFO }, 29349664Sjason@ansipunx.net { "so", LS_SOCK }, 29359664Sjason@ansipunx.net { "do", LS_DOOR }, 29369664Sjason@ansipunx.net { "bd", LS_BLK }, 29379664Sjason@ansipunx.net { "cd", LS_CHR }, 29389664Sjason@ansipunx.net { "or", LS_ORPHAN }, 29399664Sjason@ansipunx.net { "su", LS_SETUID }, 29409664Sjason@ansipunx.net { "sg", LS_SETGID }, 29419664Sjason@ansipunx.net { "tw", LS_STICKY_OTHER_WRITABLE }, 29429664Sjason@ansipunx.net { "ow", LS_OTHER_WRITABLE }, 29439664Sjason@ansipunx.net { "st", LS_STICKY }, 29449664Sjason@ansipunx.net { "ex", LS_EXEC }, 29459664Sjason@ansipunx.net { "po", LS_PORT }, 29469664Sjason@ansipunx.net { NULL, LS_NORMAL } 29479664Sjason@ansipunx.net }; 29489664Sjason@ansipunx.net 29499664Sjason@ansipunx.net char *p, *lasts; 29509664Sjason@ansipunx.net int i; 29519664Sjason@ansipunx.net int color, attr; 29529664Sjason@ansipunx.net 29539664Sjason@ansipunx.net p = strtok_r(colorstr, "=", &lasts); 29549664Sjason@ansipunx.net if (p == NULL) { 29559664Sjason@ansipunx.net colorflg = 0; 29569664Sjason@ansipunx.net return; 29579664Sjason@ansipunx.net } 29589664Sjason@ansipunx.net 29599664Sjason@ansipunx.net if (p[0] == '*') { 29609664Sjason@ansipunx.net lsc_colors[lsc_ncolors].ftype = LS_PAT; 29619664Sjason@ansipunx.net /* don't include the * in the suffix */ 29629664Sjason@ansipunx.net if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) { 29639664Sjason@ansipunx.net colorflg = 0; 29649664Sjason@ansipunx.net return; 29659664Sjason@ansipunx.net } 29669664Sjason@ansipunx.net } else { 29679664Sjason@ansipunx.net lsc_colors[lsc_ncolors].sfx = NULL; 29689664Sjason@ansipunx.net 29699664Sjason@ansipunx.net for (i = 0; type_map[i].s != NULL; ++i) { 29709664Sjason@ansipunx.net if (strncmp(type_map[i].s, p, 2) == 0) 29719664Sjason@ansipunx.net break; 29729664Sjason@ansipunx.net } 29739664Sjason@ansipunx.net 29749664Sjason@ansipunx.net /* ignore unknown file types */ 29759664Sjason@ansipunx.net if (type_map[i].s == NULL) 29769664Sjason@ansipunx.net return; 29779664Sjason@ansipunx.net 29789664Sjason@ansipunx.net lsc_colors[lsc_ncolors].ftype = type_map[i].stype; 29799664Sjason@ansipunx.net } 29809664Sjason@ansipunx.net 29819664Sjason@ansipunx.net attr = LSA_NONE; 29829664Sjason@ansipunx.net lsc_colors[lsc_ncolors].fg = -1; 29839664Sjason@ansipunx.net lsc_colors[lsc_ncolors].bg = -1; 29849664Sjason@ansipunx.net for (p = strtok_r(NULL, ";", &lasts); p != NULL; 29859664Sjason@ansipunx.net p = strtok_r(NULL, ";", &lasts)) { 29869664Sjason@ansipunx.net color = strtol(p, NULL, 10); 29879664Sjason@ansipunx.net 29889664Sjason@ansipunx.net if (color < 10) { 29899664Sjason@ansipunx.net switch (color) { 29909664Sjason@ansipunx.net case 0: 29919664Sjason@ansipunx.net attr = LSA_NONE; 29929664Sjason@ansipunx.net continue; 29939664Sjason@ansipunx.net case 1: 29949664Sjason@ansipunx.net attr |= LSA_BOLD; 29959664Sjason@ansipunx.net continue; 29969664Sjason@ansipunx.net case 4: 29979664Sjason@ansipunx.net attr |= LSA_UNDERSCORE; 29989664Sjason@ansipunx.net continue; 29999664Sjason@ansipunx.net case 5: 30009664Sjason@ansipunx.net attr |= LSA_BLINK; 30019664Sjason@ansipunx.net continue; 30029664Sjason@ansipunx.net case 7: 30039664Sjason@ansipunx.net attr |= LSA_REVERSE; 30049664Sjason@ansipunx.net continue; 30059664Sjason@ansipunx.net case 8: 30069664Sjason@ansipunx.net attr |= LSA_CONCEALED; 30079664Sjason@ansipunx.net continue; 30089664Sjason@ansipunx.net default: 30099664Sjason@ansipunx.net continue; 30105331Samw } 30115331Samw } 30129664Sjason@ansipunx.net 30139664Sjason@ansipunx.net if (color < 40) 30149664Sjason@ansipunx.net lsc_colors[lsc_ncolors].fg = color - 30; 30159664Sjason@ansipunx.net else 30169664Sjason@ansipunx.net lsc_colors[lsc_ncolors].bg = color - 40; 30179664Sjason@ansipunx.net } 30189664Sjason@ansipunx.net 30199664Sjason@ansipunx.net lsc_colors[lsc_ncolors].attr = attr; 30209664Sjason@ansipunx.net ++lsc_ncolors; 30219664Sjason@ansipunx.net } 30229664Sjason@ansipunx.net 30239664Sjason@ansipunx.net static int 30249664Sjason@ansipunx.net ls_color_compare(const void *p1, const void *p2) 30259664Sjason@ansipunx.net { 30269664Sjason@ansipunx.net const ls_color_t *c1 = (const ls_color_t *)p1; 30279664Sjason@ansipunx.net const ls_color_t *c2 = (const ls_color_t *)p2; 30289664Sjason@ansipunx.net 30299664Sjason@ansipunx.net int ret = c1->ftype - c2->ftype; 30309664Sjason@ansipunx.net 30319664Sjason@ansipunx.net if (ret != 0) 30329664Sjason@ansipunx.net return (ret); 30339664Sjason@ansipunx.net 30349664Sjason@ansipunx.net if (c1->ftype != LS_PAT) 30359664Sjason@ansipunx.net return (ret); 30369664Sjason@ansipunx.net 30379664Sjason@ansipunx.net return (strcmp(c1->sfx, c2->sfx)); 30389664Sjason@ansipunx.net } 30399664Sjason@ansipunx.net 30409664Sjason@ansipunx.net static void 30419664Sjason@ansipunx.net ls_color_init() 30429664Sjason@ansipunx.net { 30439664Sjason@ansipunx.net static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35" 30449664Sjason@ansipunx.net ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01" 30459664Sjason@ansipunx.net ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31" 30469664Sjason@ansipunx.net ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31" 30479664Sjason@ansipunx.net ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31" 30489664Sjason@ansipunx.net ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35" 30499664Sjason@ansipunx.net ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35" 30509664Sjason@ansipunx.net ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35" 30519664Sjason@ansipunx.net ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35" 30529664Sjason@ansipunx.net ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35" 30539664Sjason@ansipunx.net ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35"; 30549664Sjason@ansipunx.net 30559664Sjason@ansipunx.net char *colorstr; 30569664Sjason@ansipunx.net char *p, *lasts; 30579664Sjason@ansipunx.net size_t color_sz; 30589664Sjason@ansipunx.net int termret; 3059*10059Sjason@ansipunx.net int i; 30609664Sjason@ansipunx.net 30619664Sjason@ansipunx.net (void) setupterm(NULL, 1, &termret); 30629664Sjason@ansipunx.net if (termret != 1) 30639664Sjason@ansipunx.net return; 30649664Sjason@ansipunx.net 30659664Sjason@ansipunx.net if ((colorstr = getenv("LS_COLORS")) == NULL) 30669664Sjason@ansipunx.net colorstr = default_colorstr; 30679664Sjason@ansipunx.net 30689689Sjason@ansipunx.net /* 30699689Sjason@ansipunx.net * Determine the size of lsc_colors. color_sz can be > lsc_ncolors 30709689Sjason@ansipunx.net * if there are invalid entries passed in the string (they are ignored) 30719689Sjason@ansipunx.net */ 30729689Sjason@ansipunx.net color_sz = 1; 30739664Sjason@ansipunx.net for (p = strchr(colorstr, ':'); p != NULL && *p != '\0'; 30749664Sjason@ansipunx.net p = strchr(++p, ':')) 30759664Sjason@ansipunx.net ++color_sz; 30769664Sjason@ansipunx.net 30779664Sjason@ansipunx.net lsc_colors = calloc(color_sz, sizeof (ls_color_t)); 30789664Sjason@ansipunx.net if (lsc_colors == NULL) { 30799664Sjason@ansipunx.net free(colorstr); 30809664Sjason@ansipunx.net return; 30819664Sjason@ansipunx.net } 30829664Sjason@ansipunx.net 30839664Sjason@ansipunx.net for (p = strtok_r(colorstr, ":", &lasts); 30849664Sjason@ansipunx.net p != NULL && lsc_ncolors < color_sz; 30859664Sjason@ansipunx.net p = strtok_r(NULL, ":", &lasts)) 30869664Sjason@ansipunx.net new_color_entry(p); 30879664Sjason@ansipunx.net 30889664Sjason@ansipunx.net qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t), 30899664Sjason@ansipunx.net ls_color_compare); 30909664Sjason@ansipunx.net 3091*10059Sjason@ansipunx.net for (i = 0; i < lsc_ncolors; ++i) 3092*10059Sjason@ansipunx.net if (lsc_colors[i].ftype == LS_ORPHAN) { 3093*10059Sjason@ansipunx.net lsc_orphan = &lsc_colors[i]; 3094*10059Sjason@ansipunx.net break; 3095*10059Sjason@ansipunx.net } 3096*10059Sjason@ansipunx.net 30979664Sjason@ansipunx.net if ((lsc_bold = tigetstr("bold")) == (char *)-1) 30989664Sjason@ansipunx.net lsc_bold = NULL; 30999664Sjason@ansipunx.net 31009664Sjason@ansipunx.net if ((lsc_underline = tigetstr("smul")) == (char *)-1) 31019664Sjason@ansipunx.net lsc_underline = NULL; 31029664Sjason@ansipunx.net 31039664Sjason@ansipunx.net if ((lsc_blink = tigetstr("blink")) == (char *)-1) 31049664Sjason@ansipunx.net lsc_blink = NULL; 31059664Sjason@ansipunx.net 31069664Sjason@ansipunx.net if ((lsc_reverse = tigetstr("rev")) == (char *)-1) 31079664Sjason@ansipunx.net lsc_reverse = NULL; 31089664Sjason@ansipunx.net 31099664Sjason@ansipunx.net if ((lsc_concealed = tigetstr("prot")) == (char *)-1) 31109664Sjason@ansipunx.net lsc_concealed = NULL; 31119664Sjason@ansipunx.net 31129664Sjason@ansipunx.net if ((lsc_none = tigetstr("sgr0")) == (char *)-1) 31139664Sjason@ansipunx.net lsc_none = NULL; 31149664Sjason@ansipunx.net 31159664Sjason@ansipunx.net if ((lsc_setfg = tigetstr("setaf")) == (char *)-1) 31169664Sjason@ansipunx.net lsc_setfg = NULL; 31179664Sjason@ansipunx.net 31189664Sjason@ansipunx.net if ((lsc_setbg = tigetstr("setab")) == (char *)-1) 31199664Sjason@ansipunx.net lsc_setbg = NULL; 31209664Sjason@ansipunx.net 31219664Sjason@ansipunx.net if (getenv("_LS_COLOR_DEBUG") != NULL) { 31229664Sjason@ansipunx.net int i; 31239664Sjason@ansipunx.net 31249664Sjason@ansipunx.net lsc_debug = 1; 31259664Sjason@ansipunx.net for (i = 0; i < lsc_ncolors; ++i) 31269664Sjason@ansipunx.net dump_color(&lsc_colors[i]); 31275331Samw } 31285331Samw } 31295331Samw 31305331Samw /* Free extended system attribute lists */ 31315331Samw 31325331Samw void 31335331Samw free_sysattr(struct lbuf *p) 31345331Samw { 31355331Samw int i; 31365331Samw 31375331Samw if (p->exttr != NULL) { 31385331Samw for (i = 0; i < sacnt; i++) { 31395331Samw if (p->exttr[i].name != NULL) 31405331Samw free(p->exttr[i].name); 31415331Samw } 31425331Samw free(p->exttr); 31435331Samw } 31445331Samw if (p->extm != NULL) { 31455331Samw for (i = 0; i < sacnt; i++) { 31465331Samw if (p->extm[i].name != NULL) 31475331Samw free(p->extm[i].name); 31485331Samw } 31495331Samw free(p->extm); 31505331Samw } 31515331Samw } 31525331Samw 31535331Samw /* Allocate extended system attribute list */ 31545331Samw 31555331Samw void * 31565331Samw xmalloc(size_t size, struct lbuf *p) 31575331Samw { 31585331Samw if ((p = malloc(size)) == NULL) { 31595331Samw perror("ls"); 31605331Samw free_sysattr(p); 31615331Samw nvlist_free(response); 31625331Samw exit(2); 31635331Samw } 31645331Samw return (p); 31655331Samw } 3166