xref: /titanic_51/usr/src/cmd/ls/ls.c (revision f7387fb09b8eecf790b90ea27d4beaf186ce6597)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52236845bSakaplan  * Common Development and Distribution License (the "License").
62236845bSakaplan  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215e1c72e1SJason King 
227c478bd9Sstevel@tonic-gate /*
235e1c72e1SJason King  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245e1c72e1SJason King  * Use is subject to license terms.
255e1c72e1SJason King  */
265e1c72e1SJason King 
275e1c72e1SJason King /*
285e1c72e1SJason King  * Copyright 2009 Jason King.  All rights reserved.
297c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
337c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
367c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * List files or directories
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <sys/param.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/acl.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include <wchar.h>
497c478bd9Sstevel@tonic-gate #include <stdio.h>
507c478bd9Sstevel@tonic-gate #include <ctype.h>
517c478bd9Sstevel@tonic-gate #include <dirent.h>
527c478bd9Sstevel@tonic-gate #include <string.h>
537c478bd9Sstevel@tonic-gate #include <locale.h>
547c478bd9Sstevel@tonic-gate #include <curses.h>
555e1c72e1SJason King #include <term.h>
567c478bd9Sstevel@tonic-gate #include <termios.h>
577c478bd9Sstevel@tonic-gate #include <stdlib.h>
587c478bd9Sstevel@tonic-gate #include <widec.h>
597c478bd9Sstevel@tonic-gate #include <locale.h>
607c478bd9Sstevel@tonic-gate #include <wctype.h>
617c478bd9Sstevel@tonic-gate #include <pwd.h>
627c478bd9Sstevel@tonic-gate #include <grp.h>
637c478bd9Sstevel@tonic-gate #include <limits.h>
647c478bd9Sstevel@tonic-gate #include <fcntl.h>
657c478bd9Sstevel@tonic-gate #include <unistd.h>
667c478bd9Sstevel@tonic-gate #include <libgen.h>
677c478bd9Sstevel@tonic-gate #include <errno.h>
68fa9e4066Sahrens #include <aclutils.h>
69da6c28aaSamw #include <libnvpair.h>
70da6c28aaSamw #include <libcmdutils.h>
71da6c28aaSamw #include <attr.h>
725e1c72e1SJason King #include <getopt.h>
735e1c72e1SJason King #include <inttypes.h>
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #ifndef STANDALONE
767c478bd9Sstevel@tonic-gate #define	TERMINFO
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * -DNOTERMINFO can be defined on the cc command line to prevent
817c478bd9Sstevel@tonic-gate  * the use of terminfo.  This should be done on systems not having
82da6c28aaSamw  * the terminfo feature(pre 6.0 systems ?).
837c478bd9Sstevel@tonic-gate  * As a result, columnar listings assume 80 columns for output,
847c478bd9Sstevel@tonic-gate  * unless told otherwise via the COLUMNS environment variable.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO
877c478bd9Sstevel@tonic-gate #undef TERMINFO
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #include <term.h>
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	BFSIZE	16
937c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */
947c478bd9Sstevel@tonic-gate #define	ISARG	0100000
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * this flag has been added to manipulate the display of S instead of 'l' when
987c478bd9Sstevel@tonic-gate  * the file is not a regular file and when group execution bit is off
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate #define	LS_NOTREG	010000
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Date and time formats
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * b --- abbreviated month name
1077c478bd9Sstevel@tonic-gate  * e --- day number
1087c478bd9Sstevel@tonic-gate  * Y --- year in the form ccyy
1097c478bd9Sstevel@tonic-gate  * H --- hour(24-hour version)
1107c478bd9Sstevel@tonic-gate  * M --- minute
1117c478bd9Sstevel@tonic-gate  * F --- yyyy-mm-dd
1127c478bd9Sstevel@tonic-gate  * T --- hh:mm:ss
1137c478bd9Sstevel@tonic-gate  * z --- time zone as hours displacement from UTC
1147c478bd9Sstevel@tonic-gate  * note that %F and %z are from the ISO C99 standard and are
1157c478bd9Sstevel@tonic-gate  * not present in older C libraries
1167c478bd9Sstevel@tonic-gate  */
1175e1c72e1SJason King #define	FORMAT_OLD	" %b %e  %Y "
1185e1c72e1SJason King #define	FORMAT_NEW	" %b %e %H:%M "
1195e1c72e1SJason King #define	FORMAT_LONG	" %b %e %T %Y "
1205e1c72e1SJason King #define	FORMAT_ISO_FULL	" %%F %%T.%.09ld %%z "
1215e1c72e1SJason King #define	FORMAT_ISO_LONG	" %F %R "
1225e1c72e1SJason King #define	FORMAT_ISO_NEW	" %m-%d %H:%M "
1235e1c72e1SJason King #define	FORMAT_ISO_OLD	" %F "
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate #undef BUFSIZ
1267c478bd9Sstevel@tonic-gate #define	BUFSIZ 4096
1277c478bd9Sstevel@tonic-gate #define	NUMBER_WIDTH 40
1287c478bd9Sstevel@tonic-gate #define	FMTSIZE 50
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate struct ditem {
1317c478bd9Sstevel@tonic-gate 	dev_t	dev;			/* directory items device number */
1327c478bd9Sstevel@tonic-gate 	ino_t	ino;			/* directory items inode number */
1337c478bd9Sstevel@tonic-gate 	struct ditem *parent;		/* dir items ptr to its parent's info */
1347c478bd9Sstevel@tonic-gate };
135da6c28aaSamw /* Holds boolean extended system attributes */
136da6c28aaSamw struct attrb {
137da6c28aaSamw 	char		*name;
138da6c28aaSamw };
139da6c28aaSamw /* Holds timestamp extended system attributes */
140da6c28aaSamw struct attrtm {
141da6c28aaSamw 	char		*name;
142da6c28aaSamw 	uint64_t	stm;
143da6c28aaSamw 	uint64_t	nstm;
144da6c28aaSamw };
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate struct	lbuf	{
1477c478bd9Sstevel@tonic-gate 	union	{
1487c478bd9Sstevel@tonic-gate 		char	lname[MAXNAMLEN]; /* used for filename in a directory */
1497c478bd9Sstevel@tonic-gate 		char	*namep;		/* for name in ls-command; */
1507c478bd9Sstevel@tonic-gate 	} ln;
1517c478bd9Sstevel@tonic-gate 	char	ltype;		/* filetype */
1527c478bd9Sstevel@tonic-gate 	ino_t	lnum;		/* inode number of file */
1537c478bd9Sstevel@tonic-gate 	mode_t	lflags; 	/* 0777 bits used as r,w,x permissions */
1547c478bd9Sstevel@tonic-gate 	nlink_t	lnl;		/* number of links to file */
1557c478bd9Sstevel@tonic-gate 	uid_t	luid;
1567c478bd9Sstevel@tonic-gate 	gid_t	lgid;
1577c478bd9Sstevel@tonic-gate 	off_t	lsize;		/* filesize or major/minor dev numbers */
1587c478bd9Sstevel@tonic-gate 	blkcnt_t	lblocks;	/* number of file blocks */
1597c478bd9Sstevel@tonic-gate 	timestruc_t	lmtime;
160da6c28aaSamw 	timestruc_t	lat;
161da6c28aaSamw 	timestruc_t	lct;
162da6c28aaSamw 	timestruc_t	lmt;
1637c478bd9Sstevel@tonic-gate 	char	*flinkto;	/* symbolic link contents */
1647c478bd9Sstevel@tonic-gate 	char 	acl;		/* indicate there are additional acl entries */
1657c478bd9Sstevel@tonic-gate 	int	cycle;		/* cycle detected flag */
1667c478bd9Sstevel@tonic-gate 	struct ditem *ancinfo;	/* maintains ancestor info */
167fa9e4066Sahrens 	acl_t *aclp;		/* ACL if present */
168da6c28aaSamw 	struct attrb *exttr;	/* boolean extended system attributes */
169da6c28aaSamw 	struct attrtm *extm;	/* timestamp extended system attributes */
1707c478bd9Sstevel@tonic-gate };
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate struct dchain {
1737c478bd9Sstevel@tonic-gate 	char *dc_name;		/* path name */
1747c478bd9Sstevel@tonic-gate 	int cycle_detected;	/* cycle detected visiting this directory */
1757c478bd9Sstevel@tonic-gate 	struct ditem *myancinfo;	/* this directory's ancestry info */
1767c478bd9Sstevel@tonic-gate 	struct dchain *dc_next;	/* next directory in the chain */
1777c478bd9Sstevel@tonic-gate };
1787c478bd9Sstevel@tonic-gate 
1795e1c72e1SJason King #define	LSA_NONE	(0)
1805e1c72e1SJason King #define	LSA_BOLD	(1L << 0)
1815e1c72e1SJason King #define	LSA_UNDERSCORE	(1L << 1)
1825e1c72e1SJason King #define	LSA_BLINK	(1L << 2)
1835e1c72e1SJason King #define	LSA_REVERSE	(1L << 3)
1845e1c72e1SJason King #define	LSA_CONCEALED	(1L << 4)
1855e1c72e1SJason King 
1865e1c72e1SJason King /* these should be ordered most general to most specific */
1875e1c72e1SJason King typedef enum LS_CFTYPE {
1885e1c72e1SJason King 	LS_NORMAL,
1895e1c72e1SJason King 	LS_FILE,
1905e1c72e1SJason King 	LS_EXEC,
1915e1c72e1SJason King 	LS_DIR,
1925e1c72e1SJason King 	LS_LINK,
1935e1c72e1SJason King 	LS_FIFO,
1945e1c72e1SJason King 	LS_SOCK,
1955e1c72e1SJason King 	LS_DOOR,
1965e1c72e1SJason King 	LS_BLK,
1975e1c72e1SJason King 	LS_CHR,
1985e1c72e1SJason King 	LS_PORT,
1995e1c72e1SJason King 	LS_STICKY,
2005e1c72e1SJason King 	LS_ORPHAN,
2015e1c72e1SJason King 	LS_SETGID,
2025e1c72e1SJason King 	LS_SETUID,
2035e1c72e1SJason King 	LS_OTHER_WRITABLE,
2045e1c72e1SJason King 	LS_STICKY_OTHER_WRITABLE,
2055e1c72e1SJason King 	LS_PAT
2065e1c72e1SJason King } ls_cftype_t;
2075e1c72e1SJason King 
2085e1c72e1SJason King typedef struct ls_color {
2095e1c72e1SJason King 	char		*sfx;
2105e1c72e1SJason King 	ls_cftype_t	ftype;
2115e1c72e1SJason King 	int		attr;
2125e1c72e1SJason King 	int		fg;
2135e1c72e1SJason King 	int		bg;
2145e1c72e1SJason King } ls_color_t;
2155e1c72e1SJason King 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate  * A numbuf_t is used when converting a number to a string representation
2187c478bd9Sstevel@tonic-gate  */
2197c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH];
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static struct dchain *dfirst;	/* start of the dir chain */
2227c478bd9Sstevel@tonic-gate static struct dchain *cdfirst;	/* start of the current dir chain */
2237c478bd9Sstevel@tonic-gate static struct dchain *dtemp;	/* temporary - used for linking */
2247c478bd9Sstevel@tonic-gate static char *curdir;		/* the current directory */
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int	first = 1;	/* true if first line is not yet printed */
2277c478bd9Sstevel@tonic-gate static int	nfiles = 0;	/* number of flist entries in current use */
2287c478bd9Sstevel@tonic-gate static int	nargs = 0;	/* number of flist entries used for arguments */
2297c478bd9Sstevel@tonic-gate static int	maxfils = 0;	/* number of flist/lbuf entries allocated */
2307c478bd9Sstevel@tonic-gate static int	maxn = 0;	/* number of flist entries with lbufs asigned */
2317c478bd9Sstevel@tonic-gate static int	quantn = 64;	/* allocation growth quantum */
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static struct lbuf	*nxtlbf;	/* ptr to next lbuf to be assigned */
2347c478bd9Sstevel@tonic-gate static struct lbuf	**flist;	/* ptr to list of lbuf pointers */
2357c478bd9Sstevel@tonic-gate static struct lbuf	*gstat(char *, int, struct ditem *);
2367c478bd9Sstevel@tonic-gate static char		*getname(uid_t);
2377c478bd9Sstevel@tonic-gate static char		*getgroup(gid_t);
2387c478bd9Sstevel@tonic-gate static char		*makename(char *, char *);
2397c478bd9Sstevel@tonic-gate static void		pentry(struct lbuf *);
2407c478bd9Sstevel@tonic-gate static void		column(void);
2417c478bd9Sstevel@tonic-gate static void		pmode(mode_t aflag);
2427c478bd9Sstevel@tonic-gate static void		selection(int *);
2437c478bd9Sstevel@tonic-gate static void		new_line(void);
2447c478bd9Sstevel@tonic-gate static void		rddir(char *, struct ditem *);
2457c478bd9Sstevel@tonic-gate static int		strcol(unsigned char *);
2467c478bd9Sstevel@tonic-gate static void		pem(struct lbuf **, struct lbuf **, int);
2477c478bd9Sstevel@tonic-gate static void		pdirectory(char *, int, int, int, struct ditem *);
2487c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long);
2497c478bd9Sstevel@tonic-gate static void		csi_pprintf(unsigned char *);
2507c478bd9Sstevel@tonic-gate static void		pprintf(char *, char *);
2517c478bd9Sstevel@tonic-gate static int		compar(struct lbuf **pp1, struct lbuf **pp2);
2527c478bd9Sstevel@tonic-gate static char 		*number_to_scaled_string(numbuf_t buf,
2537c478bd9Sstevel@tonic-gate 			    unsigned long long number,
2547c478bd9Sstevel@tonic-gate 			    long scale);
2557c478bd9Sstevel@tonic-gate static void		record_ancestry(char *, struct stat *, struct lbuf *,
2567c478bd9Sstevel@tonic-gate 			    int, struct ditem *);
2575e1c72e1SJason King static void		ls_color_init(void);
2585e1c72e1SJason King static void		ls_start_color(struct lbuf *);
2595e1c72e1SJason King static void		ls_end_color(void);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate static int		aflg;
2627c478bd9Sstevel@tonic-gate static int		atflg;
2637c478bd9Sstevel@tonic-gate static int		bflg;
2647c478bd9Sstevel@tonic-gate static int		cflg;
2657c478bd9Sstevel@tonic-gate static int		dflg;
2667c478bd9Sstevel@tonic-gate static int		eflg;
2677c478bd9Sstevel@tonic-gate static int		fflg;
2687c478bd9Sstevel@tonic-gate static int		gflg;
2697c478bd9Sstevel@tonic-gate static int		hflg;
2707c478bd9Sstevel@tonic-gate static int		iflg;
2717c478bd9Sstevel@tonic-gate static int		lflg;
2727c478bd9Sstevel@tonic-gate static int		mflg;
2737c478bd9Sstevel@tonic-gate static int		nflg;
2747c478bd9Sstevel@tonic-gate static int		oflg;
2757c478bd9Sstevel@tonic-gate static int		pflg;
2767c478bd9Sstevel@tonic-gate static int		qflg;
2777c478bd9Sstevel@tonic-gate static int		rflg = 1; /* init to 1 for special use in compar */
2787c478bd9Sstevel@tonic-gate static int		sflg;
2797c478bd9Sstevel@tonic-gate static int		tflg;
2807c478bd9Sstevel@tonic-gate static int		uflg;
2815e1c72e1SJason King static int		Uflg;
2825e1c72e1SJason King static int		wflg;
2837c478bd9Sstevel@tonic-gate static int		xflg;
2847c478bd9Sstevel@tonic-gate static int		Aflg;
2855e1c72e1SJason King static int		Bflg;
2867c478bd9Sstevel@tonic-gate static int		Cflg;
2877c478bd9Sstevel@tonic-gate static int		Eflg;
2887c478bd9Sstevel@tonic-gate static int		Fflg;
2897c478bd9Sstevel@tonic-gate static int		Hflg;
2907c478bd9Sstevel@tonic-gate static int		Lflg;
2917c478bd9Sstevel@tonic-gate static int		Rflg;
2927c478bd9Sstevel@tonic-gate static int		Sflg;
293fa9e4066Sahrens static int		vflg;
2945a5eeccaSmarks static int		Vflg;
295da6c28aaSamw static int		saflg;		/* boolean extended system attr. */
296da6c28aaSamw static int		sacnt;		/* number of extended system attr. */
297da6c28aaSamw static int		copt;
298da6c28aaSamw static int		vopt;
299da6c28aaSamw static int		tmflg;		/* create time ext. system attr. */
300da6c28aaSamw static int		ctm;
301da6c28aaSamw static int		atm;
302da6c28aaSamw static int		mtm;
303da6c28aaSamw static int		crtm;
304da6c28aaSamw static int		alltm;
3057c478bd9Sstevel@tonic-gate static long		hscale;
3067c478bd9Sstevel@tonic-gate static mode_t		flags;
3077c478bd9Sstevel@tonic-gate static int		err = 0;	/* Contains return code */
3085e1c72e1SJason King static int		colorflg;
3095e1c72e1SJason King static int		file_typeflg;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate static uid_t		lastuid	= (uid_t)-1;
3127c478bd9Sstevel@tonic-gate static gid_t		lastgid = (gid_t)-1;
3137c478bd9Sstevel@tonic-gate static char		*lastuname = NULL;
3147c478bd9Sstevel@tonic-gate static char		*lastgname = NULL;
3157c478bd9Sstevel@tonic-gate 
3165e1c72e1SJason King /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */
3177c478bd9Sstevel@tonic-gate static int		statreq;
3187c478bd9Sstevel@tonic-gate 
3195e1c72e1SJason King static uint64_t		block_size = 1;
3207c478bd9Sstevel@tonic-gate static char		*dotp = ".";
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate static u_longlong_t 	tblocks; /* number of blocks of files in a directory */
3237c478bd9Sstevel@tonic-gate static time_t		year, now;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate static int		num_cols = 80;
3267c478bd9Sstevel@tonic-gate static int		colwidth;
3277c478bd9Sstevel@tonic-gate static int		filewidth;
3287c478bd9Sstevel@tonic-gate static int		fixedwidth;
3297c478bd9Sstevel@tonic-gate static int		nomocore;
3307c478bd9Sstevel@tonic-gate static int		curcol;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate static struct	winsize	win;
3337c478bd9Sstevel@tonic-gate 
3345e1c72e1SJason King /* if time_fmt_new is left NULL, time_fmt_old is used for all times */
3355e1c72e1SJason King static const char	*time_fmt_old = FORMAT_OLD;	/* non-recent files */
3365e1c72e1SJason King static const char	*time_fmt_new = FORMAT_NEW;	/* recent files */
3375e1c72e1SJason King static int		time_custom;	/* != 0 if a custom format */
338da6c28aaSamw static char	time_buf[FMTSIZE];	/* array to hold day and time */
3397c478bd9Sstevel@tonic-gate 
3405e1c72e1SJason King static int		lsc_debug;
3415e1c72e1SJason King static ls_color_t	*lsc_match;
3425e1c72e1SJason King static ls_color_t	*lsc_colors;
3435e1c72e1SJason King static size_t		lsc_ncolors;
3445e1c72e1SJason King static char		*lsc_bold;
3455e1c72e1SJason King static char		*lsc_underline;
3465e1c72e1SJason King static char		*lsc_blink;
3475e1c72e1SJason King static char		*lsc_reverse;
3485e1c72e1SJason King static char		*lsc_concealed;
3495e1c72e1SJason King static char		*lsc_none;
3505e1c72e1SJason King static char		*lsc_setfg;
3515e1c72e1SJason King static char		*lsc_setbg;
3525e1c72e1SJason King 
3537c478bd9Sstevel@tonic-gate #define	NOTWORKINGDIR(d, l)	(((l) < 2) || \
3547c478bd9Sstevel@tonic-gate 				    (strcmp((d) + (l) - 2, "/.") != 0))
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate #define	NOTPARENTDIR(d, l)	(((l) < 3) || \
3577c478bd9Sstevel@tonic-gate 				    (strcmp((d) + (l) - 3, "/..") != 0))
358da6c28aaSamw /* Extended system attributes support */
359da6c28aaSamw static int get_sysxattr(char *, struct lbuf *);
360da6c28aaSamw static void set_sysattrb_display(char *, boolean_t, struct lbuf *);
361da6c28aaSamw static void set_sysattrtm_display(char *, struct lbuf *);
3625e1c72e1SJason King static void format_time(time_t, time_t);
363da6c28aaSamw static void print_time(struct lbuf *);
364da6c28aaSamw static void format_attrtime(struct lbuf *);
365da6c28aaSamw static void *xmalloc(size_t, struct lbuf *);
366da6c28aaSamw static void free_sysattr(struct lbuf *);
367da6c28aaSamw static nvpair_t *pair;
368da6c28aaSamw static nvlist_t	*response;
36956798e90Sbasabi static int acl_err;
3707c478bd9Sstevel@tonic-gate 
3715e1c72e1SJason King const struct option long_options[] = {
3725e1c72e1SJason King 	{ "all", no_argument, NULL, 'a' },
3735e1c72e1SJason King 	{ "almost-all", no_argument, NULL, 'A' },
3745e1c72e1SJason King 	{ "escape", no_argument, NULL, 'b' },
3755e1c72e1SJason King 	{ "classify", no_argument, NULL, 'F' },
3765e1c72e1SJason King 	{ "human-readable", no_argument, NULL, 'h' },
3775e1c72e1SJason King 	{ "dereference", no_argument, NULL, 'L' },
3785e1c72e1SJason King 	{ "dereference-command-line", no_argument, NULL, 'H' },
3795e1c72e1SJason King 	{ "ignore-backups", no_argument, NULL, 'B' },
3805e1c72e1SJason King 	{ "inode", no_argument, NULL, 'i' },
3815e1c72e1SJason King 	{ "numeric-uid-gid", no_argument, NULL, 'n' },
3825e1c72e1SJason King 	{ "no-group", no_argument, NULL, 'o' },
3835e1c72e1SJason King 	{ "hide-control-chars", no_argument, NULL, 'q' },
3845e1c72e1SJason King 	{ "reverse", no_argument, NULL, 'r' },
3855e1c72e1SJason King 	{ "recursive", no_argument, NULL, 'R' },
3865e1c72e1SJason King 	{ "size", no_argument, NULL, 's' },
3875e1c72e1SJason King 	{ "width", required_argument, NULL, 'w' },
3885e1c72e1SJason King 
3895e1c72e1SJason King 	/* no short options for these */
3905e1c72e1SJason King 	{ "block-size", required_argument, NULL, 0 },
3915e1c72e1SJason King 	{ "full-time", no_argument, NULL, 0 },
3925e1c72e1SJason King 	{ "si", no_argument, NULL, 0 },
3935e1c72e1SJason King 	{ "color", optional_argument, NULL, 0 },
3945e1c72e1SJason King 	{ "colour", optional_argument, NULL, 0},
3955e1c72e1SJason King 	{ "file-type", no_argument, NULL, 0 },
3965e1c72e1SJason King 	{ "time-style", required_argument, NULL, 0 },
3975e1c72e1SJason King 
3985e1c72e1SJason King 	{0, 0, 0, 0}
3995e1c72e1SJason King };
4005e1c72e1SJason King 
4017c478bd9Sstevel@tonic-gate int
4027c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	int		c;
4057c478bd9Sstevel@tonic-gate 	int		i;
4067c478bd9Sstevel@tonic-gate 	int		width;
4077c478bd9Sstevel@tonic-gate 	int		amino = 0;
4087c478bd9Sstevel@tonic-gate 	int		opterr = 0;
4095e1c72e1SJason King 	int		option_index = 0;
4107c478bd9Sstevel@tonic-gate 	struct lbuf	*ep;
4117c478bd9Sstevel@tonic-gate 	struct lbuf	lb;
4127c478bd9Sstevel@tonic-gate 	struct ditem	*myinfo;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4157c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4167c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4197c478bd9Sstevel@tonic-gate #ifdef STANDALONE
4207c478bd9Sstevel@tonic-gate 	if (argv[0][0] == '\0')
4217c478bd9Sstevel@tonic-gate 		argc = getargv("ls", &argv, 0);
4227c478bd9Sstevel@tonic-gate #endif
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	lb.lmtime.tv_sec = time(NULL);
4257c478bd9Sstevel@tonic-gate 	lb.lmtime.tv_nsec = 0;
4267c478bd9Sstevel@tonic-gate 	year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */
4277c478bd9Sstevel@tonic-gate 	now = lb.lmtime.tv_sec + 60;
4287c478bd9Sstevel@tonic-gate 	if (isatty(1)) {
4297c478bd9Sstevel@tonic-gate 		Cflg = 1;
4307c478bd9Sstevel@tonic-gate 		mflg = 0;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4335e1c72e1SJason King 	while ((c = getopt_long(argc, argv,
4345e1c72e1SJason King 	    "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options,
4355e1c72e1SJason King 	    &option_index)) != -1)
4367c478bd9Sstevel@tonic-gate 		switch (c) {
4375e1c72e1SJason King 		case 0:
4385e1c72e1SJason King 			/* non-short options */
4395e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4405e1c72e1SJason King 			    "color") == 0 ||
4415e1c72e1SJason King 			    strcmp(long_options[option_index].name,
4425e1c72e1SJason King 			    "colour") == 0) {
4435e1c72e1SJason King 				if (optarg == NULL ||
4445e1c72e1SJason King 				    strcmp(optarg, "always") == 0 ||
4455e1c72e1SJason King 				    strcmp(optarg, "yes") == 0 ||
4465e1c72e1SJason King 				    strcmp(optarg, "force") == 0) {
4475e1c72e1SJason King 					colorflg++;
4485e1c72e1SJason King 					statreq++;
4495e1c72e1SJason King 					continue;
4505e1c72e1SJason King 				}
4515e1c72e1SJason King 
4525e1c72e1SJason King 				if ((strcmp(optarg, "auto") == 0 ||
4535e1c72e1SJason King 				    strcmp(optarg, "tty") == 0 ||
4545e1c72e1SJason King 				    strcmp(optarg, "if-tty") == 0) &&
4555e1c72e1SJason King 				    isatty(1) == 1) {
4565e1c72e1SJason King 					colorflg++;
4575e1c72e1SJason King 					statreq++;
4585e1c72e1SJason King 					continue;
4595e1c72e1SJason King 				}
4605e1c72e1SJason King 
4615e1c72e1SJason King 				if (strcmp(optarg, "never") == 0 ||
4625e1c72e1SJason King 				    strcmp(optarg, "no") == 0 ||
4635e1c72e1SJason King 				    strcmp(optarg, "none") == 0) {
4645e1c72e1SJason King 					colorflg = 0;
4655e1c72e1SJason King 					continue;
4665e1c72e1SJason King 				}
4675e1c72e1SJason King 				(void) fprintf(stderr,
4685e1c72e1SJason King 				    gettext("Invalid argument '%s' for "
4695e1c72e1SJason King 				    "--color\n"), optarg);
4705e1c72e1SJason King 				++opterr;
4715e1c72e1SJason King 				continue;
4725e1c72e1SJason King 			}
4735e1c72e1SJason King 
4745e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4755e1c72e1SJason King 			    "si") == 0) {
4765e1c72e1SJason King 				hflg++;
4775e1c72e1SJason King 				hscale = 1000;
4785e1c72e1SJason King 				continue;
4795e1c72e1SJason King 			}
4805e1c72e1SJason King 
4815e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4825e1c72e1SJason King 			    "block-size") == 0) {
4835e1c72e1SJason King 				size_t scale_len = strlen(optarg);
4845e1c72e1SJason King 				uint64_t scale = 1;
4855e1c72e1SJason King 				uint64_t kilo = 1024;
4865e1c72e1SJason King 				char scale_c;
4875e1c72e1SJason King 
4885e1c72e1SJason King 				if (scale_len == 0) {
4895e1c72e1SJason King 					(void) fprintf(stderr, gettext(
4905e1c72e1SJason King 					    "Invalid block size \'%s\'\n"),
4915e1c72e1SJason King 					    optarg);
4925e1c72e1SJason King 					exit(1);
4935e1c72e1SJason King 				}
4945e1c72e1SJason King 
4955e1c72e1SJason King 				scale_c = optarg[scale_len - 1];
4965e1c72e1SJason King 				if (scale_c == 'B') {
4975e1c72e1SJason King 					/* need at least digit, scale, B */
4985e1c72e1SJason King 					if (scale_len < 3) {
4995e1c72e1SJason King 						(void) fprintf(stderr, gettext(
5005e1c72e1SJason King 						    "Invalid block size "
5015e1c72e1SJason King 						    "\'%s\'\n"), optarg);
5025e1c72e1SJason King 						exit(1);
5035e1c72e1SJason King 					}
5045e1c72e1SJason King 					kilo = 1000;
5055e1c72e1SJason King 					scale_c = optarg[scale_len - 2];
5065e1c72e1SJason King 					if (isdigit(scale_c)) {
5075e1c72e1SJason King 						(void) fprintf(stderr,
5085e1c72e1SJason King 						    gettext("Invalid block size"
5095e1c72e1SJason King 						    " \'%s\'\n"), optarg);
5105e1c72e1SJason King 						exit(1);
5115e1c72e1SJason King 					}
5125e1c72e1SJason King 					/*
5135e1c72e1SJason King 					 * make optarg[scale_len - 1] point to
5145e1c72e1SJason King 					 * the scale factor
5155e1c72e1SJason King 					 */
5165e1c72e1SJason King 					--scale_len;
5175e1c72e1SJason King 				}
5185e1c72e1SJason King 
5195e1c72e1SJason King 				switch (scale_c) {
5205e1c72e1SJason King 				case 'y':
5215e1c72e1SJason King 				case 'Y':
5225e1c72e1SJason King 					scale *= kilo;
5235e1c72e1SJason King 					/*FALLTHROUGH*/
5245e1c72e1SJason King 				case 'Z':
5255e1c72e1SJason King 				case 'z':
5265e1c72e1SJason King 					scale *= kilo;
5275e1c72e1SJason King 					/*FALLTHROUGH*/
5285e1c72e1SJason King 				case 'E':
5295e1c72e1SJason King 				case 'e':
5305e1c72e1SJason King 					scale *= kilo;
5315e1c72e1SJason King 					/*FALLTHROUGH*/
5325e1c72e1SJason King 				case 'P':
5335e1c72e1SJason King 				case 'p':
5345e1c72e1SJason King 					scale *= kilo;
5355e1c72e1SJason King 					/*FALLTHROUGH*/
5365e1c72e1SJason King 				case 'T':
5375e1c72e1SJason King 				case 't':
5385e1c72e1SJason King 					scale *= kilo;
5395e1c72e1SJason King 					/*FALLTHROUGH*/
5405e1c72e1SJason King 				case 'G':
5415e1c72e1SJason King 				case 'g':
5425e1c72e1SJason King 					scale *= kilo;
5435e1c72e1SJason King 					/*FALLTHROUGH*/
5445e1c72e1SJason King 				case 'M':
5455e1c72e1SJason King 				case 'm':
5465e1c72e1SJason King 					scale *= kilo;
5475e1c72e1SJason King 					/*FALLTHROUGH*/
5485e1c72e1SJason King 				case 'K':
5495e1c72e1SJason King 				case 'k':
5505e1c72e1SJason King 					scale *= kilo;
5515e1c72e1SJason King 					break;
5525e1c72e1SJason King 				default:
5535e1c72e1SJason King 					if (!isdigit(scale_c)) {
5545e1c72e1SJason King 						(void) fprintf(stderr,
5555e1c72e1SJason King 						    gettext("Invalid character "
5565e1c72e1SJason King 						    "following block size in "
5575e1c72e1SJason King 						    "\'%s\'\n"), optarg);
5585e1c72e1SJason King 						exit(1);
5595e1c72e1SJason King 					}
5605e1c72e1SJason King 				}
5615e1c72e1SJason King 
5625e1c72e1SJason King 				/* NULL out scale constant if present */
5635e1c72e1SJason King 				if (scale > 1 && !isdigit(scale_c))
5645e1c72e1SJason King 					optarg[scale_len - 1] = '\0';
5655e1c72e1SJason King 
5665e1c72e1SJason King 				/* Based on testing, this is what GNU ls does */
5675e1c72e1SJason King 				block_size = strtoll(optarg, NULL, 0) * scale;
5685e1c72e1SJason King 				if (block_size < 1) {
5695e1c72e1SJason King 					(void) fprintf(stderr,
5705e1c72e1SJason King 					    gettext("Invalid block size "
5715e1c72e1SJason King 					    "\'%s\'\n"), optarg);
5725e1c72e1SJason King 					exit(1);
5735e1c72e1SJason King 				}
5745e1c72e1SJason King 				continue;
5755e1c72e1SJason King 			}
5765e1c72e1SJason King 
5775e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5785e1c72e1SJason King 			    "file-type") == 0) {
5795e1c72e1SJason King 				file_typeflg++;
5805e1c72e1SJason King 				Fflg++;
5815e1c72e1SJason King 				statreq++;
5825e1c72e1SJason King 				continue;
5835e1c72e1SJason King 			}
5845e1c72e1SJason King 
5855e1c72e1SJason King 
5865e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5875e1c72e1SJason King 			    "full-time") == 0) {
5885e1c72e1SJason King 				Eflg++;
5895e1c72e1SJason King 				statreq++;
5905e1c72e1SJason King 				eflg = 0;
5915e1c72e1SJason King 				time_fmt_old = FORMAT_ISO_FULL;
5925e1c72e1SJason King 				time_fmt_new = FORMAT_ISO_FULL;
5935e1c72e1SJason King 				continue;
5945e1c72e1SJason King 			}
5955e1c72e1SJason King 
5965e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5975e1c72e1SJason King 			    "time-style") == 0) {
5985e1c72e1SJason King 				/* like -E, but doesn't imply -l */
5995e1c72e1SJason King 				if (strcmp(optarg, "full-iso") == 0) {
6005e1c72e1SJason King 					Eflg++;
6015e1c72e1SJason King 					statreq++;
6025e1c72e1SJason King 					eflg = 0;
6035e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_FULL;
6045e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_FULL;
6055e1c72e1SJason King 					continue;
6065e1c72e1SJason King 				}
6075e1c72e1SJason King 				if (strcmp(optarg, "long-iso") == 0) {
6085e1c72e1SJason King 					statreq++;
6095e1c72e1SJason King 					Eflg = 0;
6105e1c72e1SJason King 					eflg = 0;
6115e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_LONG;
6125e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_LONG;
6135e1c72e1SJason King 					continue;
6145e1c72e1SJason King 				}
6155e1c72e1SJason King 				if (strcmp(optarg, "iso") == 0) {
6165e1c72e1SJason King 					statreq++;
6175e1c72e1SJason King 					Eflg = 0;
6185e1c72e1SJason King 					eflg = 0;
6195e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_OLD;
6205e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_NEW;
6215e1c72e1SJason King 					continue;
6225e1c72e1SJason King 				}
6235e1c72e1SJason King 				/* should be the default */
6245e1c72e1SJason King 				if (strcmp(optarg, "locale") == 0) {
6255e1c72e1SJason King 					time_fmt_old = FORMAT_OLD;
6265e1c72e1SJason King 					time_fmt_new = FORMAT_NEW;
6275e1c72e1SJason King 					continue;
6285e1c72e1SJason King 				}
6295e1c72e1SJason King 				if (optarg[0] == '+') {
6305e1c72e1SJason King 					char	*told, *tnew;
6315e1c72e1SJason King 					char	*p;
6325e1c72e1SJason King 					size_t	timelen = strlen(optarg);
6335e1c72e1SJason King 
6345e1c72e1SJason King 					p = strchr(optarg, '\n');
6355e1c72e1SJason King 					if (p != NULL)
6365e1c72e1SJason King 						*p++ = '\0';
6375e1c72e1SJason King 
6385e1c72e1SJason King 					/*
6395e1c72e1SJason King 					 * Time format requires a leading and
6405e1c72e1SJason King 					 * trailing space
6415e1c72e1SJason King 					 * Add room for 3 spaces + 2 nulls
6425e1c72e1SJason King 					 * The + in optarg is replaced with
6435e1c72e1SJason King 					 * a space.
6445e1c72e1SJason King 					 */
6455e1c72e1SJason King 					timelen += 2 + 3;
6465e1c72e1SJason King 					told = malloc(timelen);
6475e1c72e1SJason King 					if (told == NULL) {
6485e1c72e1SJason King 						perror("Out of memory");
6495e1c72e1SJason King 						exit(1);
6505e1c72e1SJason King 					}
6515e1c72e1SJason King 
6525e1c72e1SJason King 					(void) memset(told, 0, timelen);
6535e1c72e1SJason King 					told[0] = ' ';
6545e1c72e1SJason King 					(void) strlcat(told, &optarg[1],
6555e1c72e1SJason King 					    timelen);
6565e1c72e1SJason King 					(void) strlcat(told, " ", timelen);
6575e1c72e1SJason King 
6585e1c72e1SJason King 					if (p != NULL) {
6595e1c72e1SJason King 						size_t tnew_len;
6605e1c72e1SJason King 
6615e1c72e1SJason King 						tnew = told + strlen(told) + 1;
6625e1c72e1SJason King 						tnew_len = timelen -
6635e1c72e1SJason King 						    strlen(told) - 1;
6645e1c72e1SJason King 
6655e1c72e1SJason King 						tnew[0] = ' ';
6665e1c72e1SJason King 						(void) strlcat(tnew, p,
6675e1c72e1SJason King 						    tnew_len);
6685e1c72e1SJason King 						(void) strlcat(tnew, " ",
6695e1c72e1SJason King 						    tnew_len);
6705e1c72e1SJason King 						time_fmt_new =
6715e1c72e1SJason King 						    (const char *)tnew;
6725e1c72e1SJason King 					} else {
6735e1c72e1SJason King 						time_fmt_new =
6745e1c72e1SJason King 						    (const char *)told;
6755e1c72e1SJason King 					}
6765e1c72e1SJason King 
6775e1c72e1SJason King 					time_fmt_old = (const char *)told;
6785e1c72e1SJason King 					time_custom = 1;
6795e1c72e1SJason King 					continue;
6805e1c72e1SJason King 				}
6815e1c72e1SJason King 				continue;
6825e1c72e1SJason King 			}
6835e1c72e1SJason King 
6845e1c72e1SJason King 			continue;
6855e1c72e1SJason King 
6867c478bd9Sstevel@tonic-gate 		case 'a':
6877c478bd9Sstevel@tonic-gate 			aflg++;
6887c478bd9Sstevel@tonic-gate 			continue;
6897c478bd9Sstevel@tonic-gate 		case 'A':
6907c478bd9Sstevel@tonic-gate 			Aflg++;
6917c478bd9Sstevel@tonic-gate 			continue;
6927c478bd9Sstevel@tonic-gate 		case 'b':
6937c478bd9Sstevel@tonic-gate 			bflg = 1;
6947c478bd9Sstevel@tonic-gate 			qflg = 0;
6957c478bd9Sstevel@tonic-gate 			continue;
6965e1c72e1SJason King 		case 'B':
6975e1c72e1SJason King 			Bflg = 1;
6985e1c72e1SJason King 			continue;
6997c478bd9Sstevel@tonic-gate 		case 'c':
7007c478bd9Sstevel@tonic-gate 			uflg = 0;
701da6c28aaSamw 			atm = 0;
702da6c28aaSamw 			ctm = 0;
703da6c28aaSamw 			mtm = 0;
704da6c28aaSamw 			crtm = 0;
7057c478bd9Sstevel@tonic-gate 			cflg++;
7067c478bd9Sstevel@tonic-gate 			continue;
7077c478bd9Sstevel@tonic-gate 		case 'C':
7087c478bd9Sstevel@tonic-gate 			Cflg = 1;
7097c478bd9Sstevel@tonic-gate 			mflg = 0;
7107c478bd9Sstevel@tonic-gate #ifdef XPG4
7117c478bd9Sstevel@tonic-gate 			lflg = 0;
7127c478bd9Sstevel@tonic-gate #endif
7137c478bd9Sstevel@tonic-gate 			continue;
7147c478bd9Sstevel@tonic-gate 		case 'd':
7157c478bd9Sstevel@tonic-gate 			dflg++;
7167c478bd9Sstevel@tonic-gate 			continue;
7177c478bd9Sstevel@tonic-gate 		case 'e':
7187c478bd9Sstevel@tonic-gate 			eflg++;
7197c478bd9Sstevel@tonic-gate 			lflg++;
7207c478bd9Sstevel@tonic-gate 			statreq++;
7217c478bd9Sstevel@tonic-gate 			Eflg = 0;
7225e1c72e1SJason King 			time_fmt_old = FORMAT_LONG;
7235e1c72e1SJason King 			time_fmt_new = FORMAT_LONG;
7247c478bd9Sstevel@tonic-gate 			continue;
7257c478bd9Sstevel@tonic-gate 		case 'E':
7267c478bd9Sstevel@tonic-gate 			Eflg++;
7277c478bd9Sstevel@tonic-gate 			lflg++;
7287c478bd9Sstevel@tonic-gate 			statreq++;
7297c478bd9Sstevel@tonic-gate 			eflg = 0;
7305e1c72e1SJason King 			time_fmt_old = FORMAT_ISO_FULL;
7315e1c72e1SJason King 			time_fmt_new = FORMAT_ISO_FULL;
7327c478bd9Sstevel@tonic-gate 			continue;
7337c478bd9Sstevel@tonic-gate 		case 'f':
7347c478bd9Sstevel@tonic-gate 			fflg++;
7357c478bd9Sstevel@tonic-gate 			continue;
7367c478bd9Sstevel@tonic-gate 		case 'F':
7377c478bd9Sstevel@tonic-gate 			Fflg++;
7387c478bd9Sstevel@tonic-gate 			statreq++;
7397c478bd9Sstevel@tonic-gate 			continue;
7407c478bd9Sstevel@tonic-gate 		case 'g':
7417c478bd9Sstevel@tonic-gate 			gflg++;
7427c478bd9Sstevel@tonic-gate 			lflg++;
7437c478bd9Sstevel@tonic-gate 			statreq++;
7447c478bd9Sstevel@tonic-gate 			continue;
7457c478bd9Sstevel@tonic-gate 		case 'h':
7467c478bd9Sstevel@tonic-gate 			hflg++;
7477c478bd9Sstevel@tonic-gate 			hscale = 1024;
7487c478bd9Sstevel@tonic-gate 			continue;
7497c478bd9Sstevel@tonic-gate 		case 'H':
7507c478bd9Sstevel@tonic-gate 			Hflg++;
7517c478bd9Sstevel@tonic-gate 			/* -H and -L are mutually exclusive */
7527c478bd9Sstevel@tonic-gate 			Lflg = 0;
7537c478bd9Sstevel@tonic-gate 			continue;
7547c478bd9Sstevel@tonic-gate 		case 'i':
7557c478bd9Sstevel@tonic-gate 			iflg++;
7567c478bd9Sstevel@tonic-gate 			continue;
7575e1c72e1SJason King 		case 'k':
7585e1c72e1SJason King 			block_size = 1024;
7595e1c72e1SJason King 			continue;
7607c478bd9Sstevel@tonic-gate 		case 'l':
7617c478bd9Sstevel@tonic-gate 			lflg++;
7627c478bd9Sstevel@tonic-gate 			statreq++;
7637c478bd9Sstevel@tonic-gate 			Cflg = 0;
7647c478bd9Sstevel@tonic-gate 			xflg = 0;
7657c478bd9Sstevel@tonic-gate 			mflg = 0;
7667c478bd9Sstevel@tonic-gate 			atflg = 0;
7677c478bd9Sstevel@tonic-gate 			continue;
7687c478bd9Sstevel@tonic-gate 		case 'L':
7697c478bd9Sstevel@tonic-gate 			Lflg++;
7707c478bd9Sstevel@tonic-gate 			/* -H and -L are mutually exclusive */
7717c478bd9Sstevel@tonic-gate 			Hflg = 0;
7727c478bd9Sstevel@tonic-gate 			continue;
7737c478bd9Sstevel@tonic-gate 		case 'm':
7747c478bd9Sstevel@tonic-gate 			Cflg = 0;
7757c478bd9Sstevel@tonic-gate 			mflg = 1;
7767c478bd9Sstevel@tonic-gate #ifdef XPG4
7777c478bd9Sstevel@tonic-gate 			lflg = 0;
7787c478bd9Sstevel@tonic-gate #endif
7797c478bd9Sstevel@tonic-gate 			continue;
7807c478bd9Sstevel@tonic-gate 		case 'n':
7817c478bd9Sstevel@tonic-gate 			nflg++;
7827c478bd9Sstevel@tonic-gate 			lflg++;
7837c478bd9Sstevel@tonic-gate 			statreq++;
7847c478bd9Sstevel@tonic-gate 			Cflg = 0;
7857c478bd9Sstevel@tonic-gate 			xflg = 0;
7867c478bd9Sstevel@tonic-gate 			mflg = 0;
7877c478bd9Sstevel@tonic-gate 			atflg = 0;
7887c478bd9Sstevel@tonic-gate 			continue;
7897c478bd9Sstevel@tonic-gate 		case 'o':
7907c478bd9Sstevel@tonic-gate 			oflg++;
7917c478bd9Sstevel@tonic-gate 			lflg++;
7927c478bd9Sstevel@tonic-gate 			statreq++;
7937c478bd9Sstevel@tonic-gate 			continue;
7947c478bd9Sstevel@tonic-gate 		case 'p':
7957c478bd9Sstevel@tonic-gate 			pflg++;
7967c478bd9Sstevel@tonic-gate 			statreq++;
7977c478bd9Sstevel@tonic-gate 			continue;
7987c478bd9Sstevel@tonic-gate 		case 'q':
7997c478bd9Sstevel@tonic-gate 			qflg = 1;
8007c478bd9Sstevel@tonic-gate 			bflg = 0;
8017c478bd9Sstevel@tonic-gate 			continue;
8027c478bd9Sstevel@tonic-gate 		case 'r':
8037c478bd9Sstevel@tonic-gate 			rflg = -1;
8047c478bd9Sstevel@tonic-gate 			continue;
8057c478bd9Sstevel@tonic-gate 		case 'R':
8067c478bd9Sstevel@tonic-gate 			Rflg++;
8077c478bd9Sstevel@tonic-gate 			statreq++;
8087c478bd9Sstevel@tonic-gate 			continue;
8097c478bd9Sstevel@tonic-gate 		case 's':
8107c478bd9Sstevel@tonic-gate 			sflg++;
8117c478bd9Sstevel@tonic-gate 			statreq++;
8127c478bd9Sstevel@tonic-gate 			continue;
8137c478bd9Sstevel@tonic-gate 		case 'S':
8147c478bd9Sstevel@tonic-gate 			tflg = 0;
8155e1c72e1SJason King 			Uflg = 0;
8167c478bd9Sstevel@tonic-gate 			Sflg++;
8177c478bd9Sstevel@tonic-gate 			statreq++;
8187c478bd9Sstevel@tonic-gate 			continue;
8197c478bd9Sstevel@tonic-gate 		case 't':
8207c478bd9Sstevel@tonic-gate 			Sflg = 0;
8215e1c72e1SJason King 			Uflg = 0;
8227c478bd9Sstevel@tonic-gate 			tflg++;
8237c478bd9Sstevel@tonic-gate 			statreq++;
8247c478bd9Sstevel@tonic-gate 			continue;
8255e1c72e1SJason King 		case 'U':
8265e1c72e1SJason King 			Sflg = 0;
8275e1c72e1SJason King 			tflg = 0;
8285e1c72e1SJason King 			Uflg++;
8295e1c72e1SJason King 			continue;
8307c478bd9Sstevel@tonic-gate 		case 'u':
8317c478bd9Sstevel@tonic-gate 			cflg = 0;
832da6c28aaSamw 			atm = 0;
833da6c28aaSamw 			ctm = 0;
834da6c28aaSamw 			mtm = 0;
835da6c28aaSamw 			crtm = 0;
8367c478bd9Sstevel@tonic-gate 			uflg++;
8377c478bd9Sstevel@tonic-gate 			continue;
8385a5eeccaSmarks 		case 'V':
8395a5eeccaSmarks 			Vflg++;
8405a5eeccaSmarks 			/*FALLTHROUGH*/
841fa9e4066Sahrens 		case 'v':
842fa9e4066Sahrens 			vflg++;
843fa9e4066Sahrens #if !defined(XPG4)
844fa9e4066Sahrens 			if (lflg)
845fa9e4066Sahrens 				continue;
846fa9e4066Sahrens #endif
847fa9e4066Sahrens 			lflg++;
848fa9e4066Sahrens 			statreq++;
849fa9e4066Sahrens 			Cflg = 0;
850fa9e4066Sahrens 			xflg = 0;
851fa9e4066Sahrens 			mflg = 0;
852fa9e4066Sahrens 			continue;
8535e1c72e1SJason King 		case 'w':
8545e1c72e1SJason King 			wflg++;
8555e1c72e1SJason King 			num_cols = atoi(optarg);
8565e1c72e1SJason King 			continue;
8577c478bd9Sstevel@tonic-gate 		case 'x':
8587c478bd9Sstevel@tonic-gate 			xflg = 1;
8597c478bd9Sstevel@tonic-gate 			Cflg = 1;
8607c478bd9Sstevel@tonic-gate 			mflg = 0;
8617c478bd9Sstevel@tonic-gate #ifdef XPG4
8627c478bd9Sstevel@tonic-gate 			lflg = 0;
8637c478bd9Sstevel@tonic-gate #endif
8647c478bd9Sstevel@tonic-gate 			continue;
8657c478bd9Sstevel@tonic-gate 		case '1':
8667c478bd9Sstevel@tonic-gate 			Cflg = 0;
8677c478bd9Sstevel@tonic-gate 			continue;
8687c478bd9Sstevel@tonic-gate 		case '@':
8697c478bd9Sstevel@tonic-gate #if !defined(XPG4)
8707c478bd9Sstevel@tonic-gate 			/*
8717c478bd9Sstevel@tonic-gate 			 * -l has precedence over -@
8727c478bd9Sstevel@tonic-gate 			 */
8737c478bd9Sstevel@tonic-gate 			if (lflg)
8747c478bd9Sstevel@tonic-gate 				continue;
8757c478bd9Sstevel@tonic-gate #endif
8767c478bd9Sstevel@tonic-gate 			atflg++;
8777c478bd9Sstevel@tonic-gate 			lflg++;
8787c478bd9Sstevel@tonic-gate 			statreq++;
8797c478bd9Sstevel@tonic-gate 			Cflg = 0;
8807c478bd9Sstevel@tonic-gate 			xflg = 0;
8817c478bd9Sstevel@tonic-gate 			mflg = 0;
8827c478bd9Sstevel@tonic-gate 			continue;
883da6c28aaSamw 		case '/':
884da6c28aaSamw 			saflg++;
885da6c28aaSamw 			if (optarg != NULL) {
886da6c28aaSamw 				if (strcmp(optarg, "c") == 0) {
887da6c28aaSamw 					copt++;
888da6c28aaSamw 					vopt = 0;
889da6c28aaSamw 				} else if (strcmp(optarg, "v") == 0) {
890da6c28aaSamw 					vopt++;
891da6c28aaSamw 					copt = 0;
892da6c28aaSamw 				} else
893da6c28aaSamw 					opterr++;
894da6c28aaSamw 			} else
895da6c28aaSamw 				opterr++;
896da6c28aaSamw 			lflg++;
897da6c28aaSamw 			statreq++;
898da6c28aaSamw 			Cflg = 0;
899da6c28aaSamw 			xflg = 0;
900da6c28aaSamw 			mflg = 0;
901da6c28aaSamw 			continue;
902da6c28aaSamw 		case '%':
903da6c28aaSamw 			tmflg++;
904da6c28aaSamw 			if (optarg != NULL) {
905da6c28aaSamw 				if (strcmp(optarg, "ctime") == 0) {
906da6c28aaSamw 					ctm++;
907da6c28aaSamw 					atm = 0;
908da6c28aaSamw 					mtm = 0;
909da6c28aaSamw 					crtm = 0;
910da6c28aaSamw 				} else if (strcmp(optarg, "atime") == 0) {
911da6c28aaSamw 					atm++;
912da6c28aaSamw 					ctm = 0;
913da6c28aaSamw 					mtm = 0;
914da6c28aaSamw 					crtm = 0;
915da6c28aaSamw 					uflg = 0;
916da6c28aaSamw 					cflg = 0;
917da6c28aaSamw 				} else if (strcmp(optarg, "mtime") == 0) {
918da6c28aaSamw 					mtm++;
919da6c28aaSamw 					atm = 0;
920da6c28aaSamw 					ctm = 0;
921da6c28aaSamw 					crtm = 0;
922da6c28aaSamw 					uflg = 0;
923da6c28aaSamw 					cflg = 0;
924da6c28aaSamw 				} else if (strcmp(optarg, "crtime") == 0) {
925da6c28aaSamw 					crtm++;
926da6c28aaSamw 					atm = 0;
927da6c28aaSamw 					ctm = 0;
928da6c28aaSamw 					mtm = 0;
929da6c28aaSamw 					uflg = 0;
930da6c28aaSamw 					cflg = 0;
931da6c28aaSamw 				} else if (strcmp(optarg, "all") == 0) {
932da6c28aaSamw 					alltm++;
933da6c28aaSamw 					atm = 0;
934da6c28aaSamw 					ctm = 0;
935da6c28aaSamw 					mtm = 0;
936da6c28aaSamw 					crtm = 0;
937da6c28aaSamw 				} else
938da6c28aaSamw 					opterr++;
939da6c28aaSamw 			} else
940da6c28aaSamw 				opterr++;
941da6c28aaSamw 
942da6c28aaSamw 			Sflg = 0;
943da6c28aaSamw 			statreq++;
944da6c28aaSamw 			mflg = 0;
945da6c28aaSamw 			continue;
9467c478bd9Sstevel@tonic-gate 		case '?':
9477c478bd9Sstevel@tonic-gate 			opterr++;
9487c478bd9Sstevel@tonic-gate 			continue;
9497c478bd9Sstevel@tonic-gate 		}
9505e1c72e1SJason King 
9517c478bd9Sstevel@tonic-gate 	if (opterr) {
9527c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9535e1c72e1SJason King 		    "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]"
954da6c28aaSamw 		    "%%[atime | crtime | ctime | mtime | all]"
955da6c28aaSamw 		    " [files]\n"));
9567c478bd9Sstevel@tonic-gate 		exit(2);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (fflg) {
9607c478bd9Sstevel@tonic-gate 		aflg++;
9617c478bd9Sstevel@tonic-gate 		lflg = 0;
9627c478bd9Sstevel@tonic-gate 		sflg = 0;
9637c478bd9Sstevel@tonic-gate 		tflg = 0;
9647c478bd9Sstevel@tonic-gate 		Sflg = 0;
9657c478bd9Sstevel@tonic-gate 		statreq = 0;
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	fixedwidth = 2;
9697c478bd9Sstevel@tonic-gate 	if (pflg || Fflg)
9707c478bd9Sstevel@tonic-gate 		fixedwidth++;
9717c478bd9Sstevel@tonic-gate 	if (iflg)
9727c478bd9Sstevel@tonic-gate 		fixedwidth += 11;
9737c478bd9Sstevel@tonic-gate 	if (sflg)
9747c478bd9Sstevel@tonic-gate 		fixedwidth += 5;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if (lflg) {
9777c478bd9Sstevel@tonic-gate 		if (!gflg && !oflg)
9787c478bd9Sstevel@tonic-gate 			gflg = oflg = 1;
9797c478bd9Sstevel@tonic-gate 		else
9807c478bd9Sstevel@tonic-gate 		if (gflg && oflg)
9817c478bd9Sstevel@tonic-gate 			gflg = oflg = 0;
9827c478bd9Sstevel@tonic-gate 		Cflg = mflg = 0;
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9855e1c72e1SJason King 	if (!wflg && (Cflg || mflg)) {
9867c478bd9Sstevel@tonic-gate 		char *clptr;
9877c478bd9Sstevel@tonic-gate 		if ((clptr = getenv("COLUMNS")) != NULL)
9887c478bd9Sstevel@tonic-gate 			num_cols = atoi(clptr);
9897c478bd9Sstevel@tonic-gate #ifdef TERMINFO
9907c478bd9Sstevel@tonic-gate 		else {
9917c478bd9Sstevel@tonic-gate 			if (ioctl(1, TIOCGWINSZ, &win) != -1)
9927c478bd9Sstevel@tonic-gate 				num_cols = (win.ws_col == 0 ? 80 : win.ws_col);
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate #endif
9955e1c72e1SJason King 	}
9965e1c72e1SJason King 
9977c478bd9Sstevel@tonic-gate 	if (num_cols < 20 || num_cols > 1000)
9987c478bd9Sstevel@tonic-gate 		/* assume it is an error */
9997c478bd9Sstevel@tonic-gate 		num_cols = 80;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	/* allocate space for flist and the associated	*/
10027c478bd9Sstevel@tonic-gate 	/* data structures (lbufs)			*/
10037c478bd9Sstevel@tonic-gate 	maxfils = quantn;
10047c478bd9Sstevel@tonic-gate 	if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) ||
10057c478bd9Sstevel@tonic-gate 	    ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) {
10067c478bd9Sstevel@tonic-gate 		perror("ls");
10077c478bd9Sstevel@tonic-gate 		exit(2);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 	if ((amino = (argc-optind)) == 0) {
10107c478bd9Sstevel@tonic-gate 					/*
10117c478bd9Sstevel@tonic-gate 					 * case when no names are given
10127c478bd9Sstevel@tonic-gate 					 * in ls-command and current
10137c478bd9Sstevel@tonic-gate 					 * directory is to be used
10147c478bd9Sstevel@tonic-gate 					 */
10157c478bd9Sstevel@tonic-gate 		argv[optind] = dotp;
10167c478bd9Sstevel@tonic-gate 	}
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	for (i = 0; i < (amino ? amino : 1); i++) {
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		/*
10217c478bd9Sstevel@tonic-gate 		 * If we are recursing, we need to make sure we don't
10227c478bd9Sstevel@tonic-gate 		 * get into an endless loop.  To keep track of the inodes
10237c478bd9Sstevel@tonic-gate 		 * (actually, just the directories) visited, we
10247c478bd9Sstevel@tonic-gate 		 * maintain a directory ancestry list for a file
10257c478bd9Sstevel@tonic-gate 		 * hierarchy.  As we go deeper into the hierarchy,
10267c478bd9Sstevel@tonic-gate 		 * a parent directory passes its directory list
10277c478bd9Sstevel@tonic-gate 		 * info (device id, inode number, and a pointer to
10287c478bd9Sstevel@tonic-gate 		 * its parent) to each of its children.  As we
10297c478bd9Sstevel@tonic-gate 		 * process a child that is a directory, we save
10307c478bd9Sstevel@tonic-gate 		 * its own personal directory list info.  We then
10317c478bd9Sstevel@tonic-gate 		 * check to see if the child has already been
10327c478bd9Sstevel@tonic-gate 		 * processed by comparing its device id and inode
10337c478bd9Sstevel@tonic-gate 		 * number from its own personal directory list info
10347c478bd9Sstevel@tonic-gate 		 * to that of each of its ancestors.  If there is a
10357c478bd9Sstevel@tonic-gate 		 * match, then we know we've detected a cycle.
10367c478bd9Sstevel@tonic-gate 		 */
10377c478bd9Sstevel@tonic-gate 		if (Rflg) {
10387c478bd9Sstevel@tonic-gate 			/*
10397c478bd9Sstevel@tonic-gate 			 * This is the first parent in this lineage
10407c478bd9Sstevel@tonic-gate 			 * (first in a directory hierarchy), so
10417c478bd9Sstevel@tonic-gate 			 * this parent's parent doesn't exist.  We
10427c478bd9Sstevel@tonic-gate 			 * only initialize myinfo when we are
10437c478bd9Sstevel@tonic-gate 			 * recursing, otherwise it's not used.
10447c478bd9Sstevel@tonic-gate 			 */
10457c478bd9Sstevel@tonic-gate 			if ((myinfo = (struct ditem *)malloc(
10467c478bd9Sstevel@tonic-gate 			    sizeof (struct ditem))) == NULL) {
10477c478bd9Sstevel@tonic-gate 				perror("ls");
10487c478bd9Sstevel@tonic-gate 				exit(2);
10497c478bd9Sstevel@tonic-gate 			} else {
10507c478bd9Sstevel@tonic-gate 				myinfo->dev = 0;
10517c478bd9Sstevel@tonic-gate 				myinfo->ino = 0;
10527c478bd9Sstevel@tonic-gate 				myinfo->parent = NULL;
10537c478bd9Sstevel@tonic-gate 			}
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 		if (Cflg || mflg) {
10577c478bd9Sstevel@tonic-gate 			width = strcol((unsigned char *)argv[optind]);
10587c478bd9Sstevel@tonic-gate 			if (width > filewidth)
10597c478bd9Sstevel@tonic-gate 				filewidth = width;
10607c478bd9Sstevel@tonic-gate 		}
10617c478bd9Sstevel@tonic-gate 		if ((ep = gstat((*argv[optind] ? argv[optind] : dotp),
10627c478bd9Sstevel@tonic-gate 		    1, myinfo)) == NULL) {
10637c478bd9Sstevel@tonic-gate 			if (nomocore)
10647c478bd9Sstevel@tonic-gate 				exit(2);
10657c478bd9Sstevel@tonic-gate 			err = 2;
10667c478bd9Sstevel@tonic-gate 			optind++;
10677c478bd9Sstevel@tonic-gate 			continue;
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 		ep->ln.namep = (*argv[optind] ? argv[optind] : dotp);
10707c478bd9Sstevel@tonic-gate 		ep->lflags |= ISARG;
10717c478bd9Sstevel@tonic-gate 		optind++;
10727c478bd9Sstevel@tonic-gate 		nargs++;	/* count good arguments stored in flist */
107356798e90Sbasabi 		if (acl_err)
107456798e90Sbasabi 			err = 2;
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 	colwidth = fixedwidth + filewidth;
10775e1c72e1SJason King 	if (!Uflg)
10787c478bd9Sstevel@tonic-gate 		qsort(flist, (unsigned)nargs, sizeof (struct lbuf *),
10797c478bd9Sstevel@tonic-gate 		    (int (*)(const void *, const void *))compar);
10807c478bd9Sstevel@tonic-gate 	for (i = 0; i < nargs; i++) {
10817c478bd9Sstevel@tonic-gate 		if (flist[i]->ltype == 'd' && dflg == 0 || fflg)
10827c478bd9Sstevel@tonic-gate 			break;
10837c478bd9Sstevel@tonic-gate 	}
10845e1c72e1SJason King 
10855e1c72e1SJason King 	if (colorflg)
10865e1c72e1SJason King 		ls_color_init();
10875e1c72e1SJason King 
10887c478bd9Sstevel@tonic-gate 	pem(&flist[0], &flist[i], 0);
10897c478bd9Sstevel@tonic-gate 	for (; i < nargs; i++) {
10907c478bd9Sstevel@tonic-gate 		pdirectory(flist[i]->ln.namep, Rflg ||
10917c478bd9Sstevel@tonic-gate 		    (amino > 1), nargs, 0, flist[i]->ancinfo);
10927c478bd9Sstevel@tonic-gate 		if (nomocore)
10937c478bd9Sstevel@tonic-gate 			exit(2);
10947c478bd9Sstevel@tonic-gate 		/* -R: print subdirectories found */
10957c478bd9Sstevel@tonic-gate 		while (dfirst || cdfirst) {
10967c478bd9Sstevel@tonic-gate 			/* Place direct subdirs on front in right order */
10977c478bd9Sstevel@tonic-gate 			while (cdfirst) {
10987c478bd9Sstevel@tonic-gate 				/* reverse cdfirst onto front of dfirst */
10997c478bd9Sstevel@tonic-gate 				dtemp = cdfirst;
11007c478bd9Sstevel@tonic-gate 				cdfirst = cdfirst -> dc_next;
11017c478bd9Sstevel@tonic-gate 				dtemp -> dc_next = dfirst;
11027c478bd9Sstevel@tonic-gate 				dfirst = dtemp;
11037c478bd9Sstevel@tonic-gate 			}
11047c478bd9Sstevel@tonic-gate 			/* take off first dir on dfirst & print it */
11057c478bd9Sstevel@tonic-gate 			dtemp = dfirst;
11067c478bd9Sstevel@tonic-gate 			dfirst = dfirst->dc_next;
11077c478bd9Sstevel@tonic-gate 			pdirectory(dtemp->dc_name, 1, nargs,
11087c478bd9Sstevel@tonic-gate 			    dtemp->cycle_detected, dtemp->myancinfo);
11097c478bd9Sstevel@tonic-gate 			if (nomocore)
11107c478bd9Sstevel@tonic-gate 				exit(2);
11117c478bd9Sstevel@tonic-gate 			free(dtemp->dc_name);
11127c478bd9Sstevel@tonic-gate 			free(dtemp);
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 	}
11155e1c72e1SJason King 
11167c478bd9Sstevel@tonic-gate 	return (err);
11177c478bd9Sstevel@tonic-gate }
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate /*
11207c478bd9Sstevel@tonic-gate  * pdirectory: print the directory name, labelling it if title is
11217c478bd9Sstevel@tonic-gate  * nonzero, using lp as the place to start reading in the dir.
11227c478bd9Sstevel@tonic-gate  */
11237c478bd9Sstevel@tonic-gate static void
11247c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo)
11257c478bd9Sstevel@tonic-gate {
11267c478bd9Sstevel@tonic-gate 	struct dchain *dp;
11277c478bd9Sstevel@tonic-gate 	struct lbuf *ap;
11287c478bd9Sstevel@tonic-gate 	char *pname;
11297c478bd9Sstevel@tonic-gate 	int j;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	filewidth = 0;
11327c478bd9Sstevel@tonic-gate 	curdir = name;
11337c478bd9Sstevel@tonic-gate 	if (title) {
11347c478bd9Sstevel@tonic-gate 		if (!first)
11357c478bd9Sstevel@tonic-gate 			(void) putc('\n', stdout);
11367c478bd9Sstevel@tonic-gate 		pprintf(name, ":");
11377c478bd9Sstevel@tonic-gate 		new_line();
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	/*
11407c478bd9Sstevel@tonic-gate 	 * If there was a cycle detected, then notify and don't report
11417c478bd9Sstevel@tonic-gate 	 * further.
11427c478bd9Sstevel@tonic-gate 	 */
11437c478bd9Sstevel@tonic-gate 	if (cdetect) {
11447c478bd9Sstevel@tonic-gate 		if (lflg || sflg) {
11457c478bd9Sstevel@tonic-gate 			curcol += printf(gettext("total %d"), 0);
11467c478bd9Sstevel@tonic-gate 			new_line();
11477c478bd9Sstevel@tonic-gate 		}
11487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
11497c478bd9Sstevel@tonic-gate 		    "ls: cycle detected for %s\n"), name);
11507c478bd9Sstevel@tonic-gate 		return;
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	nfiles = lp;
11547c478bd9Sstevel@tonic-gate 	rddir(name, myinfo);
11557c478bd9Sstevel@tonic-gate 	if (nomocore)
11567c478bd9Sstevel@tonic-gate 		return;
11575e1c72e1SJason King 	if (fflg == 0 && Uflg == 0)
11587c478bd9Sstevel@tonic-gate 		qsort(&flist[lp], (unsigned)(nfiles - lp),
11597c478bd9Sstevel@tonic-gate 		    sizeof (struct lbuf *),
11607c478bd9Sstevel@tonic-gate 		    (int (*)(const void *, const void *))compar);
11617c478bd9Sstevel@tonic-gate 	if (Rflg) {
11627c478bd9Sstevel@tonic-gate 		for (j = nfiles - 1; j >= lp; j--) {
11637c478bd9Sstevel@tonic-gate 			ap = flist[j];
11647c478bd9Sstevel@tonic-gate 			if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") &&
11657c478bd9Sstevel@tonic-gate 			    strcmp(ap->ln.lname, "..")) {
11667c478bd9Sstevel@tonic-gate 				dp = malloc(sizeof (struct dchain));
11677c478bd9Sstevel@tonic-gate 				if (dp == NULL) {
11687c478bd9Sstevel@tonic-gate 					perror("ls");
11697c478bd9Sstevel@tonic-gate 					exit(2);
11707c478bd9Sstevel@tonic-gate 				}
11717c478bd9Sstevel@tonic-gate 				pname = makename(curdir, ap->ln.lname);
11727c478bd9Sstevel@tonic-gate 				if ((dp->dc_name = strdup(pname)) == NULL) {
11737c478bd9Sstevel@tonic-gate 					perror("ls");
11747c478bd9Sstevel@tonic-gate 					exit(2);
11757c478bd9Sstevel@tonic-gate 				}
11767c478bd9Sstevel@tonic-gate 				dp->cycle_detected = ap->cycle;
11777c478bd9Sstevel@tonic-gate 				dp->myancinfo = ap->ancinfo;
11787c478bd9Sstevel@tonic-gate 				dp->dc_next = dfirst;
11797c478bd9Sstevel@tonic-gate 				dfirst = dp;
11807c478bd9Sstevel@tonic-gate 			}
11817c478bd9Sstevel@tonic-gate 		}
11827c478bd9Sstevel@tonic-gate 	}
11837c478bd9Sstevel@tonic-gate 	if (lflg || sflg) {
11847c478bd9Sstevel@tonic-gate 		curcol += printf(gettext("total %llu"), tblocks);
11857c478bd9Sstevel@tonic-gate 		new_line();
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 	pem(&flist[lp], &flist[nfiles], lflg||sflg);
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate /*
11917c478bd9Sstevel@tonic-gate  * pem: print 'em. Print a list of files (e.g. a directory) bounded
11927c478bd9Sstevel@tonic-gate  * by slp and lp.
11937c478bd9Sstevel@tonic-gate  */
11947c478bd9Sstevel@tonic-gate static void
11957c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag)
11967c478bd9Sstevel@tonic-gate {
11977c478bd9Sstevel@tonic-gate 	long row, nrows, i;
11987c478bd9Sstevel@tonic-gate 	int col, ncols;
11997c478bd9Sstevel@tonic-gate 	struct lbuf **ep;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	if (Cflg || mflg) {
12027c478bd9Sstevel@tonic-gate 		if (colwidth > num_cols) {
12037c478bd9Sstevel@tonic-gate 			ncols = 1;
12047c478bd9Sstevel@tonic-gate 		} else {
12057c478bd9Sstevel@tonic-gate 			ncols = num_cols / colwidth;
12067c478bd9Sstevel@tonic-gate 		}
12077c478bd9Sstevel@tonic-gate 	}
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	if (ncols == 1 || mflg || xflg || !Cflg) {
12107c478bd9Sstevel@tonic-gate 		for (ep = slp; ep < lp; ep++)
12117c478bd9Sstevel@tonic-gate 			pentry(*ep);
12127c478bd9Sstevel@tonic-gate 		new_line();
12137c478bd9Sstevel@tonic-gate 		return;
12147c478bd9Sstevel@tonic-gate 	}
12157c478bd9Sstevel@tonic-gate 	/* otherwise print -C columns */
12167c478bd9Sstevel@tonic-gate 	if (tot_flag) {
12177c478bd9Sstevel@tonic-gate 		slp--;
12187c478bd9Sstevel@tonic-gate 		row = 1;
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate 	else
12217c478bd9Sstevel@tonic-gate 		row = 0;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	nrows = (lp - slp - 1) / ncols + 1;
12247c478bd9Sstevel@tonic-gate 	for (i = 0; i < nrows; i++, row++) {
12257c478bd9Sstevel@tonic-gate 		for (col = 0; col < ncols; col++) {
12267c478bd9Sstevel@tonic-gate 			ep = slp + (nrows * col) + row;
12277c478bd9Sstevel@tonic-gate 			if (ep < lp)
12287c478bd9Sstevel@tonic-gate 				pentry(*ep);
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 		new_line();
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate /*
12357c478bd9Sstevel@tonic-gate  * print one output entry;
12367c478bd9Sstevel@tonic-gate  * if uid/gid is not found in the appropriate
12377c478bd9Sstevel@tonic-gate  * file(passwd/group), then print uid/gid instead of
12387c478bd9Sstevel@tonic-gate  * user/group name;
12397c478bd9Sstevel@tonic-gate  */
12407c478bd9Sstevel@tonic-gate static void
12417c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 	struct lbuf *p;
12447c478bd9Sstevel@tonic-gate 	numbuf_t hbuf;
12457c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
12467c478bd9Sstevel@tonic-gate 	char *dmark = "";	/* Used if -p or -F option active */
12477c478bd9Sstevel@tonic-gate 	char *cp;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	p = ap;
12507c478bd9Sstevel@tonic-gate 	column();
12517c478bd9Sstevel@tonic-gate 	if (iflg)
12527c478bd9Sstevel@tonic-gate 		if (mflg && !lflg)
12537c478bd9Sstevel@tonic-gate 			curcol += printf("%llu ", (long long)p->lnum);
12547c478bd9Sstevel@tonic-gate 		else
12557c478bd9Sstevel@tonic-gate 			curcol += printf("%10llu ", (long long)p->lnum);
12567c478bd9Sstevel@tonic-gate 	if (sflg)
12577c478bd9Sstevel@tonic-gate 		curcol += printf((mflg && !lflg) ? "%lld " :
12587c478bd9Sstevel@tonic-gate 		    (p->lblocks < 10000) ? "%4lld " : "%lld ",
12597c478bd9Sstevel@tonic-gate 		    (p->ltype != 'b' && p->ltype != 'c') ?
12607c478bd9Sstevel@tonic-gate 		    p->lblocks : 0LL);
12617c478bd9Sstevel@tonic-gate 	if (lflg) {
12627c478bd9Sstevel@tonic-gate 		(void) putchar(p->ltype);
12637c478bd9Sstevel@tonic-gate 		curcol++;
12647c478bd9Sstevel@tonic-gate 		pmode(p->lflags);
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/* ACL: additional access mode flag */
12677c478bd9Sstevel@tonic-gate 		(void) putchar(p->acl);
12687c478bd9Sstevel@tonic-gate 		curcol++;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		curcol += printf("%3lu ", (ulong_t)p->lnl);
12717c478bd9Sstevel@tonic-gate 		if (oflg)
12727c478bd9Sstevel@tonic-gate 			if (!nflg) {
12737c478bd9Sstevel@tonic-gate 				cp = getname(p->luid);
12747c478bd9Sstevel@tonic-gate 				curcol += printf("%-8s ", cp);
12757c478bd9Sstevel@tonic-gate 			} else
12767c478bd9Sstevel@tonic-gate 				curcol += printf("%-8lu ", (ulong_t)p->luid);
12777c478bd9Sstevel@tonic-gate 		if (gflg)
12787c478bd9Sstevel@tonic-gate 			if (!nflg) {
12797c478bd9Sstevel@tonic-gate 				cp = getgroup(p->lgid);
12807c478bd9Sstevel@tonic-gate 				curcol += printf("%-8s ", cp);
12817c478bd9Sstevel@tonic-gate 			} else
12827c478bd9Sstevel@tonic-gate 				curcol += printf("%-8lu ", (ulong_t)p->lgid);
12837c478bd9Sstevel@tonic-gate 		if (p->ltype == 'b' || p->ltype == 'c') {
12847c478bd9Sstevel@tonic-gate 			curcol += printf("%3u, %2u",
12857c478bd9Sstevel@tonic-gate 			    (uint_t)major((dev_t)p->lsize),
12867c478bd9Sstevel@tonic-gate 			    (uint_t)minor((dev_t)p->lsize));
12877c478bd9Sstevel@tonic-gate 		} else if (hflg && (p->lsize >= hscale)) {
12887c478bd9Sstevel@tonic-gate 			curcol += printf("%7s",
12897c478bd9Sstevel@tonic-gate 			    number_to_scaled_string(hbuf, p->lsize, hscale));
12907c478bd9Sstevel@tonic-gate 		} else {
12915e1c72e1SJason King 			uint64_t bsize = p->lsize / block_size;
12925e1c72e1SJason King 
12935e1c72e1SJason King 			/*
12945e1c72e1SJason King 			 * Round up only when using blocks > 1 byte, otherwise
12955e1c72e1SJason King 			 * 'normal' sizes display 1 byte too large.
12965e1c72e1SJason King 			 */
12975e1c72e1SJason King 			if (p->lsize % block_size != 0)
12985e1c72e1SJason King 				bsize++;
12995e1c72e1SJason King 
13005e1c72e1SJason King 			curcol += printf("%7" PRIu64, bsize);
13017c478bd9Sstevel@tonic-gate 		}
13025e1c72e1SJason King 		format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec);
1303da6c28aaSamw 		/* format extended system attribute time */
1304da6c28aaSamw 		if (tmflg && crtm)
1305da6c28aaSamw 			format_attrtime(p);
13067c478bd9Sstevel@tonic-gate 
1307da6c28aaSamw 		curcol += printf("%s", time_buf);
1308da6c28aaSamw 
1309da6c28aaSamw 	}
13107c478bd9Sstevel@tonic-gate 	/*
13117c478bd9Sstevel@tonic-gate 	 * prevent both "->" and trailing marks
13127c478bd9Sstevel@tonic-gate 	 * from appearing
13137c478bd9Sstevel@tonic-gate 	 */
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	if (pflg && p->ltype == 'd')
13167c478bd9Sstevel@tonic-gate 		dmark = "/";
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	if (Fflg && !(lflg && p->flinkto)) {
13197c478bd9Sstevel@tonic-gate 		if (p->ltype == 'd')
13207c478bd9Sstevel@tonic-gate 			dmark = "/";
13217c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'D')
13227c478bd9Sstevel@tonic-gate 			dmark = ">";
13237c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'p')
13247c478bd9Sstevel@tonic-gate 			dmark = "|";
13257c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'l')
13267c478bd9Sstevel@tonic-gate 			dmark = "@";
13277c478bd9Sstevel@tonic-gate 		else if (p->ltype == 's')
13287c478bd9Sstevel@tonic-gate 			dmark = "=";
13295e1c72e1SJason King 		else if (!file_typeflg &&
13305e1c72e1SJason King 		    (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)))
13317c478bd9Sstevel@tonic-gate 			dmark = "*";
13327c478bd9Sstevel@tonic-gate 		else
13337c478bd9Sstevel@tonic-gate 			dmark = "";
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	if (lflg && p->flinkto) {
13377c478bd9Sstevel@tonic-gate 		(void) strncpy(buf, " -> ", 4);
13387c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + 4, p->flinkto);
13397c478bd9Sstevel@tonic-gate 		dmark = buf;
13407c478bd9Sstevel@tonic-gate 	}
13415e1c72e1SJason King 
13425e1c72e1SJason King 	if (colorflg)
13435e1c72e1SJason King 		ls_start_color(p);
13445e1c72e1SJason King 
13457c478bd9Sstevel@tonic-gate 	if (p->lflags & ISARG) {
13467c478bd9Sstevel@tonic-gate 		if (qflg || bflg)
13477c478bd9Sstevel@tonic-gate 			pprintf(p->ln.namep, dmark);
13487c478bd9Sstevel@tonic-gate 		else {
13497c478bd9Sstevel@tonic-gate 			(void) printf("%s%s", p->ln.namep, dmark);
13507c478bd9Sstevel@tonic-gate 			curcol += strcol((unsigned char *)p->ln.namep);
13517c478bd9Sstevel@tonic-gate 			curcol += strcol((unsigned char *)dmark);
13527c478bd9Sstevel@tonic-gate 		}
13537c478bd9Sstevel@tonic-gate 	} else {
13547c478bd9Sstevel@tonic-gate 		if (qflg || bflg)
13557c478bd9Sstevel@tonic-gate 			pprintf(p->ln.lname, dmark);
13567c478bd9Sstevel@tonic-gate 		else {
13577c478bd9Sstevel@tonic-gate 			(void) printf("%s%s", p->ln.lname, dmark);
13587c478bd9Sstevel@tonic-gate 			curcol += strcol((unsigned char *)p->ln.lname);
13597c478bd9Sstevel@tonic-gate 			curcol += strcol((unsigned char *)dmark);
13607c478bd9Sstevel@tonic-gate 		}
13617c478bd9Sstevel@tonic-gate 	}
1362fa9e4066Sahrens 
13635e1c72e1SJason King 	if (colorflg)
13645e1c72e1SJason King 		ls_end_color();
13655e1c72e1SJason King 
1366da6c28aaSamw 	/* Display extended system attributes */
1367da6c28aaSamw 	if (saflg) {
1368da6c28aaSamw 		int i;
1369da6c28aaSamw 
1370da6c28aaSamw 		new_line();
1371da6c28aaSamw 		(void) printf("	\t{");
1372da6c28aaSamw 		if (p->exttr != NULL) {
1373da6c28aaSamw 			int k = 0;
1374da6c28aaSamw 			for (i = 0; i < sacnt; i++) {
1375da6c28aaSamw 				if (p->exttr[i].name != NULL)
1376da6c28aaSamw 					k++;
1377da6c28aaSamw 			}
1378da6c28aaSamw 			for (i = 0; i < sacnt; i++) {
1379da6c28aaSamw 				if (p->exttr[i].name != NULL) {
1380da6c28aaSamw 					(void) printf("%s", p->exttr[i].name);
1381da6c28aaSamw 					k--;
1382da6c28aaSamw 					if (vopt && (k != 0))
1383da6c28aaSamw 						(void) printf(",");
1384da6c28aaSamw 				}
1385da6c28aaSamw 			}
1386da6c28aaSamw 		}
1387da6c28aaSamw 		(void) printf("}\n");
1388da6c28aaSamw 	}
1389da6c28aaSamw 	/* Display file timestamps and extended system attribute timestamps */
1390da6c28aaSamw 	if (tmflg && alltm) {
1391da6c28aaSamw 		new_line();
1392da6c28aaSamw 		print_time(p);
1393da6c28aaSamw 		new_line();
1394da6c28aaSamw 	}
1395fa9e4066Sahrens 	if (vflg) {
1396fa9e4066Sahrens 		new_line();
1397fa9e4066Sahrens 		if (p->aclp) {
13985a5eeccaSmarks 			acl_printacl(p->aclp, num_cols, Vflg);
1399fa9e4066Sahrens 		}
1400fa9e4066Sahrens 	}
1401da6c28aaSamw 	/* Free extended system attribute lists */
1402da6c28aaSamw 	if (saflg || tmflg)
1403da6c28aaSamw 		free_sysattr(p);
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */
14077c478bd9Sstevel@tonic-gate static void
14087c478bd9Sstevel@tonic-gate pmode(mode_t aflag)
14097c478bd9Sstevel@tonic-gate {
14107c478bd9Sstevel@tonic-gate 	/* these arrays are declared static to allow initializations */
14117c478bd9Sstevel@tonic-gate 	static int	m0[] = { 1, S_IRUSR, 'r', '-' };
14127c478bd9Sstevel@tonic-gate 	static int	m1[] = { 1, S_IWUSR, 'w', '-' };
14137c478bd9Sstevel@tonic-gate 	static int	m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR,
14147c478bd9Sstevel@tonic-gate 	    'x', S_ISUID, 'S', '-' };
14157c478bd9Sstevel@tonic-gate 	static int	m3[] = { 1, S_IRGRP, 'r', '-' };
14167c478bd9Sstevel@tonic-gate 	static int	m4[] = { 1, S_IWGRP, 'w', '-' };
14177c478bd9Sstevel@tonic-gate 	static int	m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP,
14187c478bd9Sstevel@tonic-gate 				'x', S_ISGID|LS_NOTREG, 'S',
14197c478bd9Sstevel@tonic-gate #ifdef XPG4
14207c478bd9Sstevel@tonic-gate 		S_ISGID, 'L', '-'};
14217c478bd9Sstevel@tonic-gate #else
14227c478bd9Sstevel@tonic-gate 		S_ISGID, 'l', '-'};
14237c478bd9Sstevel@tonic-gate #endif
14247c478bd9Sstevel@tonic-gate 	static int	m6[] = { 1, S_IROTH, 'r', '-' };
14257c478bd9Sstevel@tonic-gate 	static int	m7[] = { 1, S_IWOTH, 'w', '-' };
14267c478bd9Sstevel@tonic-gate 	static int	m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH,
14277c478bd9Sstevel@tonic-gate 	    'x', S_ISVTX, 'T', '-'};
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8};
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	int **mp;
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	flags = aflag;
14347c478bd9Sstevel@tonic-gate 	for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++)
14357c478bd9Sstevel@tonic-gate 		selection(*mp);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate static void
14397c478bd9Sstevel@tonic-gate selection(int *pairp)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate 	int n;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	n = *pairp++;
14447c478bd9Sstevel@tonic-gate 	while (n-->0) {
14457c478bd9Sstevel@tonic-gate 		if ((flags & *pairp) == *pairp) {
14467c478bd9Sstevel@tonic-gate 			pairp++;
14477c478bd9Sstevel@tonic-gate 			break;
14487c478bd9Sstevel@tonic-gate 		} else {
14497c478bd9Sstevel@tonic-gate 			pairp += 2;
14507c478bd9Sstevel@tonic-gate 		}
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 	(void) putchar(*pairp);
14537c478bd9Sstevel@tonic-gate 	curcol++;
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate /*
14577c478bd9Sstevel@tonic-gate  * column: get to the beginning of the next column.
14587c478bd9Sstevel@tonic-gate  */
14597c478bd9Sstevel@tonic-gate static void
14607c478bd9Sstevel@tonic-gate column(void)
14617c478bd9Sstevel@tonic-gate {
14627c478bd9Sstevel@tonic-gate 	if (curcol == 0)
14637c478bd9Sstevel@tonic-gate 		return;
14647c478bd9Sstevel@tonic-gate 	if (mflg) {
14657c478bd9Sstevel@tonic-gate 		(void) putc(',', stdout);
14667c478bd9Sstevel@tonic-gate 		curcol++;
14677c478bd9Sstevel@tonic-gate 		if (curcol + colwidth + 2 > num_cols) {
14687c478bd9Sstevel@tonic-gate 			(void) putc('\n', stdout);
14697c478bd9Sstevel@tonic-gate 			curcol = 0;
14707c478bd9Sstevel@tonic-gate 			return;
14717c478bd9Sstevel@tonic-gate 		}
14727c478bd9Sstevel@tonic-gate 		(void) putc(' ', stdout);
14737c478bd9Sstevel@tonic-gate 		curcol++;
14747c478bd9Sstevel@tonic-gate 		return;
14757c478bd9Sstevel@tonic-gate 	}
14767c478bd9Sstevel@tonic-gate 	if (Cflg == 0) {
14777c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
14787c478bd9Sstevel@tonic-gate 		curcol = 0;
14797c478bd9Sstevel@tonic-gate 		return;
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 	if ((curcol / colwidth + 2) * colwidth > num_cols) {
14827c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
14837c478bd9Sstevel@tonic-gate 		curcol = 0;
14847c478bd9Sstevel@tonic-gate 		return;
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 	do {
14877c478bd9Sstevel@tonic-gate 		(void) putc(' ', stdout);
14887c478bd9Sstevel@tonic-gate 		curcol++;
14897c478bd9Sstevel@tonic-gate 	} while (curcol % colwidth);
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate static void
14937c478bd9Sstevel@tonic-gate new_line(void)
14947c478bd9Sstevel@tonic-gate {
14957c478bd9Sstevel@tonic-gate 	if (curcol) {
14967c478bd9Sstevel@tonic-gate 		first = 0;
14977c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
14987c478bd9Sstevel@tonic-gate 		curcol = 0;
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate /*
15037c478bd9Sstevel@tonic-gate  * read each filename in directory dir and store its
15047c478bd9Sstevel@tonic-gate  * status in flist[nfiles]
15057c478bd9Sstevel@tonic-gate  * use makename() to form pathname dir/filename;
15067c478bd9Sstevel@tonic-gate  */
15077c478bd9Sstevel@tonic-gate static void
15087c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	struct dirent *dentry;
15117c478bd9Sstevel@tonic-gate 	DIR *dirf;
15127c478bd9Sstevel@tonic-gate 	int j;
15137c478bd9Sstevel@tonic-gate 	struct lbuf *ep;
15147c478bd9Sstevel@tonic-gate 	int width;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	if ((dirf = opendir(dir)) == NULL) {
15177c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
15187c478bd9Sstevel@tonic-gate 		perror(dir);
15197c478bd9Sstevel@tonic-gate 		err = 2;
15207c478bd9Sstevel@tonic-gate 		return;
15217c478bd9Sstevel@tonic-gate 	} else {
15227c478bd9Sstevel@tonic-gate 		tblocks = 0;
15237c478bd9Sstevel@tonic-gate 		for (;;) {
15247c478bd9Sstevel@tonic-gate 			errno = 0;
15257c478bd9Sstevel@tonic-gate 			if ((dentry = readdir(dirf)) == NULL)
15267c478bd9Sstevel@tonic-gate 				break;
15277c478bd9Sstevel@tonic-gate 			if (aflg == 0 && dentry->d_name[0] == '.' &&
15287c478bd9Sstevel@tonic-gate 			    (Aflg == 0 ||
15297c478bd9Sstevel@tonic-gate 			    dentry->d_name[1] == '\0' ||
15307c478bd9Sstevel@tonic-gate 			    dentry->d_name[1] == '.' &&
15317c478bd9Sstevel@tonic-gate 			    dentry->d_name[2] == '\0'))
15327c478bd9Sstevel@tonic-gate 				/*
15337c478bd9Sstevel@tonic-gate 				 * check for directory items '.', '..',
15347c478bd9Sstevel@tonic-gate 				 *  and items without valid inode-number;
15357c478bd9Sstevel@tonic-gate 				 */
15367c478bd9Sstevel@tonic-gate 				continue;
15377c478bd9Sstevel@tonic-gate 
15385e1c72e1SJason King 			/* skip entries ending in ~ if -B was given */
15395e1c72e1SJason King 			if (Bflg &&
15405e1c72e1SJason King 			    dentry->d_name[strlen(dentry->d_name) - 1] == '~')
15415e1c72e1SJason King 				continue;
15427c478bd9Sstevel@tonic-gate 			if (Cflg || mflg) {
15437c478bd9Sstevel@tonic-gate 				width = strcol((unsigned char *)dentry->d_name);
15447c478bd9Sstevel@tonic-gate 				if (width > filewidth)
15457c478bd9Sstevel@tonic-gate 					filewidth = width;
15467c478bd9Sstevel@tonic-gate 			}
15477c478bd9Sstevel@tonic-gate 			ep = gstat(makename(dir, dentry->d_name), 0, myinfo);
15487c478bd9Sstevel@tonic-gate 			if (ep == NULL) {
15497c478bd9Sstevel@tonic-gate 				if (nomocore)
1550da6c28aaSamw 					exit(2);
15517c478bd9Sstevel@tonic-gate 				continue;
15527c478bd9Sstevel@tonic-gate 			} else {
15537c478bd9Sstevel@tonic-gate 				ep->lnum = dentry->d_ino;
15547c478bd9Sstevel@tonic-gate 				for (j = 0; dentry->d_name[j] != '\0'; j++)
15557c478bd9Sstevel@tonic-gate 					ep->ln.lname[j] = dentry->d_name[j];
15567c478bd9Sstevel@tonic-gate 				ep->ln.lname[j] = '\0';
15577c478bd9Sstevel@tonic-gate 			}
15587c478bd9Sstevel@tonic-gate 		}
15597c478bd9Sstevel@tonic-gate 		if (errno) {
15607c478bd9Sstevel@tonic-gate 			int sav_errno = errno;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15637c478bd9Sstevel@tonic-gate 			    gettext("ls: error reading directory %s: %s\n"),
15647c478bd9Sstevel@tonic-gate 			    dir, strerror(sav_errno));
15657c478bd9Sstevel@tonic-gate 		}
15667c478bd9Sstevel@tonic-gate 		(void) closedir(dirf);
15677c478bd9Sstevel@tonic-gate 		colwidth = fixedwidth + filewidth;
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate /*
15727c478bd9Sstevel@tonic-gate  * Attaching a link to an inode's ancestors.  Search
15737c478bd9Sstevel@tonic-gate  * through the ancestors to check for cycles (an inode which
15747c478bd9Sstevel@tonic-gate  * we have already tracked in this inodes ancestry).  If a cycle
15757c478bd9Sstevel@tonic-gate  * is detected, set the exit code and record the fact so that
15767c478bd9Sstevel@tonic-gate  * it is reported at the right time when printing the directory.
15777c478bd9Sstevel@tonic-gate  * In addition, set the exit code.  Note:  If the -a flag was
15787c478bd9Sstevel@tonic-gate  * specified, we don't want to check for cycles for directories
15797c478bd9Sstevel@tonic-gate  * ending in '/.' or '/..' unless they were specified on the
15807c478bd9Sstevel@tonic-gate  * command line.
15817c478bd9Sstevel@tonic-gate  */
15827c478bd9Sstevel@tonic-gate static void
15837c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep,
15847c478bd9Sstevel@tonic-gate     int argfl, struct ditem *myparent)
15857c478bd9Sstevel@tonic-gate {
15867c478bd9Sstevel@tonic-gate 	size_t		file_len;
15877c478bd9Sstevel@tonic-gate 	struct ditem	*myinfo;
15887c478bd9Sstevel@tonic-gate 	struct ditem	*tptr;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	file_len = strlen(file);
15917c478bd9Sstevel@tonic-gate 	if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) &&
15927c478bd9Sstevel@tonic-gate 	    NOTPARENTDIR(file, file_len))) {
15937c478bd9Sstevel@tonic-gate 		/*
15947c478bd9Sstevel@tonic-gate 		 * Add this inode's ancestry
15957c478bd9Sstevel@tonic-gate 		 * info and insert it into the
15967c478bd9Sstevel@tonic-gate 		 * ancestry list by pointing
15977c478bd9Sstevel@tonic-gate 		 * back to its parent.  We save
15987c478bd9Sstevel@tonic-gate 		 * it (in rep) with the other info
15997c478bd9Sstevel@tonic-gate 		 * we're gathering for this inode.
16007c478bd9Sstevel@tonic-gate 		 */
16017c478bd9Sstevel@tonic-gate 		if ((myinfo = malloc(
16027c478bd9Sstevel@tonic-gate 		    sizeof (struct ditem))) == NULL) {
16037c478bd9Sstevel@tonic-gate 			perror("ls");
16047c478bd9Sstevel@tonic-gate 			exit(2);
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		myinfo->dev = pstatb->st_dev;
16077c478bd9Sstevel@tonic-gate 		myinfo->ino = pstatb->st_ino;
16087c478bd9Sstevel@tonic-gate 		myinfo->parent = myparent;
16097c478bd9Sstevel@tonic-gate 		rep->ancinfo = myinfo;
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 		/*
16127c478bd9Sstevel@tonic-gate 		 * If this node has the same device id and
16137c478bd9Sstevel@tonic-gate 		 * inode number of one of its ancestors,
16147c478bd9Sstevel@tonic-gate 		 * then we've detected a cycle.
16157c478bd9Sstevel@tonic-gate 		 */
16167c478bd9Sstevel@tonic-gate 		if (myparent != NULL) {
16177c478bd9Sstevel@tonic-gate 			for (tptr = myparent; tptr->parent != NULL;
16187c478bd9Sstevel@tonic-gate 			    tptr = tptr->parent) {
16197c478bd9Sstevel@tonic-gate 				if ((tptr->dev == pstatb->st_dev) &&
16207c478bd9Sstevel@tonic-gate 				    (tptr->ino == pstatb->st_ino)) {
16217c478bd9Sstevel@tonic-gate 					/*
16227c478bd9Sstevel@tonic-gate 					 * Cycle detected for this
16237c478bd9Sstevel@tonic-gate 					 * directory.  Record the fact
16247c478bd9Sstevel@tonic-gate 					 * it is a cycle so we don't
16257c478bd9Sstevel@tonic-gate 					 * try to process this
16267c478bd9Sstevel@tonic-gate 					 * directory as we are
16277c478bd9Sstevel@tonic-gate 					 * walking through the
16287c478bd9Sstevel@tonic-gate 					 * list of directories.
16297c478bd9Sstevel@tonic-gate 					 */
16307c478bd9Sstevel@tonic-gate 					rep->cycle = 1;
16317c478bd9Sstevel@tonic-gate 					err = 2;
16327c478bd9Sstevel@tonic-gate 					break;
16337c478bd9Sstevel@tonic-gate 				}
16347c478bd9Sstevel@tonic-gate 			}
16357c478bd9Sstevel@tonic-gate 		}
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate /*
164064d425a7Sny155746  * Do re-calculate the mode for group for ACE_T type of acls.
164164d425a7Sny155746  * This is because, if the server's FS happens to be UFS, supporting
164264d425a7Sny155746  * POSIX ACL's, then it does a special calculation of group mode
164364d425a7Sny155746  * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.)
164464d425a7Sny155746  *
164564d425a7Sny155746  * This algorithm is from the NFSv4 ACL Draft. Here a part of that
164664d425a7Sny155746  * algorithm is used for the group mode calculation only.
164764d425a7Sny155746  * What is modified here from the algorithm is that only the
164864d425a7Sny155746  * entries with flags ACE_GROUP are considered. For each entry
164964d425a7Sny155746  * with ACE_GROUP flag, the first occurance of a specific access
165064d425a7Sny155746  * is checked if it is allowed.
1651e2442894Sny155746  * We are not interested in perms for user and other, as they
165264d425a7Sny155746  * were taken from st_mode value.
165364d425a7Sny155746  * We are not interested in a_who field of ACE, as we need just
165464d425a7Sny155746  * unix mode bits for the group.
165564d425a7Sny155746  */
1656e2442894Sny155746 
1657e2442894Sny155746 #define	OWNED_GROUP	(ACE_GROUP | ACE_IDENTIFIER_GROUP)
1658e2442894Sny155746 #define	IS_TYPE_ALLOWED(type)	((type) == ACE_ACCESS_ALLOWED_ACE_TYPE)
1659e2442894Sny155746 
166064d425a7Sny155746 int
166164d425a7Sny155746 grp_mask_to_mode(acl_t *acep)
166264d425a7Sny155746 {
166364d425a7Sny155746 	int mode = 0, seen = 0;
166464d425a7Sny155746 	int acecnt;
1665e2442894Sny155746 	int flags;
166664d425a7Sny155746 	ace_t *ap;
166764d425a7Sny155746 
166864d425a7Sny155746 	acecnt = acl_cnt(acep);
166964d425a7Sny155746 	for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) {
1670e2442894Sny155746 
1671e2442894Sny155746 		if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE &&
1672e2442894Sny155746 		    ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE)
1673e2442894Sny155746 			continue;
1674e2442894Sny155746 
1675e2442894Sny155746 		if (ap->a_flags & ACE_INHERIT_ONLY_ACE)
1676e2442894Sny155746 			continue;
1677e2442894Sny155746 
1678e2442894Sny155746 		/*
1679e2442894Sny155746 		 * if it is first group@ or first everyone@
1680e2442894Sny155746 		 * for each of read, write and execute, then
1681e2442894Sny155746 		 * that will be the group mode bit.
1682e2442894Sny155746 		 */
1683e2442894Sny155746 		flags = ap->a_flags & ACE_TYPE_FLAGS;
1684e2442894Sny155746 		if (flags == OWNED_GROUP || flags == ACE_EVERYONE) {
168564d425a7Sny155746 			if (ap->a_access_mask & ACE_READ_DATA) {
168664d425a7Sny155746 				if (!(seen & S_IRGRP)) {
168764d425a7Sny155746 					seen |= S_IRGRP;
1688e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
168964d425a7Sny155746 						mode |= S_IRGRP;
169064d425a7Sny155746 				}
169164d425a7Sny155746 			}
169264d425a7Sny155746 			if (ap->a_access_mask & ACE_WRITE_DATA) {
169364d425a7Sny155746 				if (!(seen & S_IWGRP)) {
169464d425a7Sny155746 					seen |= S_IWGRP;
1695e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
169664d425a7Sny155746 						mode |= S_IWGRP;
169764d425a7Sny155746 				}
169864d425a7Sny155746 			}
169964d425a7Sny155746 			if (ap->a_access_mask & ACE_EXECUTE) {
170064d425a7Sny155746 				if (!(seen & S_IXGRP)) {
170164d425a7Sny155746 					seen |= S_IXGRP;
1702e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
170364d425a7Sny155746 						mode |= S_IXGRP;
170464d425a7Sny155746 				}
170564d425a7Sny155746 			}
170664d425a7Sny155746 		}
170764d425a7Sny155746 	}
170864d425a7Sny155746 	return (mode);
170964d425a7Sny155746 }
171064d425a7Sny155746 
171164d425a7Sny155746 /*
17127c478bd9Sstevel@tonic-gate  * get status of file and recomputes tblocks;
17137c478bd9Sstevel@tonic-gate  * argfl = 1 if file is a name in ls-command and = 0
17147c478bd9Sstevel@tonic-gate  * for filename in a directory whose name is an
17157c478bd9Sstevel@tonic-gate  * argument in the command;
17167c478bd9Sstevel@tonic-gate  * stores a pointer in flist[nfiles] and
17177c478bd9Sstevel@tonic-gate  * returns that pointer;
17187c478bd9Sstevel@tonic-gate  * returns NULL if failed;
17197c478bd9Sstevel@tonic-gate  */
17207c478bd9Sstevel@tonic-gate static struct lbuf *
17217c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent)
17227c478bd9Sstevel@tonic-gate {
17237c478bd9Sstevel@tonic-gate 	struct stat statb, statb1;
17247c478bd9Sstevel@tonic-gate 	struct lbuf *rep;
17257c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
17267c478bd9Sstevel@tonic-gate 	ssize_t cc;
17277c478bd9Sstevel@tonic-gate 	int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat;
17287c478bd9Sstevel@tonic-gate 	int aclcnt;
1729fa9e4066Sahrens 	int error;
17307c478bd9Sstevel@tonic-gate 	aclent_t *tp;
17317c478bd9Sstevel@tonic-gate 	o_mode_t groupperm, mask;
17327c478bd9Sstevel@tonic-gate 	int grouppermfound, maskfound;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	if (nomocore)
17357c478bd9Sstevel@tonic-gate 		return (NULL);
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 	if (nfiles >= maxfils) {
17387c478bd9Sstevel@tonic-gate 		/*
17397c478bd9Sstevel@tonic-gate 		 * all flist/lbuf pair assigned files, time to get some
17407c478bd9Sstevel@tonic-gate 		 * more space
17417c478bd9Sstevel@tonic-gate 		 */
17427c478bd9Sstevel@tonic-gate 		maxfils += quantn;
17437c478bd9Sstevel@tonic-gate 		if (((flist = realloc(flist,
17447c478bd9Sstevel@tonic-gate 		    maxfils * sizeof (struct lbuf *))) == NULL) ||
17457c478bd9Sstevel@tonic-gate 		    ((nxtlbf = malloc(quantn *
17467c478bd9Sstevel@tonic-gate 		    sizeof (struct lbuf))) == NULL)) {
17477c478bd9Sstevel@tonic-gate 			perror("ls");
17487c478bd9Sstevel@tonic-gate 			nomocore = 1;
17497c478bd9Sstevel@tonic-gate 			return (NULL);
17507c478bd9Sstevel@tonic-gate 		}
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	/*
17547c478bd9Sstevel@tonic-gate 	 * nfiles is reset to nargs for each directory
17557c478bd9Sstevel@tonic-gate 	 * that is given as an argument maxn is checked
17567c478bd9Sstevel@tonic-gate 	 * to prevent the assignment of an lbuf to a flist entry
17577c478bd9Sstevel@tonic-gate 	 * that already has one assigned.
17587c478bd9Sstevel@tonic-gate 	 */
17597c478bd9Sstevel@tonic-gate 	if (nfiles >= maxn) {
17607c478bd9Sstevel@tonic-gate 		rep = nxtlbf++;
17617c478bd9Sstevel@tonic-gate 		flist[nfiles++] = rep;
17627c478bd9Sstevel@tonic-gate 		maxn = nfiles;
17637c478bd9Sstevel@tonic-gate 	} else {
17647c478bd9Sstevel@tonic-gate 		rep = flist[nfiles++];
17657c478bd9Sstevel@tonic-gate 	}
176644f31f13Sbasabi 
176744f31f13Sbasabi 	/* Initialize */
176844f31f13Sbasabi 
17697c478bd9Sstevel@tonic-gate 	rep->lflags = (mode_t)0;
17707c478bd9Sstevel@tonic-gate 	rep->flinkto = NULL;
17717c478bd9Sstevel@tonic-gate 	rep->cycle = 0;
177244f31f13Sbasabi 	rep->lat.tv_sec = time(NULL);
177344f31f13Sbasabi 	rep->lat.tv_nsec = 0;
177444f31f13Sbasabi 	rep->lct.tv_sec = time(NULL);
177544f31f13Sbasabi 	rep->lct.tv_nsec = 0;
177644f31f13Sbasabi 	rep->lmt.tv_sec = time(NULL);
177744f31f13Sbasabi 	rep->lmt.tv_nsec = 0;
177844f31f13Sbasabi 	rep->exttr = NULL;
177944f31f13Sbasabi 	rep->extm = NULL;
178044f31f13Sbasabi 
17817c478bd9Sstevel@tonic-gate 	if (argfl || statreq) {
17827c478bd9Sstevel@tonic-gate 		int doacl;
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 		if (lflg)
17857c478bd9Sstevel@tonic-gate 			doacl = 1;
17867c478bd9Sstevel@tonic-gate 		else
17877c478bd9Sstevel@tonic-gate 			doacl = 0;
178844f31f13Sbasabi 
17897c478bd9Sstevel@tonic-gate 		if ((*statf)(file, &statb) < 0) {
17907c478bd9Sstevel@tonic-gate 			if (argfl || errno != ENOENT ||
17917c478bd9Sstevel@tonic-gate 			    (Lflg && lstat(file, &statb) == 0)) {
17927c478bd9Sstevel@tonic-gate 				/*
17937c478bd9Sstevel@tonic-gate 				 * Avoid race between readdir and lstat.
17947c478bd9Sstevel@tonic-gate 				 * Print error message in case of dangling link.
17957c478bd9Sstevel@tonic-gate 				 */
17967c478bd9Sstevel@tonic-gate 				perror(file);
17975e1c72e1SJason King 				err = 2;
17987c478bd9Sstevel@tonic-gate 			}
17997c478bd9Sstevel@tonic-gate 			nfiles--;
18007c478bd9Sstevel@tonic-gate 			return (NULL);
18017c478bd9Sstevel@tonic-gate 		}
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 		/*
18047c478bd9Sstevel@tonic-gate 		 * If -H was specified, and the file linked to was
18057c478bd9Sstevel@tonic-gate 		 * not a directory, then we need to get the info
18067c478bd9Sstevel@tonic-gate 		 * for the symlink itself.
18077c478bd9Sstevel@tonic-gate 		 */
18087c478bd9Sstevel@tonic-gate 		if ((Hflg) && (argfl) &&
18097c478bd9Sstevel@tonic-gate 		    ((statb.st_mode & S_IFMT) != S_IFDIR)) {
18107c478bd9Sstevel@tonic-gate 			if (lstat(file, &statb) < 0) {
18117c478bd9Sstevel@tonic-gate 				perror(file);
18125e1c72e1SJason King 				err = 2;
18137c478bd9Sstevel@tonic-gate 			}
18147c478bd9Sstevel@tonic-gate 		}
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 		rep->lnum = statb.st_ino;
18177c478bd9Sstevel@tonic-gate 		rep->lsize = statb.st_size;
18187c478bd9Sstevel@tonic-gate 		rep->lblocks = statb.st_blocks;
18197c478bd9Sstevel@tonic-gate 		switch (statb.st_mode & S_IFMT) {
18207c478bd9Sstevel@tonic-gate 		case S_IFDIR:
18217c478bd9Sstevel@tonic-gate 			rep->ltype = 'd';
18227c478bd9Sstevel@tonic-gate 			if (Rflg) {
18237c478bd9Sstevel@tonic-gate 				record_ancestry(file, &statb, rep,
18247c478bd9Sstevel@tonic-gate 				    argfl, myparent);
18257c478bd9Sstevel@tonic-gate 			}
18267c478bd9Sstevel@tonic-gate 			break;
18277c478bd9Sstevel@tonic-gate 		case S_IFBLK:
18287c478bd9Sstevel@tonic-gate 			rep->ltype = 'b';
18297c478bd9Sstevel@tonic-gate 			rep->lsize = (off_t)statb.st_rdev;
18307c478bd9Sstevel@tonic-gate 			break;
18317c478bd9Sstevel@tonic-gate 		case S_IFCHR:
18327c478bd9Sstevel@tonic-gate 			rep->ltype = 'c';
18337c478bd9Sstevel@tonic-gate 			rep->lsize = (off_t)statb.st_rdev;
18347c478bd9Sstevel@tonic-gate 			break;
18357c478bd9Sstevel@tonic-gate 		case S_IFIFO:
18367c478bd9Sstevel@tonic-gate 			rep->ltype = 'p';
18377c478bd9Sstevel@tonic-gate 			break;
18387c478bd9Sstevel@tonic-gate 		case S_IFSOCK:
18397c478bd9Sstevel@tonic-gate 			rep->ltype = 's';
18407c478bd9Sstevel@tonic-gate 			rep->lsize = 0;
18417c478bd9Sstevel@tonic-gate 			break;
18427c478bd9Sstevel@tonic-gate 		case S_IFLNK:
18437c478bd9Sstevel@tonic-gate 			/* symbolic links may not have ACLs, so elide acl() */
18447c478bd9Sstevel@tonic-gate 			if ((Lflg == 0) || (Hflg == 0) ||
18457c478bd9Sstevel@tonic-gate 			    ((Hflg) && (!argfl))) {
18467c478bd9Sstevel@tonic-gate 				doacl = 0;
18477c478bd9Sstevel@tonic-gate 			}
18487c478bd9Sstevel@tonic-gate 			rep->ltype = 'l';
18497c478bd9Sstevel@tonic-gate 			if (lflg) {
18507c478bd9Sstevel@tonic-gate 				cc = readlink(file, buf, BUFSIZ);
18517c478bd9Sstevel@tonic-gate 				if (cc >= 0) {
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 					/*
18547c478bd9Sstevel@tonic-gate 					 * follow the symbolic link
18557c478bd9Sstevel@tonic-gate 					 * to generate the appropriate
18567c478bd9Sstevel@tonic-gate 					 * Fflg marker for the object
18577c478bd9Sstevel@tonic-gate 					 * eg, /bin -> /sym/bin/
18587c478bd9Sstevel@tonic-gate 					 */
18597c478bd9Sstevel@tonic-gate 					if ((Fflg || pflg) &&
18607c478bd9Sstevel@tonic-gate 					    (stat(file, &statb1) >= 0)) {
18617c478bd9Sstevel@tonic-gate 						switch (statb1.st_mode &
18627c478bd9Sstevel@tonic-gate 						    S_IFMT) {
18637c478bd9Sstevel@tonic-gate 						case S_IFDIR:
18647c478bd9Sstevel@tonic-gate 							buf[cc++] = '/';
18657c478bd9Sstevel@tonic-gate 							break;
18667c478bd9Sstevel@tonic-gate 						case S_IFSOCK:
18677c478bd9Sstevel@tonic-gate 							buf[cc++] = '=';
18687c478bd9Sstevel@tonic-gate 							break;
18692236845bSakaplan 						case S_IFDOOR:
18702236845bSakaplan 							buf[cc++] = '>';
18712236845bSakaplan 							break;
18722236845bSakaplan 						case S_IFIFO:
18732236845bSakaplan 							buf[cc++] = '|';
18742236845bSakaplan 							break;
18757c478bd9Sstevel@tonic-gate 						default:
18767c478bd9Sstevel@tonic-gate 							if ((statb1.st_mode &
18777c478bd9Sstevel@tonic-gate 							    ~S_IFMT) &
18787c478bd9Sstevel@tonic-gate 							    (S_IXUSR|S_IXGRP|
18797c478bd9Sstevel@tonic-gate 							    S_IXOTH))
18807c478bd9Sstevel@tonic-gate 								buf[cc++] = '*';
18817c478bd9Sstevel@tonic-gate 							break;
18827c478bd9Sstevel@tonic-gate 						}
18837c478bd9Sstevel@tonic-gate 					}
18847c478bd9Sstevel@tonic-gate 					buf[cc] = '\0';
18857c478bd9Sstevel@tonic-gate 					rep->flinkto = strdup(buf);
18867c478bd9Sstevel@tonic-gate 				}
18877c478bd9Sstevel@tonic-gate 				break;
18887c478bd9Sstevel@tonic-gate 			}
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 			/*
18917c478bd9Sstevel@tonic-gate 			 * ls /sym behaves differently from ls /sym/
18927c478bd9Sstevel@tonic-gate 			 * when /sym is a symbolic link. This is fixed
18937c478bd9Sstevel@tonic-gate 			 * when explicit arguments are specified.
18947c478bd9Sstevel@tonic-gate 			 */
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate #ifdef XPG6
18977c478bd9Sstevel@tonic-gate 			/* Do not follow a symlink when -F is specified */
18987c478bd9Sstevel@tonic-gate 			if ((!argfl) || (argfl && Fflg) ||
18997c478bd9Sstevel@tonic-gate 			    (stat(file, &statb1) < 0))
19007c478bd9Sstevel@tonic-gate #else
19017c478bd9Sstevel@tonic-gate 			/* Follow a symlink when -F is specified */
19027c478bd9Sstevel@tonic-gate 			if (!argfl || stat(file, &statb1) < 0)
19037c478bd9Sstevel@tonic-gate #endif /* XPG6 */
19047c478bd9Sstevel@tonic-gate 				break;
19057c478bd9Sstevel@tonic-gate 			if ((statb1.st_mode & S_IFMT) == S_IFDIR) {
19067c478bd9Sstevel@tonic-gate 				statb = statb1;
19077c478bd9Sstevel@tonic-gate 				rep->ltype = 'd';
19087c478bd9Sstevel@tonic-gate 				rep->lsize = statb1.st_size;
19097c478bd9Sstevel@tonic-gate 				if (Rflg) {
19107c478bd9Sstevel@tonic-gate 					record_ancestry(file, &statb, rep,
19117c478bd9Sstevel@tonic-gate 					    argfl, myparent);
19127c478bd9Sstevel@tonic-gate 				}
19137c478bd9Sstevel@tonic-gate 			}
19147c478bd9Sstevel@tonic-gate 			break;
19157c478bd9Sstevel@tonic-gate 		case S_IFDOOR:
19167c478bd9Sstevel@tonic-gate 			rep->ltype = 'D';
19177c478bd9Sstevel@tonic-gate 			break;
19187c478bd9Sstevel@tonic-gate 		case S_IFREG:
19197c478bd9Sstevel@tonic-gate 			rep->ltype = '-';
19207c478bd9Sstevel@tonic-gate 			break;
19217c478bd9Sstevel@tonic-gate 		case S_IFPORT:
19227c478bd9Sstevel@tonic-gate 			rep->ltype = 'P';
19237c478bd9Sstevel@tonic-gate 			break;
19247c478bd9Sstevel@tonic-gate 		default:
19257c478bd9Sstevel@tonic-gate 			rep->ltype = '?';
19267c478bd9Sstevel@tonic-gate 			break;
19277c478bd9Sstevel@tonic-gate 		}
19287c478bd9Sstevel@tonic-gate 		rep->lflags = statb.st_mode & ~S_IFMT;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 		if (!S_ISREG(statb.st_mode))
19317c478bd9Sstevel@tonic-gate 			rep->lflags |= LS_NOTREG;
19327c478bd9Sstevel@tonic-gate 
193344f31f13Sbasabi 		rep->luid = statb.st_uid;
193444f31f13Sbasabi 		rep->lgid = statb.st_gid;
193544f31f13Sbasabi 		rep->lnl = statb.st_nlink;
193644f31f13Sbasabi 		if (uflg || (tmflg && atm))
193744f31f13Sbasabi 			rep->lmtime = statb.st_atim;
193844f31f13Sbasabi 		else if (cflg || (tmflg && ctm))
193944f31f13Sbasabi 			rep->lmtime = statb.st_ctim;
194044f31f13Sbasabi 		else
194144f31f13Sbasabi 			rep->lmtime = statb.st_mtim;
194244f31f13Sbasabi 		rep->lat = statb.st_atim;
194344f31f13Sbasabi 		rep->lct = statb.st_ctim;
194444f31f13Sbasabi 		rep->lmt = statb.st_mtim;
194544f31f13Sbasabi 
19467c478bd9Sstevel@tonic-gate 		/* ACL: check acl entries count */
19477c478bd9Sstevel@tonic-gate 		if (doacl) {
19487c478bd9Sstevel@tonic-gate 
1949fa9e4066Sahrens 			error = acl_get(file, 0, &rep->aclp);
1950fa9e4066Sahrens 			if (error) {
1951fa9e4066Sahrens 				(void) fprintf(stderr,
1952fa9e4066Sahrens 				    gettext("ls: can't read ACL on %s: %s\n"),
1953fa9e4066Sahrens 				    file, acl_strerror(error));
195444f31f13Sbasabi 				rep->acl = ' ';
195556798e90Sbasabi 				acl_err++;
195644f31f13Sbasabi 				return (rep);
19577c478bd9Sstevel@tonic-gate 			}
19587c478bd9Sstevel@tonic-gate 
1959fa9e4066Sahrens 			rep->acl = ' ';
1960fa9e4066Sahrens 
1961fa9e4066Sahrens 			if (rep->aclp &&
1962fa9e4066Sahrens 			    ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) {
1963fa9e4066Sahrens 				rep->acl = '+';
19647c478bd9Sstevel@tonic-gate 				/*
1965fa9e4066Sahrens 				 * Special handling for ufs aka aclent_t ACL's
1966fa9e4066Sahrens 				 */
196764d425a7Sny155746 				if (acl_type(rep->aclp) == ACLENT_T) {
1968fa9e4066Sahrens 					/*
1969fa9e4066Sahrens 					 * For files with non-trivial acls, the
1970fa9e4066Sahrens 					 * effective group permissions are the
1971fa9e4066Sahrens 					 * intersection of the GROUP_OBJ value
1972fa9e4066Sahrens 					 * and the CLASS_OBJ (acl mask) value.
1973fa9e4066Sahrens 					 * Determine both the GROUP_OBJ and
1974fa9e4066Sahrens 					 * CLASS_OBJ for this file and insert
1975fa9e4066Sahrens 					 * the logical AND of those two values
1976fa9e4066Sahrens 					 * in the group permissions field
1977fa9e4066Sahrens 					 * of the lflags value for this file.
1978fa9e4066Sahrens 					 */
1979fa9e4066Sahrens 
1980fa9e4066Sahrens 					/*
1981fa9e4066Sahrens 					 * Until found in acl list, assume
1982fa9e4066Sahrens 					 * maximum permissions for both group
1983fa9e4066Sahrens 					 * a nd mask.  (Just in case the acl
1984fa9e4066Sahrens 					 * lacks either value for some reason.)
19857c478bd9Sstevel@tonic-gate 					 */
19867c478bd9Sstevel@tonic-gate 					groupperm = 07;
19877c478bd9Sstevel@tonic-gate 					mask = 07;
19887c478bd9Sstevel@tonic-gate 					grouppermfound = 0;
19897c478bd9Sstevel@tonic-gate 					maskfound = 0;
1990fa9e4066Sahrens 					aclcnt = acl_cnt(rep->aclp);
1991fa9e4066Sahrens 					for (tp =
1992fa9e4066Sahrens 					    (aclent_t *)acl_data(rep->aclp);
1993fa9e4066Sahrens 					    aclcnt--; tp++) {
19947c478bd9Sstevel@tonic-gate 						if (tp->a_type == GROUP_OBJ) {
19957c478bd9Sstevel@tonic-gate 							groupperm = tp->a_perm;
19967c478bd9Sstevel@tonic-gate 							grouppermfound = 1;
19977c478bd9Sstevel@tonic-gate 							continue;
19987c478bd9Sstevel@tonic-gate 						}
19997c478bd9Sstevel@tonic-gate 						if (tp->a_type == CLASS_OBJ) {
20007c478bd9Sstevel@tonic-gate 							mask = tp->a_perm;
20017c478bd9Sstevel@tonic-gate 							maskfound = 1;
20027c478bd9Sstevel@tonic-gate 						}
20037c478bd9Sstevel@tonic-gate 						if (grouppermfound && maskfound)
20047c478bd9Sstevel@tonic-gate 							break;
20057c478bd9Sstevel@tonic-gate 					}
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate 					/* reset all the group bits */
20097c478bd9Sstevel@tonic-gate 					rep->lflags &= ~S_IRWXG;
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 					/*
2012fa9e4066Sahrens 					 * Now set them to the logical AND of
2013fa9e4066Sahrens 					 * the GROUP_OBJ permissions and the
2014fa9e4066Sahrens 					 * acl mask.
20157c478bd9Sstevel@tonic-gate 					 */
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 					rep->lflags |= (groupperm & mask) << 3;
2018fa9e4066Sahrens 
201964d425a7Sny155746 				} else if (acl_type(rep->aclp) == ACE_T) {
202064d425a7Sny155746 					int mode;
202164d425a7Sny155746 					mode = grp_mask_to_mode(rep->aclp);
202264d425a7Sny155746 					rep->lflags &= ~S_IRWXG;
202364d425a7Sny155746 					rep->lflags |= mode;
2024fa9e4066Sahrens 				}
20257c478bd9Sstevel@tonic-gate 			}
20267c478bd9Sstevel@tonic-gate 
20275a5eeccaSmarks 			if (!vflg && !Vflg && rep->aclp) {
20285a5eeccaSmarks 				acl_free(rep->aclp);
20295a5eeccaSmarks 				rep->aclp = NULL;
20305a5eeccaSmarks 			}
20315a5eeccaSmarks 
20327c478bd9Sstevel@tonic-gate 			if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
20337c478bd9Sstevel@tonic-gate 				rep->acl = '@';
2034da6c28aaSamw 
20357c478bd9Sstevel@tonic-gate 		} else
20367c478bd9Sstevel@tonic-gate 			rep->acl = ' ';
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 		/* mask ISARG and other file-type bits */
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 		if (rep->ltype != 'b' && rep->ltype != 'c')
20417c478bd9Sstevel@tonic-gate 			tblocks += rep->lblocks;
2042da6c28aaSamw 
2043da6c28aaSamw 		/* Get extended system attributes */
2044da6c28aaSamw 
2045da6c28aaSamw 		if ((saflg || (tmflg && crtm) || (tmflg && alltm)) &&
2046da6c28aaSamw 		    (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) {
2047da6c28aaSamw 			int i;
2048da6c28aaSamw 
2049da6c28aaSamw 			sacnt = attr_count();
2050da6c28aaSamw 			/*
2051da6c28aaSamw 			 * Allocate 'sacnt' size array to hold extended
2052da6c28aaSamw 			 * system attribute name (verbose) or respective
2053da6c28aaSamw 			 * symbol represenation (compact).
2054da6c28aaSamw 			 */
2055da6c28aaSamw 			rep->exttr = xmalloc(sacnt * sizeof (struct attrb),
2056da6c28aaSamw 			    rep);
2057da6c28aaSamw 
2058da6c28aaSamw 			/* initialize boolean attribute list */
2059da6c28aaSamw 			for (i = 0; i < sacnt; i++)
2060da6c28aaSamw 				rep->exttr[i].name = NULL;
2061da6c28aaSamw 			if (get_sysxattr(file, rep) != 0) {
2062da6c28aaSamw 				(void) fprintf(stderr,
2063da6c28aaSamw 				    gettext("ls:Failed to retrieve "
2064da6c28aaSamw 				    "extended system attribute from "
2065da6c28aaSamw 				    "%s\n"), file);
2066da6c28aaSamw 				rep->exttr[0].name = xmalloc(2, rep);
2067da6c28aaSamw 				(void) strlcpy(rep->exttr[0].name, "?", 2);
2068da6c28aaSamw 			}
2069da6c28aaSamw 		}
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate 	return (rep);
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate /*
20757c478bd9Sstevel@tonic-gate  * returns pathname of the form dir/file;
20767c478bd9Sstevel@tonic-gate  * dir and file are null-terminated strings.
20777c478bd9Sstevel@tonic-gate  */
20787c478bd9Sstevel@tonic-gate static char *
20797c478bd9Sstevel@tonic-gate makename(char *dir, char *file)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate 	/*
20827c478bd9Sstevel@tonic-gate 	 * PATH_MAX is the maximum length of a path name.
20837c478bd9Sstevel@tonic-gate 	 * MAXNAMLEN is the maximum length of any path name component.
20847c478bd9Sstevel@tonic-gate 	 * Allocate space for both, plus the '/' in the middle
20857c478bd9Sstevel@tonic-gate 	 * and the null character at the end.
20867c478bd9Sstevel@tonic-gate 	 * dfile is static as this is returned by makename().
20877c478bd9Sstevel@tonic-gate 	 */
20887c478bd9Sstevel@tonic-gate 	static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1];
20897c478bd9Sstevel@tonic-gate 	char *dp, *fp;
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	dp = dfile;
20927c478bd9Sstevel@tonic-gate 	fp = dir;
20937c478bd9Sstevel@tonic-gate 	while (*fp)
20947c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
20957c478bd9Sstevel@tonic-gate 	if (dp > dfile && *(dp - 1) != '/')
20967c478bd9Sstevel@tonic-gate 		*dp++ = '/';
20977c478bd9Sstevel@tonic-gate 	fp = file;
20987c478bd9Sstevel@tonic-gate 	while (*fp)
20997c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
21007c478bd9Sstevel@tonic-gate 	*dp = '\0';
21017c478bd9Sstevel@tonic-gate 	return (dfile);
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate #include <pwd.h>
21067c478bd9Sstevel@tonic-gate #include <grp.h>
21077c478bd9Sstevel@tonic-gate #include <utmpx.h>
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate struct	utmpx utmp;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (utmp.ut_name))
21127c478bd9Sstevel@tonic-gate #define	SCPYN(a, b)	(void) strncpy(a, b, NMAX)
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate struct cachenode {		/* this struct must be zeroed before using */
21167c478bd9Sstevel@tonic-gate 	struct cachenode *lesschild;	/* subtree whose entries < val */
21177c478bd9Sstevel@tonic-gate 	struct cachenode *grtrchild;	/* subtree whose entries > val */
21187c478bd9Sstevel@tonic-gate 	long val;			/* the uid or gid of this entry */
21197c478bd9Sstevel@tonic-gate 	int initted;			/* name has been filled in */
21207c478bd9Sstevel@tonic-gate 	char name[NMAX+1];		/* the string that val maps to */
21217c478bd9Sstevel@tonic-gate };
21227c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups;
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate static struct cachenode *
21257c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val)
21267c478bd9Sstevel@tonic-gate {
21277c478bd9Sstevel@tonic-gate 	struct cachenode **parent = head;
21287c478bd9Sstevel@tonic-gate 	struct cachenode *c = *parent;
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	while (c != NULL) {
21317c478bd9Sstevel@tonic-gate 		if (val == c->val) {
21327c478bd9Sstevel@tonic-gate 			/* found it */
21337c478bd9Sstevel@tonic-gate 			return (c);
21347c478bd9Sstevel@tonic-gate 		} else if (val < c->val) {
21357c478bd9Sstevel@tonic-gate 			parent = &c->lesschild;
21367c478bd9Sstevel@tonic-gate 			c = c->lesschild;
21377c478bd9Sstevel@tonic-gate 		} else {
21387c478bd9Sstevel@tonic-gate 			parent = &c->grtrchild;
21397c478bd9Sstevel@tonic-gate 			c = c->grtrchild;
21407c478bd9Sstevel@tonic-gate 		}
21417c478bd9Sstevel@tonic-gate 	}
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	/* not in the cache, make a new entry for it */
21447c478bd9Sstevel@tonic-gate 	c = calloc(1, sizeof (struct cachenode));
21457c478bd9Sstevel@tonic-gate 	if (c == NULL) {
21467c478bd9Sstevel@tonic-gate 		perror("ls");
21477c478bd9Sstevel@tonic-gate 		exit(2);
21487c478bd9Sstevel@tonic-gate 	}
21497c478bd9Sstevel@tonic-gate 	*parent = c;
21507c478bd9Sstevel@tonic-gate 	c->val = val;
21517c478bd9Sstevel@tonic-gate 	return (c);
21527c478bd9Sstevel@tonic-gate }
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate /*
21557c478bd9Sstevel@tonic-gate  * get name from cache, or passwd file for a given uid;
21567c478bd9Sstevel@tonic-gate  * lastuid is set to uid.
21577c478bd9Sstevel@tonic-gate  */
21587c478bd9Sstevel@tonic-gate static char *
21597c478bd9Sstevel@tonic-gate getname(uid_t uid)
21607c478bd9Sstevel@tonic-gate {
21617c478bd9Sstevel@tonic-gate 	struct passwd *pwent;
21627c478bd9Sstevel@tonic-gate 	struct cachenode *c;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	if ((uid == lastuid) && lastuname)
21657c478bd9Sstevel@tonic-gate 		return (lastuname);
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	c = findincache(&names, uid);
21687c478bd9Sstevel@tonic-gate 	if (c->initted == 0) {
21697c478bd9Sstevel@tonic-gate 		if ((pwent = getpwuid(uid)) != NULL) {
21707c478bd9Sstevel@tonic-gate 			SCPYN(&c->name[0], pwent->pw_name);
21717c478bd9Sstevel@tonic-gate 		} else {
21727c478bd9Sstevel@tonic-gate 			(void) sprintf(&c->name[0], "%-8u", (int)uid);
21737c478bd9Sstevel@tonic-gate 		}
21747c478bd9Sstevel@tonic-gate 		c->initted = 1;
21757c478bd9Sstevel@tonic-gate 	}
21767c478bd9Sstevel@tonic-gate 	lastuid = uid;
21777c478bd9Sstevel@tonic-gate 	lastuname = &c->name[0];
21787c478bd9Sstevel@tonic-gate 	return (lastuname);
21797c478bd9Sstevel@tonic-gate }
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate /*
21827c478bd9Sstevel@tonic-gate  * get name from cache, or group file for a given gid;
21837c478bd9Sstevel@tonic-gate  * lastgid is set to gid.
21847c478bd9Sstevel@tonic-gate  */
21857c478bd9Sstevel@tonic-gate static char *
21867c478bd9Sstevel@tonic-gate getgroup(gid_t gid)
21877c478bd9Sstevel@tonic-gate {
21887c478bd9Sstevel@tonic-gate 	struct group *grent;
21897c478bd9Sstevel@tonic-gate 	struct cachenode *c;
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	if ((gid == lastgid) && lastgname)
21927c478bd9Sstevel@tonic-gate 		return (lastgname);
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	c = findincache(&groups, gid);
21957c478bd9Sstevel@tonic-gate 	if (c->initted == 0) {
21967c478bd9Sstevel@tonic-gate 		if ((grent = getgrgid(gid)) != NULL) {
21977c478bd9Sstevel@tonic-gate 			SCPYN(&c->name[0], grent->gr_name);
21987c478bd9Sstevel@tonic-gate 		} else {
21997c478bd9Sstevel@tonic-gate 			(void) sprintf(&c->name[0], "%-8u", (int)gid);
22007c478bd9Sstevel@tonic-gate 		}
22017c478bd9Sstevel@tonic-gate 		c->initted = 1;
22027c478bd9Sstevel@tonic-gate 	}
22037c478bd9Sstevel@tonic-gate 	lastgid = gid;
22047c478bd9Sstevel@tonic-gate 	lastgname = &c->name[0];
22057c478bd9Sstevel@tonic-gate 	return (lastgname);
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */
22097c478bd9Sstevel@tonic-gate static int
22107c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2)
22117c478bd9Sstevel@tonic-gate {
22127c478bd9Sstevel@tonic-gate 	struct lbuf *p1, *p2;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	p1 = *pp1;
22157c478bd9Sstevel@tonic-gate 	p2 = *pp2;
22167c478bd9Sstevel@tonic-gate 	if (dflg == 0) {
22177c478bd9Sstevel@tonic-gate /*
22187c478bd9Sstevel@tonic-gate  * compare two names in ls-command one of which is file
22197c478bd9Sstevel@tonic-gate  * and the other is a directory;
22207c478bd9Sstevel@tonic-gate  * this portion is not used for comparing files within
22217c478bd9Sstevel@tonic-gate  * a directory name of ls-command;
22227c478bd9Sstevel@tonic-gate  */
22237c478bd9Sstevel@tonic-gate 		if (p1->lflags&ISARG && p1->ltype == 'd') {
22247c478bd9Sstevel@tonic-gate 			if (!(p2->lflags&ISARG && p2->ltype == 'd'))
22257c478bd9Sstevel@tonic-gate 				return (1);
22267c478bd9Sstevel@tonic-gate 		} else {
22277c478bd9Sstevel@tonic-gate 			if (p2->lflags&ISARG && p2->ltype == 'd')
22287c478bd9Sstevel@tonic-gate 				return (-1);
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 	if (tflg) {
22327c478bd9Sstevel@tonic-gate 		if (p2->lmtime.tv_sec > p1->lmtime.tv_sec)
22337c478bd9Sstevel@tonic-gate 			return (rflg);
22347c478bd9Sstevel@tonic-gate 		else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec)
22357c478bd9Sstevel@tonic-gate 			return (-rflg);
22367c478bd9Sstevel@tonic-gate 		/* times are equal to the sec, check nsec */
22377c478bd9Sstevel@tonic-gate 		if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec)
22387c478bd9Sstevel@tonic-gate 			return (rflg);
22397c478bd9Sstevel@tonic-gate 		else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec)
22407c478bd9Sstevel@tonic-gate 			return (-rflg);
22417c478bd9Sstevel@tonic-gate 		/* if times are equal, fall through and sort by name */
22427c478bd9Sstevel@tonic-gate 	} else if (Sflg) {
22437c478bd9Sstevel@tonic-gate 		/*
22447c478bd9Sstevel@tonic-gate 		 * The size stored in lsize can be either the
22457c478bd9Sstevel@tonic-gate 		 * size or the major minor number (in the case of
22467c478bd9Sstevel@tonic-gate 		 * block and character special devices).  If it's
22477c478bd9Sstevel@tonic-gate 		 * a major minor number, then the size is considered
22487c478bd9Sstevel@tonic-gate 		 * to be zero and we want to fall through and sort
22497c478bd9Sstevel@tonic-gate 		 * by name.  In addition, if the size of p2 is equal
22507c478bd9Sstevel@tonic-gate 		 * to the size of p1 we want to fall through and
22517c478bd9Sstevel@tonic-gate 		 * sort by name.
22527c478bd9Sstevel@tonic-gate 		 */
22537c478bd9Sstevel@tonic-gate 		off_t	p1size = (p1->ltype == 'b') ||
22547c478bd9Sstevel@tonic-gate 		    (p1->ltype == 'c') ? 0 : p1->lsize;
22557c478bd9Sstevel@tonic-gate 		off_t	p2size = (p2->ltype == 'b') ||
22567c478bd9Sstevel@tonic-gate 		    (p2->ltype == 'c') ? 0 : p2->lsize;
22577c478bd9Sstevel@tonic-gate 		if (p2size > p1size) {
22587c478bd9Sstevel@tonic-gate 			return (rflg);
22597c478bd9Sstevel@tonic-gate 		} else if (p2size < p1size) {
22607c478bd9Sstevel@tonic-gate 			return (-rflg);
22617c478bd9Sstevel@tonic-gate 		}
22627c478bd9Sstevel@tonic-gate 		/* Sizes are equal, fall through and sort by name. */
22637c478bd9Sstevel@tonic-gate 	}
22647c478bd9Sstevel@tonic-gate 	return (rflg * strcoll(
22657c478bd9Sstevel@tonic-gate 	    p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname,
22667c478bd9Sstevel@tonic-gate 	    p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname));
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate static void
22707c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2)
22717c478bd9Sstevel@tonic-gate {
22727c478bd9Sstevel@tonic-gate 	csi_pprintf((unsigned char *)s1);
22737c478bd9Sstevel@tonic-gate 	csi_pprintf((unsigned char *)s2);
22747c478bd9Sstevel@tonic-gate }
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate static void
22777c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s)
22787c478bd9Sstevel@tonic-gate {
22797c478bd9Sstevel@tonic-gate 	unsigned char *cp;
22807c478bd9Sstevel@tonic-gate 	char	c;
22817c478bd9Sstevel@tonic-gate 	int	i;
22827c478bd9Sstevel@tonic-gate 	int	c_len;
22837c478bd9Sstevel@tonic-gate 	int	p_col;
22847c478bd9Sstevel@tonic-gate 	wchar_t	pcode;
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	if (!qflg && !bflg) {
22877c478bd9Sstevel@tonic-gate 		for (cp = s; *cp != '\0'; cp++) {
22887c478bd9Sstevel@tonic-gate 			(void) putchar(*cp);
22897c478bd9Sstevel@tonic-gate 			curcol++;
22907c478bd9Sstevel@tonic-gate 		}
22917c478bd9Sstevel@tonic-gate 		return;
22927c478bd9Sstevel@tonic-gate 	}
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	for (cp = s; *cp; ) {
22957c478bd9Sstevel@tonic-gate 		if (isascii(c = *cp)) {
22967c478bd9Sstevel@tonic-gate 			if (!isprint(c)) {
22977c478bd9Sstevel@tonic-gate 				if (qflg) {
22987c478bd9Sstevel@tonic-gate 					c = '?';
22997c478bd9Sstevel@tonic-gate 				} else {
23007c478bd9Sstevel@tonic-gate 					curcol += 3;
23017c478bd9Sstevel@tonic-gate 					(void) putc('\\', stdout);
23027c478bd9Sstevel@tonic-gate 					c = '0' + ((*cp >> 6) & 07);
23037c478bd9Sstevel@tonic-gate 					(void) putc(c, stdout);
23047c478bd9Sstevel@tonic-gate 					c = '0' + ((*cp >> 3) & 07);
23057c478bd9Sstevel@tonic-gate 					(void) putc(c, stdout);
23067c478bd9Sstevel@tonic-gate 					c = '0' + (*cp & 07);
23077c478bd9Sstevel@tonic-gate 				}
23087c478bd9Sstevel@tonic-gate 			}
23097c478bd9Sstevel@tonic-gate 			curcol++;
23107c478bd9Sstevel@tonic-gate 			cp++;
23117c478bd9Sstevel@tonic-gate 			(void) putc(c, stdout);
23127c478bd9Sstevel@tonic-gate 			continue;
23137c478bd9Sstevel@tonic-gate 		}
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 		if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) {
23167c478bd9Sstevel@tonic-gate 			c_len = 1;
23177c478bd9Sstevel@tonic-gate 			goto not_print;
23187c478bd9Sstevel@tonic-gate 		}
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 		if ((p_col = wcwidth(pcode)) > 0) {
23217c478bd9Sstevel@tonic-gate 			(void) putwchar(pcode);
23227c478bd9Sstevel@tonic-gate 			cp += c_len;
23237c478bd9Sstevel@tonic-gate 			curcol += p_col;
23247c478bd9Sstevel@tonic-gate 			continue;
23257c478bd9Sstevel@tonic-gate 		}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate not_print:
23287c478bd9Sstevel@tonic-gate 		for (i = 0; i < c_len; i++) {
23297c478bd9Sstevel@tonic-gate 			if (qflg) {
23307c478bd9Sstevel@tonic-gate 				c = '?';
23317c478bd9Sstevel@tonic-gate 			} else {
23327c478bd9Sstevel@tonic-gate 				curcol += 3;
23337c478bd9Sstevel@tonic-gate 				(void) putc('\\', stdout);
23347c478bd9Sstevel@tonic-gate 				c = '0' + ((*cp >> 6) & 07);
23357c478bd9Sstevel@tonic-gate 				(void) putc(c, stdout);
23367c478bd9Sstevel@tonic-gate 				c = '0' + ((*cp >> 3) & 07);
23377c478bd9Sstevel@tonic-gate 				(void) putc(c, stdout);
23387c478bd9Sstevel@tonic-gate 				c = '0' + (*cp & 07);
23397c478bd9Sstevel@tonic-gate 			}
23407c478bd9Sstevel@tonic-gate 			curcol++;
23417c478bd9Sstevel@tonic-gate 			(void) putc(c, stdout);
23427c478bd9Sstevel@tonic-gate 			cp++;
23437c478bd9Sstevel@tonic-gate 		}
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate }
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate static int
23487c478bd9Sstevel@tonic-gate strcol(unsigned char *s1)
23497c478bd9Sstevel@tonic-gate {
23507c478bd9Sstevel@tonic-gate 	int	w;
23517c478bd9Sstevel@tonic-gate 	int	w_col;
23527c478bd9Sstevel@tonic-gate 	int	len;
23537c478bd9Sstevel@tonic-gate 	wchar_t	wc;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	w = 0;
23567c478bd9Sstevel@tonic-gate 	while (*s1) {
23577c478bd9Sstevel@tonic-gate 		if (isascii(*s1)) {
23587c478bd9Sstevel@tonic-gate 			w++;
23597c478bd9Sstevel@tonic-gate 			s1++;
23607c478bd9Sstevel@tonic-gate 			continue;
23617c478bd9Sstevel@tonic-gate 		}
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 		if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) {
23647c478bd9Sstevel@tonic-gate 			w++;
23657c478bd9Sstevel@tonic-gate 			s1++;
23667c478bd9Sstevel@tonic-gate 			continue;
23677c478bd9Sstevel@tonic-gate 		}
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 		if ((w_col = wcwidth(wc)) < 0)
23707c478bd9Sstevel@tonic-gate 			w_col = len;
23717c478bd9Sstevel@tonic-gate 		s1 += len;
23727c478bd9Sstevel@tonic-gate 		w += w_col;
23737c478bd9Sstevel@tonic-gate 	}
23747c478bd9Sstevel@tonic-gate 	return (w);
23757c478bd9Sstevel@tonic-gate }
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate /*
23787c478bd9Sstevel@tonic-gate  * Convert an unsigned long long to a string representation and place the
23797c478bd9Sstevel@tonic-gate  * result in the caller-supplied buffer.
23807c478bd9Sstevel@tonic-gate  *
23817c478bd9Sstevel@tonic-gate  * The number provided is a size in bytes.  The number is first
23827c478bd9Sstevel@tonic-gate  * converted to an integral multiple of 'scale' bytes.  This new
23837c478bd9Sstevel@tonic-gate  * number is then scaled down until it is small enough to be in a good
23847c478bd9Sstevel@tonic-gate  * human readable format, i.e.  in the range 0 thru scale-1.  If the
23857c478bd9Sstevel@tonic-gate  * number used to derive the final number is not a multiple of scale, and
23867c478bd9Sstevel@tonic-gate  * the final number has only a single significant digit, we compute
23877c478bd9Sstevel@tonic-gate  * tenths of units to provide a second significant digit.
23887c478bd9Sstevel@tonic-gate  *
23897c478bd9Sstevel@tonic-gate  * The value "(unsigned long long)-1" is a special case and is always
23907c478bd9Sstevel@tonic-gate  * converted to "-1".
23917c478bd9Sstevel@tonic-gate  *
23927c478bd9Sstevel@tonic-gate  * A pointer to the caller-supplied buffer is returned.
23937c478bd9Sstevel@tonic-gate  */
23947c478bd9Sstevel@tonic-gate static char *
23957c478bd9Sstevel@tonic-gate number_to_scaled_string(
23967c478bd9Sstevel@tonic-gate 			numbuf_t buf,		/* put the result here */
23977c478bd9Sstevel@tonic-gate 			unsigned long long number, /* convert this number */
23987c478bd9Sstevel@tonic-gate 			long scale)
23997c478bd9Sstevel@tonic-gate {
24007c478bd9Sstevel@tonic-gate 	unsigned long long save;
24017c478bd9Sstevel@tonic-gate 	/* Measurement: kilo, mega, giga, tera, peta, exa */
24027c478bd9Sstevel@tonic-gate 	char *uom = "KMGTPE";
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	if ((long long)number == (long long)-1) {
24057c478bd9Sstevel@tonic-gate 		(void) strlcpy(buf, "-1", sizeof (numbuf_t));
24067c478bd9Sstevel@tonic-gate 		return (buf);
24077c478bd9Sstevel@tonic-gate 	}
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 	save = number;
24107c478bd9Sstevel@tonic-gate 	number = number / scale;
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	/*
24137c478bd9Sstevel@tonic-gate 	 * Now we have number as a count of scale units.
24147c478bd9Sstevel@tonic-gate 	 * If no further scaling is necessary, we round up as appropriate.
24157c478bd9Sstevel@tonic-gate 	 *
24167c478bd9Sstevel@tonic-gate 	 * The largest value number could have had entering the routine is
24177c478bd9Sstevel@tonic-gate 	 * 16 Exabytes, so running off the end of the uom array should
24187c478bd9Sstevel@tonic-gate 	 * never happen.  We check for that, though, as a guard against
24197c478bd9Sstevel@tonic-gate 	 * a breakdown elsewhere in the algorithm.
24207c478bd9Sstevel@tonic-gate 	 */
24217c478bd9Sstevel@tonic-gate 	if (number < (unsigned long long)scale) {
24227c478bd9Sstevel@tonic-gate 		if ((save % scale) >= (unsigned long long)(scale / 2)) {
24237c478bd9Sstevel@tonic-gate 			if (++number == (unsigned long long)scale) {
24247c478bd9Sstevel@tonic-gate 				uom++;
24257c478bd9Sstevel@tonic-gate 				number = 1;
24267c478bd9Sstevel@tonic-gate 			}
24277c478bd9Sstevel@tonic-gate 		}
24287c478bd9Sstevel@tonic-gate 	} else {
24297c478bd9Sstevel@tonic-gate 		while ((number >= (unsigned long long)scale) && (*uom != 'E')) {
24307c478bd9Sstevel@tonic-gate 			uom++; /* next unit of measurement */
24317c478bd9Sstevel@tonic-gate 			save = number;
24327c478bd9Sstevel@tonic-gate 			/*
24337c478bd9Sstevel@tonic-gate 			 * If we're over half way to the next unit of
24347c478bd9Sstevel@tonic-gate 			 * 'scale' bytes (which means we should round
24357c478bd9Sstevel@tonic-gate 			 * up), then adding half of 'scale' prior to
24367c478bd9Sstevel@tonic-gate 			 * the division will push us into that next
24377c478bd9Sstevel@tonic-gate 			 * unit of scale when we perform the division
24387c478bd9Sstevel@tonic-gate 			 */
24397c478bd9Sstevel@tonic-gate 			number = (number + (scale / 2)) / scale;
24407c478bd9Sstevel@tonic-gate 		}
24417c478bd9Sstevel@tonic-gate 	}
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	/* check if we should output a decimal place after the point */
24447c478bd9Sstevel@tonic-gate 	if ((save / scale) < 10) {
24457c478bd9Sstevel@tonic-gate 		/* snprintf() will round for us */
24467c478bd9Sstevel@tonic-gate 		float fnum = (float)save / scale;
24477c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c",
24487c478bd9Sstevel@tonic-gate 		    fnum, *uom);
24497c478bd9Sstevel@tonic-gate 	} else {
24507c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (numbuf_t), "%4llu%c",
24517c478bd9Sstevel@tonic-gate 		    number, *uom);
24527c478bd9Sstevel@tonic-gate 	}
24537c478bd9Sstevel@tonic-gate 	return (buf);
24547c478bd9Sstevel@tonic-gate }
2455da6c28aaSamw 
2456da6c28aaSamw /* Get extended system attributes and set the display */
2457da6c28aaSamw 
2458da6c28aaSamw int
2459da6c28aaSamw get_sysxattr(char *fname, struct lbuf *rep)
2460da6c28aaSamw {
2461da6c28aaSamw 	boolean_t	value;
2462da6c28aaSamw 	data_type_t	type;
2463da6c28aaSamw 	int		error;
2464da6c28aaSamw 	char		*name;
2465da6c28aaSamw 	int		i;
2466da6c28aaSamw 
2467da6c28aaSamw 	if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname,
2468da6c28aaSamw 	    &response)) != 0) {
2469da6c28aaSamw 		perror("ls:getattrat");
2470da6c28aaSamw 		return (error);
2471da6c28aaSamw 	}
2472da6c28aaSamw 
2473da6c28aaSamw 	/*
2474da6c28aaSamw 	 * Allocate 'sacnt' size array to hold extended timestamp
2475da6c28aaSamw 	 * system attributes and initialize the array.
2476da6c28aaSamw 	 */
2477da6c28aaSamw 	rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep);
2478da6c28aaSamw 	for (i = 0; i < sacnt; i++) {
2479da6c28aaSamw 		rep->extm[i].stm = 0;
2480da6c28aaSamw 		rep->extm[i].nstm = 0;
2481da6c28aaSamw 		rep->extm[i].name = NULL;
2482da6c28aaSamw 	}
2483da6c28aaSamw 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2484da6c28aaSamw 		name = nvpair_name(pair);
2485da6c28aaSamw 		type = nvpair_type(pair);
2486da6c28aaSamw 		if (type == DATA_TYPE_BOOLEAN_VALUE) {
2487da6c28aaSamw 			error = nvpair_value_boolean_value(pair, &value);
2488da6c28aaSamw 			if (error) {
2489da6c28aaSamw 				(void) fprintf(stderr,
2490da6c28aaSamw 				    gettext("nvpair_value_boolean_value "
2491da6c28aaSamw 				    "failed: error = %d\n"), error);
2492da6c28aaSamw 				continue;
2493da6c28aaSamw 			}
2494da6c28aaSamw 			if (name != NULL)
2495da6c28aaSamw 				set_sysattrb_display(name, value, rep);
2496da6c28aaSamw 			continue;
2497da6c28aaSamw 		} else if (type == DATA_TYPE_UINT64_ARRAY) {
2498da6c28aaSamw 			if (name != NULL)
2499da6c28aaSamw 				set_sysattrtm_display(name, rep);
2500da6c28aaSamw 			continue;
2501da6c28aaSamw 		}
2502da6c28aaSamw 	}
2503da6c28aaSamw 	nvlist_free(response);
2504da6c28aaSamw 	return (0);
2505da6c28aaSamw }
2506da6c28aaSamw 
2507da6c28aaSamw /* Set extended system attribute boolean display */
2508da6c28aaSamw 
2509da6c28aaSamw void
2510da6c28aaSamw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep)
2511da6c28aaSamw {
2512da6c28aaSamw 	f_attr_t	fattr;
2513da6c28aaSamw 	const char	*opt;
2514da6c28aaSamw 	size_t		len;
2515da6c28aaSamw 
2516da6c28aaSamw 	fattr = name_to_attr(name);
2517da6c28aaSamw 	if (fattr != F_ATTR_INVAL && fattr < sacnt) {
2518da6c28aaSamw 		if (vopt) {
2519da6c28aaSamw 			len = strlen(name);
2520da6c28aaSamw 			if (val) {
2521da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
2522da6c28aaSamw 				(void) strlcpy(rep->exttr[fattr].name, name,
2523da6c28aaSamw 				    len + 1);
2524da6c28aaSamw 			} else {
2525da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 3, rep);
2526da6c28aaSamw 				(void) snprintf(rep->exttr[fattr].name, len + 3,
2527da6c28aaSamw 				    "no%s", name);
2528da6c28aaSamw 			}
2529da6c28aaSamw 		} else {
2530da6c28aaSamw 			opt = attr_to_option(fattr);
2531da6c28aaSamw 			if (opt != NULL) {
2532da6c28aaSamw 				len = strlen(opt);
2533da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
2534da6c28aaSamw 				if (val)
2535da6c28aaSamw 					(void) strlcpy(rep->exttr[fattr].name,
2536da6c28aaSamw 					    opt, len + 1);
2537da6c28aaSamw 				else
2538da6c28aaSamw 					(void) strlcpy(rep->exttr[fattr].name,
2539da6c28aaSamw 					    "-", len + 1);
2540da6c28aaSamw 			}
2541da6c28aaSamw 		}
2542da6c28aaSamw 	}
2543da6c28aaSamw }
2544da6c28aaSamw 
2545da6c28aaSamw /* Set extended system attribute timestamp display */
2546da6c28aaSamw 
2547da6c28aaSamw void
2548da6c28aaSamw set_sysattrtm_display(char *name, struct lbuf *rep)
2549da6c28aaSamw {
2550da6c28aaSamw 	uint_t		nelem;
2551da6c28aaSamw 	uint64_t	*value;
2552da6c28aaSamw 	int		i;
2553da6c28aaSamw 	size_t		len;
2554da6c28aaSamw 
2555da6c28aaSamw 	if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) {
2556da6c28aaSamw 		if (*value != NULL) {
2557da6c28aaSamw 			len = strlen(name);
2558da6c28aaSamw 			i = 0;
2559da6c28aaSamw 			while (rep->extm[i].stm != 0 && i < sacnt)
2560da6c28aaSamw 				i++;
2561da6c28aaSamw 			rep->extm[i].stm = value[0];
2562da6c28aaSamw 			rep->extm[i].nstm = value[1];
2563da6c28aaSamw 			rep->extm[i].name = xmalloc(len + 1, rep);
2564da6c28aaSamw 			(void) strlcpy(rep->extm[i].name, name, len + 1);
2565da6c28aaSamw 		}
2566da6c28aaSamw 	}
2567da6c28aaSamw }
2568da6c28aaSamw 
2569da6c28aaSamw void
25705e1c72e1SJason King format_time(time_t sec, time_t nsec)
2571da6c28aaSamw {
25725e1c72e1SJason King 	const char *fstr = time_fmt_new;
2573da6c28aaSamw 	char fmt_buf[FMTSIZE];
2574da6c28aaSamw 
25755e1c72e1SJason King 	if (Eflg) {
25765e1c72e1SJason King 		(void) snprintf(fmt_buf, FMTSIZE, fstr, nsec);
25775e1c72e1SJason King 		(void) strftime(time_buf, sizeof (time_buf), fmt_buf,
25785e1c72e1SJason King 		    localtime(&sec));
25795e1c72e1SJason King 		return;
2580da6c28aaSamw 	}
2581da6c28aaSamw 
25825e1c72e1SJason King 	if (sec < year || sec > now)
25835e1c72e1SJason King 		fstr = time_fmt_old;
25845e1c72e1SJason King 
25855e1c72e1SJason King 	/* if a custom time was specified, shouldn't be localized */
25865e1c72e1SJason King 	(void) strftime(time_buf, sizeof (time_buf),
25875e1c72e1SJason King 	    (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr,
25885e1c72e1SJason King 	    localtime(&sec));
25895e1c72e1SJason King }
2590da6c28aaSamw 
2591da6c28aaSamw void
2592da6c28aaSamw format_attrtime(struct lbuf *p)
2593da6c28aaSamw {
2594da6c28aaSamw 	int tmattr = 0;
2595da6c28aaSamw 	int i;
2596da6c28aaSamw 
2597da6c28aaSamw 	if (p->extm != NULL) {
2598da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
2599da6c28aaSamw 			if (p->extm[i].name != NULL) {
2600da6c28aaSamw 				tmattr = 1;
2601da6c28aaSamw 				break;
2602da6c28aaSamw 			}
2603da6c28aaSamw 		}
2604da6c28aaSamw 	}
26055e1c72e1SJason King 
2606da6c28aaSamw 	if (tmattr) {
26075e1c72e1SJason King 		const char *old_save = time_fmt_old;
26085e1c72e1SJason King 		const char *new_save = time_fmt_new;
26095e1c72e1SJason King 
26105e1c72e1SJason King 		/* Eflg always sets format to FORMAT_ISO_FULL */
26115e1c72e1SJason King 		if (!Eflg && !time_custom) {
26125e1c72e1SJason King 			time_fmt_old = FORMAT_OLD;
26135e1c72e1SJason King 			time_fmt_new = FORMAT_NEW;
2614da6c28aaSamw 		}
26155e1c72e1SJason King 
26165e1c72e1SJason King 		format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm);
26175e1c72e1SJason King 
26185e1c72e1SJason King 		time_fmt_old = old_save;
26195e1c72e1SJason King 		time_fmt_new = new_save;
2620da6c28aaSamw 	}
2621da6c28aaSamw }
2622da6c28aaSamw 
2623da6c28aaSamw void
2624da6c28aaSamw print_time(struct lbuf *p)
2625da6c28aaSamw {
26265e1c72e1SJason King 	const char *old_save = time_fmt_old;
26275e1c72e1SJason King 	const char *new_save = time_fmt_new;
26285e1c72e1SJason King 
2629da6c28aaSamw 	int i = 0;
2630da6c28aaSamw 
26315e1c72e1SJason King 	if (!Eflg) {
26325e1c72e1SJason King 		time_fmt_old = FORMAT_LONG;
26335e1c72e1SJason King 		time_fmt_new = FORMAT_LONG;
26345e1c72e1SJason King 	}
26355e1c72e1SJason King 
2636da6c28aaSamw 	new_line();
26375e1c72e1SJason King 	format_time(p->lat.tv_sec, p->lat.tv_nsec);
26385e1c72e1SJason King 	(void) printf("         timestamp: atime        %s\n", time_buf);
26395e1c72e1SJason King 	format_time(p->lct.tv_sec, p->lct.tv_nsec);
26405e1c72e1SJason King 	(void) printf("         timestamp: ctime        %s\n", time_buf);
26415e1c72e1SJason King 	format_time(p->lmt.tv_sec, p->lmt.tv_nsec);
26425e1c72e1SJason King 	(void) printf("         timestamp: mtime        %s\n", time_buf);
2643da6c28aaSamw 	if (p->extm != NULL) {
2644da6c28aaSamw 		while (p->extm[i].nstm != 0 && i < sacnt) {
26455e1c72e1SJason King 			format_time(p->extm[i].stm, p->extm[i].nstm);
2646da6c28aaSamw 			if (p->extm[i].name != NULL) {
2647da6c28aaSamw 				(void) printf("         timestamp:"
2648da6c28aaSamw 				    " %s        %s\n",
2649da6c28aaSamw 				    p->extm[i].name, time_buf);
2650da6c28aaSamw 			}
2651da6c28aaSamw 			i++;
2652da6c28aaSamw 		}
2653da6c28aaSamw 	}
26545e1c72e1SJason King 
26555e1c72e1SJason King 	time_fmt_old = old_save;
26565e1c72e1SJason King 	time_fmt_new = new_save;
26575e1c72e1SJason King }
26585e1c72e1SJason King 
26595e1c72e1SJason King /*
26605e1c72e1SJason King  * Check if color definition applies to entry, returns 1 if yes, 0 if no
26615e1c72e1SJason King  */
26625e1c72e1SJason King static int
26635e1c72e1SJason King color_match(struct lbuf *entry, ls_color_t *color)
26645e1c72e1SJason King {
26655e1c72e1SJason King 	switch (color->ftype) {
26665e1c72e1SJason King 	case LS_PAT:
26675e1c72e1SJason King 	{
26685e1c72e1SJason King 		char	*fname;
26695e1c72e1SJason King 		size_t	fname_len, sfx_len;
26705e1c72e1SJason King 
26715e1c72e1SJason King 		if (entry->lflags & ISARG)
26725e1c72e1SJason King 			fname = entry->ln.namep;
26735e1c72e1SJason King 		else
26745e1c72e1SJason King 			fname = entry->ln.lname;
26755e1c72e1SJason King 
26765e1c72e1SJason King 		fname_len = strlen(fname);
26775e1c72e1SJason King 		sfx_len = strlen(color->sfx);
26785e1c72e1SJason King 		if (sfx_len > fname_len)
26795e1c72e1SJason King 			return (0);
26805e1c72e1SJason King 
26815e1c72e1SJason King 		if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0)
26825e1c72e1SJason King 			return (1);
26835e1c72e1SJason King 		else
26845e1c72e1SJason King 			return (0);
26855e1c72e1SJason King 	}
26865e1c72e1SJason King 
26875e1c72e1SJason King 	case LS_NORMAL:
26885e1c72e1SJason King 		return (1);
26895e1c72e1SJason King 
26905e1c72e1SJason King 	case LS_FILE:
26915e1c72e1SJason King 		return ((entry->ltype == '-'));
26925e1c72e1SJason King 
26935e1c72e1SJason King 	case LS_DIR:
26945e1c72e1SJason King 		return ((entry->ltype == 'd'));
26955e1c72e1SJason King 
26965e1c72e1SJason King 	case LS_LINK:
26975e1c72e1SJason King 		return ((entry->ltype == 'l'));
26985e1c72e1SJason King 
26995e1c72e1SJason King 	case LS_FIFO:
27005e1c72e1SJason King 		return ((entry->ltype == 'p'));
27015e1c72e1SJason King 
27025e1c72e1SJason King 	case LS_SOCK:
27035e1c72e1SJason King 		return ((entry->ltype == 's'));
27045e1c72e1SJason King 
27055e1c72e1SJason King 	case LS_DOOR:
27065e1c72e1SJason King 		return ((entry->ltype == 'D'));
27075e1c72e1SJason King 
27085e1c72e1SJason King 	case LS_BLK:
27095e1c72e1SJason King 		return ((entry->ltype == 'b'));
27105e1c72e1SJason King 
27115e1c72e1SJason King 	case LS_CHR:
27125e1c72e1SJason King 		return ((entry->ltype == 'c'));
27135e1c72e1SJason King 
27145e1c72e1SJason King 	case LS_PORT:
27155e1c72e1SJason King 		return ((entry->ltype == 'P'));
27165e1c72e1SJason King 
27175e1c72e1SJason King 	case LS_ORPHAN:
27185e1c72e1SJason King 	{
27195e1c72e1SJason King 		struct stat st;
27205e1c72e1SJason King 		int rc;
27215e1c72e1SJason King 
27225e1c72e1SJason King 		if (entry->ltype != 'l')
27235e1c72e1SJason King 			return (0);
27245e1c72e1SJason King 		if (entry->flinkto == NULL)
27255e1c72e1SJason King 			return (1);
27265e1c72e1SJason King 
27275e1c72e1SJason King 		if (entry->lflags & ISARG)
27285e1c72e1SJason King 			rc = stat(entry->ln.namep, &st);
27295e1c72e1SJason King 		else
27305e1c72e1SJason King 			rc = stat(entry->ln.lname, &st);
27315e1c72e1SJason King 
27325e1c72e1SJason King 		if (rc == -1 && errno == ENOENT)
27335e1c72e1SJason King 			return (1);
27345e1c72e1SJason King 
27355e1c72e1SJason King 		return (0);
27365e1c72e1SJason King 	}
27375e1c72e1SJason King 
27385e1c72e1SJason King 	case LS_SETUID:
27395e1c72e1SJason King 		return (entry->ltype != 'l' && (entry->lflags & (S_ISUID)));
27405e1c72e1SJason King 
27415e1c72e1SJason King 	case LS_SETGID:
27425e1c72e1SJason King 		return (entry->ltype != 'l' && (entry->lflags & (S_ISGID)));
27435e1c72e1SJason King 
27445e1c72e1SJason King 	case LS_STICKY_OTHER_WRITABLE:
27455e1c72e1SJason King 		return (entry->ltype != 'l' &&
27465e1c72e1SJason King 		    (entry->lflags & (S_IWOTH|S_ISVTX)));
27475e1c72e1SJason King 
27485e1c72e1SJason King 	case LS_OTHER_WRITABLE:
27495e1c72e1SJason King 		return (entry->ltype != 'l' && (entry->lflags & (S_IWOTH)));
27505e1c72e1SJason King 
27515e1c72e1SJason King 	case LS_STICKY:
27525e1c72e1SJason King 		return (entry->ltype != 'l' && (entry->lflags & (S_ISVTX)));
27535e1c72e1SJason King 
27545e1c72e1SJason King 	case LS_EXEC:
27555e1c72e1SJason King 		return (entry->ltype != 'l' &&
27565e1c72e1SJason King 		    (entry->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)));
27575e1c72e1SJason King 	}
27585e1c72e1SJason King 
27595e1c72e1SJason King 	return (0);
27605e1c72e1SJason King }
27615e1c72e1SJason King 
27625e1c72e1SJason King static void
27635e1c72e1SJason King dump_color(ls_color_t *c)
27645e1c72e1SJason King {
27655e1c72e1SJason King 	if (c == NULL)
27665e1c72e1SJason King 		return;
27675e1c72e1SJason King 
27685e1c72e1SJason King 	(void) printf("\n\ttype: ");
27695e1c72e1SJason King 	switch (c->ftype) {
27705e1c72e1SJason King 	case LS_NORMAL:
27715e1c72e1SJason King 		(void) printf("LS_NORMAL");
27725e1c72e1SJason King 		break;
27735e1c72e1SJason King 	case LS_FILE:
27745e1c72e1SJason King 		(void) printf("LS_FILE");
27755e1c72e1SJason King 		break;
27765e1c72e1SJason King 	case LS_EXEC:
27775e1c72e1SJason King 		(void) printf("LS_EXEC");
27785e1c72e1SJason King 		break;
27795e1c72e1SJason King 	case LS_DIR:
27805e1c72e1SJason King 		(void) printf("LS_DIR");
27815e1c72e1SJason King 		break;
27825e1c72e1SJason King 	case LS_LINK:
27835e1c72e1SJason King 		(void) printf("LS_LINK");
27845e1c72e1SJason King 		break;
27855e1c72e1SJason King 
27865e1c72e1SJason King 	case LS_FIFO:
27875e1c72e1SJason King 		(void) printf("LS_FIFO");
27885e1c72e1SJason King 		break;
27895e1c72e1SJason King 
27905e1c72e1SJason King 	case LS_SOCK:
27915e1c72e1SJason King 		(void) printf("LS_SOCK");
27925e1c72e1SJason King 		break;
27935e1c72e1SJason King 
27945e1c72e1SJason King 	case LS_DOOR:
27955e1c72e1SJason King 		(void) printf("LS_DOOR");
27965e1c72e1SJason King 		break;
27975e1c72e1SJason King 
27985e1c72e1SJason King 	case LS_BLK:
27995e1c72e1SJason King 		(void) printf("LS_BLK");
28005e1c72e1SJason King 		break;
28015e1c72e1SJason King 
28025e1c72e1SJason King 	case LS_CHR:
28035e1c72e1SJason King 		(void) printf("LS_CHR");
28045e1c72e1SJason King 		break;
28055e1c72e1SJason King 
28065e1c72e1SJason King 	case LS_PORT:
28075e1c72e1SJason King 		(void) printf("LS_PORT");
28085e1c72e1SJason King 		break;
28095e1c72e1SJason King 
28105e1c72e1SJason King 	case LS_STICKY:
28115e1c72e1SJason King 		(void) printf("LS_STICKY");
28125e1c72e1SJason King 		break;
28135e1c72e1SJason King 
28145e1c72e1SJason King 	case LS_ORPHAN:
28155e1c72e1SJason King 		(void) printf("LS_ORPHAN");
28165e1c72e1SJason King 		break;
28175e1c72e1SJason King 
28185e1c72e1SJason King 	case LS_SETGID:
28195e1c72e1SJason King 		(void) printf("LS_SETGID");
28205e1c72e1SJason King 		break;
28215e1c72e1SJason King 
28225e1c72e1SJason King 	case LS_SETUID:
28235e1c72e1SJason King 		(void) printf("LS_SETUID");
28245e1c72e1SJason King 		break;
28255e1c72e1SJason King 
28265e1c72e1SJason King 	case LS_OTHER_WRITABLE:
28275e1c72e1SJason King 		(void) printf("LS_OTHER_WRITABLE");
28285e1c72e1SJason King 		break;
28295e1c72e1SJason King 
28305e1c72e1SJason King 	case LS_STICKY_OTHER_WRITABLE:
28315e1c72e1SJason King 		(void) printf("LS_STICKY_OTHER_WRITABLE");
28325e1c72e1SJason King 		break;
28335e1c72e1SJason King 
28345e1c72e1SJason King 	case LS_PAT:
28355e1c72e1SJason King 		(void) printf("LS_PAT\n");
28365e1c72e1SJason King 		(void) printf("\tpattern: %s", c->sfx);
28375e1c72e1SJason King 		break;
28385e1c72e1SJason King 	}
28395e1c72e1SJason King 	(void) printf("\n");
28405e1c72e1SJason King 	(void) printf("\tattr: %d\n", c->attr);
28415e1c72e1SJason King 	(void) printf("\tfg: %d\n", c->fg);
28425e1c72e1SJason King 	(void) printf("\tbg: %d\n", c->bg);
28435e1c72e1SJason King 	(void) printf("\t");
28445e1c72e1SJason King }
28455e1c72e1SJason King 
28465e1c72e1SJason King static ls_color_t *
28475e1c72e1SJason King get_color_attr(struct lbuf *l)
28485e1c72e1SJason King {
28495e1c72e1SJason King 	int i;
28505e1c72e1SJason King 
28515e1c72e1SJason King 	/*
28525e1c72e1SJason King 	 * Colors are sorted from most general lsc_colors[0] to most specific
28535e1c72e1SJason King 	 * lsc_colors[lsc_ncolors - 1] by ls_color_init().  Start search with
28545e1c72e1SJason King 	 * most specific color rule and work towards most general.
28555e1c72e1SJason King 	 */
28565e1c72e1SJason King 	for (i = lsc_ncolors - 1; i >= 0; --i)
28575e1c72e1SJason King 		if (color_match(l, &lsc_colors[i]))
28585e1c72e1SJason King 			return (&lsc_colors[i]);
28595e1c72e1SJason King 
28605e1c72e1SJason King 	return (NULL);
28615e1c72e1SJason King }
28625e1c72e1SJason King 
28635e1c72e1SJason King static void
28645e1c72e1SJason King ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4,
28655e1c72e1SJason King     long int p5, long int p6, long int p7, long int p8, long int p9)
28665e1c72e1SJason King {
28675e1c72e1SJason King 	char *s;
28685e1c72e1SJason King 
28695e1c72e1SJason King 	if (str == NULL)
28705e1c72e1SJason King 		return;
28715e1c72e1SJason King 
28725e1c72e1SJason King 	s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
28735e1c72e1SJason King 
28745e1c72e1SJason King 	if (s != NULL)
28755e1c72e1SJason King 		(void) putp(s);
28765e1c72e1SJason King }
28775e1c72e1SJason King 
28785e1c72e1SJason King static void
28795e1c72e1SJason King ls_start_color(struct lbuf *l)
28805e1c72e1SJason King {
28815e1c72e1SJason King 	ls_color_t *c = get_color_attr(l);
28825e1c72e1SJason King 
28835e1c72e1SJason King 	if (c == NULL)
28845e1c72e1SJason King 		return;
28855e1c72e1SJason King 
28865e1c72e1SJason King 	if (lsc_debug)
28875e1c72e1SJason King 		lsc_match = c;
28885e1c72e1SJason King 
28895e1c72e1SJason King 	if (c->attr & LSA_BOLD)
28905e1c72e1SJason King 		ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28915e1c72e1SJason King 	if (c->attr & LSA_UNDERSCORE)
28925e1c72e1SJason King 		ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28935e1c72e1SJason King 	if (c->attr & LSA_BLINK)
28945e1c72e1SJason King 		ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28955e1c72e1SJason King 	if (c->attr & LSA_REVERSE)
28965e1c72e1SJason King 		ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28975e1c72e1SJason King 	if (c->attr & LSA_CONCEALED)
28985e1c72e1SJason King 		ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28995e1c72e1SJason King 	if (c->attr == LSA_NONE)
29005e1c72e1SJason King 		ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
29015e1c72e1SJason King 
29025e1c72e1SJason King 	if (c->fg != -1)
29035e1c72e1SJason King 		ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0);
29045e1c72e1SJason King 	if (c->bg != -1)
29055e1c72e1SJason King 		ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0);
29065e1c72e1SJason King }
29075e1c72e1SJason King 
29085e1c72e1SJason King static void
29095e1c72e1SJason King ls_end_color()
29105e1c72e1SJason King {
29115e1c72e1SJason King 	ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
29125e1c72e1SJason King 	if (lsc_debug)
29135e1c72e1SJason King 		dump_color(lsc_match);
29145e1c72e1SJason King }
29155e1c72e1SJason King 
29165e1c72e1SJason King static void
29175e1c72e1SJason King new_color_entry(char *colorstr)
29185e1c72e1SJason King {
29195e1c72e1SJason King 	static const struct {
29205e1c72e1SJason King 		const char	*s;
29215e1c72e1SJason King 		ls_cftype_t	stype;
29225e1c72e1SJason King 	} type_map[] = {
29235e1c72e1SJason King 		{ "no", LS_NORMAL },
29245e1c72e1SJason King 		{ "fi", LS_FILE },
29255e1c72e1SJason King 		{ "di", LS_DIR },
29265e1c72e1SJason King 		{ "ln", LS_LINK },
29275e1c72e1SJason King 		{ "pi", LS_FIFO },
29285e1c72e1SJason King 		{ "so", LS_SOCK },
29295e1c72e1SJason King 		{ "do", LS_DOOR },
29305e1c72e1SJason King 		{ "bd", LS_BLK },
29315e1c72e1SJason King 		{ "cd", LS_CHR },
29325e1c72e1SJason King 		{ "or", LS_ORPHAN },
29335e1c72e1SJason King 		{ "su", LS_SETUID },
29345e1c72e1SJason King 		{ "sg", LS_SETGID },
29355e1c72e1SJason King 		{ "tw", LS_STICKY_OTHER_WRITABLE },
29365e1c72e1SJason King 		{ "ow", LS_OTHER_WRITABLE },
29375e1c72e1SJason King 		{ "st", LS_STICKY },
29385e1c72e1SJason King 		{ "ex", LS_EXEC },
29395e1c72e1SJason King 		{ "po", LS_PORT },
29405e1c72e1SJason King 		{ NULL, LS_NORMAL }
29415e1c72e1SJason King 	};
29425e1c72e1SJason King 
29435e1c72e1SJason King 	char		*p, *lasts;
29445e1c72e1SJason King 	int		i;
29455e1c72e1SJason King 	int		color, attr;
29465e1c72e1SJason King 
29475e1c72e1SJason King 	p = strtok_r(colorstr, "=", &lasts);
29485e1c72e1SJason King 	if (p == NULL) {
29495e1c72e1SJason King 		colorflg = 0;
29505e1c72e1SJason King 		return;
29515e1c72e1SJason King 	}
29525e1c72e1SJason King 
29535e1c72e1SJason King 	if (p[0] == '*') {
29545e1c72e1SJason King 		lsc_colors[lsc_ncolors].ftype = LS_PAT;
29555e1c72e1SJason King 		/* don't include the * in the suffix */
29565e1c72e1SJason King 		if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) {
29575e1c72e1SJason King 			colorflg = 0;
29585e1c72e1SJason King 			return;
29595e1c72e1SJason King 		}
2960da6c28aaSamw 	} else {
29615e1c72e1SJason King 		lsc_colors[lsc_ncolors].sfx = NULL;
29625e1c72e1SJason King 
29635e1c72e1SJason King 		for (i = 0; type_map[i].s != NULL; ++i) {
29645e1c72e1SJason King 			if (strncmp(type_map[i].s, p, 2) == 0)
29655e1c72e1SJason King 				break;
2966da6c28aaSamw 		}
29675e1c72e1SJason King 
29685e1c72e1SJason King 		/* ignore unknown file types */
29695e1c72e1SJason King 		if (type_map[i].s == NULL)
29705e1c72e1SJason King 			return;
29715e1c72e1SJason King 
29725e1c72e1SJason King 		lsc_colors[lsc_ncolors].ftype = type_map[i].stype;
29735e1c72e1SJason King 	}
29745e1c72e1SJason King 
29755e1c72e1SJason King 	attr = LSA_NONE;
29765e1c72e1SJason King 	lsc_colors[lsc_ncolors].fg = -1;
29775e1c72e1SJason King 	lsc_colors[lsc_ncolors].bg = -1;
29785e1c72e1SJason King 	for (p = strtok_r(NULL, ";", &lasts); p != NULL;
29795e1c72e1SJason King 	    p = strtok_r(NULL, ";", &lasts)) {
29805e1c72e1SJason King 		color = strtol(p, NULL, 10);
29815e1c72e1SJason King 
29825e1c72e1SJason King 		if (color < 10) {
29835e1c72e1SJason King 			switch (color) {
29845e1c72e1SJason King 			case 0:
29855e1c72e1SJason King 				attr = LSA_NONE;
29865e1c72e1SJason King 				continue;
29875e1c72e1SJason King 			case 1:
29885e1c72e1SJason King 				attr |= LSA_BOLD;
29895e1c72e1SJason King 				continue;
29905e1c72e1SJason King 			case 4:
29915e1c72e1SJason King 				attr |= LSA_UNDERSCORE;
29925e1c72e1SJason King 				continue;
29935e1c72e1SJason King 			case 5:
29945e1c72e1SJason King 				attr |= LSA_BLINK;
29955e1c72e1SJason King 				continue;
29965e1c72e1SJason King 			case 7:
29975e1c72e1SJason King 				attr |= LSA_REVERSE;
29985e1c72e1SJason King 				continue;
29995e1c72e1SJason King 			case 8:
30005e1c72e1SJason King 				attr |= LSA_CONCEALED;
30015e1c72e1SJason King 				continue;
30025e1c72e1SJason King 			default:
30035e1c72e1SJason King 				continue;
3004da6c28aaSamw 			}
3005da6c28aaSamw 		}
30065e1c72e1SJason King 
30075e1c72e1SJason King 		if (color < 40)
30085e1c72e1SJason King 			lsc_colors[lsc_ncolors].fg = color - 30;
30095e1c72e1SJason King 		else
30105e1c72e1SJason King 			lsc_colors[lsc_ncolors].bg = color - 40;
30115e1c72e1SJason King 	}
30125e1c72e1SJason King 
30135e1c72e1SJason King 	lsc_colors[lsc_ncolors].attr = attr;
30145e1c72e1SJason King 	++lsc_ncolors;
30155e1c72e1SJason King }
30165e1c72e1SJason King 
30175e1c72e1SJason King static int
30185e1c72e1SJason King ls_color_compare(const void *p1, const void *p2)
30195e1c72e1SJason King {
30205e1c72e1SJason King 	const ls_color_t *c1 = (const ls_color_t *)p1;
30215e1c72e1SJason King 	const ls_color_t *c2 = (const ls_color_t *)p2;
30225e1c72e1SJason King 
30235e1c72e1SJason King 	int ret = c1->ftype - c2->ftype;
30245e1c72e1SJason King 
30255e1c72e1SJason King 	if (ret != 0)
30265e1c72e1SJason King 		return (ret);
30275e1c72e1SJason King 
30285e1c72e1SJason King 	if (c1->ftype != LS_PAT)
30295e1c72e1SJason King 		return (ret);
30305e1c72e1SJason King 
30315e1c72e1SJason King 	return (strcmp(c1->sfx, c2->sfx));
30325e1c72e1SJason King }
30335e1c72e1SJason King 
30345e1c72e1SJason King static void
30355e1c72e1SJason King ls_color_init()
30365e1c72e1SJason King {
30375e1c72e1SJason King 	static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35"
30385e1c72e1SJason King 	    ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01"
30395e1c72e1SJason King 	    ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31"
30405e1c72e1SJason King 	    ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31"
30415e1c72e1SJason King 	    ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31"
30425e1c72e1SJason King 	    ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35"
30435e1c72e1SJason King 	    ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"
30445e1c72e1SJason King 	    ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35"
30455e1c72e1SJason King 	    ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35"
30465e1c72e1SJason King 	    ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35"
30475e1c72e1SJason King 	    ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35";
30485e1c72e1SJason King 
30495e1c72e1SJason King 	char    *colorstr;
30505e1c72e1SJason King 	char    *p, *lasts;
30515e1c72e1SJason King 	size_t  color_sz;
30525e1c72e1SJason King 	int	termret;
30535e1c72e1SJason King 
30545e1c72e1SJason King 	(void) setupterm(NULL, 1, &termret);
30555e1c72e1SJason King 	if (termret != 1)
30565e1c72e1SJason King 		return;
30575e1c72e1SJason King 
30585e1c72e1SJason King 	if ((colorstr = getenv("LS_COLORS")) == NULL)
30595e1c72e1SJason King 		colorstr = default_colorstr;
30605e1c72e1SJason King 
3061*f7387fb0SJason King 	/*
3062*f7387fb0SJason King 	 * Determine the size of lsc_colors.  color_sz can be > lsc_ncolors
3063*f7387fb0SJason King 	 * if there are invalid entries passed in the string (they are ignored)
3064*f7387fb0SJason King 	 */
3065*f7387fb0SJason King 	color_sz = 1;
30665e1c72e1SJason King 	for (p = strchr(colorstr, ':'); p != NULL && *p != '\0';
30675e1c72e1SJason King 	    p = strchr(++p, ':'))
30685e1c72e1SJason King 		++color_sz;
30695e1c72e1SJason King 
30705e1c72e1SJason King 	lsc_colors = calloc(color_sz, sizeof (ls_color_t));
30715e1c72e1SJason King 	if (lsc_colors == NULL) {
30725e1c72e1SJason King 		free(colorstr);
30735e1c72e1SJason King 		return;
30745e1c72e1SJason King 	}
30755e1c72e1SJason King 
30765e1c72e1SJason King 	for (p = strtok_r(colorstr, ":", &lasts);
30775e1c72e1SJason King 	    p != NULL && lsc_ncolors < color_sz;
30785e1c72e1SJason King 	    p = strtok_r(NULL, ":", &lasts))
30795e1c72e1SJason King 		new_color_entry(p);
30805e1c72e1SJason King 
30815e1c72e1SJason King 	qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t),
30825e1c72e1SJason King 	    ls_color_compare);
30835e1c72e1SJason King 
30845e1c72e1SJason King 	if ((lsc_bold = tigetstr("bold")) == (char *)-1)
30855e1c72e1SJason King 		lsc_bold = NULL;
30865e1c72e1SJason King 
30875e1c72e1SJason King 	if ((lsc_underline = tigetstr("smul")) == (char *)-1)
30885e1c72e1SJason King 		lsc_underline = NULL;
30895e1c72e1SJason King 
30905e1c72e1SJason King 	if ((lsc_blink = tigetstr("blink")) == (char *)-1)
30915e1c72e1SJason King 		lsc_blink = NULL;
30925e1c72e1SJason King 
30935e1c72e1SJason King 	if ((lsc_reverse = tigetstr("rev")) == (char *)-1)
30945e1c72e1SJason King 		lsc_reverse = NULL;
30955e1c72e1SJason King 
30965e1c72e1SJason King 	if ((lsc_concealed = tigetstr("prot")) == (char *)-1)
30975e1c72e1SJason King 		lsc_concealed = NULL;
30985e1c72e1SJason King 
30995e1c72e1SJason King 	if ((lsc_none = tigetstr("sgr0")) == (char *)-1)
31005e1c72e1SJason King 		lsc_none = NULL;
31015e1c72e1SJason King 
31025e1c72e1SJason King 	if ((lsc_setfg = tigetstr("setaf")) == (char *)-1)
31035e1c72e1SJason King 		lsc_setfg = NULL;
31045e1c72e1SJason King 
31055e1c72e1SJason King 	if ((lsc_setbg = tigetstr("setab")) == (char *)-1)
31065e1c72e1SJason King 		lsc_setbg = NULL;
31075e1c72e1SJason King 
31085e1c72e1SJason King 	if (getenv("_LS_COLOR_DEBUG") != NULL) {
31095e1c72e1SJason King 		int i;
31105e1c72e1SJason King 
31115e1c72e1SJason King 		lsc_debug = 1;
31125e1c72e1SJason King 		for (i = 0; i < lsc_ncolors; ++i)
31135e1c72e1SJason King 			dump_color(&lsc_colors[i]);
3114da6c28aaSamw 	}
3115da6c28aaSamw }
3116da6c28aaSamw 
3117da6c28aaSamw /* Free extended system attribute lists */
3118da6c28aaSamw 
3119da6c28aaSamw void
3120da6c28aaSamw free_sysattr(struct lbuf *p)
3121da6c28aaSamw {
3122da6c28aaSamw 	int i;
3123da6c28aaSamw 
3124da6c28aaSamw 	if (p->exttr != NULL) {
3125da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
3126da6c28aaSamw 			if (p->exttr[i].name != NULL)
3127da6c28aaSamw 				free(p->exttr[i].name);
3128da6c28aaSamw 		}
3129da6c28aaSamw 		free(p->exttr);
3130da6c28aaSamw 	}
3131da6c28aaSamw 	if (p->extm != NULL) {
3132da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
3133da6c28aaSamw 			if (p->extm[i].name != NULL)
3134da6c28aaSamw 				free(p->extm[i].name);
3135da6c28aaSamw 		}
3136da6c28aaSamw 		free(p->extm);
3137da6c28aaSamw 	}
3138da6c28aaSamw }
3139da6c28aaSamw 
3140da6c28aaSamw /* Allocate extended system attribute list */
3141da6c28aaSamw 
3142da6c28aaSamw void *
3143da6c28aaSamw xmalloc(size_t size, struct lbuf *p)
3144da6c28aaSamw {
3145da6c28aaSamw 	if ((p = malloc(size)) == NULL) {
3146da6c28aaSamw 		perror("ls");
3147da6c28aaSamw 		free_sysattr(p);
3148da6c28aaSamw 		nvlist_free(response);
3149da6c28aaSamw 		exit(2);
3150da6c28aaSamw 	}
3151da6c28aaSamw 	return (p);
3152da6c28aaSamw }
3153