Home | History | Annotate | Download | only in ls
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   1447   akaplan  * Common Development and Distribution License (the "License").
      6   1447   akaplan  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21   9664     jason 
     22      0    stevel /*
     23   9664     jason  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24   9664     jason  * Use is subject to license terms.
     25   9664     jason  */
     26   9664     jason 
     27   9664     jason /*
     28   9664     jason  * Copyright 2009 Jason King.  All rights reserved.
     29      0    stevel  * Use is subject to license terms.
     30      0    stevel  */
     31      0    stevel 
     32      0    stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     33      0    stevel /*	  All Rights Reserved  	*/
     34      0    stevel 
     35      0    stevel /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
     36      0    stevel /*	  All Rights Reserved	*/
     37      0    stevel 
     38      0    stevel /*
     39      0    stevel  * List files or directories
     40      0    stevel  */
     41      0    stevel 
     42      0    stevel #include <sys/param.h>
     43      0    stevel #include <sys/types.h>
     44      0    stevel #include <sys/mkdev.h>
     45      0    stevel #include <sys/stat.h>
     46      0    stevel #include <sys/acl.h>
     47      0    stevel 
     48      0    stevel #include <wchar.h>
     49      0    stevel #include <stdio.h>
     50      0    stevel #include <ctype.h>
     51      0    stevel #include <dirent.h>
     52      0    stevel #include <string.h>
     53      0    stevel #include <locale.h>
     54      0    stevel #include <curses.h>
     55   9664     jason #include <term.h>
     56      0    stevel #include <termios.h>
     57      0    stevel #include <stdlib.h>
     58      0    stevel #include <widec.h>
     59      0    stevel #include <locale.h>
     60      0    stevel #include <wctype.h>
     61      0    stevel #include <pwd.h>
     62      0    stevel #include <grp.h>
     63      0    stevel #include <limits.h>
     64      0    stevel #include <fcntl.h>
     65      0    stevel #include <unistd.h>
     66      0    stevel #include <libgen.h>
     67      0    stevel #include <errno.h>
     68    789    ahrens #include <aclutils.h>
     69   5331       amw #include <libnvpair.h>
     70   5331       amw #include <libcmdutils.h>
     71   5331       amw #include <attr.h>
     72   9664     jason #include <getopt.h>
     73   9664     jason #include <inttypes.h>
     74      0    stevel 
     75      0    stevel #ifndef STANDALONE
     76      0    stevel #define	TERMINFO
     77      0    stevel #endif
     78      0    stevel 
     79      0    stevel /*
     80      0    stevel  * -DNOTERMINFO can be defined on the cc command line to prevent
     81      0    stevel  * the use of terminfo.  This should be done on systems not having
     82   5331       amw  * the terminfo feature(pre 6.0 systems ?).
     83      0    stevel  * As a result, columnar listings assume 80 columns for output,
     84      0    stevel  * unless told otherwise via the COLUMNS environment variable.
     85      0    stevel  */
     86      0    stevel #ifdef NOTERMINFO
     87      0    stevel #undef TERMINFO
     88      0    stevel #endif
     89      0    stevel 
     90      0    stevel #include <term.h>
     91      0    stevel 
     92      0    stevel #define	BFSIZE	16
     93      0    stevel /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */
     94      0    stevel #define	ISARG	0100000
     95      0    stevel 
     96      0    stevel /*
     97      0    stevel  * this flag has been added to manipulate the display of S instead of 'l' when
     98      0    stevel  * the file is not a regular file and when group execution bit is off
     99      0    stevel  */
    100      0    stevel #define	LS_NOTREG	010000
    101      0    stevel 
    102      0    stevel 
    103      0    stevel /*
    104      0    stevel  * Date and time formats
    105      0    stevel  *
    106      0    stevel  * b --- abbreviated month name
    107      0    stevel  * e --- day number
    108      0    stevel  * Y --- year in the form ccyy
    109      0    stevel  * H --- hour(24-hour version)
    110      0    stevel  * M --- minute
    111      0    stevel  * F --- yyyy-mm-dd
    112      0    stevel  * T --- hh:mm:ss
    113      0    stevel  * z --- time zone as hours displacement from UTC
    114      0    stevel  * note that %F and %z are from the ISO C99 standard and are
    115      0    stevel  * not present in older C libraries
    116      0    stevel  */
    117   9664     jason #define	FORMAT_OLD	" %b %e  %Y "
    118   9664     jason #define	FORMAT_NEW	" %b %e %H:%M "
    119   9664     jason #define	FORMAT_LONG	" %b %e %T %Y "
    120   9664     jason #define	FORMAT_ISO_FULL	" %%F %%T.%.09ld %%z "
    121   9664     jason #define	FORMAT_ISO_LONG	" %F %R "
    122   9664     jason #define	FORMAT_ISO_NEW	" %m-%d %H:%M "
    123   9664     jason #define	FORMAT_ISO_OLD	" %F "
    124      0    stevel 
    125      0    stevel #undef BUFSIZ
    126      0    stevel #define	BUFSIZ 4096
    127      0    stevel #define	NUMBER_WIDTH 40
    128      0    stevel #define	FMTSIZE 50
    129      0    stevel 
    130      0    stevel struct ditem {
    131      0    stevel 	dev_t	dev;			/* directory items device number */
    132      0    stevel 	ino_t	ino;			/* directory items inode number */
    133      0    stevel 	struct ditem *parent;		/* dir items ptr to its parent's info */
    134      0    stevel };
    135   5331       amw /* Holds boolean extended system attributes */
    136   5331       amw struct attrb {
    137   5331       amw 	char		*name;
    138   5331       amw };
    139   5331       amw /* Holds timestamp extended system attributes */
    140   5331       amw struct attrtm {
    141   5331       amw 	char		*name;
    142   5331       amw 	uint64_t	stm;
    143   5331       amw 	uint64_t	nstm;
    144   5331       amw };
    145      0    stevel 
    146   9664     jason #define	LSA_NONE	(0)
    147   9664     jason #define	LSA_BOLD	(1L << 0)
    148   9664     jason #define	LSA_UNDERSCORE	(1L << 1)
    149   9664     jason #define	LSA_BLINK	(1L << 2)
    150   9664     jason #define	LSA_REVERSE	(1L << 3)
    151   9664     jason #define	LSA_CONCEALED	(1L << 4)
    152   9664     jason 
    153   9664     jason /* these should be ordered most general to most specific */
    154   9664     jason typedef enum LS_CFTYPE {
    155   9664     jason 	LS_NORMAL,
    156   9664     jason 	LS_FILE,
    157   9664     jason 	LS_EXEC,
    158   9664     jason 	LS_DIR,
    159   9664     jason 	LS_LINK,
    160   9664     jason 	LS_FIFO,
    161   9664     jason 	LS_SOCK,
    162   9664     jason 	LS_DOOR,
    163   9664     jason 	LS_BLK,
    164   9664     jason 	LS_CHR,
    165   9664     jason 	LS_PORT,
    166   9664     jason 	LS_STICKY,
    167   9664     jason 	LS_ORPHAN,
    168   9664     jason 	LS_SETGID,
    169   9664     jason 	LS_SETUID,
    170   9664     jason 	LS_OTHER_WRITABLE,
    171   9664     jason 	LS_STICKY_OTHER_WRITABLE,
    172   9664     jason 	LS_PAT
    173   9664     jason } ls_cftype_t;
    174   9664     jason 
    175  10059     jason typedef struct {
    176   9664     jason 	char		*sfx;
    177   9664     jason 	ls_cftype_t	ftype;
    178   9664     jason 	int		attr;
    179   9664     jason 	int		fg;
    180   9664     jason 	int		bg;
    181   9664     jason } ls_color_t;
    182  10059     jason 
    183  10059     jason struct	lbuf	{
    184  10059     jason 	union	{
    185  10059     jason 		char	lname[MAXNAMLEN]; /* used for filename in a directory */
    186  10059     jason 		char	*namep;		/* for name in ls-command; */
    187  10059     jason 	} ln;
    188  10059     jason 	char	ltype;		/* filetype */
    189  10059     jason 	ino_t	lnum;		/* inode number of file */
    190  10059     jason 	mode_t	lflags; 	/* 0777 bits used as r,w,x permissions */
    191  10059     jason 	nlink_t	lnl;		/* number of links to file */
    192  10059     jason 	uid_t	luid;
    193  10059     jason 	gid_t	lgid;
    194  10059     jason 	off_t	lsize;		/* filesize or major/minor dev numbers */
    195  10059     jason 	blkcnt_t	lblocks;	/* number of file blocks */
    196  10059     jason 	timestruc_t	lmtime;
    197  10059     jason 	timestruc_t	lat;
    198  10059     jason 	timestruc_t	lct;
    199  10059     jason 	timestruc_t	lmt;
    200  10059     jason 	char	*flinkto;	/* symbolic link contents */
    201  10059     jason 	char 	acl;		/* indicate there are additional acl entries */
    202  10059     jason 	int	cycle;		/* cycle detected flag */
    203  10059     jason 	struct ditem *ancinfo;	/* maintains ancestor info */
    204  10059     jason 	acl_t *aclp;		/* ACL if present */
    205  10059     jason 	struct attrb *exttr;	/* boolean extended system attributes */
    206  10059     jason 	struct attrtm *extm;	/* timestamp extended system attributes */
    207  10059     jason 	ls_color_t	*color;	/* color for entry */
    208  10059     jason 	ls_color_t	*link_color;	/* color for symlink */
    209  10059     jason };
    210  10059     jason 
    211  10059     jason struct dchain {
    212  10059     jason 	char *dc_name;		/* path name */
    213  10059     jason 	int cycle_detected;	/* cycle detected visiting this directory */
    214  10059     jason 	struct ditem *myancinfo;	/* this directory's ancestry info */
    215  10059     jason 	struct dchain *dc_next;	/* next directory in the chain */
    216  10059     jason };
    217   9664     jason 
    218      0    stevel /*
    219      0    stevel  * A numbuf_t is used when converting a number to a string representation
    220      0    stevel  */
    221      0    stevel typedef char numbuf_t[NUMBER_WIDTH];
    222      0    stevel 
    223      0    stevel static struct dchain *dfirst;	/* start of the dir chain */
    224      0    stevel static struct dchain *cdfirst;	/* start of the current dir chain */
    225      0    stevel static struct dchain *dtemp;	/* temporary - used for linking */
    226      0    stevel static char *curdir;		/* the current directory */
    227      0    stevel 
    228      0    stevel static int	first = 1;	/* true if first line is not yet printed */
    229      0    stevel static int	nfiles = 0;	/* number of flist entries in current use */
    230      0    stevel static int	nargs = 0;	/* number of flist entries used for arguments */
    231      0    stevel static int	maxfils = 0;	/* number of flist/lbuf entries allocated */
    232      0    stevel static int	maxn = 0;	/* number of flist entries with lbufs asigned */
    233      0    stevel static int	quantn = 64;	/* allocation growth quantum */
    234      0    stevel 
    235      0    stevel static struct lbuf	*nxtlbf;	/* ptr to next lbuf to be assigned */
    236      0    stevel static struct lbuf	**flist;	/* ptr to list of lbuf pointers */
    237      0    stevel static struct lbuf	*gstat(char *, int, struct ditem *);
    238      0    stevel static char		*getname(uid_t);
    239      0    stevel static char		*getgroup(gid_t);
    240      0    stevel static char		*makename(char *, char *);
    241      0    stevel static void		pentry(struct lbuf *);
    242      0    stevel static void		column(void);
    243      0    stevel static void		pmode(mode_t aflag);
    244      0    stevel static void		selection(int *);
    245      0    stevel static void		new_line(void);
    246      0    stevel static void		rddir(char *, struct ditem *);
    247      0    stevel static int		strcol(unsigned char *);
    248      0    stevel static void		pem(struct lbuf **, struct lbuf **, int);
    249      0    stevel static void		pdirectory(char *, int, int, int, struct ditem *);
    250      0    stevel static struct cachenode *findincache(struct cachenode **, long);
    251      0    stevel static void		csi_pprintf(unsigned char *);
    252      0    stevel static void		pprintf(char *, char *);
    253      0    stevel static int		compar(struct lbuf **pp1, struct lbuf **pp2);
    254      0    stevel static char 		*number_to_scaled_string(numbuf_t buf,
    255      0    stevel 			    unsigned long long number,
    256      0    stevel 			    long scale);
    257      0    stevel static void		record_ancestry(char *, struct stat *, struct lbuf *,
    258      0    stevel 			    int, struct ditem *);
    259   9664     jason static void		ls_color_init(void);
    260  10059     jason static ls_color_t	*ls_color_find(const char *, mode_t);
    261  10059     jason static void		ls_start_color(ls_color_t *);
    262   9664     jason static void		ls_end_color(void);
    263      0    stevel 
    264      0    stevel static int		aflg;
    265      0    stevel static int		atflg;
    266      0    stevel static int		bflg;
    267      0    stevel static int		cflg;
    268      0    stevel static int		dflg;
    269      0    stevel static int		eflg;
    270      0    stevel static int		fflg;
    271      0    stevel static int		gflg;
    272      0    stevel static int		hflg;
    273      0    stevel static int		iflg;
    274      0    stevel static int		lflg;
    275      0    stevel static int		mflg;
    276      0    stevel static int		nflg;
    277      0    stevel static int		oflg;
    278      0    stevel static int		pflg;
    279      0    stevel static int		qflg;
    280      0    stevel static int		rflg = 1; /* init to 1 for special use in compar */
    281      0    stevel static int		sflg;
    282      0    stevel static int		tflg;
    283      0    stevel static int		uflg;
    284   9664     jason static int		Uflg;
    285   9664     jason static int		wflg;
    286      0    stevel static int		xflg;
    287      0    stevel static int		Aflg;
    288   9664     jason static int		Bflg;
    289      0    stevel static int		Cflg;
    290      0    stevel static int		Eflg;
    291      0    stevel static int		Fflg;
    292      0    stevel static int		Hflg;
    293      0    stevel static int		Lflg;
    294      0    stevel static int		Rflg;
    295      0    stevel static int		Sflg;
    296    789    ahrens static int		vflg;
    297   1420     marks static int		Vflg;
    298   5331       amw static int		saflg;		/* boolean extended system attr. */
    299   5331       amw static int		sacnt;		/* number of extended system attr. */
    300   5331       amw static int		copt;
    301   5331       amw static int		vopt;
    302   5331       amw static int		tmflg;		/* create time ext. system attr. */
    303   5331       amw static int		ctm;
    304   5331       amw static int		atm;
    305   5331       amw static int		mtm;
    306   5331       amw static int		crtm;
    307   5331       amw static int		alltm;
    308      0    stevel static long		hscale;
    309      0    stevel static mode_t		flags;
    310      0    stevel static int		err = 0;	/* Contains return code */
    311   9664     jason static int		colorflg;
    312   9664     jason static int		file_typeflg;
    313      0    stevel 
    314      0    stevel static uid_t		lastuid	= (uid_t)-1;
    315      0    stevel static gid_t		lastgid = (gid_t)-1;
    316      0    stevel static char		*lastuname = NULL;
    317      0    stevel static char		*lastgname = NULL;
    318      0    stevel 
    319   9664     jason /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */
    320      0    stevel static int		statreq;
    321      0    stevel 
    322   9664     jason static uint64_t		block_size = 1;
    323      0    stevel static char		*dotp = ".";
    324      0    stevel 
    325      0    stevel static u_longlong_t 	tblocks; /* number of blocks of files in a directory */
    326      0    stevel static time_t		year, now;
    327      0    stevel 
    328      0    stevel static int		num_cols = 80;
    329      0    stevel static int		colwidth;
    330      0    stevel static int		filewidth;
    331      0    stevel static int		fixedwidth;
    332      0    stevel static int		nomocore;
    333      0    stevel static int		curcol;
    334      0    stevel 
    335      0    stevel static struct	winsize	win;
    336      0    stevel 
    337   9664     jason /* if time_fmt_new is left NULL, time_fmt_old is used for all times */
    338   9664     jason static const char	*time_fmt_old = FORMAT_OLD;	/* non-recent files */
    339   9664     jason static const char	*time_fmt_new = FORMAT_NEW;	/* recent files */
    340   9664     jason static int		time_custom;	/* != 0 if a custom format */
    341   5331       amw static char	time_buf[FMTSIZE];	/* array to hold day and time */
    342   9664     jason 
    343   9664     jason static int		lsc_debug;
    344   9664     jason static ls_color_t	*lsc_match;
    345   9664     jason static ls_color_t	*lsc_colors;
    346   9664     jason static size_t		lsc_ncolors;
    347   9664     jason static char		*lsc_bold;
    348   9664     jason static char		*lsc_underline;
    349   9664     jason static char		*lsc_blink;
    350   9664     jason static char		*lsc_reverse;
    351   9664     jason static char		*lsc_concealed;
    352   9664     jason static char		*lsc_none;
    353   9664     jason static char		*lsc_setfg;
    354   9664     jason static char		*lsc_setbg;
    355  10059     jason static ls_color_t	*lsc_orphan;
    356      0    stevel 
    357      0    stevel #define	NOTWORKINGDIR(d, l)	(((l) < 2) || \
    358      0    stevel 				    (strcmp((d) + (l) - 2, "/.") != 0))
    359      0    stevel 
    360      0    stevel #define	NOTPARENTDIR(d, l)	(((l) < 3) || \
    361      0    stevel 				    (strcmp((d) + (l) - 3, "/..") != 0))
    362   5331       amw /* Extended system attributes support */
    363   5331       amw static int get_sysxattr(char *, struct lbuf *);
    364   5331       amw static void set_sysattrb_display(char *, boolean_t, struct lbuf *);
    365   5331       amw static void set_sysattrtm_display(char *, struct lbuf *);
    366   9664     jason static void format_time(time_t, time_t);
    367   5331       amw static void print_time(struct lbuf *);
    368   5331       amw static void format_attrtime(struct lbuf *);
    369   5331       amw static void *xmalloc(size_t, struct lbuf *);
    370   5331       amw static void free_sysattr(struct lbuf *);
    371   5331       amw static nvpair_t *pair;
    372   5331       amw static nvlist_t	*response;
    373   6866    basabi static int acl_err;
    374   9664     jason 
    375   9664     jason const struct option long_options[] = {
    376   9664     jason 	{ "all", no_argument, NULL, 'a' },
    377   9664     jason 	{ "almost-all", no_argument, NULL, 'A' },
    378   9664     jason 	{ "escape", no_argument, NULL, 'b' },
    379   9664     jason 	{ "classify", no_argument, NULL, 'F' },
    380   9664     jason 	{ "human-readable", no_argument, NULL, 'h' },
    381   9664     jason 	{ "dereference", no_argument, NULL, 'L' },
    382   9664     jason 	{ "dereference-command-line", no_argument, NULL, 'H' },
    383   9664     jason 	{ "ignore-backups", no_argument, NULL, 'B' },
    384   9664     jason 	{ "inode", no_argument, NULL, 'i' },
    385   9664     jason 	{ "numeric-uid-gid", no_argument, NULL, 'n' },
    386   9664     jason 	{ "no-group", no_argument, NULL, 'o' },
    387   9664     jason 	{ "hide-control-chars", no_argument, NULL, 'q' },
    388   9664     jason 	{ "reverse", no_argument, NULL, 'r' },
    389   9664     jason 	{ "recursive", no_argument, NULL, 'R' },
    390   9664     jason 	{ "size", no_argument, NULL, 's' },
    391   9664     jason 	{ "width", required_argument, NULL, 'w' },
    392   9664     jason 
    393   9664     jason 	/* no short options for these */
    394   9664     jason 	{ "block-size", required_argument, NULL, 0 },
    395   9664     jason 	{ "full-time", no_argument, NULL, 0 },
    396   9664     jason 	{ "si", no_argument, NULL, 0 },
    397   9664     jason 	{ "color", optional_argument, NULL, 0 },
    398   9664     jason 	{ "colour", optional_argument, NULL, 0},
    399   9664     jason 	{ "file-type", no_argument, NULL, 0 },
    400   9664     jason 	{ "time-style", required_argument, NULL, 0 },
    401   9664     jason 
    402   9664     jason 	{0, 0, 0, 0}
    403   9664     jason };
    404      0    stevel 
    405      0    stevel int
    406      0    stevel main(int argc, char *argv[])
    407      0    stevel {
    408      0    stevel 	int		c;
    409      0    stevel 	int		i;
    410      0    stevel 	int		width;
    411      0    stevel 	int		amino = 0;
    412      0    stevel 	int		opterr = 0;
    413   9664     jason 	int		option_index = 0;
    414      0    stevel 	struct lbuf	*ep;
    415      0    stevel 	struct lbuf	lb;
    416      0    stevel 	struct ditem	*myinfo;
    417      0    stevel 
    418      0    stevel 	(void) setlocale(LC_ALL, "");
    419      0    stevel #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
    420      0    stevel #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
    421      0    stevel #endif
    422      0    stevel 	(void) textdomain(TEXT_DOMAIN);
    423      0    stevel #ifdef STANDALONE
    424      0    stevel 	if (argv[0][0] == '\0')
    425      0    stevel 		argc = getargv("ls", &argv, 0);
    426      0    stevel #endif
    427      0    stevel 
    428      0    stevel 	lb.lmtime.tv_sec = time(NULL);
    429      0    stevel 	lb.lmtime.tv_nsec = 0;
    430      0    stevel 	year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */
    431      0    stevel 	now = lb.lmtime.tv_sec + 60;
    432      0    stevel 	if (isatty(1)) {
    433      0    stevel 		Cflg = 1;
    434      0    stevel 		mflg = 0;
    435      0    stevel 	}
    436      0    stevel 
    437   9664     jason 	while ((c = getopt_long(argc, argv,
    438   9664     jason 	    "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options,
    439   9664     jason 	    &option_index)) != -1)
    440      0    stevel 		switch (c) {
    441   9664     jason 		case 0:
    442   9664     jason 			/* non-short options */
    443   9664     jason 			if (strcmp(long_options[option_index].name,
    444   9664     jason 			    "color") == 0 ||
    445   9664     jason 			    strcmp(long_options[option_index].name,
    446   9664     jason 			    "colour") == 0) {
    447   9664     jason 				if (optarg == NULL ||
    448   9664     jason 				    strcmp(optarg, "always") == 0 ||
    449   9664     jason 				    strcmp(optarg, "yes") == 0 ||
    450   9664     jason 				    strcmp(optarg, "force") == 0) {
    451   9664     jason 					colorflg++;
    452   9664     jason 					statreq++;
    453   9664     jason 					continue;
    454   9664     jason 				}
    455   9664     jason 
    456  10456     jason 				if (strcmp(optarg, "auto") == 0 ||
    457   9664     jason 				    strcmp(optarg, "tty") == 0 ||
    458  10456     jason 				    strcmp(optarg, "if-tty") == 0) {
    459  10456     jason 					if (isatty(1) == 1) {
    460  10456     jason 						colorflg++;
    461  10456     jason 						statreq++;
    462  10456     jason 					}
    463   9664     jason 					continue;
    464   9664     jason 				}
    465   9664     jason 
    466   9664     jason 				if (strcmp(optarg, "never") == 0 ||
    467   9664     jason 				    strcmp(optarg, "no") == 0 ||
    468   9664     jason 				    strcmp(optarg, "none") == 0) {
    469   9664     jason 					colorflg = 0;
    470   9664     jason 					continue;
    471   9664     jason 				}
    472   9664     jason 				(void) fprintf(stderr,
    473   9664     jason 				    gettext("Invalid argument '%s' for "
    474   9664     jason 				    "--color\n"), optarg);
    475   9664     jason 				++opterr;
    476   9664     jason 				continue;
    477   9664     jason 			}
    478   9664     jason 
    479   9664     jason 			if (strcmp(long_options[option_index].name,
    480   9664     jason 			    "si") == 0) {
    481   9664     jason 				hflg++;
    482   9664     jason 				hscale = 1000;
    483   9664     jason 				continue;
    484   9664     jason 			}
    485   9664     jason 
    486   9664     jason 			if (strcmp(long_options[option_index].name,
    487   9664     jason 			    "block-size") == 0) {
    488   9664     jason 				size_t scale_len = strlen(optarg);
    489   9664     jason 				uint64_t scale = 1;
    490   9664     jason 				uint64_t kilo = 1024;
    491   9664     jason 				char scale_c;
    492   9664     jason 
    493   9664     jason 				if (scale_len == 0) {
    494   9664     jason 					(void) fprintf(stderr, gettext(
    495   9664     jason 					    "Invalid block size \'%s\'\n"),
    496   9664     jason 					    optarg);
    497   9664     jason 					exit(1);
    498   9664     jason 				}
    499   9664     jason 
    500   9664     jason 				scale_c = optarg[scale_len - 1];
    501   9664     jason 				if (scale_c == 'B') {
    502   9664     jason 					/* need at least digit, scale, B */
    503   9664     jason 					if (scale_len < 3) {
    504   9664     jason 						(void) fprintf(stderr, gettext(
    505   9664     jason 						    "Invalid block size "
    506   9664     jason 						    "\'%s\'\n"), optarg);
    507   9664     jason 						exit(1);
    508   9664     jason 					}
    509   9664     jason 					kilo = 1000;
    510   9664     jason 					scale_c = optarg[scale_len - 2];
    511   9664     jason 					if (isdigit(scale_c)) {
    512   9664     jason 						(void) fprintf(stderr,
    513   9664     jason 						    gettext("Invalid block size"
    514   9664     jason 						    " \'%s\'\n"), optarg);
    515   9664     jason 						exit(1);
    516   9664     jason 					}
    517   9664     jason 					/*
    518   9664     jason 					 * make optarg[scale_len - 1] point to
    519   9664     jason 					 * the scale factor
    520   9664     jason 					 */
    521   9664     jason 					--scale_len;
    522   9664     jason 				}
    523   9664     jason 
    524   9664     jason 				switch (scale_c) {
    525   9664     jason 				case 'y':
    526   9664     jason 				case 'Y':
    527   9664     jason 					scale *= kilo;
    528   9664     jason 					/*FALLTHROUGH*/
    529   9664     jason 				case 'Z':
    530   9664     jason 				case 'z':
    531   9664     jason 					scale *= kilo;
    532   9664     jason 					/*FALLTHROUGH*/
    533   9664     jason 				case 'E':
    534   9664     jason 				case 'e':
    535   9664     jason 					scale *= kilo;
    536   9664     jason 					/*FALLTHROUGH*/
    537   9664     jason 				case 'P':
    538   9664     jason 				case 'p':
    539   9664     jason 					scale *= kilo;
    540   9664     jason 					/*FALLTHROUGH*/
    541   9664     jason 				case 'T':
    542   9664     jason 				case 't':
    543   9664     jason 					scale *= kilo;
    544   9664     jason 					/*FALLTHROUGH*/
    545   9664     jason 				case 'G':
    546   9664     jason 				case 'g':
    547   9664     jason 					scale *= kilo;
    548   9664     jason 					/*FALLTHROUGH*/
    549   9664     jason 				case 'M':
    550   9664     jason 				case 'm':
    551   9664     jason 					scale *= kilo;
    552   9664     jason 					/*FALLTHROUGH*/
    553   9664     jason 				case 'K':
    554   9664     jason 				case 'k':
    555   9664     jason 					scale *= kilo;
    556   9664     jason 					break;
    557   9664     jason 				default:
    558   9664     jason 					if (!isdigit(scale_c)) {
    559   9664     jason 						(void) fprintf(stderr,
    560   9664     jason 						    gettext("Invalid character "
    561   9664     jason 						    "following block size in "
    562   9664     jason 						    "\'%s\'\n"), optarg);
    563   9664     jason 						exit(1);
    564   9664     jason 					}
    565   9664     jason 				}
    566   9664     jason 
    567   9664     jason 				/* NULL out scale constant if present */
    568   9664     jason 				if (scale > 1 && !isdigit(scale_c))
    569   9664     jason 					optarg[scale_len - 1] = '\0';
    570   9664     jason 
    571   9664     jason 				/* Based on testing, this is what GNU ls does */
    572   9664     jason 				block_size = strtoll(optarg, NULL, 0) * scale;
    573   9664     jason 				if (block_size < 1) {
    574   9664     jason 					(void) fprintf(stderr,
    575   9664     jason 					    gettext("Invalid block size "
    576   9664     jason 					    "\'%s\'\n"), optarg);
    577   9664     jason 					exit(1);
    578   9664     jason 				}
    579   9664     jason 				continue;
    580   9664     jason 			}
    581   9664     jason 
    582   9664     jason 			if (strcmp(long_options[option_index].name,
    583   9664     jason 			    "file-type") == 0) {
    584   9664     jason 				file_typeflg++;
    585   9664     jason 				Fflg++;
    586   9664     jason 				statreq++;
    587   9664     jason 				continue;
    588   9664     jason 			}
    589   9664     jason 
    590   9664     jason 
    591   9664     jason 			if (strcmp(long_options[option_index].name,
    592   9664     jason 			    "full-time") == 0) {
    593   9664     jason 				Eflg++;
    594   9664     jason 				statreq++;
    595   9664     jason 				eflg = 0;
    596   9664     jason 				time_fmt_old = FORMAT_ISO_FULL;
    597   9664     jason 				time_fmt_new = FORMAT_ISO_FULL;
    598   9664     jason 				continue;
    599   9664     jason 			}
    600   9664     jason 
    601   9664     jason 			if (strcmp(long_options[option_index].name,
    602   9664     jason 			    "time-style") == 0) {
    603   9664     jason 				/* like -E, but doesn't imply -l */
    604   9664     jason 				if (strcmp(optarg, "full-iso") == 0) {
    605   9664     jason 					Eflg++;
    606   9664     jason 					statreq++;
    607   9664     jason 					eflg = 0;
    608   9664     jason 					time_fmt_old = FORMAT_ISO_FULL;
    609   9664     jason 					time_fmt_new = FORMAT_ISO_FULL;
    610   9664     jason 					continue;
    611   9664     jason 				}
    612   9664     jason 				if (strcmp(optarg, "long-iso") == 0) {
    613   9664     jason 					statreq++;
    614   9664     jason 					Eflg = 0;
    615   9664     jason 					eflg = 0;
    616   9664     jason 					time_fmt_old = FORMAT_ISO_LONG;
    617   9664     jason 					time_fmt_new = FORMAT_ISO_LONG;
    618   9664     jason 					continue;
    619   9664     jason 				}
    620   9664     jason 				if (strcmp(optarg, "iso") == 0) {
    621   9664     jason 					statreq++;
    622   9664     jason 					Eflg = 0;
    623   9664     jason 					eflg = 0;
    624   9664     jason 					time_fmt_old = FORMAT_ISO_OLD;
    625   9664     jason 					time_fmt_new = FORMAT_ISO_NEW;
    626   9664     jason 					continue;
    627   9664     jason 				}
    628   9664     jason 				/* should be the default */
    629   9664     jason 				if (strcmp(optarg, "locale") == 0) {
    630   9664     jason 					time_fmt_old = FORMAT_OLD;
    631   9664     jason 					time_fmt_new = FORMAT_NEW;
    632   9664     jason 					continue;
    633   9664     jason 				}
    634   9664     jason 				if (optarg[0] == '+') {
    635   9664     jason 					char	*told, *tnew;
    636   9664     jason 					char	*p;
    637   9664     jason 					size_t	timelen = strlen(optarg);
    638   9664     jason 
    639   9664     jason 					p = strchr(optarg, '\n');
    640   9664     jason 					if (p != NULL)
    641   9664     jason 						*p++ = '\0';
    642   9664     jason 
    643   9664     jason 					/*
    644   9664     jason 					 * Time format requires a leading and
    645   9664     jason 					 * trailing space
    646   9664     jason 					 * Add room for 3 spaces + 2 nulls
    647   9664     jason 					 * The + in optarg is replaced with
    648   9664     jason 					 * a space.
    649   9664     jason 					 */
    650   9664     jason 					timelen += 2 + 3;
    651   9664     jason 					told = malloc(timelen);
    652   9664     jason 					if (told == NULL) {
    653   9664     jason 						perror("Out of memory");
    654   9664     jason 						exit(1);
    655   9664     jason 					}
    656   9664     jason 
    657   9664     jason 					(void) memset(told, 0, timelen);
    658   9664     jason 					told[0] = ' ';
    659   9664     jason 					(void) strlcat(told, &optarg[1],
    660   9664     jason 					    timelen);
    661   9664     jason 					(void) strlcat(told, " ", timelen);
    662   9664     jason 
    663   9664     jason 					if (p != NULL) {
    664   9664     jason 						size_t tnew_len;
    665   9664     jason 
    666   9664     jason 						tnew = told + strlen(told) + 1;
    667   9664     jason 						tnew_len = timelen -
    668   9664     jason 						    strlen(told) - 1;
    669   9664     jason 
    670   9664     jason 						tnew[0] = ' ';
    671   9664     jason 						(void) strlcat(tnew, p,
    672   9664     jason 						    tnew_len);
    673   9664     jason 						(void) strlcat(tnew, " ",
    674   9664     jason 						    tnew_len);
    675   9664     jason 						time_fmt_new =
    676   9664     jason 						    (const char *)tnew;
    677   9664     jason 					} else {
    678   9664     jason 						time_fmt_new =
    679   9664     jason 						    (const char *)told;
    680   9664     jason 					}
    681   9664     jason 
    682   9664     jason 					time_fmt_old = (const char *)told;
    683   9664     jason 					time_custom = 1;
    684   9664     jason 					continue;
    685   9664     jason 				}
    686   9664     jason 				continue;
    687   9664     jason 			}
    688   9664     jason 
    689   9664     jason 			continue;
    690   9664     jason 
    691      0    stevel 		case 'a':
    692      0    stevel 			aflg++;
    693      0    stevel 			continue;
    694      0    stevel 		case 'A':
    695      0    stevel 			Aflg++;
    696      0    stevel 			continue;
    697      0    stevel 		case 'b':
    698      0    stevel 			bflg = 1;
    699      0    stevel 			qflg = 0;
    700   9664     jason 			continue;
    701   9664     jason 		case 'B':
    702   9664     jason 			Bflg = 1;
    703      0    stevel 			continue;
    704      0    stevel 		case 'c':
    705      0    stevel 			uflg = 0;
    706   5331       amw 			atm = 0;
    707   5331       amw 			ctm = 0;
    708   5331       amw 			mtm = 0;
    709   5331       amw 			crtm = 0;
    710      0    stevel 			cflg++;
    711      0    stevel 			continue;
    712      0    stevel 		case 'C':
    713      0    stevel 			Cflg = 1;
    714      0    stevel 			mflg = 0;
    715      0    stevel #ifdef XPG4
    716      0    stevel 			lflg = 0;
    717      0    stevel #endif
    718      0    stevel 			continue;
    719      0    stevel 		case 'd':
    720      0    stevel 			dflg++;
    721      0    stevel 			continue;
    722      0    stevel 		case 'e':
    723      0    stevel 			eflg++;
    724      0    stevel 			lflg++;
    725      0    stevel 			statreq++;
    726      0    stevel 			Eflg = 0;
    727   9664     jason 			time_fmt_old = FORMAT_LONG;
    728   9664     jason 			time_fmt_new = FORMAT_LONG;
    729      0    stevel 			continue;
    730      0    stevel 		case 'E':
    731      0    stevel 			Eflg++;
    732      0    stevel 			lflg++;
    733      0    stevel 			statreq++;
    734      0    stevel 			eflg = 0;
    735   9664     jason 			time_fmt_old = FORMAT_ISO_FULL;
    736   9664     jason 			time_fmt_new = FORMAT_ISO_FULL;
    737      0    stevel 			continue;
    738      0    stevel 		case 'f':
    739      0    stevel 			fflg++;
    740      0    stevel 			continue;
    741      0    stevel 		case 'F':
    742      0    stevel 			Fflg++;
    743      0    stevel 			statreq++;
    744      0    stevel 			continue;
    745      0    stevel 		case 'g':
    746      0    stevel 			gflg++;
    747      0    stevel 			lflg++;
    748      0    stevel 			statreq++;
    749      0    stevel 			continue;
    750      0    stevel 		case 'h':
    751      0    stevel 			hflg++;
    752      0    stevel 			hscale = 1024;
    753      0    stevel 			continue;
    754      0    stevel 		case 'H':
    755      0    stevel 			Hflg++;
    756      0    stevel 			/* -H and -L are mutually exclusive */
    757      0    stevel 			Lflg = 0;
    758      0    stevel 			continue;
    759      0    stevel 		case 'i':
    760      0    stevel 			iflg++;
    761   9664     jason 			continue;
    762   9664     jason 		case 'k':
    763   9664     jason 			block_size = 1024;
    764      0    stevel 			continue;
    765      0    stevel 		case 'l':
    766      0    stevel 			lflg++;
    767      0    stevel 			statreq++;
    768      0    stevel 			Cflg = 0;
    769      0    stevel 			xflg = 0;
    770      0    stevel 			mflg = 0;
    771      0    stevel 			atflg = 0;
    772      0    stevel 			continue;
    773      0    stevel 		case 'L':
    774      0    stevel 			Lflg++;
    775      0    stevel 			/* -H and -L are mutually exclusive */
    776      0    stevel 			Hflg = 0;
    777      0    stevel 			continue;
    778      0    stevel 		case 'm':
    779      0    stevel 			Cflg = 0;
    780      0    stevel 			mflg = 1;
    781      0    stevel #ifdef XPG4
    782      0    stevel 			lflg = 0;
    783      0    stevel #endif
    784      0    stevel 			continue;
    785      0    stevel 		case 'n':
    786      0    stevel 			nflg++;
    787      0    stevel 			lflg++;
    788      0    stevel 			statreq++;
    789      0    stevel 			Cflg = 0;
    790      0    stevel 			xflg = 0;
    791      0    stevel 			mflg = 0;
    792      0    stevel 			atflg = 0;
    793      0    stevel 			continue;
    794      0    stevel 		case 'o':
    795      0    stevel 			oflg++;
    796      0    stevel 			lflg++;
    797      0    stevel 			statreq++;
    798      0    stevel 			continue;
    799      0    stevel 		case 'p':
    800      0    stevel 			pflg++;
    801      0    stevel 			statreq++;
    802      0    stevel 			continue;
    803      0    stevel 		case 'q':
    804      0    stevel 			qflg = 1;
    805      0    stevel 			bflg = 0;
    806      0    stevel 			continue;
    807      0    stevel 		case 'r':
    808      0    stevel 			rflg = -1;
    809      0    stevel 			continue;
    810      0    stevel 		case 'R':
    811      0    stevel 			Rflg++;
    812      0    stevel 			statreq++;
    813      0    stevel 			continue;
    814      0    stevel 		case 's':
    815      0    stevel 			sflg++;
    816      0    stevel 			statreq++;
    817      0    stevel 			continue;
    818      0    stevel 		case 'S':
    819      0    stevel 			tflg = 0;
    820   9664     jason 			Uflg = 0;
    821      0    stevel 			Sflg++;
    822      0    stevel 			statreq++;
    823      0    stevel 			continue;
    824      0    stevel 		case 't':
    825      0    stevel 			Sflg = 0;
    826   9664     jason 			Uflg = 0;
    827      0    stevel 			tflg++;
    828      0    stevel 			statreq++;
    829   9664     jason 			continue;
    830   9664     jason 		case 'U':
    831   9664     jason 			Sflg = 0;
    832   9664     jason 			tflg = 0;
    833   9664     jason 			Uflg++;
    834      0    stevel 			continue;
    835      0    stevel 		case 'u':
    836      0    stevel 			cflg = 0;
    837   5331       amw 			atm = 0;
    838   5331       amw 			ctm = 0;
    839   5331       amw 			mtm = 0;
    840   5331       amw 			crtm = 0;
    841      0    stevel 			uflg++;
    842      0    stevel 			continue;
    843   1420     marks 		case 'V':
    844   1420     marks 			Vflg++;
    845   1420     marks 			/*FALLTHROUGH*/
    846    789    ahrens 		case 'v':
    847    789    ahrens 			vflg++;
    848    789    ahrens #if !defined(XPG4)
    849    789    ahrens 			if (lflg)
    850    789    ahrens 				continue;
    851    789    ahrens #endif
    852    789    ahrens 			lflg++;
    853    789    ahrens 			statreq++;
    854    789    ahrens 			Cflg = 0;
    855    789    ahrens 			xflg = 0;
    856    789    ahrens 			mflg = 0;
    857   9664     jason 			continue;
    858   9664     jason 		case 'w':
    859   9664     jason 			wflg++;
    860   9664     jason 			num_cols = atoi(optarg);
    861    789    ahrens 			continue;
    862      0    stevel 		case 'x':
    863      0    stevel 			xflg = 1;
    864      0    stevel 			Cflg = 1;
    865      0    stevel 			mflg = 0;
    866      0    stevel #ifdef XPG4
    867      0    stevel 			lflg = 0;
    868      0    stevel #endif
    869      0    stevel 			continue;
    870      0    stevel 		case '1':
    871      0    stevel 			Cflg = 0;
    872      0    stevel 			continue;
    873      0    stevel 		case '@':
    874      0    stevel #if !defined(XPG4)
    875      0    stevel 			/*
    876      0    stevel 			 * -l has precedence over -@
    877      0    stevel 			 */
    878      0    stevel 			if (lflg)
    879      0    stevel 				continue;
    880      0    stevel #endif
    881      0    stevel 			atflg++;
    882      0    stevel 			lflg++;
    883      0    stevel 			statreq++;
    884      0    stevel 			Cflg = 0;
    885      0    stevel 			xflg = 0;
    886      0    stevel 			mflg = 0;
    887      0    stevel 			continue;
    888   5331       amw 		case '/':
    889   5331       amw 			saflg++;
    890   5331       amw 			if (optarg != NULL) {
    891   5331       amw 				if (strcmp(optarg, "c") == 0) {
    892   5331       amw 					copt++;
    893   5331       amw 					vopt = 0;
    894   5331       amw 				} else if (strcmp(optarg, "v") == 0) {
    895   5331       amw 					vopt++;
    896   5331       amw 					copt = 0;
    897   5331       amw 				} else
    898   5331       amw 					opterr++;
    899   5331       amw 			} else
    900   5331       amw 				opterr++;
    901   5331       amw 			lflg++;
    902   5331       amw 			statreq++;
    903   5331       amw 			Cflg = 0;
    904   5331       amw 			xflg = 0;
    905   5331       amw 			mflg = 0;
    906   5331       amw 			continue;
    907   5331       amw 		case '%':
    908   5331       amw 			tmflg++;
    909   5331       amw 			if (optarg != NULL) {
    910   5331       amw 				if (strcmp(optarg, "ctime") == 0) {
    911   5331       amw 					ctm++;
    912   5331       amw 					atm = 0;
    913   5331       amw 					mtm = 0;
    914   5331       amw 					crtm = 0;
    915   5331       amw 				} else if (strcmp(optarg, "atime") == 0) {
    916   5331       amw 					atm++;
    917   5331       amw 					ctm = 0;
    918   5331       amw 					mtm = 0;
    919   5331       amw 					crtm = 0;
    920   5331       amw 					uflg = 0;
    921   5331       amw 					cflg = 0;
    922   5331       amw 				} else if (strcmp(optarg, "mtime") == 0) {
    923   5331       amw 					mtm++;
    924   5331       amw 					atm = 0;
    925   5331       amw 					ctm = 0;
    926   5331       amw 					crtm = 0;
    927   5331       amw 					uflg = 0;
    928   5331       amw 					cflg = 0;
    929   5331       amw 				} else if (strcmp(optarg, "crtime") == 0) {
    930   5331       amw 					crtm++;
    931   5331       amw 					atm = 0;
    932   5331       amw 					ctm = 0;
    933   5331       amw 					mtm = 0;
    934   5331       amw 					uflg = 0;
    935   5331       amw 					cflg = 0;
    936   5331       amw 				} else if (strcmp(optarg, "all") == 0) {
    937   5331       amw 					alltm++;
    938   5331       amw 					atm = 0;
    939   5331       amw 					ctm = 0;
    940   5331       amw 					mtm = 0;
    941   5331       amw 					crtm = 0;
    942   5331       amw 				} else
    943   5331       amw 					opterr++;
    944   5331       amw 			} else
    945   5331       amw 				opterr++;
    946   5331       amw 
    947   5331       amw 			Sflg = 0;
    948   5331       amw 			statreq++;
    949   5331       amw 			mflg = 0;
    950   5331       amw 			continue;
    951      0    stevel 		case '?':
    952      0    stevel 			opterr++;
    953      0    stevel 			continue;
    954      0    stevel 		}
    955   9664     jason 
    956      0    stevel 	if (opterr) {
    957      0    stevel 		(void) fprintf(stderr, gettext(
    958   9664     jason 		    "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]"
    959   5331       amw 		    "%%[atime | crtime | ctime | mtime | all]"
    960   5331       amw 		    " [files]\n"));
    961      0    stevel 		exit(2);
    962      0    stevel 	}
    963      0    stevel 
    964      0    stevel 	if (fflg) {
    965      0    stevel 		aflg++;
    966      0    stevel 		lflg = 0;
    967      0    stevel 		sflg = 0;
    968      0    stevel 		tflg = 0;
    969      0    stevel 		Sflg = 0;
    970      0    stevel 		statreq = 0;
    971      0    stevel 	}
    972      0    stevel 
    973      0    stevel 	fixedwidth = 2;
    974      0    stevel 	if (pflg || Fflg)
    975      0    stevel 		fixedwidth++;
    976      0    stevel 	if (iflg)
    977      0    stevel 		fixedwidth += 11;
    978      0    stevel 	if (sflg)
    979      0    stevel 		fixedwidth += 5;
    980      0    stevel 
    981      0    stevel 	if (lflg) {
    982      0    stevel 		if (!gflg && !oflg)
    983      0    stevel 			gflg = oflg = 1;
    984      0    stevel 		else
    985      0    stevel 		if (gflg && oflg)
    986      0    stevel 			gflg = oflg = 0;
    987      0    stevel 		Cflg = mflg = 0;
    988      0    stevel 	}
    989      0    stevel 
    990   9664     jason 	if (!wflg && (Cflg || mflg)) {
    991      0    stevel 		char *clptr;
    992      0    stevel 		if ((clptr = getenv("COLUMNS")) != NULL)
    993      0    stevel 			num_cols = atoi(clptr);
    994      0    stevel #ifdef TERMINFO
    995      0    stevel 		else {
    996      0    stevel 			if (ioctl(1, TIOCGWINSZ, &win) != -1)
    997      0    stevel 				num_cols = (win.ws_col == 0 ? 80 : win.ws_col);
    998      0    stevel 		}
    999      0    stevel #endif
   1000      0    stevel 	}
   1001   9664     jason 
   1002   9664     jason 	if (num_cols < 20 || num_cols > 1000)
   1003   9664     jason 		/* assume it is an error */
   1004   9664     jason 		num_cols = 80;
   1005      0    stevel 
   1006      0    stevel 	/* allocate space for flist and the associated	*/
   1007      0    stevel 	/* data structures (lbufs)			*/
   1008      0    stevel 	maxfils = quantn;
   1009      0    stevel 	if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) ||
   1010      0    stevel 	    ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) {
   1011      0    stevel 		perror("ls");
   1012      0    stevel 		exit(2);
   1013      0    stevel 	}
   1014      0    stevel 	if ((amino = (argc-optind)) == 0) {
   1015      0    stevel 					/*
   1016      0    stevel 					 * case when no names are given
   1017      0    stevel 					 * in ls-command and current
   1018      0    stevel 					 * directory is to be used
   1019      0    stevel 					 */
   1020      0    stevel 		argv[optind] = dotp;
   1021      0    stevel 	}
   1022      0    stevel 
   1023      0    stevel 	for (i = 0; i < (amino ? amino : 1); i++) {
   1024      0    stevel 
   1025      0    stevel 		/*
   1026      0    stevel 		 * If we are recursing, we need to make sure we don't
   1027      0    stevel 		 * get into an endless loop.  To keep track of the inodes
   1028      0    stevel 		 * (actually, just the directories) visited, we
   1029      0    stevel 		 * maintain a directory ancestry list for a file
   1030      0    stevel 		 * hierarchy.  As we go deeper into the hierarchy,
   1031      0    stevel 		 * a parent directory passes its directory list
   1032      0    stevel 		 * info (device id, inode number, and a pointer to
   1033      0    stevel 		 * its parent) to each of its children.  As we
   1034      0    stevel 		 * process a child that is a directory, we save
   1035      0    stevel 		 * its own personal directory list info.  We then
   1036      0    stevel 		 * check to see if the child has already been
   1037      0    stevel 		 * processed by comparing its device id and inode
   1038      0    stevel 		 * number from its own personal directory list info
   1039      0    stevel 		 * to that of each of its ancestors.  If there is a
   1040      0    stevel 		 * match, then we know we've detected a cycle.
   1041      0    stevel 		 */
   1042      0    stevel 		if (Rflg) {
   1043      0    stevel 			/*
   1044      0    stevel 			 * This is the first parent in this lineage
   1045      0    stevel 			 * (first in a directory hierarchy), so
   1046      0    stevel 			 * this parent's parent doesn't exist.  We
   1047      0    stevel 			 * only initialize myinfo when we are
   1048      0    stevel 			 * recursing, otherwise it's not used.
   1049      0    stevel 			 */
   1050      0    stevel 			if ((myinfo = (struct ditem *)malloc(
   1051      0    stevel 			    sizeof (struct ditem))) == NULL) {
   1052      0    stevel 				perror("ls");
   1053      0    stevel 				exit(2);
   1054      0    stevel 			} else {
   1055      0    stevel 				myinfo->dev = 0;
   1056      0    stevel 				myinfo->ino = 0;
   1057      0    stevel 				myinfo->parent = NULL;
   1058      0    stevel 			}
   1059      0    stevel 		}
   1060      0    stevel 
   1061      0    stevel 		if (Cflg || mflg) {
   1062      0    stevel 			width = strcol((unsigned char *)argv[optind]);
   1063      0    stevel 			if (width > filewidth)
   1064      0    stevel 				filewidth = width;
   1065      0    stevel 		}
   1066      0    stevel 		if ((ep = gstat((*argv[optind] ? argv[optind] : dotp),
   1067      0    stevel 		    1, myinfo)) == NULL) {
   1068      0    stevel 			if (nomocore)
   1069      0    stevel 				exit(2);
   1070      0    stevel 			err = 2;
   1071      0    stevel 			optind++;
   1072      0    stevel 			continue;
   1073      0    stevel 		}
   1074      0    stevel 		ep->ln.namep = (*argv[optind] ? argv[optind] : dotp);
   1075      0    stevel 		ep->lflags |= ISARG;
   1076      0    stevel 		optind++;
   1077      0    stevel 		nargs++;	/* count good arguments stored in flist */
   1078   6866    basabi 		if (acl_err)
   1079   6866    basabi 			err = 2;
   1080      0    stevel 	}
   1081      0    stevel 	colwidth = fixedwidth + filewidth;
   1082   9664     jason 	if (!Uflg)
   1083   9664     jason 		qsort(flist, (unsigned)nargs, sizeof (struct lbuf *),
   1084   9664     jason 		    (int (*)(const void *, const void *))compar);
   1085      0    stevel 	for (i = 0; i < nargs; i++) {
   1086      0    stevel 		if (flist[i]->ltype == 'd' && dflg == 0 || fflg)
   1087      0    stevel 			break;
   1088      0    stevel 	}
   1089   9664     jason 
   1090   9664     jason 	if (colorflg)
   1091   9664     jason 		ls_color_init();
   1092   9664     jason 
   1093      0    stevel 	pem(&flist[0], &flist[i], 0);
   1094      0    stevel 	for (; i < nargs; i++) {
   1095      0    stevel 		pdirectory(flist[i]->ln.namep, Rflg ||
   1096      0    stevel 		    (amino > 1), nargs, 0, flist[i]->ancinfo);
   1097      0    stevel 		if (nomocore)
   1098      0    stevel 			exit(2);
   1099      0    stevel 		/* -R: print subdirectories found */
   1100      0    stevel 		while (dfirst || cdfirst) {
   1101      0    stevel 			/* Place direct subdirs on front in right order */
   1102      0    stevel 			while (cdfirst) {
   1103      0    stevel 				/* reverse cdfirst onto front of dfirst */
   1104      0    stevel 				dtemp = cdfirst;
   1105      0    stevel 				cdfirst = cdfirst -> dc_next;
   1106      0    stevel 				dtemp -> dc_next = dfirst;
   1107      0    stevel 				dfirst = dtemp;
   1108      0    stevel 			}
   1109      0    stevel 			/* take off first dir on dfirst & print it */
   1110      0    stevel 			dtemp = dfirst;
   1111      0    stevel 			dfirst = dfirst->dc_next;
   1112      0    stevel 			pdirectory(dtemp->dc_name, 1, nargs,
   1113      0    stevel 			    dtemp->cycle_detected, dtemp->myancinfo);
   1114      0    stevel 			if (nomocore)
   1115      0    stevel 				exit(2);
   1116      0    stevel 			free(dtemp->dc_name);
   1117      0    stevel 			free(dtemp);
   1118      0    stevel 		}
   1119      0    stevel 	}
   1120   9664     jason 
   1121      0    stevel 	return (err);
   1122      0    stevel }
   1123      0    stevel 
   1124      0    stevel /*
   1125      0    stevel  * pdirectory: print the directory name, labelling it if title is
   1126      0    stevel  * nonzero, using lp as the place to start reading in the dir.
   1127      0    stevel  */
   1128      0    stevel static void
   1129      0    stevel pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo)
   1130      0    stevel {
   1131      0    stevel 	struct dchain *dp;
   1132      0    stevel 	struct lbuf *ap;
   1133      0    stevel 	char *pname;
   1134      0    stevel 	int j;
   1135      0    stevel 
   1136      0    stevel 	filewidth = 0;
   1137      0    stevel 	curdir = name;
   1138      0    stevel 	if (title) {
   1139      0    stevel 		if (!first)
   1140      0    stevel 			(void) putc('\n', stdout);
   1141      0    stevel 		pprintf(name, ":");
   1142      0    stevel 		new_line();
   1143      0    stevel 	}
   1144      0    stevel 	/*
   1145      0    stevel 	 * If there was a cycle detected, then notify and don't report
   1146      0    stevel 	 * further.
   1147      0    stevel 	 */
   1148      0    stevel 	if (cdetect) {
   1149      0    stevel 		if (lflg || sflg) {
   1150      0    stevel 			curcol += printf(gettext("total %d"), 0);
   1151      0    stevel 			new_line();
   1152      0    stevel 		}
   1153      0    stevel 		(void) fprintf(stderr, gettext(
   1154      0    stevel 		    "ls: cycle detected for %s\n"), name);
   1155      0    stevel 		return;
   1156      0    stevel 	}
   1157      0    stevel 
   1158      0    stevel 	nfiles = lp;
   1159      0    stevel 	rddir(name, myinfo);
   1160      0    stevel 	if (nomocore)
   1161      0    stevel 		return;
   1162   9664     jason 	if (fflg == 0 && Uflg == 0)
   1163      0    stevel 		qsort(&flist[lp], (unsigned)(nfiles - lp),
   1164      0    stevel 		    sizeof (struct lbuf *),
   1165      0    stevel 		    (int (*)(const void *, const void *))compar);
   1166      0    stevel 	if (Rflg) {
   1167      0    stevel 		for (j = nfiles - 1; j >= lp; j--) {
   1168      0    stevel 			ap = flist[j];
   1169      0    stevel 			if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") &&
   1170      0    stevel 			    strcmp(ap->ln.lname, "..")) {
   1171      0    stevel 				dp = malloc(sizeof (struct dchain));
   1172      0    stevel 				if (dp == NULL) {
   1173      0    stevel 					perror("ls");
   1174      0    stevel 					exit(2);
   1175      0    stevel 				}
   1176      0    stevel 				pname = makename(curdir, ap->ln.lname);
   1177      0    stevel 				if ((dp->dc_name = strdup(pname)) == NULL) {
   1178      0    stevel 					perror("ls");
   1179      0    stevel 					exit(2);
   1180      0    stevel 				}
   1181      0    stevel 				dp->cycle_detected = ap->cycle;
   1182      0    stevel 				dp->myancinfo = ap->ancinfo;
   1183      0    stevel 				dp->dc_next = dfirst;
   1184      0    stevel 				dfirst = dp;
   1185      0    stevel 			}
   1186      0    stevel 		}
   1187      0    stevel 	}
   1188      0    stevel 	if (lflg || sflg) {
   1189      0    stevel 		curcol += printf(gettext("total %llu"), tblocks);
   1190      0    stevel 		new_line();
   1191      0    stevel 	}
   1192      0    stevel 	pem(&flist[lp], &flist[nfiles], lflg||sflg);
   1193      0    stevel }
   1194      0    stevel 
   1195      0    stevel /*
   1196      0    stevel  * pem: print 'em. Print a list of files (e.g. a directory) bounded
   1197      0    stevel  * by slp and lp.
   1198      0    stevel  */
   1199      0    stevel static void
   1200      0    stevel pem(struct lbuf **slp, struct lbuf **lp, int tot_flag)
   1201      0    stevel {
   1202      0    stevel 	long row, nrows, i;
   1203      0    stevel 	int col, ncols;
   1204      0    stevel 	struct lbuf **ep;
   1205      0    stevel 
   1206      0    stevel 	if (Cflg || mflg) {
   1207      0    stevel 		if (colwidth > num_cols) {
   1208      0    stevel 			ncols = 1;
   1209      0    stevel 		} else {
   1210      0    stevel 			ncols = num_cols / colwidth;
   1211      0    stevel 		}
   1212      0    stevel 	}
   1213      0    stevel 
   1214      0    stevel 	if (ncols == 1 || mflg || xflg || !Cflg) {
   1215      0    stevel 		for (ep = slp; ep < lp; ep++)
   1216      0    stevel 			pentry(*ep);
   1217      0    stevel 		new_line();
   1218      0    stevel 		return;
   1219      0    stevel 	}
   1220      0    stevel 	/* otherwise print -C columns */
   1221      0    stevel 	if (tot_flag) {
   1222      0    stevel 		slp--;
   1223      0    stevel 		row = 1;
   1224      0    stevel 	}
   1225      0    stevel 	else
   1226      0    stevel 		row = 0;
   1227      0    stevel 
   1228      0    stevel 	nrows = (lp - slp - 1) / ncols + 1;
   1229      0    stevel 	for (i = 0; i < nrows; i++, row++) {
   1230      0    stevel 		for (col = 0; col < ncols; col++) {
   1231      0    stevel 			ep = slp + (nrows * col) + row;
   1232      0    stevel 			if (ep < lp)
   1233      0    stevel 				pentry(*ep);
   1234      0    stevel 		}
   1235      0    stevel 		new_line();
   1236      0    stevel 	}
   1237      0    stevel }
   1238      0    stevel 
   1239      0    stevel /*
   1240      0    stevel  * print one output entry;
   1241      0    stevel  * if uid/gid is not found in the appropriate
   1242      0    stevel  * file(passwd/group), then print uid/gid instead of
   1243      0    stevel  * user/group name;
   1244      0    stevel  */
   1245      0    stevel static void
   1246      0    stevel pentry(struct lbuf *ap)
   1247      0    stevel {
   1248      0    stevel 	struct lbuf *p;
   1249      0    stevel 	numbuf_t hbuf;
   1250      0    stevel 	char *dmark = "";	/* Used if -p or -F option active */
   1251      0    stevel 	char *cp;
   1252  10059     jason 	char *str;
   1253      0    stevel 
   1254      0    stevel 	p = ap;
   1255      0    stevel 	column();
   1256      0    stevel 	if (iflg)
   1257      0    stevel 		if (mflg && !lflg)
   1258      0    stevel 			curcol += printf("%llu ", (long long)p->lnum);
   1259      0    stevel 		else
   1260      0    stevel 			curcol += printf("%10llu ", (long long)p->lnum);
   1261      0    stevel 	if (sflg)
   1262      0    stevel 		curcol += printf((mflg && !lflg) ? "%lld " :
   1263   5331       amw 		    (p->lblocks < 10000) ? "%4lld " : "%lld ",
   1264   5331       amw 		    (p->ltype != 'b' && p->ltype != 'c') ?
   1265   5331       amw 		    p->lblocks : 0LL);
   1266      0    stevel 	if (lflg) {
   1267      0    stevel 		(void) putchar(p->ltype);
   1268      0    stevel 		curcol++;
   1269      0    stevel 		pmode(p->lflags);
   1270      0    stevel 
   1271      0    stevel 		/* ACL: additional access mode flag */
   1272      0    stevel 		(void) putchar(p->acl);
   1273      0    stevel 		curcol++;
   1274      0    stevel 
   1275      0    stevel 		curcol += printf("%3lu ", (ulong_t)p->lnl);
   1276      0    stevel 		if (oflg)
   1277      0    stevel 			if (!nflg) {
   1278      0    stevel 				cp = getname(p->luid);
   1279      0    stevel 				curcol += printf("%-8s ", cp);
   1280      0    stevel 			} else
   1281      0    stevel 				curcol += printf("%-8lu ", (ulong_t)p->luid);
   1282      0    stevel 		if (gflg)
   1283      0    stevel 			if (!nflg) {
   1284      0    stevel 				cp = getgroup(p->lgid);
   1285      0    stevel 				curcol += printf("%-8s ", cp);
   1286      0    stevel 			} else
   1287      0    stevel 				curcol += printf("%-8lu ", (ulong_t)p->lgid);
   1288      0    stevel 		if (p->ltype == 'b' || p->ltype == 'c') {
   1289      0    stevel 			curcol += printf("%3u, %2u",
   1290      0    stevel 			    (uint_t)major((dev_t)p->lsize),
   1291      0    stevel 			    (uint_t)minor((dev_t)p->lsize));
   1292      0    stevel 		} else if (hflg && (p->lsize >= hscale)) {
   1293      0    stevel 			curcol += printf("%7s",
   1294      0    stevel 			    number_to_scaled_string(hbuf, p->lsize, hscale));
   1295      0    stevel 		} else {
   1296   9664     jason 			uint64_t bsize = p->lsize / block_size;
   1297   9664     jason 
   1298   9664     jason 			/*
   1299   9664     jason 			 * Round up only when using blocks > 1 byte, otherwise
   1300   9664     jason 			 * 'normal' sizes display 1 byte too large.
   1301   9664     jason 			 */
   1302   9664     jason 			if (p->lsize % block_size != 0)
   1303   9664     jason 				bsize++;
   1304   9664     jason 
   1305   9664     jason 			curcol += printf("%7" PRIu64, bsize);
   1306      0    stevel 		}
   1307   9664     jason 		format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec);
   1308   5331       amw 		/* format extended system attribute time */
   1309   5331       amw 		if (tmflg && crtm)
   1310   5331       amw 			format_attrtime(p);
   1311   5331       amw 
   1312      0    stevel 		curcol += printf("%s", time_buf);
   1313   5331       amw 
   1314      0    stevel 	}
   1315      0    stevel 	/*
   1316      0    stevel 	 * prevent both "->" and trailing marks
   1317      0    stevel 	 * from appearing
   1318      0    stevel 	 */
   1319      0    stevel 
   1320      0    stevel 	if (pflg && p->ltype == 'd')
   1321      0    stevel 		dmark = "/";
   1322      0    stevel 
   1323      0    stevel 	if (Fflg && !(lflg && p->flinkto)) {
   1324      0    stevel 		if (p->ltype == 'd')
   1325      0    stevel 			dmark = "/";
   1326      0    stevel 		else if (p->ltype == 'D')
   1327      0    stevel 			dmark = ">";
   1328      0    stevel 		else if (p->ltype == 'p')
   1329      0    stevel 			dmark = "|";
   1330      0    stevel 		else if (p->ltype == 'l')
   1331      0    stevel 			dmark = "@";
   1332      0    stevel 		else if (p->ltype == 's')
   1333      0    stevel 			dmark = "=";
   1334   9664     jason 		else if (!file_typeflg &&
   1335   9664     jason 		    (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)))
   1336      0    stevel 			dmark = "*";
   1337      0    stevel 		else
   1338      0    stevel 			dmark = "";
   1339      0    stevel 	}
   1340      0    stevel 
   1341  10059     jason 	if (colorflg)
   1342  10059     jason 		ls_start_color(p->color);
   1343   9664     jason 
   1344  10059     jason 	if (p->lflags & ISARG)
   1345  10059     jason 		str = p->ln.namep;
   1346  10059     jason 	else
   1347  10059     jason 		str = p->ln.lname;
   1348   9664     jason 
   1349  10059     jason 	if (qflg || bflg) {
   1350  10059     jason 		csi_pprintf((unsigned char *)str);
   1351  10059     jason 
   1352  10059     jason 		if (lflg && p->flinkto) {
   1353  10059     jason 			if (colorflg)
   1354  10059     jason 				ls_end_color();
   1355  10059     jason 			csi_pprintf((unsigned char *)" -> ");
   1356  10059     jason 			if (colorflg)
   1357  10059     jason 				ls_start_color(p->link_color);
   1358  10059     jason 			csi_pprintf((unsigned char *)p->flinkto);
   1359  10059     jason 		} else {
   1360  10059     jason 			csi_pprintf((unsigned char *)dmark);
   1361      0    stevel 		}
   1362      0    stevel 	} else {
   1363  10059     jason 		(void) printf("%s", str);
   1364  10059     jason 		curcol += strcol((unsigned char *)str);
   1365  10059     jason 
   1366  10059     jason 		if (lflg && p->flinkto) {
   1367  10059     jason 			if (colorflg)
   1368  10059     jason 				ls_end_color();
   1369  10059     jason 			str = " -> ";
   1370  10059     jason 			(void) printf("%s", str);
   1371  10059     jason 			curcol += strcol((unsigned char *)str);
   1372  10059     jason 			if (colorflg)
   1373  10059     jason 				ls_start_color(p->link_color);
   1374  10059     jason 			(void) printf("%s", p->flinkto);
   1375  10059     jason 			curcol += strcol((unsigned char *)p->flinkto);
   1376  10059     jason 		} else {
   1377  10059     jason 			(void) printf("%s", dmark);
   1378      0    stevel 			curcol += strcol((unsigned char *)dmark);
   1379      0    stevel 		}
   1380      0    stevel 	}
   1381   9664     jason 
   1382   9664     jason 	if (colorflg)
   1383   9664     jason 		ls_end_color();
   1384    789    ahrens 
   1385   5331       amw 	/* Display extended system attributes */
   1386   5331       amw 	if (saflg) {
   1387   5331       amw 		int i;
   1388   5331       amw 
   1389   5331       amw 		new_line();
   1390   5331       amw 		(void) printf("	\t{");
   1391   5331       amw 		if (p->exttr != NULL) {
   1392   5331       amw 			int k = 0;
   1393   5331       amw 			for (i = 0; i < sacnt; i++) {
   1394   5331       amw 				if (p->exttr[i].name != NULL)
   1395   5331       amw 					k++;
   1396   5331       amw 			}
   1397   5331       amw 			for (i = 0; i < sacnt; i++) {
   1398   5331       amw 				if (p->exttr[i].name != NULL) {
   1399   5331       amw 					(void) printf("%s", p->exttr[i].name);
   1400   5331       amw 					k--;
   1401   5331       amw 					if (vopt && (k != 0))
   1402   5331       amw 						(void) printf(",");
   1403   5331       amw 				}
   1404   5331       amw 			}
   1405   5331       amw 		}
   1406   5331       amw 		(void) printf("}\n");
   1407   5331       amw 	}
   1408   5331       amw 	/* Display file timestamps and extended system attribute timestamps */
   1409   5331       amw 	if (tmflg && alltm) {
   1410   5331       amw 		new_line();
   1411   5331       amw 		print_time(p);
   1412   5331       amw 		new_line();
   1413   5331       amw 	}
   1414    789    ahrens 	if (vflg) {
   1415    789    ahrens 		new_line();
   1416    789    ahrens 		if (p->aclp) {
   1417   1420     marks 			acl_printacl(p->aclp, num_cols, Vflg);
   1418    789    ahrens 		}
   1419    789    ahrens 	}
   1420   5331       amw 	/* Free extended system attribute lists */
   1421   5331       amw 	if (saflg || tmflg)
   1422   5331       amw 		free_sysattr(p);
   1423      0    stevel }
   1424      0    stevel 
   1425      0    stevel /* print various r,w,x permissions */
   1426      0    stevel static void
   1427      0    stevel pmode(mode_t aflag)
   1428      0    stevel {
   1429      0    stevel 	/* these arrays are declared static to allow initializations */
   1430      0    stevel 	static int	m0[] = { 1, S_IRUSR, 'r', '-' };
   1431      0    stevel 	static int	m1[] = { 1, S_IWUSR, 'w', '-' };
   1432      0    stevel 	static int	m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR,
   1433      0    stevel 	    'x', S_ISUID, 'S', '-' };
   1434      0    stevel 	static int	m3[] = { 1, S_IRGRP, 'r', '-' };
   1435      0    stevel 	static int	m4[] = { 1, S_IWGRP, 'w', '-' };
   1436      0    stevel 	static int	m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP,
   1437      0    stevel 				'x', S_ISGID|LS_NOTREG, 'S',
   1438      0    stevel #ifdef XPG4
   1439      0    stevel 		S_ISGID, 'L', '-'};
   1440      0    stevel #else
   1441      0    stevel 		S_ISGID, 'l', '-'};
   1442      0    stevel #endif
   1443      0    stevel 	static int	m6[] = { 1, S_IROTH, 'r', '-' };
   1444      0    stevel 	static int	m7[] = { 1, S_IWOTH, 'w', '-' };
   1445      0    stevel 	static int	m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH,
   1446      0    stevel 	    'x', S_ISVTX, 'T', '-'};
   1447      0    stevel 
   1448      0    stevel 	static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8};
   1449      0    stevel 
   1450      0    stevel 	int **mp;
   1451      0    stevel 
   1452      0    stevel 	flags = aflag;
   1453      0    stevel 	for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++)
   1454      0    stevel 		selection(*mp);
   1455      0    stevel }
   1456      0    stevel 
   1457      0    stevel static void
   1458      0    stevel selection(int *pairp)
   1459      0    stevel {
   1460      0    stevel 	int n;
   1461      0    stevel 
   1462      0    stevel 	n = *pairp++;
   1463      0    stevel 	while (n-->0) {
   1464      0    stevel 		if ((flags & *pairp) == *pairp) {
   1465      0    stevel 			pairp++;
   1466      0    stevel 			break;
   1467      0    stevel 		} else {
   1468      0    stevel 			pairp += 2;
   1469      0    stevel 		}
   1470      0    stevel 	}
   1471      0    stevel 	(void) putchar(*pairp);
   1472      0    stevel 	curcol++;
   1473      0    stevel }
   1474      0    stevel 
   1475      0    stevel /*
   1476      0    stevel  * column: get to the beginning of the next column.
   1477      0    stevel  */
   1478      0    stevel static void
   1479      0    stevel column(void)
   1480      0    stevel {
   1481      0    stevel 	if (curcol == 0)
   1482      0    stevel 		return;
   1483      0    stevel 	if (mflg) {
   1484      0    stevel 		(void) putc(',', stdout);
   1485      0    stevel 		curcol++;
   1486      0    stevel 		if (curcol + colwidth + 2 > num_cols) {
   1487      0    stevel 			(void) putc('\n', stdout);
   1488      0    stevel 			curcol = 0;
   1489      0    stevel 			return;
   1490      0    stevel 		}
   1491      0    stevel 		(void) putc(' ', stdout);
   1492      0    stevel 		curcol++;
   1493      0    stevel 		return;
   1494      0    stevel 	}
   1495      0    stevel 	if (Cflg == 0) {
   1496      0    stevel 		(void) putc('\n', stdout);
   1497      0    stevel 		curcol = 0;
   1498      0    stevel 		return;
   1499      0    stevel 	}
   1500      0    stevel 	if ((curcol / colwidth + 2) * colwidth > num_cols) {
   1501      0    stevel 		(void) putc('\n', stdout);
   1502      0    stevel 		curcol = 0;
   1503      0    stevel 		return;
   1504      0    stevel 	}
   1505      0    stevel 	do {
   1506      0    stevel 		(void) putc(' ', stdout);
   1507      0    stevel 		curcol++;
   1508      0    stevel 	} while (curcol % colwidth);
   1509      0    stevel }
   1510      0    stevel 
   1511      0    stevel static void
   1512      0    stevel new_line(void)
   1513      0    stevel {
   1514      0    stevel 	if (curcol) {
   1515      0    stevel 		first = 0;
   1516      0    stevel 		(void) putc('\n', stdout);
   1517      0    stevel 		curcol = 0;
   1518      0    stevel 	}
   1519      0    stevel }
   1520      0    stevel 
   1521      0    stevel /*
   1522      0    stevel  * read each filename in directory dir and store its
   1523      0    stevel  * status in flist[nfiles]
   1524      0    stevel  * use makename() to form pathname dir/filename;
   1525      0    stevel  */
   1526      0    stevel static void
   1527      0    stevel rddir(char *dir, struct ditem *myinfo)
   1528      0    stevel {
   1529      0    stevel 	struct dirent *dentry;
   1530      0    stevel 	DIR *dirf;
   1531      0    stevel 	int j;
   1532      0    stevel 	struct lbuf *ep;
   1533      0    stevel 	int width;
   1534      0    stevel 
   1535      0    stevel 	if ((dirf = opendir(dir)) == NULL) {
   1536      0    stevel 		(void) fflush(stdout);
   1537      0    stevel 		perror(dir);
   1538      0    stevel 		err = 2;
   1539      0    stevel 		return;
   1540      0    stevel 	} else {
   1541      0    stevel 		tblocks = 0;
   1542      0    stevel 		for (;;) {
   1543      0    stevel 			errno = 0;
   1544      0    stevel 			if ((dentry = readdir(dirf)) == NULL)
   1545      0    stevel 				break;
   1546      0    stevel 			if (aflg == 0 && dentry->d_name[0] == '.' &&
   1547      0    stevel 			    (Aflg == 0 ||
   1548      0    stevel 			    dentry->d_name[1] == '\0' ||
   1549      0    stevel 			    dentry->d_name[1] == '.' &&
   1550      0    stevel 			    dentry->d_name[2] == '\0'))
   1551      0    stevel 				/*
   1552      0    stevel 				 * check for directory items '.', '..',
   1553      0    stevel 				 *  and items without valid inode-number;
   1554      0    stevel 				 */
   1555      0    stevel 				continue;
   1556      0    stevel 
   1557   9664     jason 			/* skip entries ending in ~ if -B was given */
   1558   9664     jason 			if (Bflg &&
   1559   9664     jason 			    dentry->d_name[strlen(dentry->d_name) - 1] == '~')
   1560   9664     jason 				continue;
   1561      0    stevel 			if (Cflg || mflg) {
   1562      0    stevel 				width = strcol((unsigned char *)dentry->d_name);
   1563      0    stevel 				if (width > filewidth)
   1564      0    stevel 					filewidth = width;
   1565      0    stevel 			}
   1566      0    stevel 			ep = gstat(makename(dir, dentry->d_name), 0, myinfo);
   1567      0    stevel 			if (ep == NULL) {
   1568      0    stevel 				if (nomocore)
   1569   5331       amw 					exit(2);
   1570      0    stevel 				continue;
   1571      0    stevel 			} else {
   1572      0    stevel 				ep->lnum = dentry->d_ino;
   1573      0    stevel 				for (j = 0; dentry->d_name[j] != '\0'; j++)
   1574      0    stevel 					ep->ln.lname[j] = dentry->d_name[j];
   1575      0    stevel 				ep->ln.lname[j] = '\0';
   1576      0    stevel 			}
   1577      0    stevel 		}
   1578      0    stevel 		if (errno) {
   1579      0    stevel 			int sav_errno = errno;
   1580      0    stevel 
   1581      0    stevel 			(void) fprintf(stderr,
   1582      0    stevel 			    gettext("ls: error reading directory %s: %s\n"),
   1583      0    stevel 			    dir, strerror(sav_errno));
   1584      0    stevel 		}
   1585      0    stevel 		(void) closedir(dirf);
   1586      0    stevel 		colwidth = fixedwidth + filewidth;
   1587      0    stevel 	}
   1588      0    stevel }
   1589      0    stevel 
   1590      0    stevel /*
   1591      0    stevel  * Attaching a link to an inode's ancestors.  Search
   1592      0    stevel  * through the ancestors to check for cycles (an inode which
   1593      0    stevel  * we have already tracked in this inodes ancestry).  If a cycle
   1594      0    stevel  * is detected, set the exit code and record the fact so that
   1595      0    stevel  * it is reported at the right time when printing the directory.
   1596      0    stevel  * In addition, set the exit code.  Note:  If the -a flag was
   1597      0    stevel  * specified, we don't want to check for cycles for directories
   1598      0    stevel  * ending in '/.' or '/..' unless they were specified on the
   1599      0    stevel  * command line.
   1600      0    stevel  */
   1601      0    stevel static void
   1602      0    stevel record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep,
   1603      0    stevel     int argfl, struct ditem *myparent)
   1604      0    stevel {
   1605      0    stevel 	size_t		file_len;
   1606      0    stevel 	struct ditem	*myinfo;
   1607      0    stevel 	struct ditem	*tptr;
   1608      0    stevel 
   1609      0    stevel 	file_len = strlen(file);
   1610      0    stevel 	if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) &&
   1611      0    stevel 	    NOTPARENTDIR(file, file_len))) {
   1612      0    stevel 		/*
   1613      0    stevel 		 * Add this inode's ancestry
   1614      0    stevel 		 * info and insert it into the
   1615      0    stevel 		 * ancestry list by pointing
   1616      0    stevel 		 * back to its parent.  We save
   1617      0    stevel 		 * it (in rep) with the other info
   1618      0    stevel 		 * we're gathering for this inode.
   1619      0    stevel 		 */
   1620      0    stevel 		if ((myinfo = malloc(
   1621      0    stevel 		    sizeof (struct ditem))) == NULL) {
   1622      0    stevel 			perror("ls");
   1623      0    stevel 			exit(2);
   1624      0    stevel 		}
   1625      0    stevel 		myinfo->dev = pstatb->st_dev;
   1626      0    stevel 		myinfo->ino = pstatb->st_ino;
   1627      0    stevel 		myinfo->parent = myparent;
   1628      0    stevel 		rep->ancinfo = myinfo;
   1629      0    stevel 
   1630      0    stevel 		/*
   1631      0    stevel 		 * If this node has the same device id and
   1632      0    stevel 		 * inode number of one of its ancestors,
   1633      0    stevel 		 * then we've detected a cycle.
   1634      0    stevel 		 */
   1635      0    stevel 		if (myparent != NULL) {
   1636      0    stevel 			for (tptr = myparent; tptr->parent != NULL;
   1637      0    stevel 			    tptr = tptr->parent) {
   1638      0    stevel 				if ((tptr->dev == pstatb->st_dev) &&
   1639      0    stevel 				    (tptr->ino == pstatb->st_ino)) {
   1640      0    stevel 					/*
   1641      0    stevel 					 * Cycle detected for this
   1642      0    stevel 					 * directory.  Record the fact
   1643      0    stevel 					 * it is a cycle so we don't
   1644      0    stevel 					 * try to process this
   1645      0    stevel 					 * directory as we are
   1646      0    stevel 					 * walking through the
   1647      0    stevel 					 * list of directories.
   1648      0    stevel 					 */
   1649      0    stevel 					rep->cycle = 1;
   1650      0    stevel 					err = 2;
   1651      0    stevel 					break;
   1652      0    stevel 				}
   1653      0    stevel 			}
   1654      0    stevel 		}
   1655      0    stevel 	}
   1656      0    stevel }
   1657      0    stevel 
   1658      0    stevel /*
   1659   6178  ny155746  * Do re-calculate the mode for group for ACE_T type of acls.
   1660   6178  ny155746  * This is because, if the server's FS happens to be UFS, supporting
   1661   6178  ny155746  * POSIX ACL's, then it does a special calculation of group mode
   1662   6178  ny155746  * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.)
   1663   6178  ny155746  *
   1664   6178  ny155746  * This algorithm is from the NFSv4 ACL Draft. Here a part of that
   1665   6178  ny155746  * algorithm is used for the group mode calculation only.
   1666   6178  ny155746  * What is modified here from the algorithm is that only the
   1667   6178  ny155746  * entries with flags ACE_GROUP are considered. For each entry
   1668   6178  ny155746  * with ACE_GROUP flag, the first occurance of a specific access
   1669   6178  ny155746  * is checked if it is allowed.
   1670   6373  ny155746  * We are not interested in perms for user and other, as they
   1671   6178  ny155746  * were taken from st_mode value.
   1672   6178  ny155746  * We are not interested in a_who field of ACE, as we need just
   1673   6178  ny155746  * unix mode bits for the group.
   1674   6178  ny155746  */
   1675   6373  ny155746 
   1676   6373  ny155746 #define	OWNED_GROUP	(ACE_GROUP | ACE_IDENTIFIER_GROUP)
   1677   6373  ny155746 #define	IS_TYPE_ALLOWED(type)	((type) == ACE_ACCESS_ALLOWED_ACE_TYPE)
   1678   6373  ny155746 
   1679   6178  ny155746 int
   1680   6178  ny155746 grp_mask_to_mode(acl_t *acep)
   1681   6178  ny155746 {
   1682   6178  ny155746 	int mode = 0, seen = 0;
   1683   6178  ny155746 	int acecnt;
   1684   6373  ny155746 	int flags;
   1685   6178  ny155746 	ace_t *ap;
   1686   6178  ny155746 
   1687   6178  ny155746 	acecnt = acl_cnt(acep);
   1688   6178  ny155746 	for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) {
   1689   6373  ny155746 
   1690   6373  ny155746 		if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE &&
   1691   6373  ny155746 		    ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE)
   1692   6373  ny155746 			continue;
   1693   6373  ny155746 
   1694   6373  ny155746 		if (ap->a_flags & ACE_INHERIT_ONLY_ACE)
   1695   6373  ny155746 			continue;
   1696   6373  ny155746 
   1697   6373  ny155746 		/*
   1698   6373  ny155746 		 * if it is first group@ or first everyone@
   1699   6373  ny155746 		 * for each of read, write and execute, then
   1700   6373  ny155746 		 * that will be the group mode bit.
   1701   6373  ny155746 		 */
   1702   6373  ny155746 		flags = ap->a_flags & ACE_TYPE_FLAGS;
   1703   6373  ny155746 		if (flags == OWNED_GROUP || flags == ACE_EVERYONE) {
   1704   6373  ny155746 			if (ap->a_access_mask & ACE_READ_DATA) {
   1705   6373  ny155746 				if (!(seen & S_IRGRP)) {
   1706   6373  ny155746 					seen |= S_IRGRP;
   1707   6373  ny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
   1708   6373  ny155746 						mode |= S_IRGRP;
   1709   6178  ny155746 				}
   1710   6373  ny155746 			}
   1711   6373  ny155746 			if (ap->a_access_mask & ACE_WRITE_DATA) {
   1712   6373  ny155746 				if (!(seen & S_IWGRP)) {
   1713   6373  ny155746 					seen |= S_IWGRP;
   1714   6373  ny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
   1715   6373  ny155746 						mode |= S_IWGRP;
   1716   6178  ny155746 				}
   1717   6373  ny155746 			}
   1718   6373  ny155746 			if (ap->a_access_mask & ACE_EXECUTE) {
   1719   6373  ny155746 				if (!(seen & S_IXGRP)) {
   1720   6373  ny155746 					seen |= S_IXGRP;
   1721   6373  ny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
   1722   6373  ny155746 						mode |= S_IXGRP;
   1723   6178  ny155746 				}
   1724   6178  ny155746 			}
   1725   6178  ny155746 		}
   1726   6178  ny155746 	}
   1727   6178  ny155746 	return (mode);
   1728   6178  ny155746 }
   1729   6178  ny155746 
   1730   6178  ny155746 /*
   1731      0    stevel  * get status of file and recomputes tblocks;
   1732      0    stevel  * argfl = 1 if file is a name in ls-command and = 0
   1733      0    stevel  * for filename in a directory whose name is an
   1734      0    stevel  * argument in the command;
   1735      0    stevel  * stores a pointer in flist[nfiles] and
   1736      0    stevel  * returns that pointer;
   1737      0    stevel  * returns NULL if failed;
   1738      0    stevel  */
   1739      0    stevel static struct lbuf *
   1740      0    stevel gstat(char *file, int argfl, struct ditem *myparent)
   1741      0    stevel {
   1742      0    stevel 	struct stat statb, statb1;
   1743      0    stevel 	struct lbuf *rep;
   1744      0    stevel 	char buf[BUFSIZ];
   1745      0    stevel 	ssize_t cc;
   1746      0    stevel 	int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat;
   1747      0    stevel 	int aclcnt;
   1748    789    ahrens 	int error;
   1749      0    stevel 	aclent_t *tp;
   1750      0    stevel 	o_mode_t groupperm, mask;
   1751      0    stevel 	int grouppermfound, maskfound;
   1752      0    stevel 
   1753      0    stevel 	if (nomocore)
   1754      0    stevel 		return (NULL);
   1755      0    stevel 
   1756      0    stevel 	if (nfiles >= maxfils) {
   1757      0    stevel 		/*
   1758      0    stevel 		 * all flist/lbuf pair assigned files, time to get some
   1759      0    stevel 		 * more space
   1760      0    stevel 		 */
   1761      0    stevel 		maxfils += quantn;
   1762      0    stevel 		if (((flist = realloc(flist,
   1763      0    stevel 		    maxfils * sizeof (struct lbuf *))) == NULL) ||
   1764      0    stevel 		    ((nxtlbf = malloc(quantn *
   1765      0    stevel 		    sizeof (struct lbuf))) == NULL)) {
   1766      0    stevel 			perror("ls");
   1767      0    stevel 			nomocore = 1;
   1768      0    stevel 			return (NULL);
   1769      0    stevel 		}
   1770      0    stevel 	}
   1771      0    stevel 
   1772      0    stevel 	/*
   1773      0    stevel 	 * nfiles is reset to nargs for each directory
   1774      0    stevel 	 * that is given as an argument maxn is checked
   1775      0    stevel 	 * to prevent the assignment of an lbuf to a flist entry
   1776      0    stevel 	 * that already has one assigned.
   1777      0    stevel 	 */
   1778      0    stevel 	if (nfiles >= maxn) {
   1779      0    stevel 		rep = nxtlbf++;
   1780      0    stevel 		flist[nfiles++] = rep;
   1781      0    stevel 		maxn = nfiles;
   1782      0    stevel 	} else {
   1783      0    stevel 		rep = flist[nfiles++];
   1784      0    stevel 	}
   1785   6792    basabi 
   1786   6792    basabi 	/* Initialize */
   1787   6792    basabi 
   1788      0    stevel 	rep->lflags = (mode_t)0;
   1789      0    stevel 	rep->flinkto = NULL;
   1790      0    stevel 	rep->cycle = 0;
   1791   6792    basabi 	rep->lat.tv_sec = time(NULL);
   1792   6792    basabi 	rep->lat.tv_nsec = 0;
   1793   6792    basabi 	rep->lct.tv_sec = time(NULL);
   1794   6792    basabi 	rep->lct.tv_nsec = 0;
   1795   6792    basabi 	rep->lmt.tv_sec = time(NULL);
   1796   6792    basabi 	rep->lmt.tv_nsec = 0;
   1797   6792    basabi 	rep->exttr = NULL;
   1798   6792    basabi 	rep->extm = NULL;
   1799  10059     jason 	rep->color = NULL;
   1800  10059     jason 	rep->link_color = NULL;
   1801   6792    basabi 
   1802      0    stevel 	if (argfl || statreq) {
   1803      0    stevel 		int doacl;
   1804      0    stevel 
   1805      0    stevel 		if (lflg)
   1806      0    stevel 			doacl = 1;
   1807      0    stevel 		else
   1808      0    stevel 			doacl = 0;
   1809   6792    basabi 
   1810      0    stevel 		if ((*statf)(file, &statb) < 0) {
   1811      0    stevel 			if (argfl || errno != ENOENT ||
   1812      0    stevel 			    (Lflg && lstat(file, &statb) == 0)) {
   1813      0    stevel 				/*
   1814      0    stevel 				 * Avoid race between readdir and lstat.
   1815      0    stevel 				 * Print error message in case of dangling link.
   1816      0    stevel 				 */
   1817      0    stevel 				perror(file);
   1818   9664     jason 				err = 2;
   1819      0    stevel 			}
   1820      0    stevel 			nfiles--;
   1821      0    stevel 			return (NULL);
   1822      0    stevel 		}
   1823      0    stevel 
   1824      0    stevel 		/*
   1825      0    stevel 		 * If -H was specified, and the file linked to was
   1826      0    stevel 		 * not a directory, then we need to get the info
   1827      0    stevel 		 * for the symlink itself.
   1828      0    stevel 		 */
   1829      0    stevel 		if ((Hflg) && (argfl) &&
   1830      0    stevel 		    ((statb.st_mode & S_IFMT) != S_IFDIR)) {
   1831      0    stevel 			if (lstat(file, &statb) < 0) {
   1832      0    stevel 				perror(file);
   1833   9664     jason 				err = 2;
   1834      0    stevel 			}
   1835      0    stevel 		}
   1836      0    stevel 
   1837      0    stevel 		rep->lnum = statb.st_ino;
   1838      0    stevel 		rep->lsize = statb.st_size;
   1839      0    stevel 		rep->lblocks = statb.st_blocks;
   1840  10059     jason 		if (colorflg)
   1841  10059     jason 			rep->color = ls_color_find(file, statb.st_mode);
   1842  10059     jason 
   1843      0    stevel 		switch (statb.st_mode & S_IFMT) {
   1844      0    stevel 		case S_IFDIR:
   1845      0    stevel 			rep->ltype = 'd';
   1846      0    stevel 			if (Rflg) {
   1847      0    stevel 				record_ancestry(file, &statb, rep,
   1848      0    stevel 				    argfl, myparent);
   1849      0    stevel 			}
   1850      0    stevel 			break;
   1851      0    stevel 		case S_IFBLK:
   1852      0    stevel 			rep->ltype = 'b';
   1853      0    stevel 			rep->lsize = (off_t)statb.st_rdev;
   1854      0    stevel 			break;
   1855      0    stevel 		case S_IFCHR:
   1856      0    stevel 			rep->ltype = 'c';
   1857      0    stevel 			rep->lsize = (off_t)statb.st_rdev;
   1858      0    stevel 			break;
   1859      0    stevel 		case S_IFIFO:
   1860      0    stevel 			rep->ltype = 'p';
   1861      0    stevel 			break;
   1862      0    stevel 		case S_IFSOCK:
   1863      0    stevel 			rep->ltype = 's';
   1864      0    stevel 			rep->lsize = 0;
   1865      0    stevel 			break;
   1866      0    stevel 		case S_IFLNK:
   1867      0    stevel 			/* symbolic links may not have ACLs, so elide acl() */
   1868      0    stevel 			if ((Lflg == 0) || (Hflg == 0) ||
   1869      0    stevel 			    ((Hflg) && (!argfl))) {
   1870      0    stevel 				doacl = 0;
   1871      0    stevel 			}
   1872      0    stevel 			rep->ltype = 'l';
   1873  10059     jason 			if (lflg || colorflg) {
   1874      0    stevel 				cc = readlink(file, buf, BUFSIZ);
   1875  10059     jason 				if (cc < 0)
   1876  10059     jason 					break;
   1877      0    stevel 
   1878  10059     jason 				/*
   1879  10059     jason 				 * follow the symbolic link
   1880  10059     jason 				 * to generate the appropriate
   1881  10059     jason 				 * Fflg marker for the object
   1882  10059     jason 				 * eg, /bin -> /sym/bin/
   1883  10059     jason 				 */
   1884  10059     jason 				error = 0;
   1885  10059     jason 				if (Fflg || pflg || colorflg)
   1886  10059     jason 					error = stat(file, &statb1);
   1887  10059     jason 
   1888  10059     jason 				if (colorflg) {
   1889  10059     jason 					if (error >= 0)
   1890  10059     jason 						rep->link_color =
   1891  10059     jason 						    ls_color_find(file,
   1892  10059     jason 						    statb1.st_mode);
   1893  10059     jason 					else
   1894  10059     jason 						rep->link_color =
   1895  10059     jason 						    lsc_orphan;
   1896  10059     jason 				}
   1897  10059     jason 
   1898  10059     jason 				if ((Fflg || pflg) && error >= 0) {
   1899  10059     jason 					switch (statb1.st_mode & S_IFMT) {
   1900  10059     jason 					case S_IFDIR:
   1901  10059     jason 						buf[cc++] = '/';
   1902  10059     jason 						break;
   1903  10059     jason 					case S_IFSOCK:
   1904  10059     jason 						buf[cc++] = '=';
   1905  10059     jason 						break;
   1906  10059     jason 					case S_IFDOOR:
   1907  10059     jason 						buf[cc++] = '>';
   1908  10059     jason 						break;
   1909  10059     jason 					case S_IFIFO:
   1910  10059     jason 						buf[cc++] = '|';
   1911  10059     jason 						break;
   1912  10059     jason 					default:
   1913  10059     jason 						if ((statb1.st_mode & ~S_IFMT) &
   1914  10059     jason 						    (S_IXUSR|S_IXGRP| S_IXOTH))
   1915  10059     jason 							buf[cc++] = '*';
   1916  10059     jason 						break;
   1917      0    stevel 					}
   1918      0    stevel 				}
   1919  10059     jason 				buf[cc] = '\0';
   1920  10059     jason 				rep->flinkto = strdup(buf);
   1921      0    stevel 				break;
   1922      0    stevel 			}
   1923      0    stevel 
   1924      0    stevel 			/*
   1925      0    stevel 			 * ls /sym behaves differently from ls /sym/
   1926      0    stevel 			 * when /sym is a symbolic link. This is fixed
   1927      0    stevel 			 * when explicit arguments are specified.
   1928      0    stevel 			 */
   1929      0    stevel 
   1930      0    stevel #ifdef XPG6
   1931      0    stevel 			/* Do not follow a symlink when -F is specified */
   1932      0    stevel 			if ((!argfl) || (argfl && Fflg) ||
   1933      0    stevel 			    (stat(file, &statb1) < 0))
   1934      0    stevel #else
   1935      0    stevel 			/* Follow a symlink when -F is specified */
   1936      0    stevel 			if (!argfl || stat(file, &statb1) < 0)
   1937      0    stevel #endif /* XPG6 */
   1938      0    stevel 				break;
   1939      0    stevel 			if ((statb1.st_mode & S_IFMT) == S_IFDIR) {
   1940      0    stevel 				statb = statb1;
   1941      0    stevel 				rep->ltype = 'd';
   1942      0    stevel 				rep->lsize = statb1.st_size;
   1943      0    stevel 				if (Rflg) {
   1944      0    stevel 					record_ancestry(file, &statb, rep,
   1945      0    stevel 					    argfl, myparent);
   1946      0    stevel 				}
   1947      0    stevel 			}
   1948      0    stevel 			break;
   1949      0    stevel 		case S_IFDOOR:
   1950      0    stevel 			rep->ltype = 'D';
   1951      0    stevel 			break;
   1952      0    stevel 		case S_IFREG:
   1953      0    stevel 			rep->ltype = '-';
   1954      0    stevel 			break;
   1955      0    stevel 		case S_IFPORT:
   1956      0    stevel 			rep->ltype = 'P';
   1957      0    stevel 			break;
   1958      0    stevel 		default:
   1959      0    stevel 			rep->ltype = '?';
   1960      0    stevel 			break;
   1961      0    stevel 		}
   1962      0    stevel 		rep->lflags = statb.st_mode & ~S_IFMT;
   1963      0    stevel 
   1964      0    stevel 		if (!S_ISREG(statb.st_mode))
   1965      0    stevel 			rep->lflags |= LS_NOTREG;
   1966      0    stevel 
   1967   6792    basabi 		rep->luid = statb.st_uid;
   1968   6792    basabi 		rep->lgid = statb.st_gid;
   1969   6792    basabi 		rep->lnl = statb.st_nlink;
   1970   6792    basabi 		if (uflg || (tmflg && atm))
   1971   6792    basabi 			rep->lmtime = statb.st_atim;
   1972   6792    basabi 		else if (cflg || (tmflg && ctm))
   1973   6792    basabi 			rep->lmtime = statb.st_ctim;
   1974   6792    basabi 		else
   1975   6792    basabi 			rep->lmtime = statb.st_mtim;
   1976   6792    basabi 		rep->lat = statb.st_atim;
   1977   6792    basabi 		rep->lct = statb.st_ctim;
   1978   6792    basabi 		rep->lmt = statb.st_mtim;
   1979   6792    basabi 
   1980      0    stevel 		/* ACL: check acl entries count */
   1981      0    stevel 		if (doacl) {
   1982    789    ahrens 
   1983    789    ahrens 			error = acl_get(file, 0, &rep->aclp);
   1984    789    ahrens 			if (error) {
   1985    789    ahrens 				(void) fprintf(stderr,
   1986    789    ahrens 				    gettext("ls: can't read ACL on %s: %s\n"),
   1987    789    ahrens 				    file, acl_strerror(error));
   1988   6792    basabi 				rep->acl = ' ';
   1989   6866    basabi 				acl_err++;
   1990   6792    basabi 				return (rep);
   1991    789    ahrens 			}
   1992    789    ahrens 
   1993      0    stevel 			rep->acl = ' ';
   1994      0    stevel 
   1995    789    ahrens 			if (rep->aclp &&
   1996    789    ahrens 			    ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) {
   1997    789    ahrens 				rep->acl = '+';
   1998    789    ahrens 				/*
   1999    789    ahrens 				 * Special handling for ufs aka aclent_t ACL's
   2000    789    ahrens 				 */
   2001   6178  ny155746 				if (acl_type(rep->aclp) == ACLENT_T) {
   2002    789    ahrens 					/*
   2003    789    ahrens 					 * For files with non-trivial acls, the
   2004    789    ahrens 					 * effective group permissions are the
   2005    789    ahrens 					 * intersection of the GROUP_OBJ value
   2006    789    ahrens 					 * and the CLASS_OBJ (acl mask) value.
   2007    789    ahrens 					 * Determine both the GROUP_OBJ and
   2008    789    ahrens 					 * CLASS_OBJ for this file and insert
   2009    789    ahrens 					 * the logical AND of those two values
   2010    789    ahrens 					 * in the group permissions field
   2011    789    ahrens 					 * of the lflags value for this file.
   2012    789    ahrens 					 */
   2013      0    stevel 
   2014    789    ahrens 					/*
   2015    789    ahrens 					 * Until found in acl list, assume
   2016    789    ahrens 					 * maximum permissions for both group
   2017    789    ahrens 					 * a nd mask.  (Just in case the acl
   2018    789    ahrens 					 * lacks either value for some reason.)
   2019    789    ahrens 					 */
   2020    789    ahrens 					groupperm = 07;
   2021    789    ahrens 					mask = 07;
   2022    789    ahrens 					grouppermfound = 0;
   2023    789    ahrens 					maskfound = 0;
   2024    789    ahrens 					aclcnt = acl_cnt(rep->aclp);
   2025    789    ahrens 					for (tp =
   2026    789    ahrens 					    (aclent_t *)acl_data(rep->aclp);
   2027    789    ahrens 					    aclcnt--; tp++) {
   2028    789    ahrens 						if (tp->a_type == GROUP_OBJ) {
   2029    789    ahrens 							groupperm = tp->a_perm;
   2030    789    ahrens 							grouppermfound = 1;
   2031    789    ahrens 							continue;
   2032    789    ahrens 						}
   2033    789    ahrens 						if (tp->a_type == CLASS_OBJ) {
   2034    789    ahrens 							mask = tp->a_perm;
   2035    789    ahrens 							maskfound = 1;
   2036    789    ahrens 						}
   2037    789    ahrens 						if (grouppermfound && maskfound)
   2038    789    ahrens 							break;
   2039    789    ahrens 					}
   2040      0    stevel 
   2041      0    stevel 
   2042    789    ahrens 					/* reset all the group bits */
   2043    789    ahrens 					rep->lflags &= ~S_IRWXG;
   2044    789    ahrens 
   2045    789    ahrens 					/*
   2046    789    ahrens 					 * Now set them to the logical AND of
   2047    789    ahrens 					 * the GROUP_OBJ permissions and the
   2048    789    ahrens 					 * acl mask.
   2049    789    ahrens 					 */
   2050    789    ahrens 
   2051    789    ahrens 					rep->lflags |= (groupperm & mask) << 3;
   2052    789    ahrens 
   2053   6178  ny155746 				} else if (acl_type(rep->aclp) == ACE_T) {
   2054   6178  ny155746 					int mode;
   2055   6178  ny155746 					mode = grp_mask_to_mode(rep->aclp);
   2056   6178  ny155746 					rep->lflags &= ~S_IRWXG;
   2057   6178  ny155746 					rep->lflags |= mode;
   2058      0    stevel 				}
   2059      0    stevel 			}
   2060      0    stevel 
   2061   1420     marks 			if (!vflg && !Vflg && rep->aclp) {
   2062   1420     marks 				acl_free(rep->aclp);
   2063   1420     marks 				rep->aclp = NULL;
   2064   1420     marks 			}
   2065   1420     marks 
   2066      0    stevel 			if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
   2067      0    stevel 				rep->acl = '@';
   2068   5331       amw 
   2069      0    stevel 		} else
   2070      0    stevel 			rep->acl = ' ';
   2071      0    stevel 
   2072      0    stevel 		/* mask ISARG and other file-type bits */
   2073      0    stevel 
   2074      0    stevel 		if (rep->ltype != 'b' && rep->ltype != 'c')
   2075      0    stevel 			tblocks += rep->lblocks;
   2076   5331       amw 
   2077   5331       amw 		/* Get extended system attributes */
   2078   5331       amw 
   2079   5331       amw 		if ((saflg || (tmflg && crtm) || (tmflg && alltm)) &&
   2080   5331       amw 		    (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) {
   2081   5331       amw 			int i;
   2082   5331       amw 
   2083   5331       amw 			sacnt = attr_count();
   2084   5331       amw 			/*
   2085   5331       amw 			 * Allocate 'sacnt' size array to hold extended
   2086   5331       amw 			 * system attribute name (verbose) or respective
   2087   5331       amw 			 * symbol represenation (compact).
   2088   5331       amw 			 */
   2089   5331       amw 			rep->exttr = xmalloc(sacnt * sizeof (struct attrb),
   2090   5331       amw 			    rep);
   2091   5331       amw 
   2092   5331       amw 			/* initialize boolean attribute list */
   2093   5331       amw 			for (i = 0; i < sacnt; i++)
   2094   5331       amw 				rep->exttr[i].name = NULL;
   2095   5331       amw 			if (get_sysxattr(file, rep) != 0) {
   2096   5331       amw 				(void) fprintf(stderr,
   2097   5331       amw 				    gettext("ls:Failed to retrieve "
   2098   5331       amw 				    "extended system attribute from "
   2099   5331       amw 				    "%s\n"), file);
   2100   5331       amw 				rep->exttr[0].name = xmalloc(2, rep);
   2101   5331       amw 				(void) strlcpy(rep->exttr[0].name, "?", 2);
   2102   5331       amw 			}
   2103   5331       amw 		}
   2104      0    stevel 	}
   2105      0    stevel 	return (rep);
   2106      0    stevel }
   2107      0    stevel 
   2108      0    stevel /*
   2109      0    stevel  * returns pathname of the form dir/file;
   2110      0    stevel  * dir and file are null-terminated strings.
   2111      0    stevel  */
   2112      0    stevel static char *
   2113      0    stevel makename(char *dir, char *file)
   2114      0    stevel {
   2115      0    stevel 	/*
   2116      0    stevel 	 * PATH_MAX is the maximum length of a path name.
   2117      0    stevel 	 * MAXNAMLEN is the maximum length of any path name component.
   2118      0    stevel 	 * Allocate space for both, plus the '/' in the middle
   2119      0    stevel 	 * and the null character at the end.
   2120      0    stevel 	 * dfile is static as this is returned by makename().
   2121      0    stevel 	 */
   2122      0    stevel 	static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1];
   2123      0    stevel 	char *dp, *fp;
   2124      0    stevel 
   2125      0    stevel 	dp = dfile;
   2126      0    stevel 	fp = dir;
   2127      0    stevel 	while (*fp)
   2128      0    stevel 		*dp++ = *fp++;
   2129      0    stevel 	if (dp > dfile && *(dp - 1) != '/')
   2130      0    stevel 		*dp++ = '/';
   2131      0    stevel 	fp = file;
   2132      0    stevel 	while (*fp)
   2133      0    stevel 		*dp++ = *fp++;
   2134      0    stevel 	*dp = '\0';
   2135      0    stevel 	return (dfile);
   2136      0    stevel }
   2137      0    stevel 
   2138      0    stevel 
   2139      0    stevel #include <pwd.h>
   2140      0    stevel #include <grp.h>
   2141      0    stevel #include <utmpx.h>
   2142      0    stevel 
   2143      0    stevel struct	utmpx utmp;
   2144      0    stevel 
   2145      0    stevel #define	NMAX	(sizeof (utmp.ut_name))
   2146      0    stevel #define	SCPYN(a, b)	(void) strncpy(a, b, NMAX)
   2147      0    stevel 
   2148      0    stevel 
   2149      0    stevel struct cachenode {		/* this struct must be zeroed before using */
   2150      0    stevel 	struct cachenode *lesschild;	/* subtree whose entries < val */
   2151      0    stevel 	struct cachenode *grtrchild;	/* subtree whose entries > val */
   2152      0    stevel 	long val;			/* the uid or gid of this entry */
   2153      0    stevel 	int initted;			/* name has been filled in */
   2154      0    stevel 	char name[NMAX+1];		/* the string that val maps to */
   2155      0    stevel };
   2156      0    stevel static struct cachenode *names, *groups;
   2157      0    stevel 
   2158      0    stevel static struct cachenode *
   2159      0    stevel findincache(struct cachenode **head, long val)
   2160      0    stevel {
   2161      0    stevel 	struct cachenode **parent = head;
   2162      0    stevel 	struct cachenode *c = *parent;
   2163      0    stevel 
   2164      0    stevel 	while (c != NULL) {
   2165      0    stevel 		if (val == c->val) {
   2166      0    stevel 			/* found it */
   2167      0    stevel 			return (c);
   2168      0    stevel 		} else if (val < c->val) {
   2169      0    stevel 			parent = &c->lesschild;
   2170      0    stevel 			c = c->lesschild;
   2171      0    stevel 		} else {
   2172      0    stevel 			parent = &c->grtrchild;
   2173      0    stevel 			c = c->grtrchild;
   2174      0    stevel 		}
   2175      0    stevel 	}
   2176      0    stevel 
   2177      0    stevel 	/* not in the cache, make a new entry for it */
   2178      0    stevel 	c = calloc(1, sizeof (struct cachenode));
   2179      0    stevel 	if (c == NULL) {
   2180      0    stevel 		perror("ls");
   2181      0    stevel 		exit(2);
   2182      0    stevel 	}
   2183      0    stevel 	*parent = c;
   2184      0    stevel 	c->val = val;
   2185      0    stevel 	return (c);
   2186      0    stevel }
   2187      0    stevel 
   2188      0    stevel /*
   2189      0    stevel  * get name from cache, or passwd file for a given uid;
   2190      0    stevel  * lastuid is set to uid.
   2191      0    stevel  */
   2192      0    stevel static char *
   2193      0    stevel getname(uid_t uid)
   2194      0    stevel {
   2195      0    stevel 	struct passwd *pwent;
   2196      0    stevel 	struct cachenode *c;
   2197      0    stevel 
   2198      0    stevel 	if ((uid == lastuid) && lastuname)
   2199      0    stevel 		return (lastuname);
   2200      0    stevel 
   2201      0    stevel 	c = findincache(&names, uid);
   2202      0    stevel 	if (c->initted == 0) {
   2203      0    stevel 		if ((pwent = getpwuid(uid)) != NULL) {
   2204      0    stevel 			SCPYN(&c->name[0], pwent->pw_name);
   2205      0    stevel 		} else {
   2206      0    stevel 			(void) sprintf(&c->name[0], "%-8u", (int)uid);
   2207      0    stevel 		}
   2208      0    stevel 		c->initted = 1;
   2209      0    stevel 	}
   2210      0    stevel 	lastuid = uid;
   2211      0    stevel 	lastuname = &c->name[0];
   2212      0    stevel 	return (lastuname);
   2213      0    stevel }
   2214      0    stevel 
   2215      0    stevel /*
   2216      0    stevel  * get name from cache, or group file for a given gid;
   2217      0    stevel  * lastgid is set to gid.
   2218      0    stevel  */
   2219      0    stevel static char *
   2220      0    stevel getgroup(gid_t gid)
   2221      0    stevel {
   2222      0    stevel 	struct group *grent;
   2223      0    stevel 	struct cachenode *c;
   2224      0    stevel 
   2225      0    stevel 	if ((gid == lastgid) && lastgname)
   2226      0    stevel 		return (lastgname);
   2227      0    stevel 
   2228      0    stevel 	c = findincache(&groups, gid);
   2229      0    stevel 	if (c->initted == 0) {
   2230      0    stevel 		if ((grent = getgrgid(gid)) != NULL) {
   2231      0    stevel 			SCPYN(&c->name[0], grent->gr_name);
   2232      0    stevel 		} else {
   2233      0    stevel 			(void) sprintf(&c->name[0], "%-8u", (int)gid);
   2234      0    stevel 		}
   2235      0    stevel 		c->initted = 1;
   2236      0    stevel 	}
   2237      0    stevel 	lastgid = gid;
   2238      0    stevel 	lastgname = &c->name[0];
   2239      0    stevel 	return (lastgname);
   2240      0    stevel }
   2241      0    stevel 
   2242      0    stevel /* return >0 if item pointed by pp2 should appear first */
   2243      0    stevel static int
   2244      0    stevel compar(struct lbuf **pp1, struct lbuf **pp2)
   2245      0    stevel {
   2246      0    stevel 	struct lbuf *p1, *p2;
   2247      0    stevel 
   2248      0    stevel 	p1 = *pp1;
   2249      0    stevel 	p2 = *pp2;
   2250      0    stevel 	if (dflg == 0) {
   2251      0    stevel /*
   2252      0    stevel  * compare two names in ls-command one of which is file
   2253      0    stevel  * and the other is a directory;
   2254      0    stevel  * this portion is not used for comparing files within
   2255      0    stevel  * a directory name of ls-command;
   2256      0    stevel  */
   2257      0    stevel 		if (p1->lflags&ISARG && p1->ltype == 'd') {
   2258      0    stevel 			if (!(p2->lflags&ISARG && p2->ltype == 'd'))
   2259      0    stevel 				return (1);
   2260      0    stevel 		} else {
   2261      0    stevel 			if (p2->lflags&ISARG && p2->ltype == 'd')
   2262      0    stevel 				return (-1);
   2263      0    stevel 		}
   2264      0    stevel 	}
   2265      0    stevel 	if (tflg) {
   2266      0    stevel 		if (p2->lmtime.tv_sec > p1->lmtime.tv_sec)
   2267      0    stevel 			return (rflg);
   2268      0    stevel 		else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec)
   2269      0    stevel 			return (-rflg);
   2270      0    stevel 		/* times are equal to the sec, check nsec */
   2271      0    stevel 		if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec)
   2272      0    stevel 			return (rflg);
   2273      0    stevel 		else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec)
   2274      0    stevel 			return (-rflg);
   2275      0    stevel 		/* if times are equal, fall through and sort by name */
   2276      0    stevel 	} else if (Sflg) {
   2277      0    stevel 		/*
   2278      0    stevel 		 * The size stored in lsize can be either the
   2279      0    stevel 		 * size or the major minor number (in the case of
   2280      0    stevel 		 * block and character special devices).  If it's
   2281      0    stevel 		 * a major minor number, then the size is considered
   2282      0    stevel 		 * to be zero and we want to fall through and sort
   2283      0    stevel 		 * by name.  In addition, if the size of p2 is equal
   2284      0    stevel 		 * to the size of p1 we want to fall through and
   2285      0    stevel 		 * sort by name.
   2286      0    stevel 		 */
   2287      0    stevel 		off_t	p1size = (p1->ltype == 'b') ||
   2288   5331       amw 		    (p1->ltype == 'c') ? 0 : p1->lsize;
   2289      0    stevel 		off_t	p2size = (p2->ltype == 'b') ||
   2290   5331       amw 		    (p2->ltype == 'c') ? 0 : p2->lsize;
   2291      0    stevel 		if (p2size > p1size) {
   2292      0    stevel 			return (rflg);
   2293      0    stevel 		} else if (p2size < p1size) {
   2294      0    stevel 			return (-rflg);
   2295      0    stevel 		}
   2296      0    stevel 		/* Sizes are equal, fall through and sort by name. */
   2297      0    stevel 	}
   2298      0    stevel 	return (rflg * strcoll(
   2299      0    stevel 	    p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname,
   2300      0    stevel 	    p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname));
   2301      0    stevel }
   2302      0    stevel 
   2303      0    stevel static void
   2304      0    stevel pprintf(char *s1, char *s2)
   2305      0    stevel {
   2306      0    stevel 	csi_pprintf((unsigned char *)s1);
   2307      0    stevel 	csi_pprintf((unsigned char *)s2);
   2308      0    stevel }
   2309      0    stevel 
   2310      0    stevel static void
   2311      0    stevel csi_pprintf(unsigned char *s)
   2312      0    stevel {
   2313      0    stevel 	unsigned char *cp;
   2314      0    stevel 	char	c;
   2315      0    stevel 	int	i;
   2316      0    stevel 	int	c_len;
   2317      0    stevel 	int	p_col;
   2318      0    stevel 	wchar_t	pcode;
   2319      0    stevel 
   2320      0    stevel 	if (!qflg && !bflg) {
   2321      0    stevel 		for (cp = s; *cp != '\0'; cp++) {
   2322      0    stevel 			(void) putchar(*cp);
   2323      0    stevel 			curcol++;
   2324      0    stevel 		}
   2325      0    stevel 		return;
   2326      0    stevel 	}
   2327      0    stevel 
   2328      0    stevel 	for (cp = s; *cp; ) {
   2329      0    stevel 		if (isascii(c = *cp)) {
   2330      0    stevel 			if (!isprint(c)) {
   2331      0    stevel 				if (qflg) {
   2332      0    stevel 					c = '?';
   2333      0    stevel 				} else {
   2334      0    stevel 					curcol += 3;
   2335      0    stevel 					(void) putc('\\', stdout);
   2336      0    stevel 					c = '0' + ((*cp >> 6) & 07);
   2337      0    stevel 					(void) putc(c, stdout);
   2338      0    stevel 					c = '0' + ((*cp >> 3) & 07);
   2339      0    stevel 					(void) putc(c, stdout);
   2340      0    stevel 					c = '0' + (*cp & 07);
   2341      0    stevel 				}
   2342      0    stevel 			}
   2343      0    stevel 			curcol++;
   2344      0    stevel 			cp++;
   2345      0    stevel 			(void) putc(c, stdout);
   2346      0    stevel 			continue;
   2347      0    stevel 		}
   2348      0    stevel 
   2349      0    stevel 		if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) {
   2350      0    stevel 			c_len = 1;
   2351      0    stevel 			goto not_print;
   2352      0    stevel 		}
   2353      0    stevel 
   2354      0    stevel 		if ((p_col = wcwidth(pcode)) > 0) {
   2355      0    stevel 			(void) putwchar(pcode);
   2356      0    stevel 			cp += c_len;
   2357      0    stevel 			curcol += p_col;
   2358      0    stevel 			continue;
   2359      0    stevel 		}
   2360      0    stevel 
   2361      0    stevel not_print:
   2362      0    stevel 		for (i = 0; i < c_len; i++) {
   2363      0    stevel 			if (qflg) {
   2364      0    stevel 				c = '?';
   2365      0    stevel 			} else {
   2366      0    stevel 				curcol += 3;
   2367      0    stevel 				(void) putc('\\', stdout);
   2368      0    stevel 				c = '0' + ((*cp >> 6) & 07);
   2369      0    stevel 				(void) putc(c, stdout);
   2370      0    stevel 				c = '0' + ((*cp >> 3) & 07);
   2371      0    stevel 				(void) putc(c, stdout);
   2372      0    stevel 				c = '0' + (*cp & 07);
   2373      0    stevel 			}
   2374      0    stevel 			curcol++;
   2375      0    stevel 			(void) putc(c, stdout);
   2376      0    stevel 			cp++;
   2377      0    stevel 		}
   2378      0    stevel 	}
   2379      0    stevel }
   2380      0    stevel 
   2381      0    stevel static int
   2382      0    stevel strcol(unsigned char *s1)
   2383      0    stevel {
   2384      0    stevel 	int	w;
   2385      0    stevel 	int	w_col;
   2386      0    stevel 	int	len;
   2387      0    stevel 	wchar_t	wc;
   2388      0    stevel 
   2389      0    stevel 	w = 0;
   2390      0    stevel 	while (*s1) {
   2391      0    stevel 		if (isascii(*s1)) {
   2392      0    stevel 			w++;
   2393      0    stevel 			s1++;
   2394      0    stevel 			continue;
   2395      0    stevel 		}
   2396      0    stevel 
   2397      0    stevel 		if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) {
   2398      0    stevel 			w++;
   2399      0    stevel 			s1++;
   2400      0    stevel 			continue;
   2401      0    stevel 		}
   2402      0    stevel 
   2403      0    stevel 		if ((w_col = wcwidth(wc)) < 0)
   2404      0    stevel 			w_col = len;
   2405      0    stevel 		s1 += len;
   2406      0    stevel 		w += w_col;
   2407      0    stevel 	}
   2408      0    stevel 	return (w);
   2409      0    stevel }
   2410      0    stevel 
   2411      0    stevel /*
   2412      0    stevel  * Convert an unsigned long long to a string representation and place the
   2413      0    stevel  * result in the caller-supplied buffer.
   2414      0    stevel  *
   2415      0    stevel  * The number provided is a size in bytes.  The number is first
   2416      0    stevel  * converted to an integral multiple of 'scale' bytes.  This new
   2417      0    stevel  * number is then scaled down until it is small enough to be in a good
   2418      0    stevel  * human readable format, i.e.  in the range 0 thru scale-1.  If the
   2419      0    stevel  * number used to derive the final number is not a multiple of scale, and
   2420      0    stevel  * the final number has only a single significant digit, we compute
   2421      0    stevel  * tenths of units to provide a second significant digit.
   2422      0    stevel  *
   2423      0    stevel  * The value "(unsigned long long)-1" is a special case and is always
   2424      0    stevel  * converted to "-1".
   2425      0    stevel  *
   2426      0    stevel  * A pointer to the caller-supplied buffer is returned.
   2427      0    stevel  */
   2428      0    stevel static char *
   2429      0    stevel number_to_scaled_string(
   2430      0    stevel 			numbuf_t buf,		/* put the result here */
   2431      0    stevel 			unsigned long long number, /* convert this number */
   2432      0    stevel 			long scale)
   2433      0    stevel {
   2434      0    stevel 	unsigned long long save;
   2435      0    stevel 	/* Measurement: kilo, mega, giga, tera, peta, exa */
   2436      0    stevel 	char *uom = "KMGTPE";
   2437      0    stevel 
   2438      0    stevel 	if ((long long)number == (long long)-1) {
   2439      0    stevel 		(void) strlcpy(buf, "-1", sizeof (numbuf_t));
   2440      0    stevel 		return (buf);
   2441      0    stevel 	}
   2442      0    stevel 
   2443      0    stevel 	save = number;
   2444      0    stevel 	number = number / scale;
   2445      0    stevel 
   2446      0    stevel 	/*
   2447      0    stevel 	 * Now we have number as a count of scale units.
   2448      0    stevel 	 * If no further scaling is necessary, we round up as appropriate.
   2449      0    stevel 	 *
   2450      0    stevel 	 * The largest value number could have had entering the routine is
   2451      0    stevel 	 * 16 Exabytes, so running off the end of the uom array should
   2452      0    stevel 	 * never happen.  We check for that, though, as a guard against
   2453      0    stevel 	 * a breakdown elsewhere in the algorithm.
   2454      0    stevel 	 */
   2455      0    stevel 	if (number < (unsigned long long)scale) {
   2456      0    stevel 		if ((save % scale) >= (unsigned long long)(scale / 2)) {
   2457      0    stevel 			if (++number == (unsigned long long)scale) {
   2458      0    stevel 				uom++;
   2459      0    stevel 				number = 1;
   2460      0    stevel 			}
   2461      0    stevel 		}
   2462      0    stevel 	} else {
   2463      0    stevel 		while ((number >= (unsigned long long)scale) && (*uom != 'E')) {
   2464      0    stevel 			uom++; /* next unit of measurement */
   2465      0    stevel 			save = number;
   2466      0    stevel 			/*
   2467      0    stevel 			 * If we're over half way to the next unit of
   2468      0    stevel 			 * 'scale' bytes (which means we should round
   2469      0    stevel 			 * up), then adding half of 'scale' prior to
   2470      0    stevel 			 * the division will push us into that next
   2471      0    stevel 			 * unit of scale when we perform the division
   2472      0    stevel 			 */
   2473      0    stevel 			number = (number + (scale / 2)) / scale;
   2474      0    stevel 		}
   2475      0    stevel 	}
   2476      0    stevel 
   2477      0    stevel 	/* check if we should output a decimal place after the point */
   2478      0    stevel 	if ((save / scale) < 10) {
   2479      0    stevel 		/* snprintf() will round for us */
   2480      0    stevel 		float fnum = (float)save / scale;
   2481      0    stevel 		(void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c",
   2482      0    stevel 		    fnum, *uom);
   2483      0    stevel 	} else {
   2484      0    stevel 		(void) snprintf(buf, sizeof (numbuf_t), "%4llu%c",
   2485      0    stevel 		    number, *uom);
   2486      0    stevel 	}
   2487      0    stevel 	return (buf);
   2488      0    stevel }
   2489   5331       amw 
   2490   5331       amw /* Get extended system attributes and set the display */
   2491   5331       amw 
   2492   5331       amw int
   2493   5331       amw get_sysxattr(char *fname, struct lbuf *rep)
   2494   5331       amw {
   2495   5331       amw 	boolean_t	value;
   2496   5331       amw 	data_type_t	type;
   2497   5331       amw 	int		error;
   2498   5331       amw 	char		*name;
   2499   5331       amw 	int		i;
   2500   5331       amw 
   2501   5331       amw 	if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname,
   2502   5331       amw 	    &response)) != 0) {
   2503   5331       amw 		perror("ls:getattrat");
   2504   5331       amw 		return (error);
   2505   5331       amw 	}
   2506   5331       amw 
   2507   5331       amw 	/*
   2508   5331       amw 	 * Allocate 'sacnt' size array to hold extended timestamp
   2509   5331       amw 	 * system attributes and initialize the array.
   2510   5331       amw 	 */
   2511   5331       amw 	rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep);
   2512   5331       amw 	for (i = 0; i < sacnt; i++) {
   2513   5331       amw 		rep->extm[i].stm = 0;
   2514   5331       amw 		rep->extm[i].nstm = 0;
   2515   5331       amw 		rep->extm[i].name = NULL;
   2516   5331       amw 	}
   2517   5331       amw 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
   2518   5331       amw 		name = nvpair_name(pair);
   2519   5331       amw 		type = nvpair_type(pair);
   2520   5331       amw 		if (type == DATA_TYPE_BOOLEAN_VALUE) {
   2521   5331       amw 			error = nvpair_value_boolean_value(pair, &value);
   2522   5331       amw 			if (error) {
   2523   5331       amw 				(void) fprintf(stderr,
   2524   5331       amw 				    gettext("nvpair_value_boolean_value "
   2525   5331       amw 				    "failed: error = %d\n"), error);
   2526   5331       amw 				continue;
   2527   5331       amw 			}
   2528   5331       amw 			if (name != NULL)
   2529   5331       amw 				set_sysattrb_display(name, value, rep);
   2530   5331       amw 			continue;
   2531   5331       amw 		} else if (type == DATA_TYPE_UINT64_ARRAY) {
   2532   5331       amw 			if (name != NULL)
   2533   5331       amw 				set_sysattrtm_display(name, rep);
   2534   5331       amw 			continue;
   2535   5331       amw 		}
   2536   5331       amw 	}
   2537   5331       amw 	nvlist_free(response);
   2538   5331       amw 	return (0);
   2539   5331       amw }
   2540   5331       amw 
   2541   5331       amw /* Set extended system attribute boolean display */
   2542   5331       amw 
   2543   5331       amw void
   2544   5331       amw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep)
   2545   5331       amw {
   2546   5331       amw 	f_attr_t	fattr;
   2547   5331       amw 	const char	*opt;
   2548   5331       amw 	size_t		len;
   2549   5331       amw 
   2550   5331       amw 	fattr = name_to_attr(name);
   2551   5331       amw 	if (fattr != F_ATTR_INVAL && fattr < sacnt) {
   2552   5331       amw 		if (vopt) {
   2553   5331       amw 			len = strlen(name);
   2554   5331       amw 			if (val) {
   2555   5331       amw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
   2556   5331       amw 				(void) strlcpy(rep->exttr[fattr].name, name,
   2557   5331       amw 				    len + 1);
   2558   5331       amw 			} else {
   2559   5331       amw 				rep->exttr[fattr].name = xmalloc(len + 3, rep);
   2560   5331       amw 				(void) snprintf(rep->exttr[fattr].name, len + 3,
   2561   5331       amw 				    "no%s", name);
   2562   5331       amw 			}
   2563   5331       amw 		} else {
   2564   5331       amw 			opt = attr_to_option(fattr);
   2565   5331       amw 			if (opt != NULL) {
   2566   5331       amw 				len = strlen(opt);
   2567   5331       amw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
   2568   5331       amw 				if (val)
   2569   5331       amw 					(void) strlcpy(rep->exttr[fattr].name,
   2570   5331       amw 					    opt, len + 1);
   2571   5331       amw 				else
   2572   5331       amw 					(void) strlcpy(rep->exttr[fattr].name,
   2573   5331       amw 					    "-", len + 1);
   2574   5331       amw 			}
   2575   5331       amw 		}
   2576   5331       amw 	}
   2577   5331       amw }
   2578   5331       amw 
   2579   5331       amw /* Set extended system attribute timestamp display */
   2580   5331       amw 
   2581   5331       amw void
   2582   5331       amw set_sysattrtm_display(char *name, struct lbuf *rep)
   2583   5331       amw {
   2584   5331       amw 	uint_t		nelem;
   2585   5331       amw 	uint64_t	*value;
   2586   5331       amw 	int		i;
   2587   5331       amw 	size_t		len;
   2588   5331       amw 
   2589   5331       amw 	if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) {
   2590   5331       amw 		if (*value != NULL) {
   2591   5331       amw 			len = strlen(name);
   2592   5331       amw 			i = 0;
   2593   5331       amw 			while (rep->extm[i].stm != 0 && i < sacnt)
   2594   5331       amw 				i++;
   2595   5331       amw 			rep->extm[i].stm = value[0];
   2596   5331       amw 			rep->extm[i].nstm = value[1];
   2597   5331       amw 			rep->extm[i].name = xmalloc(len + 1, rep);
   2598   5331       amw 			(void) strlcpy(rep->extm[i].name, name, len + 1);
   2599   5331       amw 		}
   2600   5331       amw 	}
   2601   5331       amw }
   2602   5331       amw 
   2603   5331       amw void
   2604   9664     jason format_time(time_t sec, time_t nsec)
   2605   5331       amw {
   2606   9664     jason 	const char *fstr = time_fmt_new;
   2607   9664     jason 	char fmt_buf[FMTSIZE];
   2608   5331       amw 
   2609   9664     jason 	if (Eflg) {
   2610   9664     jason 		(void) snprintf(fmt_buf, FMTSIZE, fstr, nsec);
   2611   9664     jason 		(void) strftime(time_buf, sizeof (time_buf), fmt_buf,
   2612   9664     jason 		    localtime(&sec));
   2613   9664     jason 		return;
   2614   9664     jason 	}
   2615   9664     jason 
   2616   9664     jason 	if (sec < year || sec > now)
   2617   9664     jason 		fstr = time_fmt_old;
   2618   9664     jason 
   2619   9664     jason 	/* if a custom time was specified, shouldn't be localized */
   2620   5331       amw 	(void) strftime(time_buf, sizeof (time_buf),
   2621   9664     jason 	    (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr,
   2622   5331       amw 	    localtime(&sec));
   2623   5331       amw }
   2624   5331       amw 
   2625   5331       amw void
   2626   5331       amw format_attrtime(struct lbuf *p)
   2627   5331       amw {
   2628   9664     jason 	int tmattr = 0;
   2629   5331       amw 	int i;
   2630   5331       amw 
   2631   5331       amw 	if (p->extm != NULL) {
   2632   5331       amw 		for (i = 0; i < sacnt; i++) {
   2633   5331       amw 			if (p->extm[i].name != NULL) {
   2634   5331       amw 				tmattr = 1;
   2635   5331       amw 				break;
   2636   5331       amw 			}
   2637   5331       amw 		}
   2638   5331       amw 	}
   2639   9664     jason 
   2640   5331       amw 	if (tmattr) {
   2641   9664     jason 		const char *old_save = time_fmt_old;
   2642   9664     jason 		const char *new_save = time_fmt_new;
   2643   9664     jason 
   2644   9664     jason 		/* Eflg always sets format to FORMAT_ISO_FULL */
   2645   9664     jason 		if (!Eflg && !time_custom) {
   2646   9664     jason 			time_fmt_old = FORMAT_OLD;
   2647   9664     jason 			time_fmt_new = FORMAT_NEW;
   2648   5331       amw 		}
   2649   9664     jason 
   2650   9664     jason 		format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm);
   2651   9664     jason 
   2652   9664     jason 		time_fmt_old = old_save;
   2653   9664     jason 		time_fmt_new = new_save;
   2654   5331       amw 	}
   2655   5331       amw }
   2656   5331       amw 
   2657   5331       amw void
   2658   5331       amw print_time(struct lbuf *p)
   2659   5331       amw {
   2660   9664     jason 	const char *old_save = time_fmt_old;
   2661   9664     jason 	const char *new_save = time_fmt_new;
   2662   9664     jason 
   2663   5331       amw 	int i = 0;
   2664   5331       amw 
   2665   9664     jason 	if (!Eflg) {
   2666   9664     jason 		time_fmt_old = FORMAT_LONG;
   2667   9664     jason 		time_fmt_new = FORMAT_LONG;
   2668   9664     jason 	}
   2669   9664     jason 
   2670   5331       amw 	new_line();
   2671   9664     jason 	format_time(p->lat.tv_sec, p->lat.tv_nsec);
   2672   9664     jason 	(void) printf("         timestamp: atime        %s\n", time_buf);
   2673   9664     jason 	format_time(p->lct.tv_sec, p->lct.tv_nsec);
   2674   9664     jason 	(void) printf("         timestamp: ctime        %s\n", time_buf);
   2675   9664     jason 	format_time(p->lmt.tv_sec, p->lmt.tv_nsec);
   2676   9664     jason 	(void) printf("         timestamp: mtime        %s\n", time_buf);
   2677   9664     jason 	if (p->extm != NULL) {
   2678   9664     jason 		while (p->extm[i].nstm != 0 && i < sacnt) {
   2679   9664     jason 			format_time(p->extm[i].stm, p->extm[i].nstm);
   2680   9664     jason 			if (p->extm[i].name != NULL) {
   2681   9664     jason 				(void) printf("         timestamp:"
   2682   9664     jason 				    " %s        %s\n",
   2683   9664     jason 				    p->extm[i].name, time_buf);
   2684   9664     jason 			}
   2685   9664     jason 			i++;
   2686   9664     jason 		}
   2687   9664     jason 	}
   2688   9664     jason 
   2689   9664     jason 	time_fmt_old = old_save;
   2690   9664     jason 	time_fmt_new = new_save;
   2691   9664     jason }
   2692   9664     jason 
   2693   9664     jason /*
   2694   9664     jason  * Check if color definition applies to entry, returns 1 if yes, 0 if no
   2695   9664     jason  */
   2696   9664     jason static int
   2697  10059     jason color_match(const char *fname, mode_t mode, ls_color_t *color)
   2698   9664     jason {
   2699   9664     jason 	switch (color->ftype) {
   2700   9664     jason 	case LS_PAT:
   2701   9664     jason 	{
   2702   9664     jason 		size_t	fname_len, sfx_len;
   2703   9664     jason 
   2704   9664     jason 		fname_len = strlen(fname);
   2705   9664     jason 		sfx_len = strlen(color->sfx);
   2706   9664     jason 		if (sfx_len > fname_len)
   2707   9664     jason 			return (0);
   2708   9664     jason 
   2709   9664     jason 		if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0)
   2710   9664     jason 			return (1);
   2711   9664     jason 		else
   2712   9664     jason 			return (0);
   2713   9664     jason 	}
   2714   9664     jason 
   2715   9664     jason 	case LS_NORMAL:
   2716   9664     jason 		return (1);
   2717   9664     jason 
   2718   9664     jason 	case LS_FILE:
   2719  10059     jason 		return (S_ISREG(mode));
   2720   9664     jason 
   2721   9664     jason 	case LS_DIR:
   2722  10059     jason 		return (S_ISDIR(mode));
   2723   9664     jason 
   2724   9664     jason 	case LS_LINK:
   2725  10059     jason 		return (S_ISLNK(mode));
   2726   9664     jason 
   2727   9664     jason 	case LS_FIFO:
   2728  10059     jason 		return (S_ISFIFO(mode));
   2729   9664     jason 
   2730   9664     jason 	case LS_SOCK:
   2731  10059     jason 		return (S_ISSOCK(mode));
   2732   9664     jason 
   2733   9664     jason 	case LS_DOOR:
   2734  10059     jason 		return (S_ISDOOR(mode));
   2735   9664     jason 
   2736   9664     jason 	case LS_BLK:
   2737  10059     jason 		return (S_ISBLK(mode));
   2738   9664     jason 
   2739   9664     jason 	case LS_CHR:
   2740  10059     jason 		return (S_ISCHR(mode));
   2741   9664     jason 
   2742   9664     jason 	case LS_PORT:
   2743  10059     jason 		return (S_ISPORT(mode));
   2744   9664     jason 
   2745   9664     jason 	case LS_ORPHAN:
   2746  10059     jason 		/* this is tested for by gstat */
   2747   9664     jason 		return (0);
   2748   9664     jason 
   2749   9664     jason 	case LS_SETUID:
   2750  10059     jason 		return (!S_ISLNK(mode) && (mode & S_ISUID));
   2751   9664     jason 
   2752   9664     jason 	case LS_SETGID:
   2753  10059     jason 		return (!S_ISLNK(mode) && (mode & S_ISGID));
   2754   9664     jason 
   2755   9664     jason 	case LS_STICKY_OTHER_WRITABLE:
   2756  10059     jason 		return (!S_ISLNK(mode) && (mode & (S_IWOTH|S_ISVTX)));
   2757   9664     jason 
   2758   9664     jason 	case LS_OTHER_WRITABLE:
   2759  10059     jason 		return (!S_ISLNK(mode) && (mode & S_IWOTH));
   2760   9664     jason 
   2761   9664     jason 	case LS_STICKY:
   2762  10059     jason 		return (!S_ISLNK(mode) && (mode & S_ISVTX));
   2763   9664     jason 
   2764   9664     jason 	case LS_EXEC:
   2765  10059     jason 		return (!S_ISLNK(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH)));
   2766   9664     jason 	}
   2767   9664     jason 
   2768   9664     jason 	return (0);
   2769   9664     jason }
   2770   9664     jason 
   2771   9664     jason static void
   2772   9664     jason dump_color(ls_color_t *c)
   2773   9664     jason {
   2774   9664     jason 	if (c == NULL)
   2775   9664     jason 		return;
   2776   9664     jason 
   2777   9664     jason 	(void) printf("\n\ttype: ");
   2778   9664     jason 	switch (c->ftype) {
   2779   9664     jason 	case LS_NORMAL:
   2780   9664     jason 		(void) printf("LS_NORMAL");
   2781   9664     jason 		break;
   2782   9664     jason 	case LS_FILE:
   2783   9664     jason 		(void) printf("LS_FILE");
   2784   9664     jason 		break;
   2785   9664     jason 	case LS_EXEC:
   2786   9664     jason 		(void) printf("LS_EXEC");
   2787   9664     jason 		break;
   2788   9664     jason 	case LS_DIR:
   2789   9664     jason 		(void) printf("LS_DIR");
   2790   9664     jason 		break;
   2791   9664     jason 	case LS_LINK:
   2792   9664     jason 		(void) printf("LS_LINK");
   2793   9664     jason 		break;
   2794   9664     jason 
   2795   9664     jason 	case LS_FIFO:
   2796   9664     jason 		(void) printf("LS_FIFO");
   2797   9664     jason 		break;
   2798   9664     jason 
   2799   9664     jason 	case LS_SOCK:
   2800   9664     jason 		(void) printf("LS_SOCK");
   2801   9664     jason 		break;
   2802   9664     jason 
   2803   9664     jason 	case LS_DOOR:
   2804   9664     jason 		(void) printf("LS_DOOR");
   2805   9664     jason 		break;
   2806   9664     jason 
   2807   9664     jason 	case LS_BLK:
   2808   9664     jason 		(void) printf("LS_BLK");
   2809   9664     jason 		break;
   2810   9664     jason 
   2811   9664     jason 	case LS_CHR:
   2812   9664     jason 		(void) printf("LS_CHR");
   2813   9664     jason 		break;
   2814   9664     jason 
   2815   9664     jason 	case LS_PORT:
   2816   9664     jason 		(void) printf("LS_PORT");
   2817   9664     jason 		break;
   2818   9664     jason 
   2819   9664     jason 	case LS_STICKY:
   2820   9664     jason 		(void) printf("LS_STICKY");
   2821   9664     jason 		break;
   2822   9664     jason 
   2823   9664     jason 	case LS_ORPHAN:
   2824   9664     jason 		(void) printf("LS_ORPHAN");
   2825   9664     jason 		break;
   2826   9664     jason 
   2827   9664     jason 	case LS_SETGID:
   2828   9664     jason 		(void) printf("LS_SETGID");
   2829   9664     jason 		break;
   2830   9664     jason 
   2831   9664     jason 	case LS_SETUID:
   2832   9664     jason 		(void) printf("LS_SETUID");
   2833   9664     jason 		break;
   2834   9664     jason 
   2835   9664     jason 	case LS_OTHER_WRITABLE:
   2836   9664     jason 		(void) printf("LS_OTHER_WRITABLE");
   2837   9664     jason 		break;
   2838   9664     jason 
   2839   9664     jason 	case LS_STICKY_OTHER_WRITABLE:
   2840   9664     jason 		(void) printf("LS_STICKY_OTHER_WRITABLE");
   2841   9664     jason 		break;
   2842   9664     jason 
   2843   9664     jason 	case LS_PAT:
   2844   9664     jason 		(void) printf("LS_PAT\n");
   2845   9664     jason 		(void) printf("\tpattern: %s", c->sfx);
   2846   9664     jason 		break;
   2847   9664     jason 	}
   2848   9664     jason 	(void) printf("\n");
   2849   9664     jason 	(void) printf("\tattr: %d\n", c->attr);
   2850   9664     jason 	(void) printf("\tfg: %d\n", c->fg);
   2851   9664     jason 	(void) printf("\tbg: %d\n", c->bg);
   2852   9664     jason 	(void) printf("\t");
   2853   9664     jason }
   2854   9664     jason 
   2855   9664     jason static ls_color_t *
   2856  10059     jason ls_color_find(const char *fname, mode_t mode)
   2857   9664     jason {
   2858   9664     jason 	int i;
   2859   9664     jason 
   2860   9664     jason 	/*
   2861   9664     jason 	 * Colors are sorted from most general lsc_colors[0] to most specific
   2862   9664     jason 	 * lsc_colors[lsc_ncolors - 1] by ls_color_init().  Start search with
   2863   9664     jason 	 * most specific color rule and work towards most general.
   2864   9664     jason 	 */
   2865   9664     jason 	for (i = lsc_ncolors - 1; i >= 0; --i)
   2866  10059     jason 		if (color_match(fname, mode, &lsc_colors[i]))
   2867   9664     jason 			return (&lsc_colors[i]);
   2868   9664     jason 
   2869   9664     jason 	return (NULL);
   2870   9664     jason }
   2871   9664     jason 
   2872   9664     jason static void
   2873   9664     jason ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4,
   2874   9664     jason     long int p5, long int p6, long int p7, long int p8, long int p9)
   2875   9664     jason {
   2876   9664     jason 	char *s;
   2877   9664     jason 
   2878   9664     jason 	if (str == NULL)
   2879   9664     jason 		return;
   2880   9664     jason 
   2881   9664     jason 	s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
   2882   9664     jason 
   2883   9664     jason 	if (s != NULL)
   2884   9664     jason 		(void) putp(s);
   2885   9664     jason }
   2886   9664     jason 
   2887   9664     jason static void
   2888  10059     jason ls_start_color(ls_color_t *c)
   2889   9664     jason {
   2890   9664     jason 	if (c == NULL)
   2891   9664     jason 		return;
   2892   9664     jason 
   2893   9664     jason 	if (lsc_debug)
   2894   9664     jason 		lsc_match = c;
   2895   9664     jason 
   2896   9664     jason 	if (c->attr & LSA_BOLD)
   2897   9664     jason 		ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2898   9664     jason 	if (c->attr & LSA_UNDERSCORE)
   2899   9664     jason 		ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2900   9664     jason 	if (c->attr & LSA_BLINK)
   2901   9664     jason 		ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2902   9664     jason 	if (c->attr & LSA_REVERSE)
   2903   9664     jason 		ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2904   9664     jason 	if (c->attr & LSA_CONCEALED)
   2905   9664     jason 		ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2906   9664     jason 	if (c->attr == LSA_NONE)
   2907   9664     jason 		ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2908   9664     jason 
   2909   9664     jason 	if (c->fg != -1)
   2910   9664     jason 		ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0);
   2911   9664     jason 	if (c->bg != -1)
   2912   9664     jason 		ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0);
   2913   9664     jason }
   2914   9664     jason 
   2915   9664     jason static void
   2916   9664     jason ls_end_color()
   2917   9664     jason {
   2918   9664     jason 	ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   2919   9664     jason 	if (lsc_debug)
   2920   9664     jason 		dump_color(lsc_match);
   2921   9664     jason }
   2922   9664     jason 
   2923   9664     jason static void
   2924   9664     jason new_color_entry(char *colorstr)
   2925   9664     jason {
   2926   9664     jason 	static const struct {
   2927   9664     jason 		const char	*s;
   2928   9664     jason 		ls_cftype_t	stype;
   2929   9664     jason 	} type_map[] = {
   2930   9664     jason 		{ "no", LS_NORMAL },
   2931   9664     jason 		{ "fi", LS_FILE },
   2932   9664     jason 		{ "di", LS_DIR },
   2933   9664     jason 		{ "ln", LS_LINK },
   2934   9664     jason 		{ "pi", LS_FIFO },
   2935   9664     jason 		{ "so", LS_SOCK },
   2936   9664     jason 		{ "do", LS_DOOR },
   2937   9664     jason 		{ "bd", LS_BLK },
   2938   9664     jason 		{ "cd", LS_CHR },
   2939   9664     jason 		{ "or", LS_ORPHAN },
   2940   9664     jason 		{ "su", LS_SETUID },
   2941   9664     jason 		{ "sg", LS_SETGID },
   2942   9664     jason 		{ "tw", LS_STICKY_OTHER_WRITABLE },
   2943   9664     jason 		{ "ow", LS_OTHER_WRITABLE },
   2944   9664     jason 		{ "st", LS_STICKY },
   2945   9664     jason 		{ "ex", LS_EXEC },
   2946   9664     jason 		{ "po", LS_PORT },
   2947   9664     jason 		{ NULL, LS_NORMAL }
   2948   9664     jason 	};
   2949   9664     jason 
   2950   9664     jason 	char		*p, *lasts;
   2951   9664     jason 	int		i;
   2952   9664     jason 	int		color, attr;
   2953   9664     jason 
   2954   9664     jason 	p = strtok_r(colorstr, "=", &lasts);
   2955   9664     jason 	if (p == NULL) {
   2956   9664     jason 		colorflg = 0;
   2957   9664     jason 		return;
   2958   9664     jason 	}
   2959   9664     jason 
   2960   9664     jason 	if (p[0] == '*') {
   2961   9664     jason 		lsc_colors[lsc_ncolors].ftype = LS_PAT;
   2962   9664     jason 		/* don't include the * in the suffix */
   2963   9664     jason 		if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) {
   2964   9664     jason 			colorflg = 0;
   2965   9664     jason 			return;
   2966   9664     jason 		}
   2967   9664     jason 	} else {
   2968   9664     jason 		lsc_colors[lsc_ncolors].sfx = NULL;
   2969   9664     jason 
   2970   9664     jason 		for (i = 0; type_map[i].s != NULL; ++i) {
   2971   9664     jason 			if (strncmp(type_map[i].s, p, 2) == 0)
   2972   9664     jason 				break;
   2973   9664     jason 		}
   2974   9664     jason 
   2975   9664     jason 		/* ignore unknown file types */
   2976   9664     jason 		if (type_map[i].s == NULL)
   2977   9664     jason 			return;
   2978   9664     jason 
   2979   9664     jason 		lsc_colors[lsc_ncolors].ftype = type_map[i].stype;
   2980   9664     jason 	}
   2981   9664     jason 
   2982   9664     jason 	attr = LSA_NONE;
   2983   9664     jason 	lsc_colors[lsc_ncolors].fg = -1;
   2984   9664     jason 	lsc_colors[lsc_ncolors].bg = -1;
   2985   9664     jason 	for (p = strtok_r(NULL, ";", &lasts); p != NULL;
   2986   9664     jason 	    p = strtok_r(NULL, ";", &lasts)) {
   2987   9664     jason 		color = strtol(p, NULL, 10);
   2988   9664     jason 
   2989   9664     jason 		if (color < 10) {
   2990   9664     jason 			switch (color) {
   2991   9664     jason 			case 0:
   2992   9664     jason 				attr = LSA_NONE;
   2993   9664     jason 				continue;
   2994   9664     jason 			case 1:
   2995   9664     jason 				attr |= LSA_BOLD;
   2996   9664     jason 				continue;
   2997   9664     jason 			case 4:
   2998   9664     jason 				attr |= LSA_UNDERSCORE;
   2999   9664     jason 				continue;
   3000   9664     jason 			case 5:
   3001   9664     jason 				attr |= LSA_BLINK;
   3002   9664     jason 				continue;
   3003   9664     jason 			case 7:
   3004   9664     jason 				attr |= LSA_REVERSE;
   3005   9664     jason 				continue;
   3006   9664     jason 			case 8:
   3007   9664     jason 				attr |= LSA_CONCEALED;
   3008   9664     jason 				continue;
   3009   9664     jason 			default:
   3010   9664     jason 				continue;
   3011   5331       amw 			}
   3012   5331       amw 		}
   3013   9664     jason 
   3014   9664     jason 		if (color < 40)
   3015   9664     jason 			lsc_colors[lsc_ncolors].fg = color - 30;
   3016   9664     jason 		else
   3017   9664     jason 			lsc_colors[lsc_ncolors].bg = color - 40;
   3018   9664     jason 	}
   3019   9664     jason 
   3020   9664     jason 	lsc_colors[lsc_ncolors].attr = attr;
   3021   9664     jason 	++lsc_ncolors;
   3022   9664     jason }
   3023   9664     jason 
   3024   9664     jason static int
   3025   9664     jason ls_color_compare(const void *p1, const void *p2)
   3026   9664     jason {
   3027   9664     jason 	const ls_color_t *c1 = (const ls_color_t *)p1;
   3028   9664     jason 	const ls_color_t *c2 = (const ls_color_t *)p2;
   3029   9664     jason 
   3030   9664     jason 	int ret = c1->ftype - c2->ftype;
   3031   9664     jason 
   3032   9664     jason 	if (ret != 0)
   3033   9664     jason 		return (ret);
   3034   9664     jason 
   3035   9664     jason 	if (c1->ftype != LS_PAT)
   3036   9664     jason 		return (ret);
   3037   9664     jason 
   3038   9664     jason 	return (strcmp(c1->sfx, c2->sfx));
   3039   9664     jason }
   3040   9664     jason 
   3041   9664     jason static void
   3042   9664     jason ls_color_init()
   3043   9664     jason {
   3044   9664     jason 	static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35"
   3045   9664     jason 	    ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01"
   3046   9664     jason 	    ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31"
   3047   9664     jason 	    ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31"
   3048   9664     jason 	    ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31"
   3049   9664     jason 	    ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35"
   3050   9664     jason 	    ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"
   3051   9664     jason 	    ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35"
   3052   9664     jason 	    ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35"
   3053   9664     jason 	    ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35"
   3054   9664     jason 	    ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35";
   3055   9664     jason 
   3056   9664     jason 	char    *colorstr;
   3057   9664     jason 	char    *p, *lasts;
   3058   9664     jason 	size_t  color_sz;
   3059   9664     jason 	int	termret;
   3060  10059     jason 	int	i;
   3061   9664     jason 
   3062   9664     jason 	(void) setupterm(NULL, 1, &termret);
   3063   9664     jason 	if (termret != 1)
   3064   9664     jason 		return;
   3065   9664     jason 
   3066   9664     jason 	if ((colorstr = getenv("LS_COLORS")) == NULL)
   3067   9664     jason 		colorstr = default_colorstr;
   3068   9664     jason 
   3069   9689     jason 	/*
   3070   9689     jason 	 * Determine the size of lsc_colors.  color_sz can be > lsc_ncolors
   3071   9689     jason 	 * if there are invalid entries passed in the string (they are ignored)
   3072   9689     jason 	 */
   3073   9689     jason 	color_sz = 1;
   3074   9664     jason 	for (p = strchr(colorstr, ':'); p != NULL && *p != '\0';
   3075   9664     jason 	    p = strchr(++p, ':'))
   3076   9664     jason 		++color_sz;
   3077   9664     jason 
   3078   9664     jason 	lsc_colors = calloc(color_sz, sizeof (ls_color_t));
   3079   9664     jason 	if (lsc_colors == NULL) {
   3080   9664     jason 		free(colorstr);
   3081   9664     jason 		return;
   3082   9664     jason 	}
   3083   9664     jason 
   3084   9664     jason 	for (p = strtok_r(colorstr, ":", &lasts);
   3085   9664     jason 	    p != NULL && lsc_ncolors < color_sz;
   3086   9664     jason 	    p = strtok_r(NULL, ":", &lasts))
   3087   9664     jason 		new_color_entry(p);
   3088   9664     jason 
   3089   9664     jason 	qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t),
   3090   9664     jason 	    ls_color_compare);
   3091  10059     jason 
   3092  10059     jason 	for (i = 0; i < lsc_ncolors; ++i)
   3093  10059     jason 		if (lsc_colors[i].ftype == LS_ORPHAN) {
   3094  10059     jason 			lsc_orphan = &lsc_colors[i];
   3095  10059     jason 			break;
   3096  10059     jason 		}
   3097   9664     jason 
   3098   9664     jason 	if ((lsc_bold = tigetstr("bold")) == (char *)-1)
   3099   9664     jason 		lsc_bold = NULL;
   3100   9664     jason 
   3101   9664     jason 	if ((lsc_underline = tigetstr("smul")) == (char *)-1)
   3102   9664     jason 		lsc_underline = NULL;
   3103   9664     jason 
   3104   9664     jason 	if ((lsc_blink = tigetstr("blink")) == (char *)-1)
   3105   9664     jason 		lsc_blink = NULL;
   3106   9664     jason 
   3107   9664     jason 	if ((lsc_reverse = tigetstr("rev")) == (char *)-1)
   3108   9664     jason 		lsc_reverse = NULL;
   3109   9664     jason 
   3110   9664     jason 	if ((lsc_concealed = tigetstr("prot")) == (char *)-1)
   3111   9664     jason 		lsc_concealed = NULL;
   3112   9664     jason 
   3113   9664     jason 	if ((lsc_none = tigetstr("sgr0")) == (char *)-1)
   3114   9664     jason 		lsc_none = NULL;
   3115   9664     jason 
   3116   9664     jason 	if ((lsc_setfg = tigetstr("setaf")) == (char *)-1)
   3117   9664     jason 		lsc_setfg = NULL;
   3118   9664     jason 
   3119   9664     jason 	if ((lsc_setbg = tigetstr("setab")) == (char *)-1)
   3120   9664     jason 		lsc_setbg = NULL;
   3121   9664     jason 
   3122   9664     jason 	if (getenv("_LS_COLOR_DEBUG") != NULL) {
   3123   9664     jason 		int i;
   3124   9664     jason 
   3125   9664     jason 		lsc_debug = 1;
   3126   9664     jason 		for (i = 0; i < lsc_ncolors; ++i)
   3127   9664     jason 			dump_color(&lsc_colors[i]);
   3128   5331       amw 	}
   3129   5331       amw }
   3130   5331       amw 
   3131   5331       amw /* Free extended system attribute lists */
   3132   5331       amw 
   3133   5331       amw void
   3134   5331       amw free_sysattr(struct lbuf *p)
   3135   5331       amw {
   3136   5331       amw 	int i;
   3137   5331       amw 
   3138   5331       amw 	if (p->exttr != NULL) {
   3139   5331       amw 		for (i = 0; i < sacnt; i++) {
   3140   5331       amw 			if (p->exttr[i].name != NULL)
   3141   5331       amw 				free(p->exttr[i].name);
   3142   5331       amw 		}
   3143   5331       amw 		free(p->exttr);
   3144   5331       amw 	}
   3145   5331       amw 	if (p->extm != NULL) {
   3146   5331       amw 		for (i = 0; i < sacnt; i++) {
   3147   5331       amw 			if (p->extm[i].name != NULL)
   3148   5331       amw 				free(p->extm[i].name);
   3149   5331       amw 		}
   3150   5331       amw 		free(p->extm);
   3151   5331       amw 	}
   3152   5331       amw }
   3153   5331       amw 
   3154   5331       amw /* Allocate extended system attribute list */
   3155   5331       amw 
   3156   5331       amw void *
   3157   5331       amw xmalloc(size_t size, struct lbuf *p)
   3158   5331       amw {
   3159   5331       amw 	if ((p = malloc(size)) == NULL) {
   3160   5331       amw 		perror("ls");
   3161   5331       amw 		free_sysattr(p);
   3162   5331       amw 		nvlist_free(response);
   3163   5331       amw 		exit(2);
   3164   5331       amw 	}
   3165   5331       amw 	return (p);
   3166   5331       amw }
   3167