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(¬used, &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