xref: /freebsd/bin/ls/ls.c (revision 7ea30648)
14b88c807SRodney W. Grimes /*
24b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993, 1994
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes  * Michael Fischbein.
74b88c807SRodney W. Grimes  *
84b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes  * are met:
114b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
164b88c807SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
174b88c807SRodney W. Grimes  *    must display the following acknowledgement:
184b88c807SRodney W. Grimes  *	This product includes software developed by the University of
194b88c807SRodney W. Grimes  *	California, Berkeley and its contributors.
204b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
214b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
224b88c807SRodney W. Grimes  *    without specific prior written permission.
234b88c807SRodney W. Grimes  *
244b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344b88c807SRodney W. Grimes  * SUCH DAMAGE.
354b88c807SRodney W. Grimes  */
364b88c807SRodney W. Grimes 
374b88c807SRodney W. Grimes #ifndef lint
38d46c1a60SSteve Price static const char copyright[] =
394b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993, 1994\n\
404b88c807SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
41febad2fcSSteve Price #endif /* not lint */
42febad2fcSSteve Price 
43febad2fcSSteve Price #ifndef lint
44febad2fcSSteve Price #if 0
45febad2fcSSteve Price static char sccsid[] = "@(#)ls.c	8.5 (Berkeley) 4/2/94";
46febad2fcSSteve Price #else
47d46c1a60SSteve Price static const char rcsid[] =
487ea30648SDag-Erling Smørgrav 	"$Id: ls.c,v 1.17 1997/09/18 06:42:27 sef Exp $";
49febad2fcSSteve Price #endif
504b88c807SRodney W. Grimes #endif /* not lint */
514b88c807SRodney W. Grimes 
524b88c807SRodney W. Grimes #include <sys/types.h>
534b88c807SRodney W. Grimes #include <sys/stat.h>
544b88c807SRodney W. Grimes #include <sys/ioctl.h>
554b88c807SRodney W. Grimes 
564b88c807SRodney W. Grimes #include <dirent.h>
574b88c807SRodney W. Grimes #include <err.h>
584b88c807SRodney W. Grimes #include <errno.h>
594b88c807SRodney W. Grimes #include <fts.h>
604b88c807SRodney W. Grimes #include <stdio.h>
614b88c807SRodney W. Grimes #include <stdlib.h>
624b88c807SRodney W. Grimes #include <string.h>
634b88c807SRodney W. Grimes #include <unistd.h>
64a409ec19SAndrey A. Chernov #include <locale.h>
654b88c807SRodney W. Grimes 
664b88c807SRodney W. Grimes #include "ls.h"
674b88c807SRodney W. Grimes #include "extern.h"
684b88c807SRodney W. Grimes 
694b88c807SRodney W. Grimes static void	 display __P((FTSENT *, FTSENT *));
704b88c807SRodney W. Grimes static int	 mastercmp __P((const FTSENT **, const FTSENT **));
714b88c807SRodney W. Grimes static void	 traverse __P((int, char **, int));
724b88c807SRodney W. Grimes 
734b88c807SRodney W. Grimes static void (*printfcn) __P((DISPLAY *));
744b88c807SRodney W. Grimes static int (*sortfcn) __P((const FTSENT *, const FTSENT *));
754b88c807SRodney W. Grimes 
764b88c807SRodney W. Grimes long blocksize;			/* block size units */
774b88c807SRodney W. Grimes int termwidth = 80;		/* default terminal width */
784b88c807SRodney W. Grimes 
794b88c807SRodney W. Grimes /* flags */
804b88c807SRodney W. Grimes int f_accesstime;		/* use time of last access */
814b88c807SRodney W. Grimes int f_column;			/* columnated format */
824b88c807SRodney W. Grimes int f_flags;			/* show flags associated with a file */
834b88c807SRodney W. Grimes int f_inode;			/* print inode */
84475727a0SPaul Traina int f_kblocks;			/* print size in kilobytes */
854b88c807SRodney W. Grimes int f_listdir;			/* list actual directory, not contents */
864b88c807SRodney W. Grimes int f_listdot;			/* list files beginning with . */
874b88c807SRodney W. Grimes int f_longform;			/* long listing format */
884b88c807SRodney W. Grimes int f_newline;			/* if precede with newline */
894b88c807SRodney W. Grimes int f_nonprint;			/* show unprintables as ? */
904b88c807SRodney W. Grimes int f_nosort;			/* don't sort output */
917ea30648SDag-Erling Smørgrav int f_octal;			/* show unprintables as \xxx */
924b88c807SRodney W. Grimes int f_recursive;		/* ls subdirectories also */
934b88c807SRodney W. Grimes int f_reversesort;		/* reverse whatever sort is used */
944b88c807SRodney W. Grimes int f_sectime;			/* print the real time for all files */
954b88c807SRodney W. Grimes int f_singlecol;		/* use single column output */
964b88c807SRodney W. Grimes int f_size;			/* list size in short listing */
974b88c807SRodney W. Grimes int f_statustime;		/* use time of last mode change */
984b88c807SRodney W. Grimes int f_dirname;			/* if precede with directory name */
994b88c807SRodney W. Grimes int f_timesort;			/* sort by time vice name */
1004b88c807SRodney W. Grimes int f_type;			/* add type character for non-regular files */
101fb5cb208SSteve Price int f_whiteout;			/* show whiteout entries */
1024b88c807SRodney W. Grimes 
103fb1000d6SAdam David int rval;
104fb1000d6SAdam David 
1054b88c807SRodney W. Grimes int
1064b88c807SRodney W. Grimes main(argc, argv)
1074b88c807SRodney W. Grimes 	int argc;
1084b88c807SRodney W. Grimes 	char *argv[];
1094b88c807SRodney W. Grimes {
1104b88c807SRodney W. Grimes 	static char dot[] = ".", *dotav[] = { dot, NULL };
1114b88c807SRodney W. Grimes 	struct winsize win;
1124b88c807SRodney W. Grimes 	int ch, fts_options, notused;
1134b88c807SRodney W. Grimes 	char *p;
1144b88c807SRodney W. Grimes 
115f5bd01c6SAndrey A. Chernov 	(void) setlocale(LC_ALL, "");
116f5bd01c6SAndrey A. Chernov 
1174b88c807SRodney W. Grimes 	/* Terminal defaults to -Cq, non-terminal defaults to -1. */
1184b88c807SRodney W. Grimes 	if (isatty(STDOUT_FILENO)) {
1194b88c807SRodney W. Grimes 		if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 ||
1204b88c807SRodney W. Grimes 		    !win.ws_col) {
1214b88c807SRodney W. Grimes 			if ((p = getenv("COLUMNS")) != NULL)
1224b88c807SRodney W. Grimes 				termwidth = atoi(p);
1234b88c807SRodney W. Grimes 		}
1244b88c807SRodney W. Grimes 		else
1254b88c807SRodney W. Grimes 			termwidth = win.ws_col;
1264b88c807SRodney W. Grimes 		f_column = f_nonprint = 1;
12734994fcdSJoerg Wunsch 	} else {
1284b88c807SRodney W. Grimes 		f_singlecol = 1;
12934994fcdSJoerg Wunsch 		/* retrieve environment variable, in case of explicit -C */
1300fd510b7SJoerg Wunsch 		if ((p = getenv("COLUMNS")))
13134994fcdSJoerg Wunsch 			termwidth = atoi(p);
13234994fcdSJoerg Wunsch 	}
1334b88c807SRodney W. Grimes 
1344b88c807SRodney W. Grimes 	/* Root is -A automatically. */
1354b88c807SRodney W. Grimes 	if (!getuid())
1364b88c807SRodney W. Grimes 		f_listdot = 1;
1374b88c807SRodney W. Grimes 
1384b88c807SRodney W. Grimes 	fts_options = FTS_PHYSICAL;
1397ea30648SDag-Erling Smørgrav 	while ((ch = getopt(argc, argv, "1ACFLRTWabcdfgikloqrstu")) != -1) {
1404b88c807SRodney W. Grimes 		switch (ch) {
1414b88c807SRodney W. Grimes 		/*
1424b88c807SRodney W. Grimes 		 * The -1, -C and -l options all override each other so shell
1434b88c807SRodney W. Grimes 		 * aliasing works right.
1444b88c807SRodney W. Grimes 		 */
1454b88c807SRodney W. Grimes 		case '1':
1464b88c807SRodney W. Grimes 			f_singlecol = 1;
1474b88c807SRodney W. Grimes 			f_column = f_longform = 0;
1484b88c807SRodney W. Grimes 			break;
1494b88c807SRodney W. Grimes 		case 'C':
1504b88c807SRodney W. Grimes 			f_column = 1;
1514b88c807SRodney W. Grimes 			f_longform = f_singlecol = 0;
1524b88c807SRodney W. Grimes 			break;
1534b88c807SRodney W. Grimes 		case 'l':
1544b88c807SRodney W. Grimes 			f_longform = 1;
1554b88c807SRodney W. Grimes 			f_column = f_singlecol = 0;
1564b88c807SRodney W. Grimes 			break;
1574b88c807SRodney W. Grimes 		/* The -c and -u options override each other. */
1584b88c807SRodney W. Grimes 		case 'c':
1594b88c807SRodney W. Grimes 			f_statustime = 1;
1604b88c807SRodney W. Grimes 			f_accesstime = 0;
1614b88c807SRodney W. Grimes 			break;
1624b88c807SRodney W. Grimes 		case 'u':
1634b88c807SRodney W. Grimes 			f_accesstime = 1;
1644b88c807SRodney W. Grimes 			f_statustime = 0;
1654b88c807SRodney W. Grimes 			break;
1664b88c807SRodney W. Grimes 		case 'F':
1674b88c807SRodney W. Grimes 			f_type = 1;
1684b88c807SRodney W. Grimes 			break;
1694b88c807SRodney W. Grimes 		case 'L':
1704b88c807SRodney W. Grimes 			fts_options &= ~FTS_PHYSICAL;
1714b88c807SRodney W. Grimes 			fts_options |= FTS_LOGICAL;
1724b88c807SRodney W. Grimes 			break;
1734b88c807SRodney W. Grimes 		case 'R':
1744b88c807SRodney W. Grimes 			f_recursive = 1;
1754b88c807SRodney W. Grimes 			break;
1764b88c807SRodney W. Grimes 		case 'a':
1774b88c807SRodney W. Grimes 			fts_options |= FTS_SEEDOT;
1784b88c807SRodney W. Grimes 			/* FALLTHROUGH */
1794b88c807SRodney W. Grimes 		case 'A':
1804b88c807SRodney W. Grimes 			f_listdot = 1;
1814b88c807SRodney W. Grimes 			break;
1824b88c807SRodney W. Grimes 		/* The -d option turns off the -R option. */
1834b88c807SRodney W. Grimes 		case 'd':
1844b88c807SRodney W. Grimes 			f_listdir = 1;
1854b88c807SRodney W. Grimes 			f_recursive = 0;
1864b88c807SRodney W. Grimes 			break;
1874b88c807SRodney W. Grimes 		case 'f':
1884b88c807SRodney W. Grimes 			f_nosort = 1;
1894b88c807SRodney W. Grimes 			break;
1904b88c807SRodney W. Grimes 		case 'g':		/* Compatibility with 4.3BSD. */
1914b88c807SRodney W. Grimes 			break;
1924b88c807SRodney W. Grimes 		case 'i':
1934b88c807SRodney W. Grimes 			f_inode = 1;
1944b88c807SRodney W. Grimes 			break;
195475727a0SPaul Traina 		case 'k':
196475727a0SPaul Traina 			f_kblocks = 1;
197475727a0SPaul Traina 			break;
1984b88c807SRodney W. Grimes 		case 'o':
1994b88c807SRodney W. Grimes 			f_flags = 1;
2004b88c807SRodney W. Grimes 			break;
2014b88c807SRodney W. Grimes 		case 'q':
2024b88c807SRodney W. Grimes 			f_nonprint = 1;
2037ea30648SDag-Erling Smørgrav 			f_octal = 0;
2044b88c807SRodney W. Grimes 			break;
2054b88c807SRodney W. Grimes 		case 'r':
2064b88c807SRodney W. Grimes 			f_reversesort = 1;
2074b88c807SRodney W. Grimes 			break;
2084b88c807SRodney W. Grimes 		case 's':
2094b88c807SRodney W. Grimes 			f_size = 1;
2104b88c807SRodney W. Grimes 			break;
2114b88c807SRodney W. Grimes 		case 'T':
2124b88c807SRodney W. Grimes 			f_sectime = 1;
2134b88c807SRodney W. Grimes 			break;
2144b88c807SRodney W. Grimes 		case 't':
2154b88c807SRodney W. Grimes 			f_timesort = 1;
2164b88c807SRodney W. Grimes 			break;
217fb5cb208SSteve Price 		case 'W':
218fb5cb208SSteve Price 			f_whiteout = 1;
219fb5cb208SSteve Price 			break;
2207ea30648SDag-Erling Smørgrav 		case 'b':
2217ea30648SDag-Erling Smørgrav 		        f_octal = 1;
2227ea30648SDag-Erling Smørgrav 			f_nonprint = 0;
2237ea30648SDag-Erling Smørgrav 			break;
2244b88c807SRodney W. Grimes 		default:
2254b88c807SRodney W. Grimes 		case '?':
2264b88c807SRodney W. Grimes 			usage();
2274b88c807SRodney W. Grimes 		}
2284b88c807SRodney W. Grimes 	}
2294b88c807SRodney W. Grimes 	argc -= optind;
2304b88c807SRodney W. Grimes 	argv += optind;
2314b88c807SRodney W. Grimes 
2324b88c807SRodney W. Grimes 	/*
2334b88c807SRodney W. Grimes 	 * If not -F, -i, -l, -s or -t options, don't require stat
2344b88c807SRodney W. Grimes 	 * information.
2354b88c807SRodney W. Grimes 	 */
2364b88c807SRodney W. Grimes 	if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type)
2374b88c807SRodney W. Grimes 		fts_options |= FTS_NOSTAT;
2384b88c807SRodney W. Grimes 
2394b88c807SRodney W. Grimes 	/*
2404b88c807SRodney W. Grimes 	 * If not -F, -d or -l options, follow any symbolic links listed on
2414b88c807SRodney W. Grimes 	 * the command line.
2424b88c807SRodney W. Grimes 	 */
2434b88c807SRodney W. Grimes 	if (!f_longform && !f_listdir && !f_type)
2444b88c807SRodney W. Grimes 		fts_options |= FTS_COMFOLLOW;
2454b88c807SRodney W. Grimes 
246fb5cb208SSteve Price 	/*
247fb5cb208SSteve Price 	 * If -W, show whiteout entries
248fb5cb208SSteve Price 	 */
249fb5cb208SSteve Price #ifdef FTS_WHITEOUT
250fb5cb208SSteve Price 	if (f_whiteout)
251fb5cb208SSteve Price 		fts_options |= FTS_WHITEOUT;
252fb5cb208SSteve Price #endif
253fb5cb208SSteve Price 
2544b88c807SRodney W. Grimes 	/* If -l or -s, figure out block size. */
2554b88c807SRodney W. Grimes 	if (f_longform || f_size) {
25690b0ec31SPoul-Henning Kamp 		if (f_kblocks)
25790b0ec31SPoul-Henning Kamp 			blocksize = 2;
25890b0ec31SPoul-Henning Kamp 		else {
2594b88c807SRodney W. Grimes 			(void)getbsize(&notused, &blocksize);
2604b88c807SRodney W. Grimes 			blocksize /= 512;
26190b0ec31SPoul-Henning Kamp 		}
2624b88c807SRodney W. Grimes 	}
2634b88c807SRodney W. Grimes 
2644b88c807SRodney W. Grimes 	/* Select a sort function. */
2654b88c807SRodney W. Grimes 	if (f_reversesort) {
2664b88c807SRodney W. Grimes 		if (!f_timesort)
2674b88c807SRodney W. Grimes 			sortfcn = revnamecmp;
2684b88c807SRodney W. Grimes 		else if (f_accesstime)
2694b88c807SRodney W. Grimes 			sortfcn = revacccmp;
2704b88c807SRodney W. Grimes 		else if (f_statustime)
2714b88c807SRodney W. Grimes 			sortfcn = revstatcmp;
2724b88c807SRodney W. Grimes 		else /* Use modification time. */
2734b88c807SRodney W. Grimes 			sortfcn = revmodcmp;
2744b88c807SRodney W. Grimes 	} else {
2754b88c807SRodney W. Grimes 		if (!f_timesort)
2764b88c807SRodney W. Grimes 			sortfcn = namecmp;
2774b88c807SRodney W. Grimes 		else if (f_accesstime)
2784b88c807SRodney W. Grimes 			sortfcn = acccmp;
2794b88c807SRodney W. Grimes 		else if (f_statustime)
2804b88c807SRodney W. Grimes 			sortfcn = statcmp;
2814b88c807SRodney W. Grimes 		else /* Use modification time. */
2824b88c807SRodney W. Grimes 			sortfcn = modcmp;
2834b88c807SRodney W. Grimes 	}
2844b88c807SRodney W. Grimes 
2854b88c807SRodney W. Grimes 	/* Select a print function. */
2864b88c807SRodney W. Grimes 	if (f_singlecol)
2874b88c807SRodney W. Grimes 		printfcn = printscol;
2884b88c807SRodney W. Grimes 	else if (f_longform)
2894b88c807SRodney W. Grimes 		printfcn = printlong;
2904b88c807SRodney W. Grimes 	else
2914b88c807SRodney W. Grimes 		printfcn = printcol;
2924b88c807SRodney W. Grimes 
2934b88c807SRodney W. Grimes 	if (argc)
2944b88c807SRodney W. Grimes 		traverse(argc, argv, fts_options);
2954b88c807SRodney W. Grimes 	else
2964b88c807SRodney W. Grimes 		traverse(1, dotav, fts_options);
297fb1000d6SAdam David 	exit(rval);
2984b88c807SRodney W. Grimes }
2994b88c807SRodney W. Grimes 
3004b88c807SRodney W. Grimes static int output;			/* If anything output. */
3014b88c807SRodney W. Grimes 
3024b88c807SRodney W. Grimes /*
3034b88c807SRodney W. Grimes  * Traverse() walks the logical directory structure specified by the argv list
3044b88c807SRodney W. Grimes  * in the order specified by the mastercmp() comparison function.  During the
3054b88c807SRodney W. Grimes  * traversal it passes linked lists of structures to display() which represent
3064b88c807SRodney W. Grimes  * a superset (may be exact set) of the files to be displayed.
3074b88c807SRodney W. Grimes  */
3084b88c807SRodney W. Grimes static void
3094b88c807SRodney W. Grimes traverse(argc, argv, options)
3104b88c807SRodney W. Grimes 	int argc, options;
3114b88c807SRodney W. Grimes 	char *argv[];
3124b88c807SRodney W. Grimes {
3134b88c807SRodney W. Grimes 	FTS *ftsp;
3144b88c807SRodney W. Grimes 	FTSENT *p, *chp;
3154b88c807SRodney W. Grimes 	int ch_options;
3164b88c807SRodney W. Grimes 
3174b88c807SRodney W. Grimes 	if ((ftsp =
3184b88c807SRodney W. Grimes 	    fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
3194b88c807SRodney W. Grimes 		err(1, NULL);
3204b88c807SRodney W. Grimes 
3214b88c807SRodney W. Grimes 	display(NULL, fts_children(ftsp, 0));
3224b88c807SRodney W. Grimes 	if (f_listdir)
3234b88c807SRodney W. Grimes 		return;
3244b88c807SRodney W. Grimes 
3254b88c807SRodney W. Grimes 	/*
3264b88c807SRodney W. Grimes 	 * If not recursing down this tree and don't need stat info, just get
3274b88c807SRodney W. Grimes 	 * the names.
3284b88c807SRodney W. Grimes 	 */
3294b88c807SRodney W. Grimes 	ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;
3304b88c807SRodney W. Grimes 
3314b88c807SRodney W. Grimes 	while ((p = fts_read(ftsp)) != NULL)
3324b88c807SRodney W. Grimes 		switch (p->fts_info) {
3334b88c807SRodney W. Grimes 		case FTS_DC:
3344b88c807SRodney W. Grimes 			warnx("%s: directory causes a cycle", p->fts_name);
3354b88c807SRodney W. Grimes 			break;
3364b88c807SRodney W. Grimes 		case FTS_DNR:
3374b88c807SRodney W. Grimes 		case FTS_ERR:
3384b88c807SRodney W. Grimes 			warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
339fb1000d6SAdam David 			rval = 1;
3404b88c807SRodney W. Grimes 			break;
3414b88c807SRodney W. Grimes 		case FTS_D:
3424b88c807SRodney W. Grimes 			if (p->fts_level != FTS_ROOTLEVEL &&
3434b88c807SRodney W. Grimes 			    p->fts_name[0] == '.' && !f_listdot)
3444b88c807SRodney W. Grimes 				break;
3454b88c807SRodney W. Grimes 
3464b88c807SRodney W. Grimes 			/*
3474b88c807SRodney W. Grimes 			 * If already output something, put out a newline as
3484b88c807SRodney W. Grimes 			 * a separator.  If multiple arguments, precede each
3494b88c807SRodney W. Grimes 			 * directory with its name.
3504b88c807SRodney W. Grimes 			 */
3514b88c807SRodney W. Grimes 			if (output)
3524b88c807SRodney W. Grimes 				(void)printf("\n%s:\n", p->fts_path);
3534b88c807SRodney W. Grimes 			else if (argc > 1) {
3544b88c807SRodney W. Grimes 				(void)printf("%s:\n", p->fts_path);
3554b88c807SRodney W. Grimes 				output = 1;
3564b88c807SRodney W. Grimes 			}
3574b88c807SRodney W. Grimes 
3584b88c807SRodney W. Grimes 			chp = fts_children(ftsp, ch_options);
3594b88c807SRodney W. Grimes 			display(p, chp);
3604b88c807SRodney W. Grimes 
3614b88c807SRodney W. Grimes 			if (!f_recursive && chp != NULL)
3624b88c807SRodney W. Grimes 				(void)fts_set(ftsp, p, FTS_SKIP);
3634b88c807SRodney W. Grimes 			break;
3644b88c807SRodney W. Grimes 		}
3654b88c807SRodney W. Grimes 	if (errno)
3664b88c807SRodney W. Grimes 		err(1, "fts_read");
3674b88c807SRodney W. Grimes }
3684b88c807SRodney W. Grimes 
3694b88c807SRodney W. Grimes /*
3704b88c807SRodney W. Grimes  * Display() takes a linked list of FTSENT structures and passes the list
3714b88c807SRodney W. Grimes  * along with any other necessary information to the print function.  P
3724b88c807SRodney W. Grimes  * points to the parent directory of the display list.
3734b88c807SRodney W. Grimes  */
3744b88c807SRodney W. Grimes static void
3754b88c807SRodney W. Grimes display(p, list)
3764b88c807SRodney W. Grimes 	FTSENT *p, *list;
3774b88c807SRodney W. Grimes {
3784b88c807SRodney W. Grimes 	struct stat *sp;
3794b88c807SRodney W. Grimes 	DISPLAY d;
3804b88c807SRodney W. Grimes 	FTSENT *cur;
3814b88c807SRodney W. Grimes 	NAMES *np;
3824b88c807SRodney W. Grimes 	u_quad_t maxsize;
3834b88c807SRodney W. Grimes 	u_long btotal, maxblock, maxinode, maxlen, maxnlink;
3844b88c807SRodney W. Grimes 	int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser;
3854b88c807SRodney W. Grimes 	int entries, needstats;
3864b88c807SRodney W. Grimes 	char *user, *group, *flags, buf[20];	/* 32 bits == 10 digits */
3874b88c807SRodney W. Grimes 
3884b88c807SRodney W. Grimes 	/*
3894b88c807SRodney W. Grimes 	 * If list is NULL there are two possibilities: that the parent
3904b88c807SRodney W. Grimes 	 * directory p has no children, or that fts_children() returned an
3914b88c807SRodney W. Grimes 	 * error.  We ignore the error case since it will be replicated
3924b88c807SRodney W. Grimes 	 * on the next call to fts_read() on the post-order visit to the
3934b88c807SRodney W. Grimes 	 * directory p, and will be signalled in traverse().
3944b88c807SRodney W. Grimes 	 */
3954b88c807SRodney W. Grimes 	if (list == NULL)
3964b88c807SRodney W. Grimes 		return;
3974b88c807SRodney W. Grimes 
3984b88c807SRodney W. Grimes 	needstats = f_inode || f_longform || f_size;
3994b88c807SRodney W. Grimes 	flen = 0;
4004b88c807SRodney W. Grimes 	btotal = maxblock = maxinode = maxlen = maxnlink = 0;
4014b88c807SRodney W. Grimes 	bcfile = 0;
4024b88c807SRodney W. Grimes 	maxuser = maxgroup = maxflags = 0;
4030fd510b7SJoerg Wunsch 	flags = NULL;
4044b88c807SRodney W. Grimes 	maxsize = 0;
4054b88c807SRodney W. Grimes 	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
4064b88c807SRodney W. Grimes 		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
4074b88c807SRodney W. Grimes 			warnx("%s: %s",
4084b88c807SRodney W. Grimes 			    cur->fts_name, strerror(cur->fts_errno));
4094b88c807SRodney W. Grimes 			cur->fts_number = NO_PRINT;
410fb1000d6SAdam David 			rval = 1;
4114b88c807SRodney W. Grimes 			continue;
4124b88c807SRodney W. Grimes 		}
4134b88c807SRodney W. Grimes 
4144b88c807SRodney W. Grimes 		/*
4154b88c807SRodney W. Grimes 		 * P is NULL if list is the argv list, to which different rules
4164b88c807SRodney W. Grimes 		 * apply.
4174b88c807SRodney W. Grimes 		 */
4184b88c807SRodney W. Grimes 		if (p == NULL) {
4194b88c807SRodney W. Grimes 			/* Directories will be displayed later. */
4204b88c807SRodney W. Grimes 			if (cur->fts_info == FTS_D && !f_listdir) {
4214b88c807SRodney W. Grimes 				cur->fts_number = NO_PRINT;
4224b88c807SRodney W. Grimes 				continue;
4234b88c807SRodney W. Grimes 			}
4244b88c807SRodney W. Grimes 		} else {
4254b88c807SRodney W. Grimes 			/* Only display dot file if -a/-A set. */
4264b88c807SRodney W. Grimes 			if (cur->fts_name[0] == '.' && !f_listdot) {
4274b88c807SRodney W. Grimes 				cur->fts_number = NO_PRINT;
4284b88c807SRodney W. Grimes 				continue;
4294b88c807SRodney W. Grimes 			}
4304b88c807SRodney W. Grimes 		}
4314b88c807SRodney W. Grimes 		if (f_nonprint)
4324b88c807SRodney W. Grimes 			prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen);
4334b88c807SRodney W. Grimes 		if (cur->fts_namelen > maxlen)
4344b88c807SRodney W. Grimes 			maxlen = cur->fts_namelen;
4357ea30648SDag-Erling Smørgrav 		if (f_octal) {
4367ea30648SDag-Erling Smørgrav 		        int t = len_octal(cur->fts_name, cur->fts_namelen);
4377ea30648SDag-Erling Smørgrav 			if (t > maxlen) maxlen = t;
4387ea30648SDag-Erling Smørgrav 		}
4394b88c807SRodney W. Grimes 		if (needstats) {
4404b88c807SRodney W. Grimes 			sp = cur->fts_statp;
4414b88c807SRodney W. Grimes 			if (sp->st_blocks > maxblock)
4424b88c807SRodney W. Grimes 				maxblock = sp->st_blocks;
4434b88c807SRodney W. Grimes 			if (sp->st_ino > maxinode)
4444b88c807SRodney W. Grimes 				maxinode = sp->st_ino;
4454b88c807SRodney W. Grimes 			if (sp->st_nlink > maxnlink)
4464b88c807SRodney W. Grimes 				maxnlink = sp->st_nlink;
4474b88c807SRodney W. Grimes 			if (sp->st_size > maxsize)
4484b88c807SRodney W. Grimes 				maxsize = sp->st_size;
4494b88c807SRodney W. Grimes 
4504b88c807SRodney W. Grimes 			btotal += sp->st_blocks;
4514b88c807SRodney W. Grimes 			if (f_longform) {
4524b88c807SRodney W. Grimes 				user = user_from_uid(sp->st_uid, 0);
4534b88c807SRodney W. Grimes 				if ((ulen = strlen(user)) > maxuser)
4544b88c807SRodney W. Grimes 					maxuser = ulen;
4554b88c807SRodney W. Grimes 				group = group_from_gid(sp->st_gid, 0);
4564b88c807SRodney W. Grimes 				if ((glen = strlen(group)) > maxgroup)
4574b88c807SRodney W. Grimes 					maxgroup = glen;
4584b88c807SRodney W. Grimes 				if (f_flags) {
4594b88c807SRodney W. Grimes 					flags =
4604b88c807SRodney W. Grimes 					    flags_to_string(sp->st_flags, "-");
4614b88c807SRodney W. Grimes 					if ((flen = strlen(flags)) > maxflags)
4624b88c807SRodney W. Grimes 						maxflags = flen;
4634b88c807SRodney W. Grimes 				} else
4644b88c807SRodney W. Grimes 					flen = 0;
4654b88c807SRodney W. Grimes 
4664b88c807SRodney W. Grimes 				if ((np = malloc(sizeof(NAMES) +
4674b88c807SRodney W. Grimes 				    ulen + glen + flen + 3)) == NULL)
4684b88c807SRodney W. Grimes 					err(1, NULL);
4694b88c807SRodney W. Grimes 
4704b88c807SRodney W. Grimes 				np->user = &np->data[0];
4714b88c807SRodney W. Grimes 				(void)strcpy(np->user, user);
4724b88c807SRodney W. Grimes 				np->group = &np->data[ulen + 1];
4734b88c807SRodney W. Grimes 				(void)strcpy(np->group, group);
4744b88c807SRodney W. Grimes 
4754b88c807SRodney W. Grimes 				if (S_ISCHR(sp->st_mode) ||
4764b88c807SRodney W. Grimes 				    S_ISBLK(sp->st_mode))
4774b88c807SRodney W. Grimes 					bcfile = 1;
4784b88c807SRodney W. Grimes 
4794b88c807SRodney W. Grimes 				if (f_flags) {
4804b88c807SRodney W. Grimes 					np->flags = &np->data[ulen + glen + 2];
4814b88c807SRodney W. Grimes 				  	(void)strcpy(np->flags, flags);
4824b88c807SRodney W. Grimes 				}
4834b88c807SRodney W. Grimes 				cur->fts_pointer = np;
4844b88c807SRodney W. Grimes 			}
4854b88c807SRodney W. Grimes 		}
4864b88c807SRodney W. Grimes 		++entries;
4874b88c807SRodney W. Grimes 	}
4884b88c807SRodney W. Grimes 
4894b88c807SRodney W. Grimes 	if (!entries)
4904b88c807SRodney W. Grimes 		return;
4914b88c807SRodney W. Grimes 
4924b88c807SRodney W. Grimes 	d.list = list;
4934b88c807SRodney W. Grimes 	d.entries = entries;
4944b88c807SRodney W. Grimes 	d.maxlen = maxlen;
4954b88c807SRodney W. Grimes 	if (needstats) {
4964b88c807SRodney W. Grimes 		d.bcfile = bcfile;
4974b88c807SRodney W. Grimes 		d.btotal = btotal;
4984b88c807SRodney W. Grimes 		(void)snprintf(buf, sizeof(buf), "%lu", maxblock);
4994b88c807SRodney W. Grimes 		d.s_block = strlen(buf);
5004b88c807SRodney W. Grimes 		d.s_flags = maxflags;
5014b88c807SRodney W. Grimes 		d.s_group = maxgroup;
5024b88c807SRodney W. Grimes 		(void)snprintf(buf, sizeof(buf), "%lu", maxinode);
5034b88c807SRodney W. Grimes 		d.s_inode = strlen(buf);
5044b88c807SRodney W. Grimes 		(void)snprintf(buf, sizeof(buf), "%lu", maxnlink);
5054b88c807SRodney W. Grimes 		d.s_nlink = strlen(buf);
5064b88c807SRodney W. Grimes 		(void)snprintf(buf, sizeof(buf), "%qu", maxsize);
5074b88c807SRodney W. Grimes 		d.s_size = strlen(buf);
5084b88c807SRodney W. Grimes 		d.s_user = maxuser;
5094b88c807SRodney W. Grimes 	}
5104b88c807SRodney W. Grimes 
5114b88c807SRodney W. Grimes 	printfcn(&d);
5124b88c807SRodney W. Grimes 	output = 1;
5134b88c807SRodney W. Grimes 
5144b88c807SRodney W. Grimes 	if (f_longform)
5154b88c807SRodney W. Grimes 		for (cur = list; cur; cur = cur->fts_link)
5164b88c807SRodney W. Grimes 			free(cur->fts_pointer);
5174b88c807SRodney W. Grimes }
5184b88c807SRodney W. Grimes 
5194b88c807SRodney W. Grimes /*
5204b88c807SRodney W. Grimes  * Ordering for mastercmp:
5214b88c807SRodney W. Grimes  * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories
5224b88c807SRodney W. Grimes  * as larger than directories.  Within either group, use the sort function.
5234b88c807SRodney W. Grimes  * All other levels use the sort function.  Error entries remain unsorted.
5244b88c807SRodney W. Grimes  */
5254b88c807SRodney W. Grimes static int
5264b88c807SRodney W. Grimes mastercmp(a, b)
5274b88c807SRodney W. Grimes 	const FTSENT **a, **b;
5284b88c807SRodney W. Grimes {
5294b88c807SRodney W. Grimes 	int a_info, b_info;
5304b88c807SRodney W. Grimes 
5314b88c807SRodney W. Grimes 	a_info = (*a)->fts_info;
5324b88c807SRodney W. Grimes 	if (a_info == FTS_ERR)
5334b88c807SRodney W. Grimes 		return (0);
5344b88c807SRodney W. Grimes 	b_info = (*b)->fts_info;
5354b88c807SRodney W. Grimes 	if (b_info == FTS_ERR)
5364b88c807SRodney W. Grimes 		return (0);
5374b88c807SRodney W. Grimes 
5384b88c807SRodney W. Grimes 	if (a_info == FTS_NS || b_info == FTS_NS)
5394b88c807SRodney W. Grimes 		return (namecmp(*a, *b));
5404b88c807SRodney W. Grimes 
54151f26ac5SSean Eric Fagan 	if (a_info != b_info &&
54251f26ac5SSean Eric Fagan 	    (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) {
5434b88c807SRodney W. Grimes 		if (a_info == FTS_D)
5444b88c807SRodney W. Grimes 			return (1);
54551f26ac5SSean Eric Fagan 		if (b_info == FTS_D)
5464b88c807SRodney W. Grimes 			return (-1);
54751f26ac5SSean Eric Fagan 	}
5484b88c807SRodney W. Grimes 	return (sortfcn(*a, *b));
5494b88c807SRodney W. Grimes }
550