xref: /titanic_51/usr/src/cmd/ls/ls.c (revision fc30d4661fdf50c4c69dacbc572af35439c28cd8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52236845bSakaplan  * Common Development and Distribution License (the "License").
62236845bSakaplan  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215e1c72e1SJason King 
227c478bd9Sstevel@tonic-gate /*
2327dd1e87SMark Shellenbaum  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
2491bbe3fdSBill Pijewski  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
25b9c81738SGary Mills  * Copyright 2015 Gary Mills
265e1c72e1SJason King  */
275e1c72e1SJason King 
285e1c72e1SJason King /*
29*fc30d466SJason King  * Copyright 2017 Jason King.  All rights reserved.
307c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
347c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
377c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * List files or directories
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/param.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <sys/acl.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <wchar.h>
507c478bd9Sstevel@tonic-gate #include <stdio.h>
517c478bd9Sstevel@tonic-gate #include <ctype.h>
527c478bd9Sstevel@tonic-gate #include <dirent.h>
537c478bd9Sstevel@tonic-gate #include <string.h>
547c478bd9Sstevel@tonic-gate #include <locale.h>
557c478bd9Sstevel@tonic-gate #include <curses.h>
565e1c72e1SJason King #include <term.h>
577c478bd9Sstevel@tonic-gate #include <termios.h>
587c478bd9Sstevel@tonic-gate #include <stdlib.h>
597c478bd9Sstevel@tonic-gate #include <widec.h>
607c478bd9Sstevel@tonic-gate #include <locale.h>
617c478bd9Sstevel@tonic-gate #include <wctype.h>
627c478bd9Sstevel@tonic-gate #include <pwd.h>
637c478bd9Sstevel@tonic-gate #include <grp.h>
647c478bd9Sstevel@tonic-gate #include <limits.h>
657c478bd9Sstevel@tonic-gate #include <fcntl.h>
667c478bd9Sstevel@tonic-gate #include <unistd.h>
677c478bd9Sstevel@tonic-gate #include <libgen.h>
687c478bd9Sstevel@tonic-gate #include <errno.h>
69fa9e4066Sahrens #include <aclutils.h>
70da6c28aaSamw #include <libnvpair.h>
71da6c28aaSamw #include <libcmdutils.h>
72da6c28aaSamw #include <attr.h>
735e1c72e1SJason King #include <getopt.h>
745e1c72e1SJason King #include <inttypes.h>
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #ifndef STANDALONE
777c478bd9Sstevel@tonic-gate #define	TERMINFO
787c478bd9Sstevel@tonic-gate #endif
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * -DNOTERMINFO can be defined on the cc command line to prevent
827c478bd9Sstevel@tonic-gate  * the use of terminfo.  This should be done on systems not having
83da6c28aaSamw  * the terminfo feature(pre 6.0 systems ?).
847c478bd9Sstevel@tonic-gate  * As a result, columnar listings assume 80 columns for output,
857c478bd9Sstevel@tonic-gate  * unless told otherwise via the COLUMNS environment variable.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO
887c478bd9Sstevel@tonic-gate #undef TERMINFO
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #include <term.h>
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	BFSIZE	16
947c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */
957c478bd9Sstevel@tonic-gate #define	ISARG	0100000
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * this flag has been added to manipulate the display of S instead of 'l' when
997c478bd9Sstevel@tonic-gate  * the file is not a regular file and when group execution bit is off
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate #define	LS_NOTREG	010000
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Date and time formats
1067c478bd9Sstevel@tonic-gate  *
1077c478bd9Sstevel@tonic-gate  * b --- abbreviated month name
1087c478bd9Sstevel@tonic-gate  * e --- day number
1097c478bd9Sstevel@tonic-gate  * Y --- year in the form ccyy
1107c478bd9Sstevel@tonic-gate  * H --- hour(24-hour version)
1117c478bd9Sstevel@tonic-gate  * M --- minute
1127c478bd9Sstevel@tonic-gate  * F --- yyyy-mm-dd
1137c478bd9Sstevel@tonic-gate  * T --- hh:mm:ss
1147c478bd9Sstevel@tonic-gate  * z --- time zone as hours displacement from UTC
1157c478bd9Sstevel@tonic-gate  * note that %F and %z are from the ISO C99 standard and are
1167c478bd9Sstevel@tonic-gate  * not present in older C libraries
1177c478bd9Sstevel@tonic-gate  */
1185e1c72e1SJason King #define	FORMAT_OLD	" %b %e  %Y "
1195e1c72e1SJason King #define	FORMAT_NEW	" %b %e %H:%M "
1205e1c72e1SJason King #define	FORMAT_LONG	" %b %e %T %Y "
1215e1c72e1SJason King #define	FORMAT_ISO_FULL	" %%F %%T.%.09ld %%z "
1225e1c72e1SJason King #define	FORMAT_ISO_LONG	" %F %R "
1235e1c72e1SJason King #define	FORMAT_ISO_NEW	" %m-%d %H:%M "
1245e1c72e1SJason King #define	FORMAT_ISO_OLD	" %F "
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #undef BUFSIZ
1277c478bd9Sstevel@tonic-gate #define	BUFSIZ 4096
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 
1465e1c72e1SJason King #define	LSA_NONE	(0)
1475e1c72e1SJason King #define	LSA_BOLD	(1L << 0)
1485e1c72e1SJason King #define	LSA_UNDERSCORE	(1L << 1)
1495e1c72e1SJason King #define	LSA_BLINK	(1L << 2)
1505e1c72e1SJason King #define	LSA_REVERSE	(1L << 3)
1515e1c72e1SJason King #define	LSA_CONCEALED	(1L << 4)
1525e1c72e1SJason King 
1535e1c72e1SJason King /* these should be ordered most general to most specific */
1545e1c72e1SJason King typedef enum LS_CFTYPE {
1555e1c72e1SJason King 	LS_NORMAL,
1565e1c72e1SJason King 	LS_FILE,
1575e1c72e1SJason King 	LS_EXEC,
1585e1c72e1SJason King 	LS_DIR,
1595e1c72e1SJason King 	LS_LINK,
1605e1c72e1SJason King 	LS_FIFO,
1615e1c72e1SJason King 	LS_SOCK,
1625e1c72e1SJason King 	LS_DOOR,
1635e1c72e1SJason King 	LS_BLK,
1645e1c72e1SJason King 	LS_CHR,
1655e1c72e1SJason King 	LS_PORT,
1665e1c72e1SJason King 	LS_STICKY,
1675e1c72e1SJason King 	LS_ORPHAN,
1685e1c72e1SJason King 	LS_SETGID,
1695e1c72e1SJason King 	LS_SETUID,
1705e1c72e1SJason King 	LS_OTHER_WRITABLE,
1715e1c72e1SJason King 	LS_STICKY_OTHER_WRITABLE,
1725e1c72e1SJason King 	LS_PAT
1735e1c72e1SJason King } ls_cftype_t;
1745e1c72e1SJason King 
1751b628248SJason King typedef struct {
1765e1c72e1SJason King 	char		*sfx;
1775e1c72e1SJason King 	ls_cftype_t	ftype;
1785e1c72e1SJason King 	int		attr;
1795e1c72e1SJason King 	int		fg;
1805e1c72e1SJason King 	int		bg;
1815e1c72e1SJason King } ls_color_t;
1825e1c72e1SJason King 
1831b628248SJason King struct	lbuf	{
1841b628248SJason King 	union	{
1851b628248SJason King 		char	lname[MAXNAMLEN]; /* used for filename in a directory */
1861b628248SJason King 		char	*namep;		/* for name in ls-command; */
1871b628248SJason King 	} ln;
1881b628248SJason King 	char	ltype;		/* filetype */
1891b628248SJason King 	ino_t	lnum;		/* inode number of file */
1901b628248SJason King 	mode_t	lflags; 	/* 0777 bits used as r,w,x permissions */
1911b628248SJason King 	nlink_t	lnl;		/* number of links to file */
1921b628248SJason King 	uid_t	luid;
1931b628248SJason King 	gid_t	lgid;
1941b628248SJason King 	off_t	lsize;		/* filesize or major/minor dev numbers */
1951b628248SJason King 	blkcnt_t	lblocks;	/* number of file blocks */
1961b628248SJason King 	timestruc_t	lmtime;
1971b628248SJason King 	timestruc_t	lat;
1981b628248SJason King 	timestruc_t	lct;
1991b628248SJason King 	timestruc_t	lmt;
2001b628248SJason King 	char	*flinkto;	/* symbolic link contents */
2011b628248SJason King 	char 	acl;		/* indicate there are additional acl entries */
2021b628248SJason King 	int	cycle;		/* cycle detected flag */
2031b628248SJason King 	struct ditem *ancinfo;	/* maintains ancestor info */
2041b628248SJason King 	acl_t *aclp;		/* ACL if present */
2051b628248SJason King 	struct attrb *exttr;	/* boolean extended system attributes */
2061b628248SJason King 	struct attrtm *extm;	/* timestamp extended system attributes */
2071b628248SJason King 	ls_color_t	*color;	/* color for entry */
2081b628248SJason King 	ls_color_t	*link_color;	/* color for symlink */
2091b628248SJason King };
2101b628248SJason King 
2111b628248SJason King struct dchain {
2121b628248SJason King 	char *dc_name;		/* path name */
2131b628248SJason King 	int cycle_detected;	/* cycle detected visiting this directory */
2141b628248SJason King 	struct ditem *myancinfo;	/* this directory's ancestry info */
2151b628248SJason King 	struct dchain *dc_next;	/* next directory in the chain */
2161b628248SJason King };
2171b628248SJason King 
2187c478bd9Sstevel@tonic-gate static struct dchain *dfirst;	/* start of the dir chain */
2197c478bd9Sstevel@tonic-gate static struct dchain *cdfirst;	/* start of the current dir chain */
2207c478bd9Sstevel@tonic-gate static struct dchain *dtemp;	/* temporary - used for linking */
2217c478bd9Sstevel@tonic-gate static char *curdir;		/* the current directory */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate static int	first = 1;	/* true if first line is not yet printed */
2247c478bd9Sstevel@tonic-gate static int	nfiles = 0;	/* number of flist entries in current use */
2257c478bd9Sstevel@tonic-gate static int	nargs = 0;	/* number of flist entries used for arguments */
2267c478bd9Sstevel@tonic-gate static int	maxfils = 0;	/* number of flist/lbuf entries allocated */
2277c478bd9Sstevel@tonic-gate static int	maxn = 0;	/* number of flist entries with lbufs asigned */
2287c478bd9Sstevel@tonic-gate static int	quantn = 64;	/* allocation growth quantum */
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static struct lbuf	*nxtlbf;	/* ptr to next lbuf to be assigned */
2317c478bd9Sstevel@tonic-gate static struct lbuf	**flist;	/* ptr to list of lbuf pointers */
2327c478bd9Sstevel@tonic-gate static struct lbuf	*gstat(char *, int, struct ditem *);
2337c478bd9Sstevel@tonic-gate static char		*getname(uid_t);
2347c478bd9Sstevel@tonic-gate static char		*getgroup(gid_t);
2357c478bd9Sstevel@tonic-gate static char		*makename(char *, char *);
2367c478bd9Sstevel@tonic-gate static void		pentry(struct lbuf *);
2377c478bd9Sstevel@tonic-gate static void		column(void);
2387c478bd9Sstevel@tonic-gate static void		pmode(mode_t aflag);
2397c478bd9Sstevel@tonic-gate static void		selection(int *);
2407c478bd9Sstevel@tonic-gate static void		new_line(void);
2417c478bd9Sstevel@tonic-gate static void		rddir(char *, struct ditem *);
2427c478bd9Sstevel@tonic-gate static int		strcol(unsigned char *);
2437c478bd9Sstevel@tonic-gate static void		pem(struct lbuf **, struct lbuf **, int);
2447c478bd9Sstevel@tonic-gate static void		pdirectory(char *, int, int, int, struct ditem *);
2457c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long);
2467c478bd9Sstevel@tonic-gate static void		csi_pprintf(unsigned char *);
2477c478bd9Sstevel@tonic-gate static void		pprintf(char *, char *);
2487c478bd9Sstevel@tonic-gate static int		compar(struct lbuf **pp1, struct lbuf **pp2);
2497c478bd9Sstevel@tonic-gate static void		record_ancestry(char *, struct stat *, struct lbuf *,
2507c478bd9Sstevel@tonic-gate 			    int, struct ditem *);
2515e1c72e1SJason King static void		ls_color_init(void);
2521b628248SJason King static ls_color_t	*ls_color_find(const char *, mode_t);
2531b628248SJason King static void		ls_start_color(ls_color_t *);
2545e1c72e1SJason King static void		ls_end_color(void);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate static int		aflg;
2577c478bd9Sstevel@tonic-gate static int		atflg;
2587c478bd9Sstevel@tonic-gate static int		bflg;
2597c478bd9Sstevel@tonic-gate static int		cflg;
2607c478bd9Sstevel@tonic-gate static int		dflg;
2617c478bd9Sstevel@tonic-gate static int		eflg;
2627c478bd9Sstevel@tonic-gate static int		fflg;
2637c478bd9Sstevel@tonic-gate static int		gflg;
2647c478bd9Sstevel@tonic-gate static int		hflg;
2657c478bd9Sstevel@tonic-gate static int		iflg;
2667c478bd9Sstevel@tonic-gate static int		lflg;
2677c478bd9Sstevel@tonic-gate static int		mflg;
2687c478bd9Sstevel@tonic-gate static int		nflg;
2697c478bd9Sstevel@tonic-gate static int		oflg;
2707c478bd9Sstevel@tonic-gate static int		pflg;
2717c478bd9Sstevel@tonic-gate static int		qflg;
2727c478bd9Sstevel@tonic-gate static int		rflg = 1; /* init to 1 for special use in compar */
2737c478bd9Sstevel@tonic-gate static int		sflg;
2747c478bd9Sstevel@tonic-gate static int		tflg;
2757c478bd9Sstevel@tonic-gate static int		uflg;
2765e1c72e1SJason King static int		Uflg;
2775e1c72e1SJason King static int		wflg;
2787c478bd9Sstevel@tonic-gate static int		xflg;
2797c478bd9Sstevel@tonic-gate static int		Aflg;
2805e1c72e1SJason King static int		Bflg;
2817c478bd9Sstevel@tonic-gate static int		Cflg;
2827c478bd9Sstevel@tonic-gate static int		Eflg;
2837c478bd9Sstevel@tonic-gate static int		Fflg;
2847c478bd9Sstevel@tonic-gate static int		Hflg;
2857c478bd9Sstevel@tonic-gate static int		Lflg;
2867c478bd9Sstevel@tonic-gate static int		Rflg;
2877c478bd9Sstevel@tonic-gate static int		Sflg;
288fa9e4066Sahrens static int		vflg;
2895a5eeccaSmarks static int		Vflg;
290da6c28aaSamw static int		saflg;		/* boolean extended system attr. */
291da6c28aaSamw static int		sacnt;		/* number of extended system attr. */
292da6c28aaSamw static int		copt;
293da6c28aaSamw static int		vopt;
294da6c28aaSamw static int		tmflg;		/* create time ext. system attr. */
295da6c28aaSamw static int		ctm;
296da6c28aaSamw static int		atm;
297da6c28aaSamw static int		mtm;
298da6c28aaSamw static int		crtm;
299da6c28aaSamw static int		alltm;
300*fc30d466SJason King static uint_t		nicenum_flags;
3017c478bd9Sstevel@tonic-gate static mode_t		flags;
3027c478bd9Sstevel@tonic-gate static int		err = 0;	/* Contains return code */
3035e1c72e1SJason King static int		colorflg;
3045e1c72e1SJason King static int		file_typeflg;
30591bbe3fdSBill Pijewski static int		noflist = 0;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate static uid_t		lastuid	= (uid_t)-1;
3087c478bd9Sstevel@tonic-gate static gid_t		lastgid = (gid_t)-1;
3097c478bd9Sstevel@tonic-gate static char		*lastuname = NULL;
3107c478bd9Sstevel@tonic-gate static char		*lastgname = NULL;
3117c478bd9Sstevel@tonic-gate 
3125e1c72e1SJason King /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */
3137c478bd9Sstevel@tonic-gate static int		statreq;
3147c478bd9Sstevel@tonic-gate 
3155e1c72e1SJason King static uint64_t		block_size = 1;
3167c478bd9Sstevel@tonic-gate static char		*dotp = ".";
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate static u_longlong_t 	tblocks; /* number of blocks of files in a directory */
3197c478bd9Sstevel@tonic-gate static time_t		year, now;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static int		num_cols = 80;
3227c478bd9Sstevel@tonic-gate static int		colwidth;
3237c478bd9Sstevel@tonic-gate static int		filewidth;
3247c478bd9Sstevel@tonic-gate static int		fixedwidth;
3257c478bd9Sstevel@tonic-gate static int		nomocore;
3267c478bd9Sstevel@tonic-gate static int		curcol;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate static struct	winsize	win;
3297c478bd9Sstevel@tonic-gate 
3305e1c72e1SJason King /* if time_fmt_new is left NULL, time_fmt_old is used for all times */
3315e1c72e1SJason King static const char	*time_fmt_old = FORMAT_OLD;	/* non-recent files */
3325e1c72e1SJason King static const char	*time_fmt_new = FORMAT_NEW;	/* recent files */
3335e1c72e1SJason King static int		time_custom;	/* != 0 if a custom format */
334da6c28aaSamw static char	time_buf[FMTSIZE];	/* array to hold day and time */
3357c478bd9Sstevel@tonic-gate 
3365e1c72e1SJason King static int		lsc_debug;
3375e1c72e1SJason King static ls_color_t	*lsc_match;
3385e1c72e1SJason King static ls_color_t	*lsc_colors;
3395e1c72e1SJason King static size_t		lsc_ncolors;
3405e1c72e1SJason King static char		*lsc_bold;
3415e1c72e1SJason King static char		*lsc_underline;
3425e1c72e1SJason King static char		*lsc_blink;
3435e1c72e1SJason King static char		*lsc_reverse;
3445e1c72e1SJason King static char		*lsc_concealed;
3455e1c72e1SJason King static char		*lsc_none;
3465e1c72e1SJason King static char		*lsc_setfg;
3475e1c72e1SJason King static char		*lsc_setbg;
3481b628248SJason King static ls_color_t	*lsc_orphan;
3495e1c72e1SJason King 
3507c478bd9Sstevel@tonic-gate #define	NOTWORKINGDIR(d, l)	(((l) < 2) || \
3517c478bd9Sstevel@tonic-gate 				    (strcmp((d) + (l) - 2, "/.") != 0))
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate #define	NOTPARENTDIR(d, l)	(((l) < 3) || \
3547c478bd9Sstevel@tonic-gate 				    (strcmp((d) + (l) - 3, "/..") != 0))
355da6c28aaSamw /* Extended system attributes support */
356da6c28aaSamw static int get_sysxattr(char *, struct lbuf *);
357da6c28aaSamw static void set_sysattrb_display(char *, boolean_t, struct lbuf *);
358da6c28aaSamw static void set_sysattrtm_display(char *, struct lbuf *);
3595e1c72e1SJason King static void format_time(time_t, time_t);
360da6c28aaSamw static void print_time(struct lbuf *);
361da6c28aaSamw static void format_attrtime(struct lbuf *);
362da6c28aaSamw static void *xmalloc(size_t, struct lbuf *);
363da6c28aaSamw static void free_sysattr(struct lbuf *);
364da6c28aaSamw static nvpair_t *pair;
365da6c28aaSamw static nvlist_t	*response;
36656798e90Sbasabi static int acl_err;
3677c478bd9Sstevel@tonic-gate 
3685e1c72e1SJason King const struct option long_options[] = {
3695e1c72e1SJason King 	{ "all", no_argument, NULL, 'a' },
3705e1c72e1SJason King 	{ "almost-all", no_argument, NULL, 'A' },
3715e1c72e1SJason King 	{ "escape", no_argument, NULL, 'b' },
3725e1c72e1SJason King 	{ "classify", no_argument, NULL, 'F' },
3735e1c72e1SJason King 	{ "human-readable", no_argument, NULL, 'h' },
3745e1c72e1SJason King 	{ "dereference", no_argument, NULL, 'L' },
3755e1c72e1SJason King 	{ "dereference-command-line", no_argument, NULL, 'H' },
3765e1c72e1SJason King 	{ "ignore-backups", no_argument, NULL, 'B' },
3775e1c72e1SJason King 	{ "inode", no_argument, NULL, 'i' },
3785e1c72e1SJason King 	{ "numeric-uid-gid", no_argument, NULL, 'n' },
3795e1c72e1SJason King 	{ "no-group", no_argument, NULL, 'o' },
3805e1c72e1SJason King 	{ "hide-control-chars", no_argument, NULL, 'q' },
3815e1c72e1SJason King 	{ "reverse", no_argument, NULL, 'r' },
3825e1c72e1SJason King 	{ "recursive", no_argument, NULL, 'R' },
3835e1c72e1SJason King 	{ "size", no_argument, NULL, 's' },
3845e1c72e1SJason King 	{ "width", required_argument, NULL, 'w' },
3855e1c72e1SJason King 
3865e1c72e1SJason King 	/* no short options for these */
3875e1c72e1SJason King 	{ "block-size", required_argument, NULL, 0 },
3885e1c72e1SJason King 	{ "full-time", no_argument, NULL, 0 },
3895e1c72e1SJason King 	{ "si", no_argument, NULL, 0 },
3905e1c72e1SJason King 	{ "color", optional_argument, NULL, 0 },
3915e1c72e1SJason King 	{ "colour", optional_argument, NULL, 0},
3925e1c72e1SJason King 	{ "file-type", no_argument, NULL, 0 },
3935e1c72e1SJason King 	{ "time-style", required_argument, NULL, 0 },
3945e1c72e1SJason King 
3955e1c72e1SJason King 	{0, 0, 0, 0}
3965e1c72e1SJason King };
3975e1c72e1SJason King 
3987c478bd9Sstevel@tonic-gate int
3997c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	int		c;
4027c478bd9Sstevel@tonic-gate 	int		i;
4037c478bd9Sstevel@tonic-gate 	int		width;
4047c478bd9Sstevel@tonic-gate 	int		amino = 0;
4057c478bd9Sstevel@tonic-gate 	int		opterr = 0;
4065e1c72e1SJason King 	int		option_index = 0;
4077c478bd9Sstevel@tonic-gate 	struct lbuf	*ep;
4087c478bd9Sstevel@tonic-gate 	struct lbuf	lb;
40929e6ab97SIgor Kozhukhov 	struct ditem	*myinfo = NULL;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4127c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4137c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
4147c478bd9Sstevel@tonic-gate #endif
4157c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4167c478bd9Sstevel@tonic-gate #ifdef STANDALONE
4177c478bd9Sstevel@tonic-gate 	if (argv[0][0] == '\0')
4187c478bd9Sstevel@tonic-gate 		argc = getargv("ls", &argv, 0);
4197c478bd9Sstevel@tonic-gate #endif
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	lb.lmtime.tv_sec = time(NULL);
4227c478bd9Sstevel@tonic-gate 	lb.lmtime.tv_nsec = 0;
4237c478bd9Sstevel@tonic-gate 	year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */
4247c478bd9Sstevel@tonic-gate 	now = lb.lmtime.tv_sec + 60;
4257c478bd9Sstevel@tonic-gate 	if (isatty(1)) {
4267c478bd9Sstevel@tonic-gate 		Cflg = 1;
4277c478bd9Sstevel@tonic-gate 		mflg = 0;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4305e1c72e1SJason King 	while ((c = getopt_long(argc, argv,
4315e1c72e1SJason King 	    "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options,
4325e1c72e1SJason King 	    &option_index)) != -1)
4337c478bd9Sstevel@tonic-gate 		switch (c) {
4345e1c72e1SJason King 		case 0:
4355e1c72e1SJason King 			/* non-short options */
4365e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4375e1c72e1SJason King 			    "color") == 0 ||
4385e1c72e1SJason King 			    strcmp(long_options[option_index].name,
4395e1c72e1SJason King 			    "colour") == 0) {
4405e1c72e1SJason King 				if (optarg == NULL ||
4415e1c72e1SJason King 				    strcmp(optarg, "always") == 0 ||
4425e1c72e1SJason King 				    strcmp(optarg, "yes") == 0 ||
4435e1c72e1SJason King 				    strcmp(optarg, "force") == 0) {
4445e1c72e1SJason King 					colorflg++;
4455e1c72e1SJason King 					statreq++;
4465e1c72e1SJason King 					continue;
4475e1c72e1SJason King 				}
4485e1c72e1SJason King 
449c7a7d03cSJason King 				if (strcmp(optarg, "auto") == 0 ||
4505e1c72e1SJason King 				    strcmp(optarg, "tty") == 0 ||
451c7a7d03cSJason King 				    strcmp(optarg, "if-tty") == 0) {
452c7a7d03cSJason King 					if (isatty(1) == 1) {
4535e1c72e1SJason King 						colorflg++;
4545e1c72e1SJason King 						statreq++;
455c7a7d03cSJason King 					}
4565e1c72e1SJason King 					continue;
4575e1c72e1SJason King 				}
4585e1c72e1SJason King 
4595e1c72e1SJason King 				if (strcmp(optarg, "never") == 0 ||
4605e1c72e1SJason King 				    strcmp(optarg, "no") == 0 ||
4615e1c72e1SJason King 				    strcmp(optarg, "none") == 0) {
4625e1c72e1SJason King 					colorflg = 0;
4635e1c72e1SJason King 					continue;
4645e1c72e1SJason King 				}
4655e1c72e1SJason King 				(void) fprintf(stderr,
4665e1c72e1SJason King 				    gettext("Invalid argument '%s' for "
4675e1c72e1SJason King 				    "--color\n"), optarg);
4685e1c72e1SJason King 				++opterr;
4695e1c72e1SJason King 				continue;
4705e1c72e1SJason King 			}
4715e1c72e1SJason King 
4725e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4735e1c72e1SJason King 			    "si") == 0) {
4745e1c72e1SJason King 				hflg++;
475*fc30d466SJason King 				nicenum_flags |= NN_DIVISOR_1000;
4765e1c72e1SJason King 				continue;
4775e1c72e1SJason King 			}
4785e1c72e1SJason King 
4795e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
4805e1c72e1SJason King 			    "block-size") == 0) {
4815e1c72e1SJason King 				size_t scale_len = strlen(optarg);
4825e1c72e1SJason King 				uint64_t scale = 1;
4835e1c72e1SJason King 				uint64_t kilo = 1024;
4845e1c72e1SJason King 				char scale_c;
4855e1c72e1SJason King 
4865e1c72e1SJason King 				if (scale_len == 0) {
4875e1c72e1SJason King 					(void) fprintf(stderr, gettext(
4885e1c72e1SJason King 					    "Invalid block size \'%s\'\n"),
4895e1c72e1SJason King 					    optarg);
4905e1c72e1SJason King 					exit(1);
4915e1c72e1SJason King 				}
4925e1c72e1SJason King 
4935e1c72e1SJason King 				scale_c = optarg[scale_len - 1];
4945e1c72e1SJason King 				if (scale_c == 'B') {
4955e1c72e1SJason King 					/* need at least digit, scale, B */
4965e1c72e1SJason King 					if (scale_len < 3) {
4975e1c72e1SJason King 						(void) fprintf(stderr, gettext(
4985e1c72e1SJason King 						    "Invalid block size "
4995e1c72e1SJason King 						    "\'%s\'\n"), optarg);
5005e1c72e1SJason King 						exit(1);
5015e1c72e1SJason King 					}
5025e1c72e1SJason King 					kilo = 1000;
5035e1c72e1SJason King 					scale_c = optarg[scale_len - 2];
5045e1c72e1SJason King 					if (isdigit(scale_c)) {
5055e1c72e1SJason King 						(void) fprintf(stderr,
5065e1c72e1SJason King 						    gettext("Invalid block size"
5075e1c72e1SJason King 						    " \'%s\'\n"), optarg);
5085e1c72e1SJason King 						exit(1);
5095e1c72e1SJason King 					}
5105e1c72e1SJason King 					/*
5115e1c72e1SJason King 					 * make optarg[scale_len - 1] point to
5125e1c72e1SJason King 					 * the scale factor
5135e1c72e1SJason King 					 */
5145e1c72e1SJason King 					--scale_len;
5155e1c72e1SJason King 				}
5165e1c72e1SJason King 
5175e1c72e1SJason King 				switch (scale_c) {
5185e1c72e1SJason King 				case 'y':
5195e1c72e1SJason King 				case 'Y':
5205e1c72e1SJason King 					scale *= kilo;
5215e1c72e1SJason King 					/*FALLTHROUGH*/
5225e1c72e1SJason King 				case 'Z':
5235e1c72e1SJason King 				case 'z':
5245e1c72e1SJason King 					scale *= kilo;
5255e1c72e1SJason King 					/*FALLTHROUGH*/
5265e1c72e1SJason King 				case 'E':
5275e1c72e1SJason King 				case 'e':
5285e1c72e1SJason King 					scale *= kilo;
5295e1c72e1SJason King 					/*FALLTHROUGH*/
5305e1c72e1SJason King 				case 'P':
5315e1c72e1SJason King 				case 'p':
5325e1c72e1SJason King 					scale *= kilo;
5335e1c72e1SJason King 					/*FALLTHROUGH*/
5345e1c72e1SJason King 				case 'T':
5355e1c72e1SJason King 				case 't':
5365e1c72e1SJason King 					scale *= kilo;
5375e1c72e1SJason King 					/*FALLTHROUGH*/
5385e1c72e1SJason King 				case 'G':
5395e1c72e1SJason King 				case 'g':
5405e1c72e1SJason King 					scale *= kilo;
5415e1c72e1SJason King 					/*FALLTHROUGH*/
5425e1c72e1SJason King 				case 'M':
5435e1c72e1SJason King 				case 'm':
5445e1c72e1SJason King 					scale *= kilo;
5455e1c72e1SJason King 					/*FALLTHROUGH*/
5465e1c72e1SJason King 				case 'K':
5475e1c72e1SJason King 				case 'k':
5485e1c72e1SJason King 					scale *= kilo;
5495e1c72e1SJason King 					break;
5505e1c72e1SJason King 				default:
5515e1c72e1SJason King 					if (!isdigit(scale_c)) {
5525e1c72e1SJason King 						(void) fprintf(stderr,
5535e1c72e1SJason King 						    gettext("Invalid character "
5545e1c72e1SJason King 						    "following block size in "
5555e1c72e1SJason King 						    "\'%s\'\n"), optarg);
5565e1c72e1SJason King 						exit(1);
5575e1c72e1SJason King 					}
5585e1c72e1SJason King 				}
5595e1c72e1SJason King 
5605e1c72e1SJason King 				/* NULL out scale constant if present */
5615e1c72e1SJason King 				if (scale > 1 && !isdigit(scale_c))
5625e1c72e1SJason King 					optarg[scale_len - 1] = '\0';
5635e1c72e1SJason King 
5645e1c72e1SJason King 				/* Based on testing, this is what GNU ls does */
5655e1c72e1SJason King 				block_size = strtoll(optarg, NULL, 0) * scale;
5665e1c72e1SJason King 				if (block_size < 1) {
5675e1c72e1SJason King 					(void) fprintf(stderr,
5685e1c72e1SJason King 					    gettext("Invalid block size "
5695e1c72e1SJason King 					    "\'%s\'\n"), optarg);
5705e1c72e1SJason King 					exit(1);
5715e1c72e1SJason King 				}
5725e1c72e1SJason King 				continue;
5735e1c72e1SJason King 			}
5745e1c72e1SJason King 
5755e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5765e1c72e1SJason King 			    "file-type") == 0) {
5775e1c72e1SJason King 				file_typeflg++;
5785e1c72e1SJason King 				Fflg++;
5795e1c72e1SJason King 				statreq++;
5805e1c72e1SJason King 				continue;
5815e1c72e1SJason King 			}
5825e1c72e1SJason King 
5835e1c72e1SJason King 
5845e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5855e1c72e1SJason King 			    "full-time") == 0) {
5865e1c72e1SJason King 				Eflg++;
5875e1c72e1SJason King 				statreq++;
5885e1c72e1SJason King 				eflg = 0;
5895e1c72e1SJason King 				time_fmt_old = FORMAT_ISO_FULL;
5905e1c72e1SJason King 				time_fmt_new = FORMAT_ISO_FULL;
5915e1c72e1SJason King 				continue;
5925e1c72e1SJason King 			}
5935e1c72e1SJason King 
5945e1c72e1SJason King 			if (strcmp(long_options[option_index].name,
5955e1c72e1SJason King 			    "time-style") == 0) {
5965e1c72e1SJason King 				/* like -E, but doesn't imply -l */
5975e1c72e1SJason King 				if (strcmp(optarg, "full-iso") == 0) {
5985e1c72e1SJason King 					Eflg++;
5995e1c72e1SJason King 					statreq++;
6005e1c72e1SJason King 					eflg = 0;
6015e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_FULL;
6025e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_FULL;
6035e1c72e1SJason King 					continue;
6045e1c72e1SJason King 				}
6055e1c72e1SJason King 				if (strcmp(optarg, "long-iso") == 0) {
6065e1c72e1SJason King 					statreq++;
6075e1c72e1SJason King 					Eflg = 0;
6085e1c72e1SJason King 					eflg = 0;
6095e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_LONG;
6105e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_LONG;
6115e1c72e1SJason King 					continue;
6125e1c72e1SJason King 				}
6135e1c72e1SJason King 				if (strcmp(optarg, "iso") == 0) {
6145e1c72e1SJason King 					statreq++;
6155e1c72e1SJason King 					Eflg = 0;
6165e1c72e1SJason King 					eflg = 0;
6175e1c72e1SJason King 					time_fmt_old = FORMAT_ISO_OLD;
6185e1c72e1SJason King 					time_fmt_new = FORMAT_ISO_NEW;
6195e1c72e1SJason King 					continue;
6205e1c72e1SJason King 				}
6215e1c72e1SJason King 				/* should be the default */
6225e1c72e1SJason King 				if (strcmp(optarg, "locale") == 0) {
6235e1c72e1SJason King 					time_fmt_old = FORMAT_OLD;
6245e1c72e1SJason King 					time_fmt_new = FORMAT_NEW;
6255e1c72e1SJason King 					continue;
6265e1c72e1SJason King 				}
6275e1c72e1SJason King 				if (optarg[0] == '+') {
6285e1c72e1SJason King 					char	*told, *tnew;
6295e1c72e1SJason King 					char	*p;
6305e1c72e1SJason King 					size_t	timelen = strlen(optarg);
6315e1c72e1SJason King 
6325e1c72e1SJason King 					p = strchr(optarg, '\n');
6335e1c72e1SJason King 					if (p != NULL)
6345e1c72e1SJason King 						*p++ = '\0';
6355e1c72e1SJason King 
6365e1c72e1SJason King 					/*
6375e1c72e1SJason King 					 * Time format requires a leading and
6385e1c72e1SJason King 					 * trailing space
6395e1c72e1SJason King 					 * Add room for 3 spaces + 2 nulls
6405e1c72e1SJason King 					 * The + in optarg is replaced with
6415e1c72e1SJason King 					 * a space.
6425e1c72e1SJason King 					 */
6435e1c72e1SJason King 					timelen += 2 + 3;
6445e1c72e1SJason King 					told = malloc(timelen);
6455e1c72e1SJason King 					if (told == NULL) {
64638f2a414SAlbert Lee 						perror("ls");
64738f2a414SAlbert Lee 						exit(2);
6485e1c72e1SJason King 					}
6495e1c72e1SJason King 
6505e1c72e1SJason King 					(void) memset(told, 0, timelen);
6515e1c72e1SJason King 					told[0] = ' ';
6525e1c72e1SJason King 					(void) strlcat(told, &optarg[1],
6535e1c72e1SJason King 					    timelen);
6545e1c72e1SJason King 					(void) strlcat(told, " ", timelen);
6555e1c72e1SJason King 
6565e1c72e1SJason King 					if (p != NULL) {
6575e1c72e1SJason King 						size_t tnew_len;
6585e1c72e1SJason King 
6595e1c72e1SJason King 						tnew = told + strlen(told) + 1;
6605e1c72e1SJason King 						tnew_len = timelen -
6615e1c72e1SJason King 						    strlen(told) - 1;
6625e1c72e1SJason King 
6635e1c72e1SJason King 						tnew[0] = ' ';
6645e1c72e1SJason King 						(void) strlcat(tnew, p,
6655e1c72e1SJason King 						    tnew_len);
6665e1c72e1SJason King 						(void) strlcat(tnew, " ",
6675e1c72e1SJason King 						    tnew_len);
6685e1c72e1SJason King 						time_fmt_new =
6695e1c72e1SJason King 						    (const char *)tnew;
6705e1c72e1SJason King 					} else {
6715e1c72e1SJason King 						time_fmt_new =
6725e1c72e1SJason King 						    (const char *)told;
6735e1c72e1SJason King 					}
6745e1c72e1SJason King 
6755e1c72e1SJason King 					time_fmt_old = (const char *)told;
6765e1c72e1SJason King 					time_custom = 1;
6775e1c72e1SJason King 					continue;
6785e1c72e1SJason King 				}
6795e1c72e1SJason King 				continue;
6805e1c72e1SJason King 			}
6815e1c72e1SJason King 
6825e1c72e1SJason King 			continue;
6835e1c72e1SJason King 
6847c478bd9Sstevel@tonic-gate 		case 'a':
6857c478bd9Sstevel@tonic-gate 			aflg++;
6867c478bd9Sstevel@tonic-gate 			continue;
6877c478bd9Sstevel@tonic-gate 		case 'A':
6887c478bd9Sstevel@tonic-gate 			Aflg++;
6897c478bd9Sstevel@tonic-gate 			continue;
6907c478bd9Sstevel@tonic-gate 		case 'b':
6917c478bd9Sstevel@tonic-gate 			bflg = 1;
6927c478bd9Sstevel@tonic-gate 			qflg = 0;
6937c478bd9Sstevel@tonic-gate 			continue;
6945e1c72e1SJason King 		case 'B':
6955e1c72e1SJason King 			Bflg = 1;
6965e1c72e1SJason King 			continue;
6977c478bd9Sstevel@tonic-gate 		case 'c':
6987c478bd9Sstevel@tonic-gate 			uflg = 0;
699da6c28aaSamw 			atm = 0;
700da6c28aaSamw 			ctm = 0;
701da6c28aaSamw 			mtm = 0;
702da6c28aaSamw 			crtm = 0;
7037c478bd9Sstevel@tonic-gate 			cflg++;
7047c478bd9Sstevel@tonic-gate 			continue;
7057c478bd9Sstevel@tonic-gate 		case 'C':
7067c478bd9Sstevel@tonic-gate 			Cflg = 1;
7077c478bd9Sstevel@tonic-gate 			mflg = 0;
7087c478bd9Sstevel@tonic-gate #ifdef XPG4
7097c478bd9Sstevel@tonic-gate 			lflg = 0;
7107c478bd9Sstevel@tonic-gate #endif
7117c478bd9Sstevel@tonic-gate 			continue;
7127c478bd9Sstevel@tonic-gate 		case 'd':
7137c478bd9Sstevel@tonic-gate 			dflg++;
7147c478bd9Sstevel@tonic-gate 			continue;
7157c478bd9Sstevel@tonic-gate 		case 'e':
7167c478bd9Sstevel@tonic-gate 			eflg++;
7177c478bd9Sstevel@tonic-gate 			lflg++;
7187c478bd9Sstevel@tonic-gate 			statreq++;
7197c478bd9Sstevel@tonic-gate 			Eflg = 0;
7205e1c72e1SJason King 			time_fmt_old = FORMAT_LONG;
7215e1c72e1SJason King 			time_fmt_new = FORMAT_LONG;
7227c478bd9Sstevel@tonic-gate 			continue;
7237c478bd9Sstevel@tonic-gate 		case 'E':
7247c478bd9Sstevel@tonic-gate 			Eflg++;
7257c478bd9Sstevel@tonic-gate 			lflg++;
7267c478bd9Sstevel@tonic-gate 			statreq++;
7277c478bd9Sstevel@tonic-gate 			eflg = 0;
7285e1c72e1SJason King 			time_fmt_old = FORMAT_ISO_FULL;
7295e1c72e1SJason King 			time_fmt_new = FORMAT_ISO_FULL;
7307c478bd9Sstevel@tonic-gate 			continue;
7317c478bd9Sstevel@tonic-gate 		case 'f':
7327c478bd9Sstevel@tonic-gate 			fflg++;
7337c478bd9Sstevel@tonic-gate 			continue;
7347c478bd9Sstevel@tonic-gate 		case 'F':
7357c478bd9Sstevel@tonic-gate 			Fflg++;
7367c478bd9Sstevel@tonic-gate 			statreq++;
7377c478bd9Sstevel@tonic-gate 			continue;
7387c478bd9Sstevel@tonic-gate 		case 'g':
7397c478bd9Sstevel@tonic-gate 			gflg++;
7407c478bd9Sstevel@tonic-gate 			lflg++;
7417c478bd9Sstevel@tonic-gate 			statreq++;
7427c478bd9Sstevel@tonic-gate 			continue;
7437c478bd9Sstevel@tonic-gate 		case 'h':
7447c478bd9Sstevel@tonic-gate 			hflg++;
7457c478bd9Sstevel@tonic-gate 			continue;
7467c478bd9Sstevel@tonic-gate 		case 'H':
7477c478bd9Sstevel@tonic-gate 			Hflg++;
7487c478bd9Sstevel@tonic-gate 			/* -H and -L are mutually exclusive */
7497c478bd9Sstevel@tonic-gate 			Lflg = 0;
7507c478bd9Sstevel@tonic-gate 			continue;
7517c478bd9Sstevel@tonic-gate 		case 'i':
7527c478bd9Sstevel@tonic-gate 			iflg++;
7537c478bd9Sstevel@tonic-gate 			continue;
7545e1c72e1SJason King 		case 'k':
7555e1c72e1SJason King 			block_size = 1024;
7565e1c72e1SJason King 			continue;
7577c478bd9Sstevel@tonic-gate 		case 'l':
7587c478bd9Sstevel@tonic-gate 			lflg++;
7597c478bd9Sstevel@tonic-gate 			statreq++;
7607c478bd9Sstevel@tonic-gate 			Cflg = 0;
7617c478bd9Sstevel@tonic-gate 			xflg = 0;
7627c478bd9Sstevel@tonic-gate 			mflg = 0;
7637c478bd9Sstevel@tonic-gate 			atflg = 0;
7647c478bd9Sstevel@tonic-gate 			continue;
7657c478bd9Sstevel@tonic-gate 		case 'L':
7667c478bd9Sstevel@tonic-gate 			Lflg++;
7677c478bd9Sstevel@tonic-gate 			/* -H and -L are mutually exclusive */
7687c478bd9Sstevel@tonic-gate 			Hflg = 0;
7697c478bd9Sstevel@tonic-gate 			continue;
7707c478bd9Sstevel@tonic-gate 		case 'm':
7717c478bd9Sstevel@tonic-gate 			Cflg = 0;
7727c478bd9Sstevel@tonic-gate 			mflg = 1;
7737c478bd9Sstevel@tonic-gate #ifdef XPG4
7747c478bd9Sstevel@tonic-gate 			lflg = 0;
7757c478bd9Sstevel@tonic-gate #endif
7767c478bd9Sstevel@tonic-gate 			continue;
7777c478bd9Sstevel@tonic-gate 		case 'n':
7787c478bd9Sstevel@tonic-gate 			nflg++;
7797c478bd9Sstevel@tonic-gate 			lflg++;
7807c478bd9Sstevel@tonic-gate 			statreq++;
7817c478bd9Sstevel@tonic-gate 			Cflg = 0;
7827c478bd9Sstevel@tonic-gate 			xflg = 0;
7837c478bd9Sstevel@tonic-gate 			mflg = 0;
7847c478bd9Sstevel@tonic-gate 			atflg = 0;
7857c478bd9Sstevel@tonic-gate 			continue;
7867c478bd9Sstevel@tonic-gate 		case 'o':
7877c478bd9Sstevel@tonic-gate 			oflg++;
7887c478bd9Sstevel@tonic-gate 			lflg++;
7897c478bd9Sstevel@tonic-gate 			statreq++;
7907c478bd9Sstevel@tonic-gate 			continue;
7917c478bd9Sstevel@tonic-gate 		case 'p':
7927c478bd9Sstevel@tonic-gate 			pflg++;
7937c478bd9Sstevel@tonic-gate 			statreq++;
7947c478bd9Sstevel@tonic-gate 			continue;
7957c478bd9Sstevel@tonic-gate 		case 'q':
7967c478bd9Sstevel@tonic-gate 			qflg = 1;
7977c478bd9Sstevel@tonic-gate 			bflg = 0;
7987c478bd9Sstevel@tonic-gate 			continue;
7997c478bd9Sstevel@tonic-gate 		case 'r':
8007c478bd9Sstevel@tonic-gate 			rflg = -1;
8017c478bd9Sstevel@tonic-gate 			continue;
8027c478bd9Sstevel@tonic-gate 		case 'R':
8037c478bd9Sstevel@tonic-gate 			Rflg++;
8047c478bd9Sstevel@tonic-gate 			statreq++;
8057c478bd9Sstevel@tonic-gate 			continue;
8067c478bd9Sstevel@tonic-gate 		case 's':
8077c478bd9Sstevel@tonic-gate 			sflg++;
8087c478bd9Sstevel@tonic-gate 			statreq++;
8097c478bd9Sstevel@tonic-gate 			continue;
8107c478bd9Sstevel@tonic-gate 		case 'S':
8117c478bd9Sstevel@tonic-gate 			tflg = 0;
8125e1c72e1SJason King 			Uflg = 0;
8137c478bd9Sstevel@tonic-gate 			Sflg++;
8147c478bd9Sstevel@tonic-gate 			statreq++;
8157c478bd9Sstevel@tonic-gate 			continue;
8167c478bd9Sstevel@tonic-gate 		case 't':
8177c478bd9Sstevel@tonic-gate 			Sflg = 0;
8185e1c72e1SJason King 			Uflg = 0;
8197c478bd9Sstevel@tonic-gate 			tflg++;
8207c478bd9Sstevel@tonic-gate 			statreq++;
8217c478bd9Sstevel@tonic-gate 			continue;
8225e1c72e1SJason King 		case 'U':
8235e1c72e1SJason King 			Sflg = 0;
8245e1c72e1SJason King 			tflg = 0;
8255e1c72e1SJason King 			Uflg++;
8265e1c72e1SJason King 			continue;
8277c478bd9Sstevel@tonic-gate 		case 'u':
8287c478bd9Sstevel@tonic-gate 			cflg = 0;
829da6c28aaSamw 			atm = 0;
830da6c28aaSamw 			ctm = 0;
831da6c28aaSamw 			mtm = 0;
832da6c28aaSamw 			crtm = 0;
8337c478bd9Sstevel@tonic-gate 			uflg++;
8347c478bd9Sstevel@tonic-gate 			continue;
8355a5eeccaSmarks 		case 'V':
8365a5eeccaSmarks 			Vflg++;
8375a5eeccaSmarks 			/*FALLTHROUGH*/
838fa9e4066Sahrens 		case 'v':
839fa9e4066Sahrens 			vflg++;
840fa9e4066Sahrens #if !defined(XPG4)
841fa9e4066Sahrens 			if (lflg)
842fa9e4066Sahrens 				continue;
843fa9e4066Sahrens #endif
844fa9e4066Sahrens 			lflg++;
845fa9e4066Sahrens 			statreq++;
846fa9e4066Sahrens 			Cflg = 0;
847fa9e4066Sahrens 			xflg = 0;
848fa9e4066Sahrens 			mflg = 0;
849fa9e4066Sahrens 			continue;
8505e1c72e1SJason King 		case 'w':
8515e1c72e1SJason King 			wflg++;
8525e1c72e1SJason King 			num_cols = atoi(optarg);
8535e1c72e1SJason King 			continue;
8547c478bd9Sstevel@tonic-gate 		case 'x':
8557c478bd9Sstevel@tonic-gate 			xflg = 1;
8567c478bd9Sstevel@tonic-gate 			Cflg = 1;
8577c478bd9Sstevel@tonic-gate 			mflg = 0;
8587c478bd9Sstevel@tonic-gate #ifdef XPG4
8597c478bd9Sstevel@tonic-gate 			lflg = 0;
8607c478bd9Sstevel@tonic-gate #endif
8617c478bd9Sstevel@tonic-gate 			continue;
8627c478bd9Sstevel@tonic-gate 		case '1':
8637c478bd9Sstevel@tonic-gate 			Cflg = 0;
8647c478bd9Sstevel@tonic-gate 			continue;
8657c478bd9Sstevel@tonic-gate 		case '@':
8667c478bd9Sstevel@tonic-gate #if !defined(XPG4)
8677c478bd9Sstevel@tonic-gate 			/*
8687c478bd9Sstevel@tonic-gate 			 * -l has precedence over -@
8697c478bd9Sstevel@tonic-gate 			 */
8707c478bd9Sstevel@tonic-gate 			if (lflg)
8717c478bd9Sstevel@tonic-gate 				continue;
8727c478bd9Sstevel@tonic-gate #endif
8737c478bd9Sstevel@tonic-gate 			atflg++;
8747c478bd9Sstevel@tonic-gate 			lflg++;
8757c478bd9Sstevel@tonic-gate 			statreq++;
8767c478bd9Sstevel@tonic-gate 			Cflg = 0;
8777c478bd9Sstevel@tonic-gate 			xflg = 0;
8787c478bd9Sstevel@tonic-gate 			mflg = 0;
8797c478bd9Sstevel@tonic-gate 			continue;
880da6c28aaSamw 		case '/':
881da6c28aaSamw 			saflg++;
882da6c28aaSamw 			if (optarg != NULL) {
883da6c28aaSamw 				if (strcmp(optarg, "c") == 0) {
884da6c28aaSamw 					copt++;
885da6c28aaSamw 					vopt = 0;
886da6c28aaSamw 				} else if (strcmp(optarg, "v") == 0) {
887da6c28aaSamw 					vopt++;
888da6c28aaSamw 					copt = 0;
889da6c28aaSamw 				} else
890da6c28aaSamw 					opterr++;
891da6c28aaSamw 			} else
892da6c28aaSamw 				opterr++;
893da6c28aaSamw 			lflg++;
894da6c28aaSamw 			statreq++;
895da6c28aaSamw 			Cflg = 0;
896da6c28aaSamw 			xflg = 0;
897da6c28aaSamw 			mflg = 0;
898da6c28aaSamw 			continue;
899da6c28aaSamw 		case '%':
900da6c28aaSamw 			tmflg++;
901da6c28aaSamw 			if (optarg != NULL) {
902da6c28aaSamw 				if (strcmp(optarg, "ctime") == 0) {
903da6c28aaSamw 					ctm++;
904da6c28aaSamw 					atm = 0;
905da6c28aaSamw 					mtm = 0;
906da6c28aaSamw 					crtm = 0;
907da6c28aaSamw 				} else if (strcmp(optarg, "atime") == 0) {
908da6c28aaSamw 					atm++;
909da6c28aaSamw 					ctm = 0;
910da6c28aaSamw 					mtm = 0;
911da6c28aaSamw 					crtm = 0;
912da6c28aaSamw 					uflg = 0;
913da6c28aaSamw 					cflg = 0;
914da6c28aaSamw 				} else if (strcmp(optarg, "mtime") == 0) {
915da6c28aaSamw 					mtm++;
916da6c28aaSamw 					atm = 0;
917da6c28aaSamw 					ctm = 0;
918da6c28aaSamw 					crtm = 0;
919da6c28aaSamw 					uflg = 0;
920da6c28aaSamw 					cflg = 0;
921da6c28aaSamw 				} else if (strcmp(optarg, "crtime") == 0) {
922da6c28aaSamw 					crtm++;
923da6c28aaSamw 					atm = 0;
924da6c28aaSamw 					ctm = 0;
925da6c28aaSamw 					mtm = 0;
926da6c28aaSamw 					uflg = 0;
927da6c28aaSamw 					cflg = 0;
928da6c28aaSamw 				} else if (strcmp(optarg, "all") == 0) {
929da6c28aaSamw 					alltm++;
930da6c28aaSamw 					atm = 0;
931da6c28aaSamw 					ctm = 0;
932da6c28aaSamw 					mtm = 0;
933da6c28aaSamw 					crtm = 0;
934da6c28aaSamw 				} else
935da6c28aaSamw 					opterr++;
936da6c28aaSamw 			} else
937da6c28aaSamw 				opterr++;
938da6c28aaSamw 
939da6c28aaSamw 			Sflg = 0;
940da6c28aaSamw 			statreq++;
941da6c28aaSamw 			mflg = 0;
942da6c28aaSamw 			continue;
9437c478bd9Sstevel@tonic-gate 		case '?':
9447c478bd9Sstevel@tonic-gate 			opterr++;
9457c478bd9Sstevel@tonic-gate 			continue;
9467c478bd9Sstevel@tonic-gate 		}
9475e1c72e1SJason King 
9487c478bd9Sstevel@tonic-gate 	if (opterr) {
9497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9505e1c72e1SJason King 		    "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]"
951da6c28aaSamw 		    "%%[atime | crtime | ctime | mtime | all]"
952da6c28aaSamw 		    " [files]\n"));
9537c478bd9Sstevel@tonic-gate 		exit(2);
9547c478bd9Sstevel@tonic-gate 	}
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	if (fflg) {
9577c478bd9Sstevel@tonic-gate 		aflg++;
9587c478bd9Sstevel@tonic-gate 		lflg = 0;
9597c478bd9Sstevel@tonic-gate 		sflg = 0;
9607c478bd9Sstevel@tonic-gate 		tflg = 0;
9617c478bd9Sstevel@tonic-gate 		Sflg = 0;
9627c478bd9Sstevel@tonic-gate 		statreq = 0;
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	fixedwidth = 2;
9667c478bd9Sstevel@tonic-gate 	if (pflg || Fflg)
9677c478bd9Sstevel@tonic-gate 		fixedwidth++;
9687c478bd9Sstevel@tonic-gate 	if (iflg)
9697c478bd9Sstevel@tonic-gate 		fixedwidth += 11;
9707c478bd9Sstevel@tonic-gate 	if (sflg)
9717c478bd9Sstevel@tonic-gate 		fixedwidth += 5;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	if (lflg) {
9747c478bd9Sstevel@tonic-gate 		if (!gflg && !oflg)
9757c478bd9Sstevel@tonic-gate 			gflg = oflg = 1;
9767c478bd9Sstevel@tonic-gate 		else
9777c478bd9Sstevel@tonic-gate 		if (gflg && oflg)
9787c478bd9Sstevel@tonic-gate 			gflg = oflg = 0;
9797c478bd9Sstevel@tonic-gate 		Cflg = mflg = 0;
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9825e1c72e1SJason King 	if (!wflg && (Cflg || mflg)) {
9837c478bd9Sstevel@tonic-gate 		char *clptr;
9847c478bd9Sstevel@tonic-gate 		if ((clptr = getenv("COLUMNS")) != NULL)
9857c478bd9Sstevel@tonic-gate 			num_cols = atoi(clptr);
9867c478bd9Sstevel@tonic-gate #ifdef TERMINFO
9877c478bd9Sstevel@tonic-gate 		else {
9887c478bd9Sstevel@tonic-gate 			if (ioctl(1, TIOCGWINSZ, &win) != -1)
9897c478bd9Sstevel@tonic-gate 				num_cols = (win.ws_col == 0 ? 80 : win.ws_col);
9907c478bd9Sstevel@tonic-gate 		}
9917c478bd9Sstevel@tonic-gate #endif
9925e1c72e1SJason King 	}
9935e1c72e1SJason King 
99491bbe3fdSBill Pijewski 	/*
99591bbe3fdSBill Pijewski 	 * When certain options (-f, or -U and -1, and not -l, etc.) are
99691bbe3fdSBill Pijewski 	 * specified, don't cache each dirent as it's read.  This 'noflist'
99791bbe3fdSBill Pijewski 	 * option is set when there's no need to cache those dirents; instead,
99891bbe3fdSBill Pijewski 	 * print them out as they're read.
99991bbe3fdSBill Pijewski 	 */
100091bbe3fdSBill Pijewski 	if ((Uflg || fflg) && !Cflg && !lflg && !iflg && statreq == 0)
100191bbe3fdSBill Pijewski 		noflist = 1;
100291bbe3fdSBill Pijewski 
10037c478bd9Sstevel@tonic-gate 	if (num_cols < 20 || num_cols > 1000)
10047c478bd9Sstevel@tonic-gate 		/* assume it is an error */
10057c478bd9Sstevel@tonic-gate 		num_cols = 80;
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	/* allocate space for flist and the associated	*/
10087c478bd9Sstevel@tonic-gate 	/* data structures (lbufs)			*/
10097c478bd9Sstevel@tonic-gate 	maxfils = quantn;
10107c478bd9Sstevel@tonic-gate 	if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) ||
10117c478bd9Sstevel@tonic-gate 	    ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) {
10127c478bd9Sstevel@tonic-gate 		perror("ls");
10137c478bd9Sstevel@tonic-gate 		exit(2);
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 	if ((amino = (argc-optind)) == 0) {
10167c478bd9Sstevel@tonic-gate 					/*
10177c478bd9Sstevel@tonic-gate 					 * case when no names are given
10187c478bd9Sstevel@tonic-gate 					 * in ls-command and current
10197c478bd9Sstevel@tonic-gate 					 * directory is to be used
10207c478bd9Sstevel@tonic-gate 					 */
10217c478bd9Sstevel@tonic-gate 		argv[optind] = dotp;
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
102471ef9ec8SLauri Tirkkonen 	if (colorflg)
102571ef9ec8SLauri Tirkkonen 		ls_color_init();
102671ef9ec8SLauri Tirkkonen 
10277c478bd9Sstevel@tonic-gate 	for (i = 0; i < (amino ? amino : 1); i++) {
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 		/*
10307c478bd9Sstevel@tonic-gate 		 * If we are recursing, we need to make sure we don't
10317c478bd9Sstevel@tonic-gate 		 * get into an endless loop.  To keep track of the inodes
10327c478bd9Sstevel@tonic-gate 		 * (actually, just the directories) visited, we
10337c478bd9Sstevel@tonic-gate 		 * maintain a directory ancestry list for a file
10347c478bd9Sstevel@tonic-gate 		 * hierarchy.  As we go deeper into the hierarchy,
10357c478bd9Sstevel@tonic-gate 		 * a parent directory passes its directory list
10367c478bd9Sstevel@tonic-gate 		 * info (device id, inode number, and a pointer to
10377c478bd9Sstevel@tonic-gate 		 * its parent) to each of its children.  As we
10387c478bd9Sstevel@tonic-gate 		 * process a child that is a directory, we save
10397c478bd9Sstevel@tonic-gate 		 * its own personal directory list info.  We then
10407c478bd9Sstevel@tonic-gate 		 * check to see if the child has already been
10417c478bd9Sstevel@tonic-gate 		 * processed by comparing its device id and inode
10427c478bd9Sstevel@tonic-gate 		 * number from its own personal directory list info
10437c478bd9Sstevel@tonic-gate 		 * to that of each of its ancestors.  If there is a
10447c478bd9Sstevel@tonic-gate 		 * match, then we know we've detected a cycle.
10457c478bd9Sstevel@tonic-gate 		 */
10467c478bd9Sstevel@tonic-gate 		if (Rflg) {
10477c478bd9Sstevel@tonic-gate 			/*
10487c478bd9Sstevel@tonic-gate 			 * This is the first parent in this lineage
10497c478bd9Sstevel@tonic-gate 			 * (first in a directory hierarchy), so
10507c478bd9Sstevel@tonic-gate 			 * this parent's parent doesn't exist.  We
10517c478bd9Sstevel@tonic-gate 			 * only initialize myinfo when we are
10527c478bd9Sstevel@tonic-gate 			 * recursing, otherwise it's not used.
10537c478bd9Sstevel@tonic-gate 			 */
10547c478bd9Sstevel@tonic-gate 			if ((myinfo = (struct ditem *)malloc(
10557c478bd9Sstevel@tonic-gate 			    sizeof (struct ditem))) == NULL) {
10567c478bd9Sstevel@tonic-gate 				perror("ls");
10577c478bd9Sstevel@tonic-gate 				exit(2);
10587c478bd9Sstevel@tonic-gate 			} else {
10597c478bd9Sstevel@tonic-gate 				myinfo->dev = 0;
10607c478bd9Sstevel@tonic-gate 				myinfo->ino = 0;
10617c478bd9Sstevel@tonic-gate 				myinfo->parent = NULL;
10627c478bd9Sstevel@tonic-gate 			}
10637c478bd9Sstevel@tonic-gate 		}
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		if (Cflg || mflg) {
10667c478bd9Sstevel@tonic-gate 			width = strcol((unsigned char *)argv[optind]);
10677c478bd9Sstevel@tonic-gate 			if (width > filewidth)
10687c478bd9Sstevel@tonic-gate 				filewidth = width;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 		if ((ep = gstat((*argv[optind] ? argv[optind] : dotp),
10717c478bd9Sstevel@tonic-gate 		    1, myinfo)) == NULL) {
10727c478bd9Sstevel@tonic-gate 			if (nomocore)
10737c478bd9Sstevel@tonic-gate 				exit(2);
10747c478bd9Sstevel@tonic-gate 			err = 2;
10757c478bd9Sstevel@tonic-gate 			optind++;
10767c478bd9Sstevel@tonic-gate 			continue;
10777c478bd9Sstevel@tonic-gate 		}
10787c478bd9Sstevel@tonic-gate 		ep->ln.namep = (*argv[optind] ? argv[optind] : dotp);
10797c478bd9Sstevel@tonic-gate 		ep->lflags |= ISARG;
10807c478bd9Sstevel@tonic-gate 		optind++;
10817c478bd9Sstevel@tonic-gate 		nargs++;	/* count good arguments stored in flist */
108256798e90Sbasabi 		if (acl_err)
108356798e90Sbasabi 			err = 2;
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 	colwidth = fixedwidth + filewidth;
10865e1c72e1SJason King 	if (!Uflg)
10877c478bd9Sstevel@tonic-gate 		qsort(flist, (unsigned)nargs, sizeof (struct lbuf *),
10887c478bd9Sstevel@tonic-gate 		    (int (*)(const void *, const void *))compar);
10897c478bd9Sstevel@tonic-gate 	for (i = 0; i < nargs; i++) {
109029e6ab97SIgor Kozhukhov 		if ((flist[i]->ltype == 'd' && dflg == 0) || fflg)
10917c478bd9Sstevel@tonic-gate 			break;
10927c478bd9Sstevel@tonic-gate 	}
10935e1c72e1SJason King 
10947c478bd9Sstevel@tonic-gate 	pem(&flist[0], &flist[i], 0);
10957c478bd9Sstevel@tonic-gate 	for (; i < nargs; i++) {
10967c478bd9Sstevel@tonic-gate 		pdirectory(flist[i]->ln.namep, Rflg ||
10977c478bd9Sstevel@tonic-gate 		    (amino > 1), nargs, 0, flist[i]->ancinfo);
10987c478bd9Sstevel@tonic-gate 		if (nomocore)
10997c478bd9Sstevel@tonic-gate 			exit(2);
11007c478bd9Sstevel@tonic-gate 		/* -R: print subdirectories found */
11017c478bd9Sstevel@tonic-gate 		while (dfirst || cdfirst) {
11027c478bd9Sstevel@tonic-gate 			/* Place direct subdirs on front in right order */
11037c478bd9Sstevel@tonic-gate 			while (cdfirst) {
11047c478bd9Sstevel@tonic-gate 				/* reverse cdfirst onto front of dfirst */
11057c478bd9Sstevel@tonic-gate 				dtemp = cdfirst;
11067c478bd9Sstevel@tonic-gate 				cdfirst = cdfirst -> dc_next;
11077c478bd9Sstevel@tonic-gate 				dtemp -> dc_next = dfirst;
11087c478bd9Sstevel@tonic-gate 				dfirst = dtemp;
11097c478bd9Sstevel@tonic-gate 			}
11107c478bd9Sstevel@tonic-gate 			/* take off first dir on dfirst & print it */
11117c478bd9Sstevel@tonic-gate 			dtemp = dfirst;
11127c478bd9Sstevel@tonic-gate 			dfirst = dfirst->dc_next;
11137c478bd9Sstevel@tonic-gate 			pdirectory(dtemp->dc_name, 1, nargs,
11147c478bd9Sstevel@tonic-gate 			    dtemp->cycle_detected, dtemp->myancinfo);
11157c478bd9Sstevel@tonic-gate 			if (nomocore)
11167c478bd9Sstevel@tonic-gate 				exit(2);
11177c478bd9Sstevel@tonic-gate 			free(dtemp->dc_name);
11187c478bd9Sstevel@tonic-gate 			free(dtemp);
11197c478bd9Sstevel@tonic-gate 		}
11207c478bd9Sstevel@tonic-gate 	}
11215e1c72e1SJason King 
11227c478bd9Sstevel@tonic-gate 	return (err);
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate /*
11267c478bd9Sstevel@tonic-gate  * pdirectory: print the directory name, labelling it if title is
11277c478bd9Sstevel@tonic-gate  * nonzero, using lp as the place to start reading in the dir.
11287c478bd9Sstevel@tonic-gate  */
11297c478bd9Sstevel@tonic-gate static void
11307c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo)
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate 	struct dchain *dp;
11337c478bd9Sstevel@tonic-gate 	struct lbuf *ap;
11347c478bd9Sstevel@tonic-gate 	char *pname;
11357c478bd9Sstevel@tonic-gate 	int j;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	filewidth = 0;
11387c478bd9Sstevel@tonic-gate 	curdir = name;
11397c478bd9Sstevel@tonic-gate 	if (title) {
11407c478bd9Sstevel@tonic-gate 		if (!first)
11417c478bd9Sstevel@tonic-gate 			(void) putc('\n', stdout);
11427c478bd9Sstevel@tonic-gate 		pprintf(name, ":");
11437c478bd9Sstevel@tonic-gate 		new_line();
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 	/*
11467c478bd9Sstevel@tonic-gate 	 * If there was a cycle detected, then notify and don't report
11477c478bd9Sstevel@tonic-gate 	 * further.
11487c478bd9Sstevel@tonic-gate 	 */
11497c478bd9Sstevel@tonic-gate 	if (cdetect) {
11507c478bd9Sstevel@tonic-gate 		if (lflg || sflg) {
11517c478bd9Sstevel@tonic-gate 			curcol += printf(gettext("total %d"), 0);
11527c478bd9Sstevel@tonic-gate 			new_line();
11537c478bd9Sstevel@tonic-gate 		}
11547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
11557c478bd9Sstevel@tonic-gate 		    "ls: cycle detected for %s\n"), name);
11567c478bd9Sstevel@tonic-gate 		return;
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	nfiles = lp;
11607c478bd9Sstevel@tonic-gate 	rddir(name, myinfo);
116191bbe3fdSBill Pijewski 	if (nomocore || noflist)
11627c478bd9Sstevel@tonic-gate 		return;
11635e1c72e1SJason King 	if (fflg == 0 && Uflg == 0)
11647c478bd9Sstevel@tonic-gate 		qsort(&flist[lp], (unsigned)(nfiles - lp),
11657c478bd9Sstevel@tonic-gate 		    sizeof (struct lbuf *),
11667c478bd9Sstevel@tonic-gate 		    (int (*)(const void *, const void *))compar);
11677c478bd9Sstevel@tonic-gate 	if (Rflg) {
11687c478bd9Sstevel@tonic-gate 		for (j = nfiles - 1; j >= lp; j--) {
11697c478bd9Sstevel@tonic-gate 			ap = flist[j];
11707c478bd9Sstevel@tonic-gate 			if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") &&
11717c478bd9Sstevel@tonic-gate 			    strcmp(ap->ln.lname, "..")) {
11727c478bd9Sstevel@tonic-gate 				dp = malloc(sizeof (struct dchain));
11737c478bd9Sstevel@tonic-gate 				if (dp == NULL) {
11747c478bd9Sstevel@tonic-gate 					perror("ls");
11757c478bd9Sstevel@tonic-gate 					exit(2);
11767c478bd9Sstevel@tonic-gate 				}
11777c478bd9Sstevel@tonic-gate 				pname = makename(curdir, ap->ln.lname);
11787c478bd9Sstevel@tonic-gate 				if ((dp->dc_name = strdup(pname)) == NULL) {
11797c478bd9Sstevel@tonic-gate 					perror("ls");
11807c478bd9Sstevel@tonic-gate 					exit(2);
11817c478bd9Sstevel@tonic-gate 				}
11827c478bd9Sstevel@tonic-gate 				dp->cycle_detected = ap->cycle;
11837c478bd9Sstevel@tonic-gate 				dp->myancinfo = ap->ancinfo;
11847c478bd9Sstevel@tonic-gate 				dp->dc_next = dfirst;
11857c478bd9Sstevel@tonic-gate 				dfirst = dp;
11867c478bd9Sstevel@tonic-gate 			}
11877c478bd9Sstevel@tonic-gate 		}
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 	if (lflg || sflg) {
11907c478bd9Sstevel@tonic-gate 		curcol += printf(gettext("total %llu"), tblocks);
11917c478bd9Sstevel@tonic-gate 		new_line();
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 	pem(&flist[lp], &flist[nfiles], lflg||sflg);
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate /*
11977c478bd9Sstevel@tonic-gate  * pem: print 'em. Print a list of files (e.g. a directory) bounded
11987c478bd9Sstevel@tonic-gate  * by slp and lp.
11997c478bd9Sstevel@tonic-gate  */
12007c478bd9Sstevel@tonic-gate static void
12017c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	long row, nrows, i;
120429e6ab97SIgor Kozhukhov 	int col, ncols = 1;
12057c478bd9Sstevel@tonic-gate 	struct lbuf **ep;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	if (Cflg || mflg) {
120829e6ab97SIgor Kozhukhov 		if (colwidth <= num_cols) {
12097c478bd9Sstevel@tonic-gate 			ncols = num_cols / colwidth;
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	if (ncols == 1 || mflg || xflg || !Cflg) {
12147c478bd9Sstevel@tonic-gate 		for (ep = slp; ep < lp; ep++)
12157c478bd9Sstevel@tonic-gate 			pentry(*ep);
12167c478bd9Sstevel@tonic-gate 		new_line();
12177c478bd9Sstevel@tonic-gate 		return;
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 	/* otherwise print -C columns */
12207c478bd9Sstevel@tonic-gate 	if (tot_flag) {
12217c478bd9Sstevel@tonic-gate 		slp--;
12227c478bd9Sstevel@tonic-gate 		row = 1;
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 	else
12257c478bd9Sstevel@tonic-gate 		row = 0;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	nrows = (lp - slp - 1) / ncols + 1;
12287c478bd9Sstevel@tonic-gate 	for (i = 0; i < nrows; i++, row++) {
12297c478bd9Sstevel@tonic-gate 		for (col = 0; col < ncols; col++) {
12307c478bd9Sstevel@tonic-gate 			ep = slp + (nrows * col) + row;
12317c478bd9Sstevel@tonic-gate 			if (ep < lp)
12327c478bd9Sstevel@tonic-gate 				pentry(*ep);
12337c478bd9Sstevel@tonic-gate 		}
12347c478bd9Sstevel@tonic-gate 		new_line();
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate /*
12397c478bd9Sstevel@tonic-gate  * print one output entry;
12407c478bd9Sstevel@tonic-gate  * if uid/gid is not found in the appropriate
12417c478bd9Sstevel@tonic-gate  * file(passwd/group), then print uid/gid instead of
12427c478bd9Sstevel@tonic-gate  * user/group name;
12437c478bd9Sstevel@tonic-gate  */
12447c478bd9Sstevel@tonic-gate static void
12457c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap)
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate 	struct lbuf *p;
12487c478bd9Sstevel@tonic-gate 	char *dmark = "";	/* Used if -p or -F option active */
12497c478bd9Sstevel@tonic-gate 	char *cp;
12501b628248SJason King 	char *str;
12517c478bd9Sstevel@tonic-gate 
125291bbe3fdSBill Pijewski 	if (noflist) {
1253b9c81738SGary Mills 		(void) printf("%s\n", (ap->lflags & ISARG) ? ap->ln.namep :
1254b9c81738SGary Mills 		    ap->ln.lname);
125591bbe3fdSBill Pijewski 		return;
125691bbe3fdSBill Pijewski 	}
125791bbe3fdSBill Pijewski 
12587c478bd9Sstevel@tonic-gate 	p = ap;
12597c478bd9Sstevel@tonic-gate 	column();
126029e6ab97SIgor Kozhukhov 	if (iflg) {
12617c478bd9Sstevel@tonic-gate 		if (mflg && !lflg)
12627c478bd9Sstevel@tonic-gate 			curcol += printf("%llu ", (long long)p->lnum);
12637c478bd9Sstevel@tonic-gate 		else
12647c478bd9Sstevel@tonic-gate 			curcol += printf("%10llu ", (long long)p->lnum);
126529e6ab97SIgor Kozhukhov 	}
126629e6ab97SIgor Kozhukhov 	if (sflg) {
12677c478bd9Sstevel@tonic-gate 		curcol += printf((mflg && !lflg) ? "%lld " :
12687c478bd9Sstevel@tonic-gate 		    (p->lblocks < 10000) ? "%4lld " : "%lld ",
12697c478bd9Sstevel@tonic-gate 		    (p->ltype != 'b' && p->ltype != 'c') ?
12707c478bd9Sstevel@tonic-gate 		    p->lblocks : 0LL);
127129e6ab97SIgor Kozhukhov 	}
12727c478bd9Sstevel@tonic-gate 	if (lflg) {
12737c478bd9Sstevel@tonic-gate 		(void) putchar(p->ltype);
12747c478bd9Sstevel@tonic-gate 		curcol++;
12757c478bd9Sstevel@tonic-gate 		pmode(p->lflags);
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		/* ACL: additional access mode flag */
12787c478bd9Sstevel@tonic-gate 		(void) putchar(p->acl);
12797c478bd9Sstevel@tonic-gate 		curcol++;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 		curcol += printf("%3lu ", (ulong_t)p->lnl);
128229e6ab97SIgor Kozhukhov 		if (oflg) {
12837c478bd9Sstevel@tonic-gate 			if (!nflg) {
12847c478bd9Sstevel@tonic-gate 				cp = getname(p->luid);
12857c478bd9Sstevel@tonic-gate 				curcol += printf("%-8s ", cp);
12867c478bd9Sstevel@tonic-gate 			} else
12877c478bd9Sstevel@tonic-gate 				curcol += printf("%-8lu ", (ulong_t)p->luid);
128829e6ab97SIgor Kozhukhov 		}
128929e6ab97SIgor Kozhukhov 		if (gflg) {
12907c478bd9Sstevel@tonic-gate 			if (!nflg) {
12917c478bd9Sstevel@tonic-gate 				cp = getgroup(p->lgid);
12927c478bd9Sstevel@tonic-gate 				curcol += printf("%-8s ", cp);
12937c478bd9Sstevel@tonic-gate 			} else
12947c478bd9Sstevel@tonic-gate 				curcol += printf("%-8lu ", (ulong_t)p->lgid);
129529e6ab97SIgor Kozhukhov 		}
12967c478bd9Sstevel@tonic-gate 		if (p->ltype == 'b' || p->ltype == 'c') {
12977c478bd9Sstevel@tonic-gate 			curcol += printf("%3u, %2u",
12987c478bd9Sstevel@tonic-gate 			    (uint_t)major((dev_t)p->lsize),
12997c478bd9Sstevel@tonic-gate 			    (uint_t)minor((dev_t)p->lsize));
1300*fc30d466SJason King 		} else if (hflg) {
1301*fc30d466SJason King 			char numbuf[NN_NUMBUF_SZ];
1302*fc30d466SJason King 
1303*fc30d466SJason King 			nicenum_scale(p->lsize, 1, numbuf, sizeof (numbuf),
1304*fc30d466SJason King 			    nicenum_flags);
1305*fc30d466SJason King 
1306*fc30d466SJason King 			curcol += printf("%7s", numbuf);
13077c478bd9Sstevel@tonic-gate 		} else {
13085e1c72e1SJason King 			uint64_t bsize = p->lsize / block_size;
13095e1c72e1SJason King 
13105e1c72e1SJason King 			/*
13115e1c72e1SJason King 			 * Round up only when using blocks > 1 byte, otherwise
13125e1c72e1SJason King 			 * 'normal' sizes display 1 byte too large.
13135e1c72e1SJason King 			 */
13145e1c72e1SJason King 			if (p->lsize % block_size != 0)
13155e1c72e1SJason King 				bsize++;
13165e1c72e1SJason King 
13175e1c72e1SJason King 			curcol += printf("%7" PRIu64, bsize);
13187c478bd9Sstevel@tonic-gate 		}
13195e1c72e1SJason King 		format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec);
1320da6c28aaSamw 		/* format extended system attribute time */
1321da6c28aaSamw 		if (tmflg && crtm)
1322da6c28aaSamw 			format_attrtime(p);
13237c478bd9Sstevel@tonic-gate 
1324da6c28aaSamw 		curcol += printf("%s", time_buf);
1325da6c28aaSamw 
1326da6c28aaSamw 	}
13277c478bd9Sstevel@tonic-gate 	/*
13287c478bd9Sstevel@tonic-gate 	 * prevent both "->" and trailing marks
13297c478bd9Sstevel@tonic-gate 	 * from appearing
13307c478bd9Sstevel@tonic-gate 	 */
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	if (pflg && p->ltype == 'd')
13337c478bd9Sstevel@tonic-gate 		dmark = "/";
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (Fflg && !(lflg && p->flinkto)) {
13367c478bd9Sstevel@tonic-gate 		if (p->ltype == 'd')
13377c478bd9Sstevel@tonic-gate 			dmark = "/";
13387c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'D')
13397c478bd9Sstevel@tonic-gate 			dmark = ">";
13407c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'p')
13417c478bd9Sstevel@tonic-gate 			dmark = "|";
13427c478bd9Sstevel@tonic-gate 		else if (p->ltype == 'l')
13437c478bd9Sstevel@tonic-gate 			dmark = "@";
13447c478bd9Sstevel@tonic-gate 		else if (p->ltype == 's')
13457c478bd9Sstevel@tonic-gate 			dmark = "=";
13465e1c72e1SJason King 		else if (!file_typeflg &&
13475e1c72e1SJason King 		    (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)))
13487c478bd9Sstevel@tonic-gate 			dmark = "*";
13497c478bd9Sstevel@tonic-gate 		else
13507c478bd9Sstevel@tonic-gate 			dmark = "";
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 
13535e1c72e1SJason King 	if (colorflg)
13541b628248SJason King 		ls_start_color(p->color);
13555e1c72e1SJason King 
13561b628248SJason King 	if (p->lflags & ISARG)
13571b628248SJason King 		str = p->ln.namep;
13581b628248SJason King 	else
13591b628248SJason King 		str = p->ln.lname;
13601b628248SJason King 
13611b628248SJason King 	if (qflg || bflg) {
13621b628248SJason King 		csi_pprintf((unsigned char *)str);
13631b628248SJason King 
13641b628248SJason King 		if (lflg && p->flinkto) {
13651b628248SJason King 			if (colorflg)
13661b628248SJason King 				ls_end_color();
13671b628248SJason King 			csi_pprintf((unsigned char *)" -> ");
13681b628248SJason King 			if (colorflg)
13691b628248SJason King 				ls_start_color(p->link_color);
13701b628248SJason King 			csi_pprintf((unsigned char *)p->flinkto);
13711b628248SJason King 		} else {
13721b628248SJason King 			csi_pprintf((unsigned char *)dmark);
13737c478bd9Sstevel@tonic-gate 		}
13747c478bd9Sstevel@tonic-gate 	} else {
13751b628248SJason King 		(void) printf("%s", str);
13761b628248SJason King 		curcol += strcol((unsigned char *)str);
13771b628248SJason King 
13781b628248SJason King 		if (lflg && p->flinkto) {
13791b628248SJason King 			if (colorflg)
13801b628248SJason King 				ls_end_color();
13811b628248SJason King 			str = " -> ";
13821b628248SJason King 			(void) printf("%s", str);
13831b628248SJason King 			curcol += strcol((unsigned char *)str);
13841b628248SJason King 			if (colorflg)
13851b628248SJason King 				ls_start_color(p->link_color);
13861b628248SJason King 			(void) printf("%s", p->flinkto);
13871b628248SJason King 			curcol += strcol((unsigned char *)p->flinkto);
13881b628248SJason King 		} else {
13891b628248SJason King 			(void) printf("%s", dmark);
13907c478bd9Sstevel@tonic-gate 			curcol += strcol((unsigned char *)dmark);
13917c478bd9Sstevel@tonic-gate 		}
13927c478bd9Sstevel@tonic-gate 	}
1393fa9e4066Sahrens 
13945e1c72e1SJason King 	if (colorflg)
13955e1c72e1SJason King 		ls_end_color();
13965e1c72e1SJason King 
1397da6c28aaSamw 	/* Display extended system attributes */
1398da6c28aaSamw 	if (saflg) {
1399da6c28aaSamw 		int i;
1400da6c28aaSamw 
1401da6c28aaSamw 		new_line();
1402da6c28aaSamw 		(void) printf("	\t{");
1403da6c28aaSamw 		if (p->exttr != NULL) {
1404da6c28aaSamw 			int k = 0;
1405da6c28aaSamw 			for (i = 0; i < sacnt; i++) {
1406da6c28aaSamw 				if (p->exttr[i].name != NULL)
1407da6c28aaSamw 					k++;
1408da6c28aaSamw 			}
1409da6c28aaSamw 			for (i = 0; i < sacnt; i++) {
1410da6c28aaSamw 				if (p->exttr[i].name != NULL) {
1411da6c28aaSamw 					(void) printf("%s", p->exttr[i].name);
1412da6c28aaSamw 					k--;
1413da6c28aaSamw 					if (vopt && (k != 0))
1414da6c28aaSamw 						(void) printf(",");
1415da6c28aaSamw 				}
1416da6c28aaSamw 			}
1417da6c28aaSamw 		}
1418da6c28aaSamw 		(void) printf("}\n");
1419da6c28aaSamw 	}
1420da6c28aaSamw 	/* Display file timestamps and extended system attribute timestamps */
1421da6c28aaSamw 	if (tmflg && alltm) {
1422da6c28aaSamw 		new_line();
1423da6c28aaSamw 		print_time(p);
1424da6c28aaSamw 		new_line();
1425da6c28aaSamw 	}
1426fa9e4066Sahrens 	if (vflg) {
1427fa9e4066Sahrens 		new_line();
1428fa9e4066Sahrens 		if (p->aclp) {
14295a5eeccaSmarks 			acl_printacl(p->aclp, num_cols, Vflg);
1430fa9e4066Sahrens 		}
1431fa9e4066Sahrens 	}
1432da6c28aaSamw 	/* Free extended system attribute lists */
1433da6c28aaSamw 	if (saflg || tmflg)
1434da6c28aaSamw 		free_sysattr(p);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */
14387c478bd9Sstevel@tonic-gate static void
14397c478bd9Sstevel@tonic-gate pmode(mode_t aflag)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate 	/* these arrays are declared static to allow initializations */
14427c478bd9Sstevel@tonic-gate 	static int	m0[] = { 1, S_IRUSR, 'r', '-' };
14437c478bd9Sstevel@tonic-gate 	static int	m1[] = { 1, S_IWUSR, 'w', '-' };
14447c478bd9Sstevel@tonic-gate 	static int	m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR,
14457c478bd9Sstevel@tonic-gate 	    'x', S_ISUID, 'S', '-' };
14467c478bd9Sstevel@tonic-gate 	static int	m3[] = { 1, S_IRGRP, 'r', '-' };
14477c478bd9Sstevel@tonic-gate 	static int	m4[] = { 1, S_IWGRP, 'w', '-' };
14487c478bd9Sstevel@tonic-gate 	static int	m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP,
14497c478bd9Sstevel@tonic-gate 				'x', S_ISGID|LS_NOTREG, 'S',
14507c478bd9Sstevel@tonic-gate #ifdef XPG4
14517c478bd9Sstevel@tonic-gate 		S_ISGID, 'L', '-'};
14527c478bd9Sstevel@tonic-gate #else
14537c478bd9Sstevel@tonic-gate 		S_ISGID, 'l', '-'};
14547c478bd9Sstevel@tonic-gate #endif
14557c478bd9Sstevel@tonic-gate 	static int	m6[] = { 1, S_IROTH, 'r', '-' };
14567c478bd9Sstevel@tonic-gate 	static int	m7[] = { 1, S_IWOTH, 'w', '-' };
14577c478bd9Sstevel@tonic-gate 	static int	m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH,
14587c478bd9Sstevel@tonic-gate 	    'x', S_ISVTX, 'T', '-'};
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8};
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	int **mp;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	flags = aflag;
14657c478bd9Sstevel@tonic-gate 	for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++)
14667c478bd9Sstevel@tonic-gate 		selection(*mp);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate static void
14707c478bd9Sstevel@tonic-gate selection(int *pairp)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate 	int n;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	n = *pairp++;
14757c478bd9Sstevel@tonic-gate 	while (n-->0) {
14767c478bd9Sstevel@tonic-gate 		if ((flags & *pairp) == *pairp) {
14777c478bd9Sstevel@tonic-gate 			pairp++;
14787c478bd9Sstevel@tonic-gate 			break;
14797c478bd9Sstevel@tonic-gate 		} else {
14807c478bd9Sstevel@tonic-gate 			pairp += 2;
14817c478bd9Sstevel@tonic-gate 		}
14827c478bd9Sstevel@tonic-gate 	}
14837c478bd9Sstevel@tonic-gate 	(void) putchar(*pairp);
14847c478bd9Sstevel@tonic-gate 	curcol++;
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate  * column: get to the beginning of the next column.
14897c478bd9Sstevel@tonic-gate  */
14907c478bd9Sstevel@tonic-gate static void
14917c478bd9Sstevel@tonic-gate column(void)
14927c478bd9Sstevel@tonic-gate {
14937c478bd9Sstevel@tonic-gate 	if (curcol == 0)
14947c478bd9Sstevel@tonic-gate 		return;
14957c478bd9Sstevel@tonic-gate 	if (mflg) {
14967c478bd9Sstevel@tonic-gate 		(void) putc(',', stdout);
14977c478bd9Sstevel@tonic-gate 		curcol++;
14987c478bd9Sstevel@tonic-gate 		if (curcol + colwidth + 2 > num_cols) {
14997c478bd9Sstevel@tonic-gate 			(void) putc('\n', stdout);
15007c478bd9Sstevel@tonic-gate 			curcol = 0;
15017c478bd9Sstevel@tonic-gate 			return;
15027c478bd9Sstevel@tonic-gate 		}
15037c478bd9Sstevel@tonic-gate 		(void) putc(' ', stdout);
15047c478bd9Sstevel@tonic-gate 		curcol++;
15057c478bd9Sstevel@tonic-gate 		return;
15067c478bd9Sstevel@tonic-gate 	}
15077c478bd9Sstevel@tonic-gate 	if (Cflg == 0) {
15087c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
15097c478bd9Sstevel@tonic-gate 		curcol = 0;
15107c478bd9Sstevel@tonic-gate 		return;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 	if ((curcol / colwidth + 2) * colwidth > num_cols) {
15137c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
15147c478bd9Sstevel@tonic-gate 		curcol = 0;
15157c478bd9Sstevel@tonic-gate 		return;
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 	do {
15187c478bd9Sstevel@tonic-gate 		(void) putc(' ', stdout);
15197c478bd9Sstevel@tonic-gate 		curcol++;
15207c478bd9Sstevel@tonic-gate 	} while (curcol % colwidth);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate static void
15247c478bd9Sstevel@tonic-gate new_line(void)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	if (curcol) {
15277c478bd9Sstevel@tonic-gate 		first = 0;
15287c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
15297c478bd9Sstevel@tonic-gate 		curcol = 0;
15307c478bd9Sstevel@tonic-gate 	}
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate  * read each filename in directory dir and store its
15357c478bd9Sstevel@tonic-gate  * status in flist[nfiles]
15367c478bd9Sstevel@tonic-gate  * use makename() to form pathname dir/filename;
15377c478bd9Sstevel@tonic-gate  */
15387c478bd9Sstevel@tonic-gate static void
15397c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate 	struct dirent *dentry;
15427c478bd9Sstevel@tonic-gate 	DIR *dirf;
15437c478bd9Sstevel@tonic-gate 	int j;
15447c478bd9Sstevel@tonic-gate 	struct lbuf *ep;
15457c478bd9Sstevel@tonic-gate 	int width;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	if ((dirf = opendir(dir)) == NULL) {
15487c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
15497c478bd9Sstevel@tonic-gate 		perror(dir);
15507c478bd9Sstevel@tonic-gate 		err = 2;
15517c478bd9Sstevel@tonic-gate 		return;
15527c478bd9Sstevel@tonic-gate 	} else {
15537c478bd9Sstevel@tonic-gate 		tblocks = 0;
15547c478bd9Sstevel@tonic-gate 		for (;;) {
15557c478bd9Sstevel@tonic-gate 			errno = 0;
15567c478bd9Sstevel@tonic-gate 			if ((dentry = readdir(dirf)) == NULL)
15577c478bd9Sstevel@tonic-gate 				break;
15587c478bd9Sstevel@tonic-gate 			if (aflg == 0 && dentry->d_name[0] == '.' &&
15597c478bd9Sstevel@tonic-gate 			    (Aflg == 0 ||
15607c478bd9Sstevel@tonic-gate 			    dentry->d_name[1] == '\0' ||
156129e6ab97SIgor Kozhukhov 			    (dentry->d_name[1] == '.' &&
156229e6ab97SIgor Kozhukhov 			    dentry->d_name[2] == '\0')))
15637c478bd9Sstevel@tonic-gate 				/*
15647c478bd9Sstevel@tonic-gate 				 * check for directory items '.', '..',
15657c478bd9Sstevel@tonic-gate 				 *  and items without valid inode-number;
15667c478bd9Sstevel@tonic-gate 				 */
15677c478bd9Sstevel@tonic-gate 				continue;
15687c478bd9Sstevel@tonic-gate 
15695e1c72e1SJason King 			/* skip entries ending in ~ if -B was given */
15705e1c72e1SJason King 			if (Bflg &&
15715e1c72e1SJason King 			    dentry->d_name[strlen(dentry->d_name) - 1] == '~')
15725e1c72e1SJason King 				continue;
15737c478bd9Sstevel@tonic-gate 			if (Cflg || mflg) {
15747c478bd9Sstevel@tonic-gate 				width = strcol((unsigned char *)dentry->d_name);
15757c478bd9Sstevel@tonic-gate 				if (width > filewidth)
15767c478bd9Sstevel@tonic-gate 					filewidth = width;
15777c478bd9Sstevel@tonic-gate 			}
15787c478bd9Sstevel@tonic-gate 			ep = gstat(makename(dir, dentry->d_name), 0, myinfo);
15797c478bd9Sstevel@tonic-gate 			if (ep == NULL) {
15807c478bd9Sstevel@tonic-gate 				if (nomocore)
1581da6c28aaSamw 					exit(2);
15827c478bd9Sstevel@tonic-gate 				continue;
15837c478bd9Sstevel@tonic-gate 			} else {
15847c478bd9Sstevel@tonic-gate 				ep->lnum = dentry->d_ino;
15857c478bd9Sstevel@tonic-gate 				for (j = 0; dentry->d_name[j] != '\0'; j++)
15867c478bd9Sstevel@tonic-gate 					ep->ln.lname[j] = dentry->d_name[j];
15877c478bd9Sstevel@tonic-gate 				ep->ln.lname[j] = '\0';
158891bbe3fdSBill Pijewski 
158991bbe3fdSBill Pijewski 				/*
159091bbe3fdSBill Pijewski 				 * Since this entry doesn't need to be sorted
159191bbe3fdSBill Pijewski 				 * or further processed, print it right away.
159291bbe3fdSBill Pijewski 				 */
159391bbe3fdSBill Pijewski 				if (noflist) {
159491bbe3fdSBill Pijewski 					pem(&ep, &ep + 1, 0);
159591bbe3fdSBill Pijewski 					nfiles--;
159691bbe3fdSBill Pijewski 				}
15977c478bd9Sstevel@tonic-gate 			}
15987c478bd9Sstevel@tonic-gate 		}
15997c478bd9Sstevel@tonic-gate 		if (errno) {
16007c478bd9Sstevel@tonic-gate 			int sav_errno = errno;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
16037c478bd9Sstevel@tonic-gate 			    gettext("ls: error reading directory %s: %s\n"),
16047c478bd9Sstevel@tonic-gate 			    dir, strerror(sav_errno));
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		(void) closedir(dirf);
16077c478bd9Sstevel@tonic-gate 		colwidth = fixedwidth + filewidth;
16087c478bd9Sstevel@tonic-gate 	}
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate /*
16127c478bd9Sstevel@tonic-gate  * Attaching a link to an inode's ancestors.  Search
16137c478bd9Sstevel@tonic-gate  * through the ancestors to check for cycles (an inode which
16147c478bd9Sstevel@tonic-gate  * we have already tracked in this inodes ancestry).  If a cycle
16157c478bd9Sstevel@tonic-gate  * is detected, set the exit code and record the fact so that
16167c478bd9Sstevel@tonic-gate  * it is reported at the right time when printing the directory.
16177c478bd9Sstevel@tonic-gate  * In addition, set the exit code.  Note:  If the -a flag was
16187c478bd9Sstevel@tonic-gate  * specified, we don't want to check for cycles for directories
16197c478bd9Sstevel@tonic-gate  * ending in '/.' or '/..' unless they were specified on the
16207c478bd9Sstevel@tonic-gate  * command line.
16217c478bd9Sstevel@tonic-gate  */
16227c478bd9Sstevel@tonic-gate static void
16237c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep,
16247c478bd9Sstevel@tonic-gate     int argfl, struct ditem *myparent)
16257c478bd9Sstevel@tonic-gate {
16267c478bd9Sstevel@tonic-gate 	size_t		file_len;
16277c478bd9Sstevel@tonic-gate 	struct ditem	*myinfo;
16287c478bd9Sstevel@tonic-gate 	struct ditem	*tptr;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	file_len = strlen(file);
16317c478bd9Sstevel@tonic-gate 	if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) &&
16327c478bd9Sstevel@tonic-gate 	    NOTPARENTDIR(file, file_len))) {
16337c478bd9Sstevel@tonic-gate 		/*
16347c478bd9Sstevel@tonic-gate 		 * Add this inode's ancestry
16357c478bd9Sstevel@tonic-gate 		 * info and insert it into the
16367c478bd9Sstevel@tonic-gate 		 * ancestry list by pointing
16377c478bd9Sstevel@tonic-gate 		 * back to its parent.  We save
16387c478bd9Sstevel@tonic-gate 		 * it (in rep) with the other info
16397c478bd9Sstevel@tonic-gate 		 * we're gathering for this inode.
16407c478bd9Sstevel@tonic-gate 		 */
16417c478bd9Sstevel@tonic-gate 		if ((myinfo = malloc(
16427c478bd9Sstevel@tonic-gate 		    sizeof (struct ditem))) == NULL) {
16437c478bd9Sstevel@tonic-gate 			perror("ls");
16447c478bd9Sstevel@tonic-gate 			exit(2);
16457c478bd9Sstevel@tonic-gate 		}
16467c478bd9Sstevel@tonic-gate 		myinfo->dev = pstatb->st_dev;
16477c478bd9Sstevel@tonic-gate 		myinfo->ino = pstatb->st_ino;
16487c478bd9Sstevel@tonic-gate 		myinfo->parent = myparent;
16497c478bd9Sstevel@tonic-gate 		rep->ancinfo = myinfo;
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 		/*
16527c478bd9Sstevel@tonic-gate 		 * If this node has the same device id and
16537c478bd9Sstevel@tonic-gate 		 * inode number of one of its ancestors,
16547c478bd9Sstevel@tonic-gate 		 * then we've detected a cycle.
16557c478bd9Sstevel@tonic-gate 		 */
16567c478bd9Sstevel@tonic-gate 		if (myparent != NULL) {
16577c478bd9Sstevel@tonic-gate 			for (tptr = myparent; tptr->parent != NULL;
16587c478bd9Sstevel@tonic-gate 			    tptr = tptr->parent) {
16597c478bd9Sstevel@tonic-gate 				if ((tptr->dev == pstatb->st_dev) &&
16607c478bd9Sstevel@tonic-gate 				    (tptr->ino == pstatb->st_ino)) {
16617c478bd9Sstevel@tonic-gate 					/*
16627c478bd9Sstevel@tonic-gate 					 * Cycle detected for this
16637c478bd9Sstevel@tonic-gate 					 * directory.  Record the fact
16647c478bd9Sstevel@tonic-gate 					 * it is a cycle so we don't
16657c478bd9Sstevel@tonic-gate 					 * try to process this
16667c478bd9Sstevel@tonic-gate 					 * directory as we are
16677c478bd9Sstevel@tonic-gate 					 * walking through the
16687c478bd9Sstevel@tonic-gate 					 * list of directories.
16697c478bd9Sstevel@tonic-gate 					 */
16707c478bd9Sstevel@tonic-gate 					rep->cycle = 1;
16717c478bd9Sstevel@tonic-gate 					err = 2;
16727c478bd9Sstevel@tonic-gate 					break;
16737c478bd9Sstevel@tonic-gate 				}
16747c478bd9Sstevel@tonic-gate 			}
16757c478bd9Sstevel@tonic-gate 		}
16767c478bd9Sstevel@tonic-gate 	}
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate /*
168064d425a7Sny155746  * Do re-calculate the mode for group for ACE_T type of acls.
168164d425a7Sny155746  * This is because, if the server's FS happens to be UFS, supporting
168264d425a7Sny155746  * POSIX ACL's, then it does a special calculation of group mode
168364d425a7Sny155746  * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.)
168464d425a7Sny155746  *
168564d425a7Sny155746  * This algorithm is from the NFSv4 ACL Draft. Here a part of that
168664d425a7Sny155746  * algorithm is used for the group mode calculation only.
168764d425a7Sny155746  * What is modified here from the algorithm is that only the
168864d425a7Sny155746  * entries with flags ACE_GROUP are considered. For each entry
168964d425a7Sny155746  * with ACE_GROUP flag, the first occurance of a specific access
169064d425a7Sny155746  * is checked if it is allowed.
1691e2442894Sny155746  * We are not interested in perms for user and other, as they
169264d425a7Sny155746  * were taken from st_mode value.
169364d425a7Sny155746  * We are not interested in a_who field of ACE, as we need just
169464d425a7Sny155746  * unix mode bits for the group.
169564d425a7Sny155746  */
1696e2442894Sny155746 
1697e2442894Sny155746 #define	OWNED_GROUP	(ACE_GROUP | ACE_IDENTIFIER_GROUP)
1698e2442894Sny155746 #define	IS_TYPE_ALLOWED(type)	((type) == ACE_ACCESS_ALLOWED_ACE_TYPE)
1699e2442894Sny155746 
170064d425a7Sny155746 int
170127dd1e87SMark Shellenbaum grp_mask_to_mode(struct lbuf *p)
170264d425a7Sny155746 {
170364d425a7Sny155746 	int mode = 0, seen = 0;
170464d425a7Sny155746 	int acecnt;
1705e2442894Sny155746 	int flags;
170664d425a7Sny155746 	ace_t *ap;
170727dd1e87SMark Shellenbaum 	acl_t *acep = p->aclp;
170864d425a7Sny155746 
170964d425a7Sny155746 	acecnt = acl_cnt(acep);
171064d425a7Sny155746 	for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) {
1711e2442894Sny155746 
1712e2442894Sny155746 		if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE &&
1713e2442894Sny155746 		    ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE)
1714e2442894Sny155746 			continue;
1715e2442894Sny155746 
1716e2442894Sny155746 		if (ap->a_flags & ACE_INHERIT_ONLY_ACE)
1717e2442894Sny155746 			continue;
1718e2442894Sny155746 
1719e2442894Sny155746 		/*
1720e2442894Sny155746 		 * if it is first group@ or first everyone@
1721e2442894Sny155746 		 * for each of read, write and execute, then
1722e2442894Sny155746 		 * that will be the group mode bit.
1723e2442894Sny155746 		 */
1724e2442894Sny155746 		flags = ap->a_flags & ACE_TYPE_FLAGS;
172527dd1e87SMark Shellenbaum 		if (flags == OWNED_GROUP || (flags == ACE_IDENTIFIER_GROUP &&
172627dd1e87SMark Shellenbaum 		    ap->a_who == p->lgid) || flags == ACE_EVERYONE) {
172764d425a7Sny155746 			if (ap->a_access_mask & ACE_READ_DATA) {
172864d425a7Sny155746 				if (!(seen & S_IRGRP)) {
172964d425a7Sny155746 					seen |= S_IRGRP;
1730e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
173164d425a7Sny155746 						mode |= S_IRGRP;
173264d425a7Sny155746 				}
173364d425a7Sny155746 			}
173464d425a7Sny155746 			if (ap->a_access_mask & ACE_WRITE_DATA) {
173564d425a7Sny155746 				if (!(seen & S_IWGRP)) {
173664d425a7Sny155746 					seen |= S_IWGRP;
1737e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
173864d425a7Sny155746 						mode |= S_IWGRP;
173964d425a7Sny155746 				}
174064d425a7Sny155746 			}
174164d425a7Sny155746 			if (ap->a_access_mask & ACE_EXECUTE) {
174264d425a7Sny155746 				if (!(seen & S_IXGRP)) {
174364d425a7Sny155746 					seen |= S_IXGRP;
1744e2442894Sny155746 					if (IS_TYPE_ALLOWED(ap->a_type))
174564d425a7Sny155746 						mode |= S_IXGRP;
174664d425a7Sny155746 				}
174764d425a7Sny155746 			}
174864d425a7Sny155746 		}
174964d425a7Sny155746 	}
175064d425a7Sny155746 	return (mode);
175164d425a7Sny155746 }
175264d425a7Sny155746 
175364d425a7Sny155746 /*
17547c478bd9Sstevel@tonic-gate  * get status of file and recomputes tblocks;
17557c478bd9Sstevel@tonic-gate  * argfl = 1 if file is a name in ls-command and = 0
17567c478bd9Sstevel@tonic-gate  * for filename in a directory whose name is an
17577c478bd9Sstevel@tonic-gate  * argument in the command;
17587c478bd9Sstevel@tonic-gate  * stores a pointer in flist[nfiles] and
17597c478bd9Sstevel@tonic-gate  * returns that pointer;
17607c478bd9Sstevel@tonic-gate  * returns NULL if failed;
17617c478bd9Sstevel@tonic-gate  */
17627c478bd9Sstevel@tonic-gate static struct lbuf *
17637c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent)
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate 	struct stat statb, statb1;
17667c478bd9Sstevel@tonic-gate 	struct lbuf *rep;
17677c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
17687c478bd9Sstevel@tonic-gate 	ssize_t cc;
17697c478bd9Sstevel@tonic-gate 	int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat;
17707c478bd9Sstevel@tonic-gate 	int aclcnt;
1771fa9e4066Sahrens 	int error;
17727c478bd9Sstevel@tonic-gate 	aclent_t *tp;
17737c478bd9Sstevel@tonic-gate 	o_mode_t groupperm, mask;
17747c478bd9Sstevel@tonic-gate 	int grouppermfound, maskfound;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	if (nomocore)
17777c478bd9Sstevel@tonic-gate 		return (NULL);
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	if (nfiles >= maxfils) {
17807c478bd9Sstevel@tonic-gate 		/*
17817c478bd9Sstevel@tonic-gate 		 * all flist/lbuf pair assigned files, time to get some
17827c478bd9Sstevel@tonic-gate 		 * more space
17837c478bd9Sstevel@tonic-gate 		 */
17847c478bd9Sstevel@tonic-gate 		maxfils += quantn;
17857c478bd9Sstevel@tonic-gate 		if (((flist = realloc(flist,
17867c478bd9Sstevel@tonic-gate 		    maxfils * sizeof (struct lbuf *))) == NULL) ||
17877c478bd9Sstevel@tonic-gate 		    ((nxtlbf = malloc(quantn *
17887c478bd9Sstevel@tonic-gate 		    sizeof (struct lbuf))) == NULL)) {
17897c478bd9Sstevel@tonic-gate 			perror("ls");
17907c478bd9Sstevel@tonic-gate 			nomocore = 1;
17917c478bd9Sstevel@tonic-gate 			return (NULL);
17927c478bd9Sstevel@tonic-gate 		}
17937c478bd9Sstevel@tonic-gate 	}
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	/*
17967c478bd9Sstevel@tonic-gate 	 * nfiles is reset to nargs for each directory
17977c478bd9Sstevel@tonic-gate 	 * that is given as an argument maxn is checked
17987c478bd9Sstevel@tonic-gate 	 * to prevent the assignment of an lbuf to a flist entry
17997c478bd9Sstevel@tonic-gate 	 * that already has one assigned.
18007c478bd9Sstevel@tonic-gate 	 */
18017c478bd9Sstevel@tonic-gate 	if (nfiles >= maxn) {
18027c478bd9Sstevel@tonic-gate 		rep = nxtlbf++;
18037c478bd9Sstevel@tonic-gate 		flist[nfiles++] = rep;
18047c478bd9Sstevel@tonic-gate 		maxn = nfiles;
18057c478bd9Sstevel@tonic-gate 	} else {
18067c478bd9Sstevel@tonic-gate 		rep = flist[nfiles++];
18077c478bd9Sstevel@tonic-gate 	}
180844f31f13Sbasabi 
1809b9c81738SGary Mills 	/* Clear the lbuf */
1810b9c81738SGary Mills 	(void) memset((void *) rep, 0, sizeof (struct lbuf));
1811b9c81738SGary Mills 
181291bbe3fdSBill Pijewski 	/*
181391bbe3fdSBill Pijewski 	 * When noflist is set, none of the extra information about the dirent
1814b9c81738SGary Mills 	 * will be printed, so omit remaining initialization of this lbuf
1815b9c81738SGary Mills 	 * as well as the  stat(2) call.
181691bbe3fdSBill Pijewski 	 */
181791bbe3fdSBill Pijewski 	if (!argfl && noflist)
181891bbe3fdSBill Pijewski 		return (rep);
181991bbe3fdSBill Pijewski 
1820b9c81738SGary Mills 	/* Initialize non-zero members */
182144f31f13Sbasabi 
182244f31f13Sbasabi 	rep->lat.tv_sec = time(NULL);
182344f31f13Sbasabi 	rep->lct.tv_sec = time(NULL);
182444f31f13Sbasabi 	rep->lmt.tv_sec = time(NULL);
182544f31f13Sbasabi 
18267c478bd9Sstevel@tonic-gate 	if (argfl || statreq) {
18277c478bd9Sstevel@tonic-gate 		int doacl;
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 		if (lflg)
18307c478bd9Sstevel@tonic-gate 			doacl = 1;
18317c478bd9Sstevel@tonic-gate 		else
18327c478bd9Sstevel@tonic-gate 			doacl = 0;
183344f31f13Sbasabi 
18347c478bd9Sstevel@tonic-gate 		if ((*statf)(file, &statb) < 0) {
18357c478bd9Sstevel@tonic-gate 			if (argfl || errno != ENOENT ||
18367c478bd9Sstevel@tonic-gate 			    (Lflg && lstat(file, &statb) == 0)) {
18377c478bd9Sstevel@tonic-gate 				/*
18387c478bd9Sstevel@tonic-gate 				 * Avoid race between readdir and lstat.
18397c478bd9Sstevel@tonic-gate 				 * Print error message in case of dangling link.
18407c478bd9Sstevel@tonic-gate 				 */
18417c478bd9Sstevel@tonic-gate 				perror(file);
18425e1c72e1SJason King 				err = 2;
18437c478bd9Sstevel@tonic-gate 			}
18447c478bd9Sstevel@tonic-gate 			nfiles--;
18457c478bd9Sstevel@tonic-gate 			return (NULL);
18467c478bd9Sstevel@tonic-gate 		}
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 		/*
18497c478bd9Sstevel@tonic-gate 		 * If -H was specified, and the file linked to was
18507c478bd9Sstevel@tonic-gate 		 * not a directory, then we need to get the info
18517c478bd9Sstevel@tonic-gate 		 * for the symlink itself.
18527c478bd9Sstevel@tonic-gate 		 */
18537c478bd9Sstevel@tonic-gate 		if ((Hflg) && (argfl) &&
18547c478bd9Sstevel@tonic-gate 		    ((statb.st_mode & S_IFMT) != S_IFDIR)) {
18557c478bd9Sstevel@tonic-gate 			if (lstat(file, &statb) < 0) {
18567c478bd9Sstevel@tonic-gate 				perror(file);
18575e1c72e1SJason King 				err = 2;
18587c478bd9Sstevel@tonic-gate 			}
18597c478bd9Sstevel@tonic-gate 		}
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 		rep->lnum = statb.st_ino;
18627c478bd9Sstevel@tonic-gate 		rep->lsize = statb.st_size;
18637c478bd9Sstevel@tonic-gate 		rep->lblocks = statb.st_blocks;
18641b628248SJason King 		if (colorflg)
18651b628248SJason King 			rep->color = ls_color_find(file, statb.st_mode);
18661b628248SJason King 
18677c478bd9Sstevel@tonic-gate 		switch (statb.st_mode & S_IFMT) {
18687c478bd9Sstevel@tonic-gate 		case S_IFDIR:
18697c478bd9Sstevel@tonic-gate 			rep->ltype = 'd';
18707c478bd9Sstevel@tonic-gate 			if (Rflg) {
18717c478bd9Sstevel@tonic-gate 				record_ancestry(file, &statb, rep,
18727c478bd9Sstevel@tonic-gate 				    argfl, myparent);
18737c478bd9Sstevel@tonic-gate 			}
18747c478bd9Sstevel@tonic-gate 			break;
18757c478bd9Sstevel@tonic-gate 		case S_IFBLK:
18767c478bd9Sstevel@tonic-gate 			rep->ltype = 'b';
18777c478bd9Sstevel@tonic-gate 			rep->lsize = (off_t)statb.st_rdev;
18787c478bd9Sstevel@tonic-gate 			break;
18797c478bd9Sstevel@tonic-gate 		case S_IFCHR:
18807c478bd9Sstevel@tonic-gate 			rep->ltype = 'c';
18817c478bd9Sstevel@tonic-gate 			rep->lsize = (off_t)statb.st_rdev;
18827c478bd9Sstevel@tonic-gate 			break;
18837c478bd9Sstevel@tonic-gate 		case S_IFIFO:
18847c478bd9Sstevel@tonic-gate 			rep->ltype = 'p';
18857c478bd9Sstevel@tonic-gate 			break;
18867c478bd9Sstevel@tonic-gate 		case S_IFSOCK:
18877c478bd9Sstevel@tonic-gate 			rep->ltype = 's';
18887c478bd9Sstevel@tonic-gate 			rep->lsize = 0;
18897c478bd9Sstevel@tonic-gate 			break;
18907c478bd9Sstevel@tonic-gate 		case S_IFLNK:
18917c478bd9Sstevel@tonic-gate 			/* symbolic links may not have ACLs, so elide acl() */
18927c478bd9Sstevel@tonic-gate 			if ((Lflg == 0) || (Hflg == 0) ||
18937c478bd9Sstevel@tonic-gate 			    ((Hflg) && (!argfl))) {
18947c478bd9Sstevel@tonic-gate 				doacl = 0;
18957c478bd9Sstevel@tonic-gate 			}
18967c478bd9Sstevel@tonic-gate 			rep->ltype = 'l';
18971b628248SJason King 			if (lflg || colorflg) {
18987c478bd9Sstevel@tonic-gate 				cc = readlink(file, buf, BUFSIZ);
18991b628248SJason King 				if (cc < 0)
19001b628248SJason King 					break;
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 				/*
19037c478bd9Sstevel@tonic-gate 				 * follow the symbolic link
19047c478bd9Sstevel@tonic-gate 				 * to generate the appropriate
19057c478bd9Sstevel@tonic-gate 				 * Fflg marker for the object
19067c478bd9Sstevel@tonic-gate 				 * eg, /bin -> /sym/bin/
19077c478bd9Sstevel@tonic-gate 				 */
19081b628248SJason King 				error = 0;
19091b628248SJason King 				if (Fflg || pflg || colorflg)
19101b628248SJason King 					error = stat(file, &statb1);
19111b628248SJason King 
19121b628248SJason King 				if (colorflg) {
19131b628248SJason King 					if (error >= 0)
19141b628248SJason King 						rep->link_color =
19151b628248SJason King 						    ls_color_find(file,
19161b628248SJason King 						    statb1.st_mode);
19171b628248SJason King 					else
19181b628248SJason King 						rep->link_color =
19191b628248SJason King 						    lsc_orphan;
19201b628248SJason King 				}
19211b628248SJason King 
19221b628248SJason King 				if ((Fflg || pflg) && error >= 0) {
19231b628248SJason King 					switch (statb1.st_mode & S_IFMT) {
19247c478bd9Sstevel@tonic-gate 					case S_IFDIR:
19257c478bd9Sstevel@tonic-gate 						buf[cc++] = '/';
19267c478bd9Sstevel@tonic-gate 						break;
19277c478bd9Sstevel@tonic-gate 					case S_IFSOCK:
19287c478bd9Sstevel@tonic-gate 						buf[cc++] = '=';
19297c478bd9Sstevel@tonic-gate 						break;
19302236845bSakaplan 					case S_IFDOOR:
19312236845bSakaplan 						buf[cc++] = '>';
19322236845bSakaplan 						break;
19332236845bSakaplan 					case S_IFIFO:
19342236845bSakaplan 						buf[cc++] = '|';
19352236845bSakaplan 						break;
19367c478bd9Sstevel@tonic-gate 					default:
19371b628248SJason King 						if ((statb1.st_mode & ~S_IFMT) &
19381b628248SJason King 						    (S_IXUSR|S_IXGRP| S_IXOTH))
19397c478bd9Sstevel@tonic-gate 							buf[cc++] = '*';
19407c478bd9Sstevel@tonic-gate 						break;
19417c478bd9Sstevel@tonic-gate 					}
19427c478bd9Sstevel@tonic-gate 				}
19437c478bd9Sstevel@tonic-gate 				buf[cc] = '\0';
19447c478bd9Sstevel@tonic-gate 				rep->flinkto = strdup(buf);
194538f2a414SAlbert Lee 				if (rep->flinkto == NULL) {
194638f2a414SAlbert Lee 					perror("ls");
194738f2a414SAlbert Lee 					nomocore = 1;
194838f2a414SAlbert Lee 					return (NULL);
194938f2a414SAlbert Lee 				}
19507c478bd9Sstevel@tonic-gate 				break;
19517c478bd9Sstevel@tonic-gate 			}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 			/*
19547c478bd9Sstevel@tonic-gate 			 * ls /sym behaves differently from ls /sym/
19557c478bd9Sstevel@tonic-gate 			 * when /sym is a symbolic link. This is fixed
19567c478bd9Sstevel@tonic-gate 			 * when explicit arguments are specified.
19577c478bd9Sstevel@tonic-gate 			 */
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate #ifdef XPG6
19607c478bd9Sstevel@tonic-gate 			/* Do not follow a symlink when -F is specified */
19617c478bd9Sstevel@tonic-gate 			if ((!argfl) || (argfl && Fflg) ||
19627c478bd9Sstevel@tonic-gate 			    (stat(file, &statb1) < 0))
19637c478bd9Sstevel@tonic-gate #else
19647c478bd9Sstevel@tonic-gate 			/* Follow a symlink when -F is specified */
19657c478bd9Sstevel@tonic-gate 			if (!argfl || stat(file, &statb1) < 0)
19667c478bd9Sstevel@tonic-gate #endif /* XPG6 */
19677c478bd9Sstevel@tonic-gate 				break;
19687c478bd9Sstevel@tonic-gate 			if ((statb1.st_mode & S_IFMT) == S_IFDIR) {
19697c478bd9Sstevel@tonic-gate 				statb = statb1;
19707c478bd9Sstevel@tonic-gate 				rep->ltype = 'd';
19717c478bd9Sstevel@tonic-gate 				rep->lsize = statb1.st_size;
19727c478bd9Sstevel@tonic-gate 				if (Rflg) {
19737c478bd9Sstevel@tonic-gate 					record_ancestry(file, &statb, rep,
19747c478bd9Sstevel@tonic-gate 					    argfl, myparent);
19757c478bd9Sstevel@tonic-gate 				}
19767c478bd9Sstevel@tonic-gate 			}
19777c478bd9Sstevel@tonic-gate 			break;
19787c478bd9Sstevel@tonic-gate 		case S_IFDOOR:
19797c478bd9Sstevel@tonic-gate 			rep->ltype = 'D';
19807c478bd9Sstevel@tonic-gate 			break;
19817c478bd9Sstevel@tonic-gate 		case S_IFREG:
19827c478bd9Sstevel@tonic-gate 			rep->ltype = '-';
19837c478bd9Sstevel@tonic-gate 			break;
19847c478bd9Sstevel@tonic-gate 		case S_IFPORT:
19857c478bd9Sstevel@tonic-gate 			rep->ltype = 'P';
19867c478bd9Sstevel@tonic-gate 			break;
19877c478bd9Sstevel@tonic-gate 		default:
19887c478bd9Sstevel@tonic-gate 			rep->ltype = '?';
19897c478bd9Sstevel@tonic-gate 			break;
19907c478bd9Sstevel@tonic-gate 		}
19917c478bd9Sstevel@tonic-gate 		rep->lflags = statb.st_mode & ~S_IFMT;
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 		if (!S_ISREG(statb.st_mode))
19947c478bd9Sstevel@tonic-gate 			rep->lflags |= LS_NOTREG;
19957c478bd9Sstevel@tonic-gate 
199644f31f13Sbasabi 		rep->luid = statb.st_uid;
199744f31f13Sbasabi 		rep->lgid = statb.st_gid;
199844f31f13Sbasabi 		rep->lnl = statb.st_nlink;
199944f31f13Sbasabi 		if (uflg || (tmflg && atm))
200044f31f13Sbasabi 			rep->lmtime = statb.st_atim;
200144f31f13Sbasabi 		else if (cflg || (tmflg && ctm))
200244f31f13Sbasabi 			rep->lmtime = statb.st_ctim;
200344f31f13Sbasabi 		else
200444f31f13Sbasabi 			rep->lmtime = statb.st_mtim;
200544f31f13Sbasabi 		rep->lat = statb.st_atim;
200644f31f13Sbasabi 		rep->lct = statb.st_ctim;
200744f31f13Sbasabi 		rep->lmt = statb.st_mtim;
200844f31f13Sbasabi 
20097c478bd9Sstevel@tonic-gate 		/* ACL: check acl entries count */
20107c478bd9Sstevel@tonic-gate 		if (doacl) {
20117c478bd9Sstevel@tonic-gate 
2012fa9e4066Sahrens 			error = acl_get(file, 0, &rep->aclp);
2013fa9e4066Sahrens 			if (error) {
2014fa9e4066Sahrens 				(void) fprintf(stderr,
2015fa9e4066Sahrens 				    gettext("ls: can't read ACL on %s: %s\n"),
2016fa9e4066Sahrens 				    file, acl_strerror(error));
201744f31f13Sbasabi 				rep->acl = ' ';
201856798e90Sbasabi 				acl_err++;
201944f31f13Sbasabi 				return (rep);
20207c478bd9Sstevel@tonic-gate 			}
20217c478bd9Sstevel@tonic-gate 
2022fa9e4066Sahrens 			rep->acl = ' ';
2023fa9e4066Sahrens 
2024fa9e4066Sahrens 			if (rep->aclp &&
2025fa9e4066Sahrens 			    ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) {
2026fa9e4066Sahrens 				rep->acl = '+';
20277c478bd9Sstevel@tonic-gate 				/*
2028fa9e4066Sahrens 				 * Special handling for ufs aka aclent_t ACL's
2029fa9e4066Sahrens 				 */
203064d425a7Sny155746 				if (acl_type(rep->aclp) == ACLENT_T) {
2031fa9e4066Sahrens 					/*
2032fa9e4066Sahrens 					 * For files with non-trivial acls, the
2033fa9e4066Sahrens 					 * effective group permissions are the
2034fa9e4066Sahrens 					 * intersection of the GROUP_OBJ value
2035fa9e4066Sahrens 					 * and the CLASS_OBJ (acl mask) value.
2036fa9e4066Sahrens 					 * Determine both the GROUP_OBJ and
2037fa9e4066Sahrens 					 * CLASS_OBJ for this file and insert
2038fa9e4066Sahrens 					 * the logical AND of those two values
2039fa9e4066Sahrens 					 * in the group permissions field
2040fa9e4066Sahrens 					 * of the lflags value for this file.
2041fa9e4066Sahrens 					 */
2042fa9e4066Sahrens 
2043fa9e4066Sahrens 					/*
2044fa9e4066Sahrens 					 * Until found in acl list, assume
2045fa9e4066Sahrens 					 * maximum permissions for both group
2046fa9e4066Sahrens 					 * a nd mask.  (Just in case the acl
2047fa9e4066Sahrens 					 * lacks either value for some reason.)
20487c478bd9Sstevel@tonic-gate 					 */
20497c478bd9Sstevel@tonic-gate 					groupperm = 07;
20507c478bd9Sstevel@tonic-gate 					mask = 07;
20517c478bd9Sstevel@tonic-gate 					grouppermfound = 0;
20527c478bd9Sstevel@tonic-gate 					maskfound = 0;
2053fa9e4066Sahrens 					aclcnt = acl_cnt(rep->aclp);
2054fa9e4066Sahrens 					for (tp =
2055fa9e4066Sahrens 					    (aclent_t *)acl_data(rep->aclp);
2056fa9e4066Sahrens 					    aclcnt--; tp++) {
20577c478bd9Sstevel@tonic-gate 						if (tp->a_type == GROUP_OBJ) {
20587c478bd9Sstevel@tonic-gate 							groupperm = tp->a_perm;
20597c478bd9Sstevel@tonic-gate 							grouppermfound = 1;
20607c478bd9Sstevel@tonic-gate 							continue;
20617c478bd9Sstevel@tonic-gate 						}
20627c478bd9Sstevel@tonic-gate 						if (tp->a_type == CLASS_OBJ) {
20637c478bd9Sstevel@tonic-gate 							mask = tp->a_perm;
20647c478bd9Sstevel@tonic-gate 							maskfound = 1;
20657c478bd9Sstevel@tonic-gate 						}
20667c478bd9Sstevel@tonic-gate 						if (grouppermfound && maskfound)
20677c478bd9Sstevel@tonic-gate 							break;
20687c478bd9Sstevel@tonic-gate 					}
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 					/* reset all the group bits */
20727c478bd9Sstevel@tonic-gate 					rep->lflags &= ~S_IRWXG;
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 					/*
2075fa9e4066Sahrens 					 * Now set them to the logical AND of
2076fa9e4066Sahrens 					 * the GROUP_OBJ permissions and the
2077fa9e4066Sahrens 					 * acl mask.
20787c478bd9Sstevel@tonic-gate 					 */
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 					rep->lflags |= (groupperm & mask) << 3;
2081fa9e4066Sahrens 
208264d425a7Sny155746 				} else if (acl_type(rep->aclp) == ACE_T) {
208364d425a7Sny155746 					int mode;
208427dd1e87SMark Shellenbaum 					mode = grp_mask_to_mode(rep);
208564d425a7Sny155746 					rep->lflags &= ~S_IRWXG;
208664d425a7Sny155746 					rep->lflags |= mode;
2087fa9e4066Sahrens 				}
20887c478bd9Sstevel@tonic-gate 			}
20897c478bd9Sstevel@tonic-gate 
20905a5eeccaSmarks 			if (!vflg && !Vflg && rep->aclp) {
20915a5eeccaSmarks 				acl_free(rep->aclp);
20925a5eeccaSmarks 				rep->aclp = NULL;
20935a5eeccaSmarks 			}
20945a5eeccaSmarks 
20957c478bd9Sstevel@tonic-gate 			if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
20967c478bd9Sstevel@tonic-gate 				rep->acl = '@';
2097da6c28aaSamw 
20987c478bd9Sstevel@tonic-gate 		} else
20997c478bd9Sstevel@tonic-gate 			rep->acl = ' ';
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 		/* mask ISARG and other file-type bits */
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 		if (rep->ltype != 'b' && rep->ltype != 'c')
21047c478bd9Sstevel@tonic-gate 			tblocks += rep->lblocks;
2105da6c28aaSamw 
2106da6c28aaSamw 		/* Get extended system attributes */
2107da6c28aaSamw 
2108da6c28aaSamw 		if ((saflg || (tmflg && crtm) || (tmflg && alltm)) &&
2109da6c28aaSamw 		    (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) {
2110da6c28aaSamw 			int i;
2111da6c28aaSamw 
2112da6c28aaSamw 			sacnt = attr_count();
2113da6c28aaSamw 			/*
2114da6c28aaSamw 			 * Allocate 'sacnt' size array to hold extended
2115da6c28aaSamw 			 * system attribute name (verbose) or respective
2116da6c28aaSamw 			 * symbol represenation (compact).
2117da6c28aaSamw 			 */
2118da6c28aaSamw 			rep->exttr = xmalloc(sacnt * sizeof (struct attrb),
2119da6c28aaSamw 			    rep);
2120da6c28aaSamw 
2121da6c28aaSamw 			/* initialize boolean attribute list */
2122da6c28aaSamw 			for (i = 0; i < sacnt; i++)
2123da6c28aaSamw 				rep->exttr[i].name = NULL;
2124da6c28aaSamw 			if (get_sysxattr(file, rep) != 0) {
2125da6c28aaSamw 				(void) fprintf(stderr,
2126da6c28aaSamw 				    gettext("ls:Failed to retrieve "
2127da6c28aaSamw 				    "extended system attribute from "
2128da6c28aaSamw 				    "%s\n"), file);
2129da6c28aaSamw 				rep->exttr[0].name = xmalloc(2, rep);
2130da6c28aaSamw 				(void) strlcpy(rep->exttr[0].name, "?", 2);
2131da6c28aaSamw 			}
2132da6c28aaSamw 		}
21337c478bd9Sstevel@tonic-gate 	}
21347c478bd9Sstevel@tonic-gate 	return (rep);
21357c478bd9Sstevel@tonic-gate }
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate /*
21387c478bd9Sstevel@tonic-gate  * returns pathname of the form dir/file;
21397c478bd9Sstevel@tonic-gate  * dir and file are null-terminated strings.
21407c478bd9Sstevel@tonic-gate  */
21417c478bd9Sstevel@tonic-gate static char *
21427c478bd9Sstevel@tonic-gate makename(char *dir, char *file)
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate 	/*
21457c478bd9Sstevel@tonic-gate 	 * PATH_MAX is the maximum length of a path name.
21467c478bd9Sstevel@tonic-gate 	 * MAXNAMLEN is the maximum length of any path name component.
21477c478bd9Sstevel@tonic-gate 	 * Allocate space for both, plus the '/' in the middle
21487c478bd9Sstevel@tonic-gate 	 * and the null character at the end.
21497c478bd9Sstevel@tonic-gate 	 * dfile is static as this is returned by makename().
21507c478bd9Sstevel@tonic-gate 	 */
21517c478bd9Sstevel@tonic-gate 	static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1];
21527c478bd9Sstevel@tonic-gate 	char *dp, *fp;
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 	dp = dfile;
21557c478bd9Sstevel@tonic-gate 	fp = dir;
21567c478bd9Sstevel@tonic-gate 	while (*fp)
21577c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
21587c478bd9Sstevel@tonic-gate 	if (dp > dfile && *(dp - 1) != '/')
21597c478bd9Sstevel@tonic-gate 		*dp++ = '/';
21607c478bd9Sstevel@tonic-gate 	fp = file;
21617c478bd9Sstevel@tonic-gate 	while (*fp)
21627c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
21637c478bd9Sstevel@tonic-gate 	*dp = '\0';
21647c478bd9Sstevel@tonic-gate 	return (dfile);
21657c478bd9Sstevel@tonic-gate }
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate #include <pwd.h>
21697c478bd9Sstevel@tonic-gate #include <grp.h>
21707c478bd9Sstevel@tonic-gate #include <utmpx.h>
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate struct	utmpx utmp;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (utmp.ut_name))
21757c478bd9Sstevel@tonic-gate #define	SCPYN(a, b)	(void) strncpy(a, b, NMAX)
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate struct cachenode {		/* this struct must be zeroed before using */
21797c478bd9Sstevel@tonic-gate 	struct cachenode *lesschild;	/* subtree whose entries < val */
21807c478bd9Sstevel@tonic-gate 	struct cachenode *grtrchild;	/* subtree whose entries > val */
21817c478bd9Sstevel@tonic-gate 	long val;			/* the uid or gid of this entry */
21827c478bd9Sstevel@tonic-gate 	int initted;			/* name has been filled in */
21837c478bd9Sstevel@tonic-gate 	char name[NMAX+1];		/* the string that val maps to */
21847c478bd9Sstevel@tonic-gate };
21857c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups;
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate static struct cachenode *
21887c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val)
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	struct cachenode **parent = head;
21917c478bd9Sstevel@tonic-gate 	struct cachenode *c = *parent;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	while (c != NULL) {
21947c478bd9Sstevel@tonic-gate 		if (val == c->val) {
21957c478bd9Sstevel@tonic-gate 			/* found it */
21967c478bd9Sstevel@tonic-gate 			return (c);
21977c478bd9Sstevel@tonic-gate 		} else if (val < c->val) {
21987c478bd9Sstevel@tonic-gate 			parent = &c->lesschild;
21997c478bd9Sstevel@tonic-gate 			c = c->lesschild;
22007c478bd9Sstevel@tonic-gate 		} else {
22017c478bd9Sstevel@tonic-gate 			parent = &c->grtrchild;
22027c478bd9Sstevel@tonic-gate 			c = c->grtrchild;
22037c478bd9Sstevel@tonic-gate 		}
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	/* not in the cache, make a new entry for it */
22077c478bd9Sstevel@tonic-gate 	c = calloc(1, sizeof (struct cachenode));
22087c478bd9Sstevel@tonic-gate 	if (c == NULL) {
22097c478bd9Sstevel@tonic-gate 		perror("ls");
22107c478bd9Sstevel@tonic-gate 		exit(2);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 	*parent = c;
22137c478bd9Sstevel@tonic-gate 	c->val = val;
22147c478bd9Sstevel@tonic-gate 	return (c);
22157c478bd9Sstevel@tonic-gate }
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate /*
22187c478bd9Sstevel@tonic-gate  * get name from cache, or passwd file for a given uid;
22197c478bd9Sstevel@tonic-gate  * lastuid is set to uid.
22207c478bd9Sstevel@tonic-gate  */
22217c478bd9Sstevel@tonic-gate static char *
22227c478bd9Sstevel@tonic-gate getname(uid_t uid)
22237c478bd9Sstevel@tonic-gate {
22247c478bd9Sstevel@tonic-gate 	struct passwd *pwent;
22257c478bd9Sstevel@tonic-gate 	struct cachenode *c;
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	if ((uid == lastuid) && lastuname)
22287c478bd9Sstevel@tonic-gate 		return (lastuname);
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	c = findincache(&names, uid);
22317c478bd9Sstevel@tonic-gate 	if (c->initted == 0) {
22327c478bd9Sstevel@tonic-gate 		if ((pwent = getpwuid(uid)) != NULL) {
22337c478bd9Sstevel@tonic-gate 			SCPYN(&c->name[0], pwent->pw_name);
22347c478bd9Sstevel@tonic-gate 		} else {
22357c478bd9Sstevel@tonic-gate 			(void) sprintf(&c->name[0], "%-8u", (int)uid);
22367c478bd9Sstevel@tonic-gate 		}
22377c478bd9Sstevel@tonic-gate 		c->initted = 1;
22387c478bd9Sstevel@tonic-gate 	}
22397c478bd9Sstevel@tonic-gate 	lastuid = uid;
22407c478bd9Sstevel@tonic-gate 	lastuname = &c->name[0];
22417c478bd9Sstevel@tonic-gate 	return (lastuname);
22427c478bd9Sstevel@tonic-gate }
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate /*
22457c478bd9Sstevel@tonic-gate  * get name from cache, or group file for a given gid;
22467c478bd9Sstevel@tonic-gate  * lastgid is set to gid.
22477c478bd9Sstevel@tonic-gate  */
22487c478bd9Sstevel@tonic-gate static char *
22497c478bd9Sstevel@tonic-gate getgroup(gid_t gid)
22507c478bd9Sstevel@tonic-gate {
22517c478bd9Sstevel@tonic-gate 	struct group *grent;
22527c478bd9Sstevel@tonic-gate 	struct cachenode *c;
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	if ((gid == lastgid) && lastgname)
22557c478bd9Sstevel@tonic-gate 		return (lastgname);
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	c = findincache(&groups, gid);
22587c478bd9Sstevel@tonic-gate 	if (c->initted == 0) {
22597c478bd9Sstevel@tonic-gate 		if ((grent = getgrgid(gid)) != NULL) {
22607c478bd9Sstevel@tonic-gate 			SCPYN(&c->name[0], grent->gr_name);
22617c478bd9Sstevel@tonic-gate 		} else {
22627c478bd9Sstevel@tonic-gate 			(void) sprintf(&c->name[0], "%-8u", (int)gid);
22637c478bd9Sstevel@tonic-gate 		}
22647c478bd9Sstevel@tonic-gate 		c->initted = 1;
22657c478bd9Sstevel@tonic-gate 	}
22667c478bd9Sstevel@tonic-gate 	lastgid = gid;
22677c478bd9Sstevel@tonic-gate 	lastgname = &c->name[0];
22687c478bd9Sstevel@tonic-gate 	return (lastgname);
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */
22727c478bd9Sstevel@tonic-gate static int
22737c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2)
22747c478bd9Sstevel@tonic-gate {
22757c478bd9Sstevel@tonic-gate 	struct lbuf *p1, *p2;
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	p1 = *pp1;
22787c478bd9Sstevel@tonic-gate 	p2 = *pp2;
22797c478bd9Sstevel@tonic-gate 	if (dflg == 0) {
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate  * compare two names in ls-command one of which is file
22827c478bd9Sstevel@tonic-gate  * and the other is a directory;
22837c478bd9Sstevel@tonic-gate  * this portion is not used for comparing files within
22847c478bd9Sstevel@tonic-gate  * a directory name of ls-command;
22857c478bd9Sstevel@tonic-gate  */
22867c478bd9Sstevel@tonic-gate 		if (p1->lflags&ISARG && p1->ltype == 'd') {
22877c478bd9Sstevel@tonic-gate 			if (!(p2->lflags&ISARG && p2->ltype == 'd'))
22887c478bd9Sstevel@tonic-gate 				return (1);
22897c478bd9Sstevel@tonic-gate 		} else {
22907c478bd9Sstevel@tonic-gate 			if (p2->lflags&ISARG && p2->ltype == 'd')
22917c478bd9Sstevel@tonic-gate 				return (-1);
22927c478bd9Sstevel@tonic-gate 		}
22937c478bd9Sstevel@tonic-gate 	}
22947c478bd9Sstevel@tonic-gate 	if (tflg) {
22957c478bd9Sstevel@tonic-gate 		if (p2->lmtime.tv_sec > p1->lmtime.tv_sec)
22967c478bd9Sstevel@tonic-gate 			return (rflg);
22977c478bd9Sstevel@tonic-gate 		else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec)
22987c478bd9Sstevel@tonic-gate 			return (-rflg);
22997c478bd9Sstevel@tonic-gate 		/* times are equal to the sec, check nsec */
23007c478bd9Sstevel@tonic-gate 		if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec)
23017c478bd9Sstevel@tonic-gate 			return (rflg);
23027c478bd9Sstevel@tonic-gate 		else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec)
23037c478bd9Sstevel@tonic-gate 			return (-rflg);
23047c478bd9Sstevel@tonic-gate 		/* if times are equal, fall through and sort by name */
23057c478bd9Sstevel@tonic-gate 	} else if (Sflg) {
23067c478bd9Sstevel@tonic-gate 		/*
23077c478bd9Sstevel@tonic-gate 		 * The size stored in lsize can be either the
23087c478bd9Sstevel@tonic-gate 		 * size or the major minor number (in the case of
23097c478bd9Sstevel@tonic-gate 		 * block and character special devices).  If it's
23107c478bd9Sstevel@tonic-gate 		 * a major minor number, then the size is considered
23117c478bd9Sstevel@tonic-gate 		 * to be zero and we want to fall through and sort
23127c478bd9Sstevel@tonic-gate 		 * by name.  In addition, if the size of p2 is equal
23137c478bd9Sstevel@tonic-gate 		 * to the size of p1 we want to fall through and
23147c478bd9Sstevel@tonic-gate 		 * sort by name.
23157c478bd9Sstevel@tonic-gate 		 */
23167c478bd9Sstevel@tonic-gate 		off_t	p1size = (p1->ltype == 'b') ||
23177c478bd9Sstevel@tonic-gate 		    (p1->ltype == 'c') ? 0 : p1->lsize;
23187c478bd9Sstevel@tonic-gate 		off_t	p2size = (p2->ltype == 'b') ||
23197c478bd9Sstevel@tonic-gate 		    (p2->ltype == 'c') ? 0 : p2->lsize;
23207c478bd9Sstevel@tonic-gate 		if (p2size > p1size) {
23217c478bd9Sstevel@tonic-gate 			return (rflg);
23227c478bd9Sstevel@tonic-gate 		} else if (p2size < p1size) {
23237c478bd9Sstevel@tonic-gate 			return (-rflg);
23247c478bd9Sstevel@tonic-gate 		}
23257c478bd9Sstevel@tonic-gate 		/* Sizes are equal, fall through and sort by name. */
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 	return (rflg * strcoll(
23287c478bd9Sstevel@tonic-gate 	    p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname,
23297c478bd9Sstevel@tonic-gate 	    p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname));
23307c478bd9Sstevel@tonic-gate }
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate static void
23337c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2)
23347c478bd9Sstevel@tonic-gate {
23357c478bd9Sstevel@tonic-gate 	csi_pprintf((unsigned char *)s1);
23367c478bd9Sstevel@tonic-gate 	csi_pprintf((unsigned char *)s2);
23377c478bd9Sstevel@tonic-gate }
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate static void
23407c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s)
23417c478bd9Sstevel@tonic-gate {
23427c478bd9Sstevel@tonic-gate 	unsigned char *cp;
23437c478bd9Sstevel@tonic-gate 	char	c;
23447c478bd9Sstevel@tonic-gate 	int	i;
23457c478bd9Sstevel@tonic-gate 	int	c_len;
23467c478bd9Sstevel@tonic-gate 	int	p_col;
23477c478bd9Sstevel@tonic-gate 	wchar_t	pcode;
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	if (!qflg && !bflg) {
23507c478bd9Sstevel@tonic-gate 		for (cp = s; *cp != '\0'; cp++) {
23517c478bd9Sstevel@tonic-gate 			(void) putchar(*cp);
23527c478bd9Sstevel@tonic-gate 			curcol++;
23537c478bd9Sstevel@tonic-gate 		}
23547c478bd9Sstevel@tonic-gate 		return;
23557c478bd9Sstevel@tonic-gate 	}
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	for (cp = s; *cp; ) {
23587c478bd9Sstevel@tonic-gate 		if (isascii(c = *cp)) {
23597c478bd9Sstevel@tonic-gate 			if (!isprint(c)) {
23607c478bd9Sstevel@tonic-gate 				if (qflg) {
23617c478bd9Sstevel@tonic-gate 					c = '?';
23627c478bd9Sstevel@tonic-gate 				} else {
23637c478bd9Sstevel@tonic-gate 					curcol += 3;
23647c478bd9Sstevel@tonic-gate 					(void) putc('\\', stdout);
23657c478bd9Sstevel@tonic-gate 					c = '0' + ((*cp >> 6) & 07);
23667c478bd9Sstevel@tonic-gate 					(void) putc(c, stdout);
23677c478bd9Sstevel@tonic-gate 					c = '0' + ((*cp >> 3) & 07);
23687c478bd9Sstevel@tonic-gate 					(void) putc(c, stdout);
23697c478bd9Sstevel@tonic-gate 					c = '0' + (*cp & 07);
23707c478bd9Sstevel@tonic-gate 				}
23717c478bd9Sstevel@tonic-gate 			}
23727c478bd9Sstevel@tonic-gate 			curcol++;
23737c478bd9Sstevel@tonic-gate 			cp++;
23747c478bd9Sstevel@tonic-gate 			(void) putc(c, stdout);
23757c478bd9Sstevel@tonic-gate 			continue;
23767c478bd9Sstevel@tonic-gate 		}
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 		if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) {
23797c478bd9Sstevel@tonic-gate 			c_len = 1;
23807c478bd9Sstevel@tonic-gate 			goto not_print;
23817c478bd9Sstevel@tonic-gate 		}
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 		if ((p_col = wcwidth(pcode)) > 0) {
23847c478bd9Sstevel@tonic-gate 			(void) putwchar(pcode);
23857c478bd9Sstevel@tonic-gate 			cp += c_len;
23867c478bd9Sstevel@tonic-gate 			curcol += p_col;
23877c478bd9Sstevel@tonic-gate 			continue;
23887c478bd9Sstevel@tonic-gate 		}
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate not_print:
23917c478bd9Sstevel@tonic-gate 		for (i = 0; i < c_len; i++) {
23927c478bd9Sstevel@tonic-gate 			if (qflg) {
23937c478bd9Sstevel@tonic-gate 				c = '?';
23947c478bd9Sstevel@tonic-gate 			} else {
23957c478bd9Sstevel@tonic-gate 				curcol += 3;
23967c478bd9Sstevel@tonic-gate 				(void) putc('\\', stdout);
23977c478bd9Sstevel@tonic-gate 				c = '0' + ((*cp >> 6) & 07);
23987c478bd9Sstevel@tonic-gate 				(void) putc(c, stdout);
23997c478bd9Sstevel@tonic-gate 				c = '0' + ((*cp >> 3) & 07);
24007c478bd9Sstevel@tonic-gate 				(void) putc(c, stdout);
24017c478bd9Sstevel@tonic-gate 				c = '0' + (*cp & 07);
24027c478bd9Sstevel@tonic-gate 			}
24037c478bd9Sstevel@tonic-gate 			curcol++;
24047c478bd9Sstevel@tonic-gate 			(void) putc(c, stdout);
24057c478bd9Sstevel@tonic-gate 			cp++;
24067c478bd9Sstevel@tonic-gate 		}
24077c478bd9Sstevel@tonic-gate 	}
24087c478bd9Sstevel@tonic-gate }
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate static int
24117c478bd9Sstevel@tonic-gate strcol(unsigned char *s1)
24127c478bd9Sstevel@tonic-gate {
24137c478bd9Sstevel@tonic-gate 	int	w;
24147c478bd9Sstevel@tonic-gate 	int	w_col;
24157c478bd9Sstevel@tonic-gate 	int	len;
24167c478bd9Sstevel@tonic-gate 	wchar_t	wc;
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	w = 0;
24197c478bd9Sstevel@tonic-gate 	while (*s1) {
24207c478bd9Sstevel@tonic-gate 		if (isascii(*s1)) {
24217c478bd9Sstevel@tonic-gate 			w++;
24227c478bd9Sstevel@tonic-gate 			s1++;
24237c478bd9Sstevel@tonic-gate 			continue;
24247c478bd9Sstevel@tonic-gate 		}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 		if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) {
24277c478bd9Sstevel@tonic-gate 			w++;
24287c478bd9Sstevel@tonic-gate 			s1++;
24297c478bd9Sstevel@tonic-gate 			continue;
24307c478bd9Sstevel@tonic-gate 		}
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 		if ((w_col = wcwidth(wc)) < 0)
24337c478bd9Sstevel@tonic-gate 			w_col = len;
24347c478bd9Sstevel@tonic-gate 		s1 += len;
24357c478bd9Sstevel@tonic-gate 		w += w_col;
24367c478bd9Sstevel@tonic-gate 	}
24377c478bd9Sstevel@tonic-gate 	return (w);
24387c478bd9Sstevel@tonic-gate }
24397c478bd9Sstevel@tonic-gate 
2440da6c28aaSamw /* Get extended system attributes and set the display */
2441da6c28aaSamw 
2442da6c28aaSamw int
2443da6c28aaSamw get_sysxattr(char *fname, struct lbuf *rep)
2444da6c28aaSamw {
2445da6c28aaSamw 	boolean_t	value;
2446da6c28aaSamw 	data_type_t	type;
2447da6c28aaSamw 	int		error;
2448da6c28aaSamw 	char		*name;
2449da6c28aaSamw 	int		i;
2450da6c28aaSamw 
2451da6c28aaSamw 	if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname,
2452da6c28aaSamw 	    &response)) != 0) {
2453da6c28aaSamw 		perror("ls:getattrat");
2454da6c28aaSamw 		return (error);
2455da6c28aaSamw 	}
2456da6c28aaSamw 
2457da6c28aaSamw 	/*
2458da6c28aaSamw 	 * Allocate 'sacnt' size array to hold extended timestamp
2459da6c28aaSamw 	 * system attributes and initialize the array.
2460da6c28aaSamw 	 */
2461da6c28aaSamw 	rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep);
2462da6c28aaSamw 	for (i = 0; i < sacnt; i++) {
2463da6c28aaSamw 		rep->extm[i].stm = 0;
2464da6c28aaSamw 		rep->extm[i].nstm = 0;
2465da6c28aaSamw 		rep->extm[i].name = NULL;
2466da6c28aaSamw 	}
2467da6c28aaSamw 	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2468da6c28aaSamw 		name = nvpair_name(pair);
2469da6c28aaSamw 		type = nvpair_type(pair);
2470da6c28aaSamw 		if (type == DATA_TYPE_BOOLEAN_VALUE) {
2471da6c28aaSamw 			error = nvpair_value_boolean_value(pair, &value);
2472da6c28aaSamw 			if (error) {
2473da6c28aaSamw 				(void) fprintf(stderr,
2474da6c28aaSamw 				    gettext("nvpair_value_boolean_value "
2475da6c28aaSamw 				    "failed: error = %d\n"), error);
2476da6c28aaSamw 				continue;
2477da6c28aaSamw 			}
2478da6c28aaSamw 			if (name != NULL)
2479da6c28aaSamw 				set_sysattrb_display(name, value, rep);
2480da6c28aaSamw 			continue;
2481da6c28aaSamw 		} else if (type == DATA_TYPE_UINT64_ARRAY) {
2482da6c28aaSamw 			if (name != NULL)
2483da6c28aaSamw 				set_sysattrtm_display(name, rep);
2484da6c28aaSamw 			continue;
2485da6c28aaSamw 		}
2486da6c28aaSamw 	}
2487da6c28aaSamw 	nvlist_free(response);
2488da6c28aaSamw 	return (0);
2489da6c28aaSamw }
2490da6c28aaSamw 
2491da6c28aaSamw /* Set extended system attribute boolean display */
2492da6c28aaSamw 
2493da6c28aaSamw void
2494da6c28aaSamw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep)
2495da6c28aaSamw {
2496da6c28aaSamw 	f_attr_t	fattr;
2497da6c28aaSamw 	const char	*opt;
2498da6c28aaSamw 	size_t		len;
2499da6c28aaSamw 
2500da6c28aaSamw 	fattr = name_to_attr(name);
2501da6c28aaSamw 	if (fattr != F_ATTR_INVAL && fattr < sacnt) {
2502da6c28aaSamw 		if (vopt) {
2503da6c28aaSamw 			len = strlen(name);
2504da6c28aaSamw 			if (val) {
2505da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
2506da6c28aaSamw 				(void) strlcpy(rep->exttr[fattr].name, name,
2507da6c28aaSamw 				    len + 1);
2508da6c28aaSamw 			} else {
2509da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 3, rep);
2510da6c28aaSamw 				(void) snprintf(rep->exttr[fattr].name, len + 3,
2511da6c28aaSamw 				    "no%s", name);
2512da6c28aaSamw 			}
2513da6c28aaSamw 		} else {
2514da6c28aaSamw 			opt = attr_to_option(fattr);
2515da6c28aaSamw 			if (opt != NULL) {
2516da6c28aaSamw 				len = strlen(opt);
2517da6c28aaSamw 				rep->exttr[fattr].name = xmalloc(len + 1, rep);
2518da6c28aaSamw 				if (val)
2519da6c28aaSamw 					(void) strlcpy(rep->exttr[fattr].name,
2520da6c28aaSamw 					    opt, len + 1);
2521da6c28aaSamw 				else
2522da6c28aaSamw 					(void) strlcpy(rep->exttr[fattr].name,
2523da6c28aaSamw 					    "-", len + 1);
2524da6c28aaSamw 			}
2525da6c28aaSamw 		}
2526da6c28aaSamw 	}
2527da6c28aaSamw }
2528da6c28aaSamw 
2529da6c28aaSamw /* Set extended system attribute timestamp display */
2530da6c28aaSamw 
2531da6c28aaSamw void
2532da6c28aaSamw set_sysattrtm_display(char *name, struct lbuf *rep)
2533da6c28aaSamw {
2534da6c28aaSamw 	uint_t		nelem;
2535da6c28aaSamw 	uint64_t	*value;
2536da6c28aaSamw 	int		i;
2537da6c28aaSamw 	size_t		len;
2538da6c28aaSamw 
2539da6c28aaSamw 	if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) {
2540da6c28aaSamw 		if (*value != NULL) {
2541da6c28aaSamw 			len = strlen(name);
2542da6c28aaSamw 			i = 0;
2543da6c28aaSamw 			while (rep->extm[i].stm != 0 && i < sacnt)
2544da6c28aaSamw 				i++;
2545da6c28aaSamw 			rep->extm[i].stm = value[0];
2546da6c28aaSamw 			rep->extm[i].nstm = value[1];
2547da6c28aaSamw 			rep->extm[i].name = xmalloc(len + 1, rep);
2548da6c28aaSamw 			(void) strlcpy(rep->extm[i].name, name, len + 1);
2549da6c28aaSamw 		}
2550da6c28aaSamw 	}
2551da6c28aaSamw }
2552da6c28aaSamw 
2553da6c28aaSamw void
25545e1c72e1SJason King format_time(time_t sec, time_t nsec)
2555da6c28aaSamw {
25565e1c72e1SJason King 	const char *fstr = time_fmt_new;
2557da6c28aaSamw 	char fmt_buf[FMTSIZE];
2558da6c28aaSamw 
25595e1c72e1SJason King 	if (Eflg) {
25605e1c72e1SJason King 		(void) snprintf(fmt_buf, FMTSIZE, fstr, nsec);
25615e1c72e1SJason King 		(void) strftime(time_buf, sizeof (time_buf), fmt_buf,
25625e1c72e1SJason King 		    localtime(&sec));
25635e1c72e1SJason King 		return;
2564da6c28aaSamw 	}
2565da6c28aaSamw 
25665e1c72e1SJason King 	if (sec < year || sec > now)
25675e1c72e1SJason King 		fstr = time_fmt_old;
25685e1c72e1SJason King 
25695e1c72e1SJason King 	/* if a custom time was specified, shouldn't be localized */
25705e1c72e1SJason King 	(void) strftime(time_buf, sizeof (time_buf),
25715e1c72e1SJason King 	    (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr,
25725e1c72e1SJason King 	    localtime(&sec));
25735e1c72e1SJason King }
2574da6c28aaSamw 
2575da6c28aaSamw void
2576da6c28aaSamw format_attrtime(struct lbuf *p)
2577da6c28aaSamw {
2578da6c28aaSamw 	int tmattr = 0;
2579da6c28aaSamw 	int i;
2580da6c28aaSamw 
2581da6c28aaSamw 	if (p->extm != NULL) {
2582da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
2583da6c28aaSamw 			if (p->extm[i].name != NULL) {
2584da6c28aaSamw 				tmattr = 1;
2585da6c28aaSamw 				break;
2586da6c28aaSamw 			}
2587da6c28aaSamw 		}
2588da6c28aaSamw 	}
25895e1c72e1SJason King 
2590da6c28aaSamw 	if (tmattr) {
25915e1c72e1SJason King 		const char *old_save = time_fmt_old;
25925e1c72e1SJason King 		const char *new_save = time_fmt_new;
25935e1c72e1SJason King 
25945e1c72e1SJason King 		/* Eflg always sets format to FORMAT_ISO_FULL */
25955e1c72e1SJason King 		if (!Eflg && !time_custom) {
25965e1c72e1SJason King 			time_fmt_old = FORMAT_OLD;
25975e1c72e1SJason King 			time_fmt_new = FORMAT_NEW;
2598da6c28aaSamw 		}
25995e1c72e1SJason King 
26005e1c72e1SJason King 		format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm);
26015e1c72e1SJason King 
26025e1c72e1SJason King 		time_fmt_old = old_save;
26035e1c72e1SJason King 		time_fmt_new = new_save;
2604da6c28aaSamw 	}
2605da6c28aaSamw }
2606da6c28aaSamw 
2607da6c28aaSamw void
2608da6c28aaSamw print_time(struct lbuf *p)
2609da6c28aaSamw {
26105e1c72e1SJason King 	const char *old_save = time_fmt_old;
26115e1c72e1SJason King 	const char *new_save = time_fmt_new;
26125e1c72e1SJason King 
2613da6c28aaSamw 	int i = 0;
2614da6c28aaSamw 
26155e1c72e1SJason King 	if (!Eflg) {
26165e1c72e1SJason King 		time_fmt_old = FORMAT_LONG;
26175e1c72e1SJason King 		time_fmt_new = FORMAT_LONG;
26185e1c72e1SJason King 	}
26195e1c72e1SJason King 
2620da6c28aaSamw 	new_line();
26215e1c72e1SJason King 	format_time(p->lat.tv_sec, p->lat.tv_nsec);
26225e1c72e1SJason King 	(void) printf("         timestamp: atime        %s\n", time_buf);
26235e1c72e1SJason King 	format_time(p->lct.tv_sec, p->lct.tv_nsec);
26245e1c72e1SJason King 	(void) printf("         timestamp: ctime        %s\n", time_buf);
26255e1c72e1SJason King 	format_time(p->lmt.tv_sec, p->lmt.tv_nsec);
26265e1c72e1SJason King 	(void) printf("         timestamp: mtime        %s\n", time_buf);
2627da6c28aaSamw 	if (p->extm != NULL) {
2628da6c28aaSamw 		while (p->extm[i].nstm != 0 && i < sacnt) {
26295e1c72e1SJason King 			format_time(p->extm[i].stm, p->extm[i].nstm);
2630da6c28aaSamw 			if (p->extm[i].name != NULL) {
2631da6c28aaSamw 				(void) printf("         timestamp:"
2632da6c28aaSamw 				    " %s        %s\n",
2633da6c28aaSamw 				    p->extm[i].name, time_buf);
2634da6c28aaSamw 			}
2635da6c28aaSamw 			i++;
2636da6c28aaSamw 		}
2637da6c28aaSamw 	}
26385e1c72e1SJason King 
26395e1c72e1SJason King 	time_fmt_old = old_save;
26405e1c72e1SJason King 	time_fmt_new = new_save;
26415e1c72e1SJason King }
26425e1c72e1SJason King 
26435e1c72e1SJason King /*
26445e1c72e1SJason King  * Check if color definition applies to entry, returns 1 if yes, 0 if no
26455e1c72e1SJason King  */
26465e1c72e1SJason King static int
26471b628248SJason King color_match(const char *fname, mode_t mode, ls_color_t *color)
26485e1c72e1SJason King {
26495e1c72e1SJason King 	switch (color->ftype) {
26505e1c72e1SJason King 	case LS_PAT:
26515e1c72e1SJason King 	{
26525e1c72e1SJason King 		size_t	fname_len, sfx_len;
26535e1c72e1SJason King 
26545e1c72e1SJason King 		fname_len = strlen(fname);
26555e1c72e1SJason King 		sfx_len = strlen(color->sfx);
26565e1c72e1SJason King 		if (sfx_len > fname_len)
26575e1c72e1SJason King 			return (0);
26585e1c72e1SJason King 
26595e1c72e1SJason King 		if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0)
26605e1c72e1SJason King 			return (1);
26615e1c72e1SJason King 		else
26625e1c72e1SJason King 			return (0);
26635e1c72e1SJason King 	}
26645e1c72e1SJason King 
26655e1c72e1SJason King 	case LS_NORMAL:
26665e1c72e1SJason King 		return (1);
26675e1c72e1SJason King 
26685e1c72e1SJason King 	case LS_FILE:
26691b628248SJason King 		return (S_ISREG(mode));
26705e1c72e1SJason King 
26715e1c72e1SJason King 	case LS_DIR:
26721b628248SJason King 		return (S_ISDIR(mode));
26735e1c72e1SJason King 
26745e1c72e1SJason King 	case LS_LINK:
26751b628248SJason King 		return (S_ISLNK(mode));
26765e1c72e1SJason King 
26775e1c72e1SJason King 	case LS_FIFO:
26781b628248SJason King 		return (S_ISFIFO(mode));
26795e1c72e1SJason King 
26805e1c72e1SJason King 	case LS_SOCK:
26811b628248SJason King 		return (S_ISSOCK(mode));
26825e1c72e1SJason King 
26835e1c72e1SJason King 	case LS_DOOR:
26841b628248SJason King 		return (S_ISDOOR(mode));
26855e1c72e1SJason King 
26865e1c72e1SJason King 	case LS_BLK:
26871b628248SJason King 		return (S_ISBLK(mode));
26885e1c72e1SJason King 
26895e1c72e1SJason King 	case LS_CHR:
26901b628248SJason King 		return (S_ISCHR(mode));
26915e1c72e1SJason King 
26925e1c72e1SJason King 	case LS_PORT:
26931b628248SJason King 		return (S_ISPORT(mode));
26945e1c72e1SJason King 
26955e1c72e1SJason King 	case LS_ORPHAN:
26961b628248SJason King 		/* this is tested for by gstat */
26975e1c72e1SJason King 		return (0);
26985e1c72e1SJason King 
26995e1c72e1SJason King 	case LS_SETUID:
27001b628248SJason King 		return (!S_ISLNK(mode) && (mode & S_ISUID));
27015e1c72e1SJason King 
27025e1c72e1SJason King 	case LS_SETGID:
27031b628248SJason King 		return (!S_ISLNK(mode) && (mode & S_ISGID));
27045e1c72e1SJason King 
27055e1c72e1SJason King 	case LS_STICKY_OTHER_WRITABLE:
27061b628248SJason King 		return (!S_ISLNK(mode) && (mode & (S_IWOTH|S_ISVTX)));
27075e1c72e1SJason King 
27085e1c72e1SJason King 	case LS_OTHER_WRITABLE:
27091b628248SJason King 		return (!S_ISLNK(mode) && (mode & S_IWOTH));
27105e1c72e1SJason King 
27115e1c72e1SJason King 	case LS_STICKY:
27121b628248SJason King 		return (!S_ISLNK(mode) && (mode & S_ISVTX));
27135e1c72e1SJason King 
27145e1c72e1SJason King 	case LS_EXEC:
27151b628248SJason King 		return (!S_ISLNK(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH)));
27165e1c72e1SJason King 	}
27175e1c72e1SJason King 
27185e1c72e1SJason King 	return (0);
27195e1c72e1SJason King }
27205e1c72e1SJason King 
27215e1c72e1SJason King static void
27225e1c72e1SJason King dump_color(ls_color_t *c)
27235e1c72e1SJason King {
27245e1c72e1SJason King 	if (c == NULL)
27255e1c72e1SJason King 		return;
27265e1c72e1SJason King 
27275e1c72e1SJason King 	(void) printf("\n\ttype: ");
27285e1c72e1SJason King 	switch (c->ftype) {
27295e1c72e1SJason King 	case LS_NORMAL:
27305e1c72e1SJason King 		(void) printf("LS_NORMAL");
27315e1c72e1SJason King 		break;
27325e1c72e1SJason King 	case LS_FILE:
27335e1c72e1SJason King 		(void) printf("LS_FILE");
27345e1c72e1SJason King 		break;
27355e1c72e1SJason King 	case LS_EXEC:
27365e1c72e1SJason King 		(void) printf("LS_EXEC");
27375e1c72e1SJason King 		break;
27385e1c72e1SJason King 	case LS_DIR:
27395e1c72e1SJason King 		(void) printf("LS_DIR");
27405e1c72e1SJason King 		break;
27415e1c72e1SJason King 	case LS_LINK:
27425e1c72e1SJason King 		(void) printf("LS_LINK");
27435e1c72e1SJason King 		break;
27445e1c72e1SJason King 
27455e1c72e1SJason King 	case LS_FIFO:
27465e1c72e1SJason King 		(void) printf("LS_FIFO");
27475e1c72e1SJason King 		break;
27485e1c72e1SJason King 
27495e1c72e1SJason King 	case LS_SOCK:
27505e1c72e1SJason King 		(void) printf("LS_SOCK");
27515e1c72e1SJason King 		break;
27525e1c72e1SJason King 
27535e1c72e1SJason King 	case LS_DOOR:
27545e1c72e1SJason King 		(void) printf("LS_DOOR");
27555e1c72e1SJason King 		break;
27565e1c72e1SJason King 
27575e1c72e1SJason King 	case LS_BLK:
27585e1c72e1SJason King 		(void) printf("LS_BLK");
27595e1c72e1SJason King 		break;
27605e1c72e1SJason King 
27615e1c72e1SJason King 	case LS_CHR:
27625e1c72e1SJason King 		(void) printf("LS_CHR");
27635e1c72e1SJason King 		break;
27645e1c72e1SJason King 
27655e1c72e1SJason King 	case LS_PORT:
27665e1c72e1SJason King 		(void) printf("LS_PORT");
27675e1c72e1SJason King 		break;
27685e1c72e1SJason King 
27695e1c72e1SJason King 	case LS_STICKY:
27705e1c72e1SJason King 		(void) printf("LS_STICKY");
27715e1c72e1SJason King 		break;
27725e1c72e1SJason King 
27735e1c72e1SJason King 	case LS_ORPHAN:
27745e1c72e1SJason King 		(void) printf("LS_ORPHAN");
27755e1c72e1SJason King 		break;
27765e1c72e1SJason King 
27775e1c72e1SJason King 	case LS_SETGID:
27785e1c72e1SJason King 		(void) printf("LS_SETGID");
27795e1c72e1SJason King 		break;
27805e1c72e1SJason King 
27815e1c72e1SJason King 	case LS_SETUID:
27825e1c72e1SJason King 		(void) printf("LS_SETUID");
27835e1c72e1SJason King 		break;
27845e1c72e1SJason King 
27855e1c72e1SJason King 	case LS_OTHER_WRITABLE:
27865e1c72e1SJason King 		(void) printf("LS_OTHER_WRITABLE");
27875e1c72e1SJason King 		break;
27885e1c72e1SJason King 
27895e1c72e1SJason King 	case LS_STICKY_OTHER_WRITABLE:
27905e1c72e1SJason King 		(void) printf("LS_STICKY_OTHER_WRITABLE");
27915e1c72e1SJason King 		break;
27925e1c72e1SJason King 
27935e1c72e1SJason King 	case LS_PAT:
27945e1c72e1SJason King 		(void) printf("LS_PAT\n");
27955e1c72e1SJason King 		(void) printf("\tpattern: %s", c->sfx);
27965e1c72e1SJason King 		break;
27975e1c72e1SJason King 	}
27985e1c72e1SJason King 	(void) printf("\n");
27995e1c72e1SJason King 	(void) printf("\tattr: %d\n", c->attr);
28005e1c72e1SJason King 	(void) printf("\tfg: %d\n", c->fg);
28015e1c72e1SJason King 	(void) printf("\tbg: %d\n", c->bg);
28025e1c72e1SJason King 	(void) printf("\t");
28035e1c72e1SJason King }
28045e1c72e1SJason King 
28055e1c72e1SJason King static ls_color_t *
28061b628248SJason King ls_color_find(const char *fname, mode_t mode)
28075e1c72e1SJason King {
28085e1c72e1SJason King 	int i;
28095e1c72e1SJason King 
28105e1c72e1SJason King 	/*
28115e1c72e1SJason King 	 * Colors are sorted from most general lsc_colors[0] to most specific
28125e1c72e1SJason King 	 * lsc_colors[lsc_ncolors - 1] by ls_color_init().  Start search with
28135e1c72e1SJason King 	 * most specific color rule and work towards most general.
28145e1c72e1SJason King 	 */
28155e1c72e1SJason King 	for (i = lsc_ncolors - 1; i >= 0; --i)
28161b628248SJason King 		if (color_match(fname, mode, &lsc_colors[i]))
28175e1c72e1SJason King 			return (&lsc_colors[i]);
28185e1c72e1SJason King 
28195e1c72e1SJason King 	return (NULL);
28205e1c72e1SJason King }
28215e1c72e1SJason King 
28225e1c72e1SJason King static void
28235e1c72e1SJason King ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4,
28245e1c72e1SJason King     long int p5, long int p6, long int p7, long int p8, long int p9)
28255e1c72e1SJason King {
28265e1c72e1SJason King 	char *s;
28275e1c72e1SJason King 
28285e1c72e1SJason King 	if (str == NULL)
28295e1c72e1SJason King 		return;
28305e1c72e1SJason King 
28315e1c72e1SJason King 	s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
28325e1c72e1SJason King 
28335e1c72e1SJason King 	if (s != NULL)
28345e1c72e1SJason King 		(void) putp(s);
28355e1c72e1SJason King }
28365e1c72e1SJason King 
28375e1c72e1SJason King static void
28381b628248SJason King ls_start_color(ls_color_t *c)
28395e1c72e1SJason King {
28405e1c72e1SJason King 	if (c == NULL)
28415e1c72e1SJason King 		return;
28425e1c72e1SJason King 
28435e1c72e1SJason King 	if (lsc_debug)
28445e1c72e1SJason King 		lsc_match = c;
28455e1c72e1SJason King 
28465e1c72e1SJason King 	if (c->attr & LSA_BOLD)
28475e1c72e1SJason King 		ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28485e1c72e1SJason King 	if (c->attr & LSA_UNDERSCORE)
28495e1c72e1SJason King 		ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28505e1c72e1SJason King 	if (c->attr & LSA_BLINK)
28515e1c72e1SJason King 		ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28525e1c72e1SJason King 	if (c->attr & LSA_REVERSE)
28535e1c72e1SJason King 		ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28545e1c72e1SJason King 	if (c->attr & LSA_CONCEALED)
28555e1c72e1SJason King 		ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28565e1c72e1SJason King 	if (c->attr == LSA_NONE)
28575e1c72e1SJason King 		ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28585e1c72e1SJason King 
28595e1c72e1SJason King 	if (c->fg != -1)
28605e1c72e1SJason King 		ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0);
28615e1c72e1SJason King 	if (c->bg != -1)
28625e1c72e1SJason King 		ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0);
28635e1c72e1SJason King }
28645e1c72e1SJason King 
28655e1c72e1SJason King static void
28665e1c72e1SJason King ls_end_color()
28675e1c72e1SJason King {
28685e1c72e1SJason King 	ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0);
28695e1c72e1SJason King 	if (lsc_debug)
28705e1c72e1SJason King 		dump_color(lsc_match);
28715e1c72e1SJason King }
28725e1c72e1SJason King 
28735e1c72e1SJason King static void
28745e1c72e1SJason King new_color_entry(char *colorstr)
28755e1c72e1SJason King {
28765e1c72e1SJason King 	static const struct {
28775e1c72e1SJason King 		const char	*s;
28785e1c72e1SJason King 		ls_cftype_t	stype;
28795e1c72e1SJason King 	} type_map[] = {
28805e1c72e1SJason King 		{ "no", LS_NORMAL },
28815e1c72e1SJason King 		{ "fi", LS_FILE },
28825e1c72e1SJason King 		{ "di", LS_DIR },
28835e1c72e1SJason King 		{ "ln", LS_LINK },
28845e1c72e1SJason King 		{ "pi", LS_FIFO },
28855e1c72e1SJason King 		{ "so", LS_SOCK },
28865e1c72e1SJason King 		{ "do", LS_DOOR },
28875e1c72e1SJason King 		{ "bd", LS_BLK },
28885e1c72e1SJason King 		{ "cd", LS_CHR },
28895e1c72e1SJason King 		{ "or", LS_ORPHAN },
28905e1c72e1SJason King 		{ "su", LS_SETUID },
28915e1c72e1SJason King 		{ "sg", LS_SETGID },
28925e1c72e1SJason King 		{ "tw", LS_STICKY_OTHER_WRITABLE },
28935e1c72e1SJason King 		{ "ow", LS_OTHER_WRITABLE },
28945e1c72e1SJason King 		{ "st", LS_STICKY },
28955e1c72e1SJason King 		{ "ex", LS_EXEC },
28965e1c72e1SJason King 		{ "po", LS_PORT },
28975e1c72e1SJason King 		{ NULL, LS_NORMAL }
28985e1c72e1SJason King 	};
28995e1c72e1SJason King 
29005e1c72e1SJason King 	char		*p, *lasts;
29015e1c72e1SJason King 	int		i;
29025e1c72e1SJason King 	int		color, attr;
29035e1c72e1SJason King 
29045e1c72e1SJason King 	p = strtok_r(colorstr, "=", &lasts);
29055e1c72e1SJason King 	if (p == NULL) {
29065e1c72e1SJason King 		colorflg = 0;
29075e1c72e1SJason King 		return;
29085e1c72e1SJason King 	}
29095e1c72e1SJason King 
29105e1c72e1SJason King 	if (p[0] == '*') {
29115e1c72e1SJason King 		lsc_colors[lsc_ncolors].ftype = LS_PAT;
29125e1c72e1SJason King 		/* don't include the * in the suffix */
29135e1c72e1SJason King 		if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) {
29145e1c72e1SJason King 			colorflg = 0;
29155e1c72e1SJason King 			return;
29165e1c72e1SJason King 		}
2917da6c28aaSamw 	} else {
29185e1c72e1SJason King 		lsc_colors[lsc_ncolors].sfx = NULL;
29195e1c72e1SJason King 
29205e1c72e1SJason King 		for (i = 0; type_map[i].s != NULL; ++i) {
29215e1c72e1SJason King 			if (strncmp(type_map[i].s, p, 2) == 0)
29225e1c72e1SJason King 				break;
2923da6c28aaSamw 		}
29245e1c72e1SJason King 
29255e1c72e1SJason King 		/* ignore unknown file types */
29265e1c72e1SJason King 		if (type_map[i].s == NULL)
29275e1c72e1SJason King 			return;
29285e1c72e1SJason King 
29295e1c72e1SJason King 		lsc_colors[lsc_ncolors].ftype = type_map[i].stype;
29305e1c72e1SJason King 	}
29315e1c72e1SJason King 
29325e1c72e1SJason King 	attr = LSA_NONE;
29335e1c72e1SJason King 	lsc_colors[lsc_ncolors].fg = -1;
29345e1c72e1SJason King 	lsc_colors[lsc_ncolors].bg = -1;
29355e1c72e1SJason King 	for (p = strtok_r(NULL, ";", &lasts); p != NULL;
29365e1c72e1SJason King 	    p = strtok_r(NULL, ";", &lasts)) {
29375e1c72e1SJason King 		color = strtol(p, NULL, 10);
29385e1c72e1SJason King 
29395e1c72e1SJason King 		if (color < 10) {
29405e1c72e1SJason King 			switch (color) {
29415e1c72e1SJason King 			case 0:
29425e1c72e1SJason King 				attr = LSA_NONE;
29435e1c72e1SJason King 				continue;
29445e1c72e1SJason King 			case 1:
29455e1c72e1SJason King 				attr |= LSA_BOLD;
29465e1c72e1SJason King 				continue;
29475e1c72e1SJason King 			case 4:
29485e1c72e1SJason King 				attr |= LSA_UNDERSCORE;
29495e1c72e1SJason King 				continue;
29505e1c72e1SJason King 			case 5:
29515e1c72e1SJason King 				attr |= LSA_BLINK;
29525e1c72e1SJason King 				continue;
29535e1c72e1SJason King 			case 7:
29545e1c72e1SJason King 				attr |= LSA_REVERSE;
29555e1c72e1SJason King 				continue;
29565e1c72e1SJason King 			case 8:
29575e1c72e1SJason King 				attr |= LSA_CONCEALED;
29585e1c72e1SJason King 				continue;
29595e1c72e1SJason King 			default:
29605e1c72e1SJason King 				continue;
2961da6c28aaSamw 			}
2962da6c28aaSamw 		}
29635e1c72e1SJason King 
29645e1c72e1SJason King 		if (color < 40)
29655e1c72e1SJason King 			lsc_colors[lsc_ncolors].fg = color - 30;
29665e1c72e1SJason King 		else
29675e1c72e1SJason King 			lsc_colors[lsc_ncolors].bg = color - 40;
29685e1c72e1SJason King 	}
29695e1c72e1SJason King 
29705e1c72e1SJason King 	lsc_colors[lsc_ncolors].attr = attr;
29715e1c72e1SJason King 	++lsc_ncolors;
29725e1c72e1SJason King }
29735e1c72e1SJason King 
29745e1c72e1SJason King static int
29755e1c72e1SJason King ls_color_compare(const void *p1, const void *p2)
29765e1c72e1SJason King {
29775e1c72e1SJason King 	const ls_color_t *c1 = (const ls_color_t *)p1;
29785e1c72e1SJason King 	const ls_color_t *c2 = (const ls_color_t *)p2;
29795e1c72e1SJason King 
29805e1c72e1SJason King 	int ret = c1->ftype - c2->ftype;
29815e1c72e1SJason King 
29825e1c72e1SJason King 	if (ret != 0)
29835e1c72e1SJason King 		return (ret);
29845e1c72e1SJason King 
29855e1c72e1SJason King 	if (c1->ftype != LS_PAT)
29865e1c72e1SJason King 		return (ret);
29875e1c72e1SJason King 
29885e1c72e1SJason King 	return (strcmp(c1->sfx, c2->sfx));
29895e1c72e1SJason King }
29905e1c72e1SJason King 
29915e1c72e1SJason King static void
29925e1c72e1SJason King ls_color_init()
29935e1c72e1SJason King {
29945e1c72e1SJason King 	static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35"
29955e1c72e1SJason King 	    ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01"
29965e1c72e1SJason King 	    ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31"
29975e1c72e1SJason King 	    ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31"
29985e1c72e1SJason King 	    ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31"
29995e1c72e1SJason King 	    ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35"
30005e1c72e1SJason King 	    ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"
30015e1c72e1SJason King 	    ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35"
30025e1c72e1SJason King 	    ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35"
30035e1c72e1SJason King 	    ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35"
30045e1c72e1SJason King 	    ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35";
30055e1c72e1SJason King 
30065e1c72e1SJason King 	char    *colorstr;
30075e1c72e1SJason King 	char    *p, *lasts;
30085e1c72e1SJason King 	size_t  color_sz;
30095e1c72e1SJason King 	int	termret;
30101b628248SJason King 	int	i;
30115e1c72e1SJason King 
30125e1c72e1SJason King 	(void) setupterm(NULL, 1, &termret);
30135e1c72e1SJason King 	if (termret != 1)
30145e1c72e1SJason King 		return;
30155e1c72e1SJason King 
301638f2a414SAlbert Lee 	if ((p = getenv("LS_COLORS")) == NULL)
301738f2a414SAlbert Lee 		p = default_colorstr;
301838f2a414SAlbert Lee 	colorstr = strdup(p);
301938f2a414SAlbert Lee 	if (colorstr == NULL)
302038f2a414SAlbert Lee 		return;
30215e1c72e1SJason King 
3022f7387fb0SJason King 	/*
3023f7387fb0SJason King 	 * Determine the size of lsc_colors.  color_sz can be > lsc_ncolors
3024f7387fb0SJason King 	 * if there are invalid entries passed in the string (they are ignored)
3025f7387fb0SJason King 	 */
3026f7387fb0SJason King 	color_sz = 1;
30275e1c72e1SJason King 	for (p = strchr(colorstr, ':'); p != NULL && *p != '\0';
30285e1c72e1SJason King 	    p = strchr(++p, ':'))
30295e1c72e1SJason King 		++color_sz;
30305e1c72e1SJason King 
30315e1c72e1SJason King 	lsc_colors = calloc(color_sz, sizeof (ls_color_t));
30325e1c72e1SJason King 	if (lsc_colors == NULL) {
30335e1c72e1SJason King 		free(colorstr);
30345e1c72e1SJason King 		return;
30355e1c72e1SJason King 	}
30365e1c72e1SJason King 
30375e1c72e1SJason King 	for (p = strtok_r(colorstr, ":", &lasts);
30385e1c72e1SJason King 	    p != NULL && lsc_ncolors < color_sz;
30395e1c72e1SJason King 	    p = strtok_r(NULL, ":", &lasts))
30405e1c72e1SJason King 		new_color_entry(p);
30415e1c72e1SJason King 
30425e1c72e1SJason King 	qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t),
30435e1c72e1SJason King 	    ls_color_compare);
30445e1c72e1SJason King 
30451b628248SJason King 	for (i = 0; i < lsc_ncolors; ++i)
30461b628248SJason King 		if (lsc_colors[i].ftype == LS_ORPHAN) {
30471b628248SJason King 			lsc_orphan = &lsc_colors[i];
30481b628248SJason King 			break;
30491b628248SJason King 		}
30501b628248SJason King 
30515e1c72e1SJason King 	if ((lsc_bold = tigetstr("bold")) == (char *)-1)
30525e1c72e1SJason King 		lsc_bold = NULL;
30535e1c72e1SJason King 
30545e1c72e1SJason King 	if ((lsc_underline = tigetstr("smul")) == (char *)-1)
30555e1c72e1SJason King 		lsc_underline = NULL;
30565e1c72e1SJason King 
30575e1c72e1SJason King 	if ((lsc_blink = tigetstr("blink")) == (char *)-1)
30585e1c72e1SJason King 		lsc_blink = NULL;
30595e1c72e1SJason King 
30605e1c72e1SJason King 	if ((lsc_reverse = tigetstr("rev")) == (char *)-1)
30615e1c72e1SJason King 		lsc_reverse = NULL;
30625e1c72e1SJason King 
30635e1c72e1SJason King 	if ((lsc_concealed = tigetstr("prot")) == (char *)-1)
30645e1c72e1SJason King 		lsc_concealed = NULL;
30655e1c72e1SJason King 
30665e1c72e1SJason King 	if ((lsc_none = tigetstr("sgr0")) == (char *)-1)
30675e1c72e1SJason King 		lsc_none = NULL;
30685e1c72e1SJason King 
30695e1c72e1SJason King 	if ((lsc_setfg = tigetstr("setaf")) == (char *)-1)
30705e1c72e1SJason King 		lsc_setfg = NULL;
30715e1c72e1SJason King 
30725e1c72e1SJason King 	if ((lsc_setbg = tigetstr("setab")) == (char *)-1)
30735e1c72e1SJason King 		lsc_setbg = NULL;
30745e1c72e1SJason King 
30755e1c72e1SJason King 	if (getenv("_LS_COLOR_DEBUG") != NULL) {
30765e1c72e1SJason King 		int i;
30775e1c72e1SJason King 
30785e1c72e1SJason King 		lsc_debug = 1;
30795e1c72e1SJason King 		for (i = 0; i < lsc_ncolors; ++i)
30805e1c72e1SJason King 			dump_color(&lsc_colors[i]);
3081da6c28aaSamw 	}
308238f2a414SAlbert Lee 
308338f2a414SAlbert Lee 	free(colorstr);
3084da6c28aaSamw }
3085da6c28aaSamw 
3086da6c28aaSamw /* Free extended system attribute lists */
3087da6c28aaSamw 
3088da6c28aaSamw void
3089da6c28aaSamw free_sysattr(struct lbuf *p)
3090da6c28aaSamw {
3091da6c28aaSamw 	int i;
3092da6c28aaSamw 
3093da6c28aaSamw 	if (p->exttr != NULL) {
3094da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
3095da6c28aaSamw 			if (p->exttr[i].name != NULL)
3096da6c28aaSamw 				free(p->exttr[i].name);
3097da6c28aaSamw 		}
3098da6c28aaSamw 		free(p->exttr);
3099da6c28aaSamw 	}
3100da6c28aaSamw 	if (p->extm != NULL) {
3101da6c28aaSamw 		for (i = 0; i < sacnt; i++) {
3102da6c28aaSamw 			if (p->extm[i].name != NULL)
3103da6c28aaSamw 				free(p->extm[i].name);
3104da6c28aaSamw 		}
3105da6c28aaSamw 		free(p->extm);
3106da6c28aaSamw 	}
3107da6c28aaSamw }
3108da6c28aaSamw 
3109da6c28aaSamw /* Allocate extended system attribute list */
3110da6c28aaSamw 
3111da6c28aaSamw void *
3112da6c28aaSamw xmalloc(size_t size, struct lbuf *p)
3113da6c28aaSamw {
3114da6c28aaSamw 	if ((p = malloc(size)) == NULL) {
3115da6c28aaSamw 		perror("ls");
3116da6c28aaSamw 		free_sysattr(p);
3117da6c28aaSamw 		nvlist_free(response);
3118da6c28aaSamw 		exit(2);
3119da6c28aaSamw 	}
3120da6c28aaSamw 	return (p);
3121da6c28aaSamw }
3122