19ddb49cbSWarner Losh /*- 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. 16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 334b88c807SRodney W. Grimes #ifndef lint 34d46c1a60SSteve Price static const char copyright[] = 354b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993, 1994\n\ 364b88c807SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 37febad2fcSSteve Price #endif /* not lint */ 38febad2fcSSteve Price 39febad2fcSSteve Price #if 0 40c73d77ceSMark Murray #ifndef lint 41febad2fcSSteve Price static char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94"; 424b88c807SRodney W. Grimes #endif /* not lint */ 43c73d77ceSMark Murray #endif 445eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 455eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 464b88c807SRodney W. Grimes 47cf147939SDag-Erling Smørgrav #include <sys/param.h> 484b88c807SRodney W. Grimes #include <sys/stat.h> 494b88c807SRodney W. Grimes #include <sys/ioctl.h> 504d33b62eSRobert Watson #include <sys/mac.h> 514b88c807SRodney W. Grimes 524b88c807SRodney W. Grimes #include <dirent.h> 534b88c807SRodney W. Grimes #include <err.h> 544b88c807SRodney W. Grimes #include <errno.h> 554b88c807SRodney W. Grimes #include <fts.h> 56576541a9SWarner Losh #include <grp.h> 5740feca3aSMark Murray #include <inttypes.h> 58008a4910SSheldon Hearn #include <limits.h> 59008a4910SSheldon Hearn #include <locale.h> 60576541a9SWarner Losh #include <pwd.h> 614b88c807SRodney W. Grimes #include <stdio.h> 624b88c807SRodney W. Grimes #include <stdlib.h> 634b88c807SRodney W. Grimes #include <string.h> 644b88c807SRodney W. Grimes #include <unistd.h> 65bd82d8abSAndrey A. Chernov #ifdef COLORLS 66bd82d8abSAndrey A. Chernov #include <termcap.h> 67bd82d8abSAndrey A. Chernov #include <signal.h> 68bd82d8abSAndrey A. Chernov #endif 6952e4a08cSMarcel Moolenaar #include <libxo/xo.h> 704b88c807SRodney W. Grimes 714b88c807SRodney W. Grimes #include "ls.h" 724b88c807SRodney W. Grimes #include "extern.h" 734b88c807SRodney W. Grimes 74008a4910SSheldon Hearn /* 75008a4910SSheldon Hearn * Upward approximation of the maximum number of characters needed to 76008a4910SSheldon Hearn * represent a value of integral type t as a string, excluding the 77008a4910SSheldon Hearn * NUL terminator, with provision for a sign. 78008a4910SSheldon Hearn */ 791f94b779SSheldon Hearn #define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) 80008a4910SSheldon Hearn 8140feca3aSMark Murray /* 8240feca3aSMark Murray * MAKENINES(n) turns n into (10**n)-1. This is useful for converting a width 8340feca3aSMark Murray * into a number that wide in decimal. 8440feca3aSMark Murray * XXX: Overflows are not considered. 8540feca3aSMark Murray */ 8640feca3aSMark Murray #define MAKENINES(n) \ 8740feca3aSMark Murray do { \ 8840feca3aSMark Murray intmax_t i; \ 8940feca3aSMark Murray \ 9040feca3aSMark Murray /* Use a loop as all values of n are small. */ \ 9140feca3aSMark Murray for (i = 1; n > 0; i *= 10) \ 9240feca3aSMark Murray n--; \ 9340feca3aSMark Murray n = i - 1; \ 9440feca3aSMark Murray } while(0) 9540feca3aSMark Murray 9640feca3aSMark Murray static void display(const FTSENT *, FTSENT *, int); 970d3bcc2eSGarrett Wollman static int mastercmp(const FTSENT * const *, const FTSENT * const *); 9846251ddeSWarner Losh static void traverse(int, char **, int); 994b88c807SRodney W. Grimes 10040feca3aSMark Murray static void (*printfcn)(const DISPLAY *); 10146251ddeSWarner Losh static int (*sortfcn)(const FTSENT *, const FTSENT *); 1024b88c807SRodney W. Grimes 1034b88c807SRodney W. Grimes long blocksize; /* block size units */ 1044b88c807SRodney W. Grimes int termwidth = 80; /* default terminal width */ 1054b88c807SRodney W. Grimes 1064b88c807SRodney W. Grimes /* flags */ 1074b88c807SRodney W. Grimes int f_accesstime; /* use time of last access */ 108fe79420eSJohn Baldwin int f_birthtime; /* use time of birth */ 1094b88c807SRodney W. Grimes int f_flags; /* show flags associated with a file */ 1100e8d1551SJosef Karthauser int f_humanval; /* show human-readable file sizes */ 1114b88c807SRodney W. Grimes int f_inode; /* print inode */ 1129052855aSMark Murray static int f_kblocks; /* print size in kilobytes */ 1139aa68a3fSGreg Lehey int f_label; /* show MAC label */ 1149052855aSMark Murray static int f_listdir; /* list actual directory, not contents */ 1159052855aSMark Murray static int f_listdot; /* list files beginning with . */ 1164b88c807SRodney W. Grimes int f_longform; /* long listing format */ 1179aa68a3fSGreg Lehey static int f_noautodot; /* do not automatically enable -A for root */ 1181fe8c2a9SJaakko Heinonen static int f_nofollow; /* don't follow symbolic link arguments */ 1194b88c807SRodney W. Grimes int f_nonprint; /* show unprintables as ? */ 1209052855aSMark Murray static int f_nosort; /* don't sort output */ 121008a4910SSheldon Hearn int f_notabs; /* don't use tab-separated multi-col output */ 122e5542be4SAllan Jude int f_numericonly; /* don't convert uid/gid to name */ 1237ea30648SDag-Erling Smørgrav int f_octal; /* show unprintables as \xxx */ 1240d86878cSDag-Erling Smørgrav int f_octal_escape; /* like f_octal but use C escapes if possible */ 1259052855aSMark Murray static int f_recursive; /* ls subdirectories also */ 1269052855aSMark Murray static int f_reversesort; /* reverse whatever sort is used */ 1279aa68a3fSGreg Lehey int f_samesort; /* sort time and name in same direction */ 1289aa68a3fSGreg Lehey int f_sectime; /* print full time information */ 1299052855aSMark Murray static int f_singlecol; /* use single column output */ 1304b88c807SRodney W. Grimes int f_size; /* list size in short listing */ 1319aa68a3fSGreg Lehey static int f_sizesort; 13294274c73STim J. Robbins int f_slash; /* similar to f_type, but only for dirs */ 13394274c73STim J. Robbins int f_sortacross; /* sort across rows, not down columns */ 1344b88c807SRodney W. Grimes int f_statustime; /* use time of last mode change */ 13540feca3aSMark Murray static int f_stream; /* stream the output, separate with commas */ 1369aa68a3fSGreg Lehey int f_thousands; /* show file sizes with thousands separators */ 1372269fa57SGreg Lehey char *f_timeformat; /* user-specified time format */ 1389aa68a3fSGreg Lehey static int f_timesort; /* sort by time vice name */ 1394b88c807SRodney W. Grimes int f_type; /* add type character for non-regular files */ 1409052855aSMark Murray static int f_whiteout; /* show whiteout entries */ 1419aa68a3fSGreg Lehey 14274985094SJosef Karthauser #ifdef COLORLS 1433885812cSJosef Karthauser int f_color; /* add type in color for non-regular files */ 1445a890e22SJosef Karthauser 1455a890e22SJosef Karthauser char *ansi_bgcol; /* ANSI sequence to set background colour */ 1465a890e22SJosef Karthauser char *ansi_fgcol; /* ANSI sequence to set foreground colour */ 1475a890e22SJosef Karthauser char *ansi_coloff; /* ANSI sequence to reset colours */ 148c1499cf6SJosef Karthauser char *attrs_off; /* ANSI sequence to turn off attributes */ 149c1499cf6SJosef Karthauser char *enter_bold; /* ANSI sequence to set color to bold mode */ 15074985094SJosef Karthauser #endif 1514b88c807SRodney W. Grimes 1529052855aSMark Murray static int rval; 153fb1000d6SAdam David 1544b88c807SRodney W. Grimes int 15546251ddeSWarner Losh main(int argc, char *argv[]) 1564b88c807SRodney W. Grimes { 1574b88c807SRodney W. Grimes static char dot[] = ".", *dotav[] = {dot, NULL}; 1584b88c807SRodney W. Grimes struct winsize win; 1594b88c807SRodney W. Grimes int ch, fts_options, notused; 1604b88c807SRodney W. Grimes char *p; 161d4bf4151SBaptiste Daroussin const char *errstr = NULL; 1625a890e22SJosef Karthauser #ifdef COLORLS 1635a890e22SJosef Karthauser char termcapbuf[1024]; /* termcap definition buffer */ 1645a890e22SJosef Karthauser char tcapbuf[512]; /* capability buffer */ 1655a890e22SJosef Karthauser char *bp = tcapbuf; 1665a890e22SJosef Karthauser #endif 1675a890e22SJosef Karthauser 168f5bd01c6SAndrey A. Chernov (void)setlocale(LC_ALL, ""); 169f5bd01c6SAndrey A. Chernov 1704b88c807SRodney W. Grimes /* Terminal defaults to -Cq, non-terminal defaults to -1. */ 1714b88c807SRodney W. Grimes if (isatty(STDOUT_FILENO)) { 172a28edf9aSTim J. Robbins termwidth = 80; 173a28edf9aSTim J. Robbins if ((p = getenv("COLUMNS")) != NULL && *p != '\0') 174d4bf4151SBaptiste Daroussin termwidth = strtonum(p, 0, INT_MAX, &errstr); 175a28edf9aSTim J. Robbins else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1 && 176a28edf9aSTim J. Robbins win.ws_col > 0) 1774b88c807SRodney W. Grimes termwidth = win.ws_col; 1789052855aSMark Murray f_nonprint = 1; 17934994fcdSJoerg Wunsch } else { 1804b88c807SRodney W. Grimes f_singlecol = 1; 18134994fcdSJoerg Wunsch /* retrieve environment variable, in case of explicit -C */ 1829052855aSMark Murray p = getenv("COLUMNS"); 1839052855aSMark Murray if (p) 184d4bf4151SBaptiste Daroussin termwidth = strtonum(p, 0, INT_MAX, &errstr); 18534994fcdSJoerg Wunsch } 1864b88c807SRodney W. Grimes 187d4bf4151SBaptiste Daroussin if (errstr) 188d4bf4151SBaptiste Daroussin termwidth = 80; 189d4bf4151SBaptiste Daroussin 1904b88c807SRodney W. Grimes fts_options = FTS_PHYSICAL; 1919aa68a3fSGreg Lehey if (getenv("LS_SAMESORT")) 1929aa68a3fSGreg Lehey f_samesort = 1; 19352e4a08cSMarcel Moolenaar 19452e4a08cSMarcel Moolenaar argc = xo_parse_args(argc, argv); 19552e4a08cSMarcel Moolenaar if (argc < 0) 19652e4a08cSMarcel Moolenaar return (1); 19752e4a08cSMarcel Moolenaar xo_set_flags(NULL, XOF_COLUMNS); 198e5542be4SAllan Jude xo_set_version(LS_XO_VERSION); 19952e4a08cSMarcel Moolenaar 20071b8b748SDima Dorfman while ((ch = getopt(argc, argv, 2019aa68a3fSGreg Lehey "1ABCD:FGHILPRSTUWXZabcdfghiklmnopqrstuwxy,")) != -1) { 2024b88c807SRodney W. Grimes switch (ch) { 2034b88c807SRodney W. Grimes /* 20494274c73STim J. Robbins * The -1, -C, -x and -l options all override each other so 20594274c73STim J. Robbins * shell aliasing works right. 2064b88c807SRodney W. Grimes */ 2074b88c807SRodney W. Grimes case '1': 2084b88c807SRodney W. Grimes f_singlecol = 1; 2099052855aSMark Murray f_longform = 0; 21094274c73STim J. Robbins f_stream = 0; 2114b88c807SRodney W. Grimes break; 2124b88c807SRodney W. Grimes case 'C': 21394274c73STim J. Robbins f_sortacross = f_longform = f_singlecol = 0; 2144b88c807SRodney W. Grimes break; 2154b88c807SRodney W. Grimes case 'l': 2164b88c807SRodney W. Grimes f_longform = 1; 2179052855aSMark Murray f_singlecol = 0; 21894274c73STim J. Robbins f_stream = 0; 21994274c73STim J. Robbins break; 22094274c73STim J. Robbins case 'x': 22194274c73STim J. Robbins f_sortacross = 1; 22294274c73STim J. Robbins f_longform = 0; 22394274c73STim J. Robbins f_singlecol = 0; 2244b88c807SRodney W. Grimes break; 225fe79420eSJohn Baldwin /* The -c, -u, and -U options override each other. */ 2264b88c807SRodney W. Grimes case 'c': 2274b88c807SRodney W. Grimes f_statustime = 1; 2284b88c807SRodney W. Grimes f_accesstime = 0; 229fe79420eSJohn Baldwin f_birthtime = 0; 2304b88c807SRodney W. Grimes break; 2314b88c807SRodney W. Grimes case 'u': 2324b88c807SRodney W. Grimes f_accesstime = 1; 2334b88c807SRodney W. Grimes f_statustime = 0; 234fe79420eSJohn Baldwin f_birthtime = 0; 235fe79420eSJohn Baldwin break; 236fe79420eSJohn Baldwin case 'U': 237fe79420eSJohn Baldwin f_birthtime = 1; 238fe79420eSJohn Baldwin f_accesstime = 0; 239fe79420eSJohn Baldwin f_statustime = 0; 2404b88c807SRodney W. Grimes break; 2413651faa5SGreg Lehey case 'f': 2423651faa5SGreg Lehey f_nosort = 1; 2433651faa5SGreg Lehey /* FALLTHROUGH */ 24444f17a81SGreg Lehey case 'a': 24544f17a81SGreg Lehey fts_options |= FTS_SEEDOT; 24644f17a81SGreg Lehey /* FALLTHROUGH */ 24744f17a81SGreg Lehey case 'A': 24844f17a81SGreg Lehey f_listdot = 1; 24944f17a81SGreg Lehey break; 25044f17a81SGreg Lehey /* The -t and -S options override each other. */ 25144f17a81SGreg Lehey case 'S': 25244f17a81SGreg Lehey f_sizesort = 1; 25344f17a81SGreg Lehey f_timesort = 0; 25444f17a81SGreg Lehey break; 25544f17a81SGreg Lehey case 't': 25644f17a81SGreg Lehey f_timesort = 1; 25744f17a81SGreg Lehey f_sizesort = 0; 25844f17a81SGreg Lehey break; 25944f17a81SGreg Lehey /* Other flags. Please keep alphabetic. */ 2609aa68a3fSGreg Lehey case ',': 2619aa68a3fSGreg Lehey f_thousands = 1; 2629aa68a3fSGreg Lehey break; 26344f17a81SGreg Lehey case 'B': 26444f17a81SGreg Lehey f_nonprint = 0; 26544f17a81SGreg Lehey f_octal = 1; 26644f17a81SGreg Lehey f_octal_escape = 0; 26744f17a81SGreg Lehey break; 26844f17a81SGreg Lehey case 'D': 26944f17a81SGreg Lehey f_timeformat = optarg; 27044f17a81SGreg Lehey break; 2714b88c807SRodney W. Grimes case 'F': 2724b88c807SRodney W. Grimes f_type = 1; 27394274c73STim J. Robbins f_slash = 0; 2744b88c807SRodney W. Grimes break; 27544f17a81SGreg Lehey case 'G': 27644f17a81SGreg Lehey setenv("CLICOLOR", "", 1); 27744f17a81SGreg Lehey break; 2783a34dbf7SDag-Erling Smørgrav case 'H': 2793a34dbf7SDag-Erling Smørgrav fts_options |= FTS_COMFOLLOW; 2801fe8c2a9SJaakko Heinonen f_nofollow = 0; 2813a34dbf7SDag-Erling Smørgrav break; 28244f17a81SGreg Lehey case 'I': 28344f17a81SGreg Lehey f_noautodot = 1; 2843885812cSJosef Karthauser break; 2854b88c807SRodney W. Grimes case 'L': 2864b88c807SRodney W. Grimes fts_options &= ~FTS_PHYSICAL; 2874b88c807SRodney W. Grimes fts_options |= FTS_LOGICAL; 2881fe8c2a9SJaakko Heinonen f_nofollow = 0; 2894b88c807SRodney W. Grimes break; 2903a34dbf7SDag-Erling Smørgrav case 'P': 2913a34dbf7SDag-Erling Smørgrav fts_options &= ~FTS_COMFOLLOW; 2923a34dbf7SDag-Erling Smørgrav fts_options &= ~FTS_LOGICAL; 2933a34dbf7SDag-Erling Smørgrav fts_options |= FTS_PHYSICAL; 2941fe8c2a9SJaakko Heinonen f_nofollow = 1; 2953a34dbf7SDag-Erling Smørgrav break; 2964b88c807SRodney W. Grimes case 'R': 2974b88c807SRodney W. Grimes f_recursive = 1; 2984b88c807SRodney W. Grimes break; 29944f17a81SGreg Lehey case 'T': 30044f17a81SGreg Lehey f_sectime = 1; 3014b88c807SRodney W. Grimes break; 30244f17a81SGreg Lehey case 'W': 30344f17a81SGreg Lehey f_whiteout = 1; 30444f17a81SGreg Lehey break; 30544f17a81SGreg Lehey case 'Z': 30644f17a81SGreg Lehey f_label = 1; 30744f17a81SGreg Lehey break; 30844f17a81SGreg Lehey case 'b': 30944f17a81SGreg Lehey f_nonprint = 0; 31044f17a81SGreg Lehey f_octal = 0; 31144f17a81SGreg Lehey f_octal_escape = 1; 3127b7d153bSMaxime Henrion break; 3134b88c807SRodney W. Grimes /* The -d option turns off the -R option. */ 3144b88c807SRodney W. Grimes case 'd': 3154b88c807SRodney W. Grimes f_listdir = 1; 3164b88c807SRodney W. Grimes f_recursive = 0; 3174b88c807SRodney W. Grimes break; 3184b88c807SRodney W. Grimes case 'g': /* Compatibility with 4.3BSD. */ 3194b88c807SRodney W. Grimes break; 3200e8d1551SJosef Karthauser case 'h': 3210e8d1551SJosef Karthauser f_humanval = 1; 3220e8d1551SJosef Karthauser break; 3234b88c807SRodney W. Grimes case 'i': 3244b88c807SRodney W. Grimes f_inode = 1; 3254b88c807SRodney W. Grimes break; 326475727a0SPaul Traina case 'k': 327d5f9f41cSDavid E. O'Brien f_humanval = 0; 328475727a0SPaul Traina f_kblocks = 1; 329475727a0SPaul Traina break; 33094274c73STim J. Robbins case 'm': 33194274c73STim J. Robbins f_stream = 1; 33294274c73STim J. Robbins f_singlecol = 0; 33394274c73STim J. Robbins f_longform = 0; 33494274c73STim J. Robbins break; 335f3a6a64eSSheldon Hearn case 'n': 336f3a6a64eSSheldon Hearn f_numericonly = 1; 337f3a6a64eSSheldon Hearn break; 3384b88c807SRodney W. Grimes case 'o': 3394b88c807SRodney W. Grimes f_flags = 1; 3404b88c807SRodney W. Grimes break; 34194274c73STim J. Robbins case 'p': 34294274c73STim J. Robbins f_slash = 1; 34394274c73STim J. Robbins f_type = 1; 34494274c73STim J. Robbins break; 3454b88c807SRodney W. Grimes case 'q': 3464b88c807SRodney W. Grimes f_nonprint = 1; 3477ea30648SDag-Erling Smørgrav f_octal = 0; 3480d86878cSDag-Erling Smørgrav f_octal_escape = 0; 3494b88c807SRodney W. Grimes break; 3504b88c807SRodney W. Grimes case 'r': 3514b88c807SRodney W. Grimes f_reversesort = 1; 3524b88c807SRodney W. Grimes break; 3534b88c807SRodney W. Grimes case 's': 3544b88c807SRodney W. Grimes f_size = 1; 3554b88c807SRodney W. Grimes break; 35647f884f0SJosef Karthauser case 'w': 35747f884f0SJosef Karthauser f_nonprint = 0; 35847f884f0SJosef Karthauser f_octal = 0; 35947f884f0SJosef Karthauser f_octal_escape = 0; 36047f884f0SJosef Karthauser break; 3619aa68a3fSGreg Lehey case 'y': 3629aa68a3fSGreg Lehey f_samesort = 1; 3639aa68a3fSGreg Lehey break; 3644b88c807SRodney W. Grimes default: 3654b88c807SRodney W. Grimes case '?': 3664b88c807SRodney W. Grimes usage(); 3674b88c807SRodney W. Grimes } 3684b88c807SRodney W. Grimes } 3694b88c807SRodney W. Grimes argc -= optind; 3704b88c807SRodney W. Grimes argv += optind; 3714b88c807SRodney W. Grimes 372390a478eSRuslan Ermilov /* Root is -A automatically unless -I. */ 373390a478eSRuslan Ermilov if (!f_listdot && getuid() == (uid_t)0 && !f_noautodot) 3747b7d153bSMaxime Henrion f_listdot = 1; 3757b7d153bSMaxime Henrion 3763d2ddc9eSJosef Karthauser /* Enabling of colours is conditional on the environment. */ 3773d2ddc9eSJosef Karthauser if (getenv("CLICOLOR") && 3783d2ddc9eSJosef Karthauser (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE"))) 379d4413063SJosef Karthauser #ifdef COLORLS 3803d2ddc9eSJosef Karthauser if (tgetent(termcapbuf, getenv("TERM")) == 1) { 3813d2ddc9eSJosef Karthauser ansi_fgcol = tgetstr("AF", &bp); 3823d2ddc9eSJosef Karthauser ansi_bgcol = tgetstr("AB", &bp); 383c1499cf6SJosef Karthauser attrs_off = tgetstr("me", &bp); 384c1499cf6SJosef Karthauser enter_bold = tgetstr("md", &bp); 3853d2ddc9eSJosef Karthauser 3863d2ddc9eSJosef Karthauser /* To switch colours off use 'op' if 3873d2ddc9eSJosef Karthauser * available, otherwise use 'oc', or 3883d2ddc9eSJosef Karthauser * don't do colours at all. */ 3893d2ddc9eSJosef Karthauser ansi_coloff = tgetstr("op", &bp); 3903d2ddc9eSJosef Karthauser if (!ansi_coloff) 3913d2ddc9eSJosef Karthauser ansi_coloff = tgetstr("oc", &bp); 3923d2ddc9eSJosef Karthauser if (ansi_fgcol && ansi_bgcol && ansi_coloff) 3933d2ddc9eSJosef Karthauser f_color = 1; 3943d2ddc9eSJosef Karthauser } 395d4413063SJosef Karthauser #else 39652e4a08cSMarcel Moolenaar xo_warnx("color support not compiled in"); 397d4413063SJosef Karthauser #endif /*COLORLS*/ 3983d2ddc9eSJosef Karthauser 399d4413063SJosef Karthauser #ifdef COLORLS 400bd82d8abSAndrey A. Chernov if (f_color) { 40122ff3e9eSAndrey A. Chernov /* 40222ff3e9eSAndrey A. Chernov * We can't put tabs and color sequences together: 40322ff3e9eSAndrey A. Chernov * column number will be incremented incorrectly 40422ff3e9eSAndrey A. Chernov * for "stty oxtabs" mode. 40522ff3e9eSAndrey A. Chernov */ 40622ff3e9eSAndrey A. Chernov f_notabs = 1; 407bd82d8abSAndrey A. Chernov (void)signal(SIGINT, colorquit); 408ab08444fSMartin Cracauer (void)signal(SIGQUIT, colorquit); 4093885812cSJosef Karthauser parsecolors(getenv("LSCOLORS")); 410bd82d8abSAndrey A. Chernov } 41174985094SJosef Karthauser #endif 4123885812cSJosef Karthauser 4134b88c807SRodney W. Grimes /* 41471b8b748SDima Dorfman * If not -F, -i, -l, -s, -S or -t options, don't require stat 4153885812cSJosef Karthauser * information, unless in color mode in which case we do 4163885812cSJosef Karthauser * need this to determine which colors to display. 4174b88c807SRodney W. Grimes */ 41871b8b748SDima Dorfman if (!f_inode && !f_longform && !f_size && !f_timesort && 41971b8b748SDima Dorfman !f_sizesort && !f_type 42074985094SJosef Karthauser #ifdef COLORLS 42174985094SJosef Karthauser && !f_color 42274985094SJosef Karthauser #endif 42374985094SJosef Karthauser ) 4244b88c807SRodney W. Grimes fts_options |= FTS_NOSTAT; 4254b88c807SRodney W. Grimes 4264b88c807SRodney W. Grimes /* 4271fe8c2a9SJaakko Heinonen * If not -F, -P, -d or -l options, follow any symbolic links listed on 428183714f3SXin LI * the command line, unless in color mode in which case we need to 429183714f3SXin LI * distinguish file type for a symbolic link itself and its target. 4304b88c807SRodney W. Grimes */ 431183714f3SXin LI if (!f_nofollow && !f_longform && !f_listdir && (!f_type || f_slash) 432183714f3SXin LI #ifdef COLORLS 433183714f3SXin LI && !f_color 434183714f3SXin LI #endif 435183714f3SXin LI ) 4364b88c807SRodney W. Grimes fts_options |= FTS_COMFOLLOW; 4374b88c807SRodney W. Grimes 438fb5cb208SSteve Price /* 439fb5cb208SSteve Price * If -W, show whiteout entries 440fb5cb208SSteve Price */ 441fb5cb208SSteve Price #ifdef FTS_WHITEOUT 442fb5cb208SSteve Price if (f_whiteout) 443fb5cb208SSteve Price fts_options |= FTS_WHITEOUT; 444fb5cb208SSteve Price #endif 445fb5cb208SSteve Price 4464d4dcc7aSDag-Erling Smørgrav /* If -i, -l or -s, figure out block size. */ 4474d4dcc7aSDag-Erling Smørgrav if (f_inode || f_longform || f_size) { 44890b0ec31SPoul-Henning Kamp if (f_kblocks) 44990b0ec31SPoul-Henning Kamp blocksize = 2; 45090b0ec31SPoul-Henning Kamp else { 4514b88c807SRodney W. Grimes (void)getbsize(¬used, &blocksize); 4524b88c807SRodney W. Grimes blocksize /= 512; 45390b0ec31SPoul-Henning Kamp } 4544b88c807SRodney W. Grimes } 4554b88c807SRodney W. Grimes /* Select a sort function. */ 4564b88c807SRodney W. Grimes if (f_reversesort) { 45771b8b748SDima Dorfman if (!f_timesort && !f_sizesort) 4584b88c807SRodney W. Grimes sortfcn = revnamecmp; 45986cca1e7SJohn Baldwin else if (f_sizesort) 46086cca1e7SJohn Baldwin sortfcn = revsizecmp; 4614b88c807SRodney W. Grimes else if (f_accesstime) 4624b88c807SRodney W. Grimes sortfcn = revacccmp; 463fe79420eSJohn Baldwin else if (f_birthtime) 464fe79420eSJohn Baldwin sortfcn = revbirthcmp; 4654b88c807SRodney W. Grimes else if (f_statustime) 4664b88c807SRodney W. Grimes sortfcn = revstatcmp; 4674b88c807SRodney W. Grimes else /* Use modification time. */ 4684b88c807SRodney W. Grimes sortfcn = revmodcmp; 4694b88c807SRodney W. Grimes } else { 47071b8b748SDima Dorfman if (!f_timesort && !f_sizesort) 4714b88c807SRodney W. Grimes sortfcn = namecmp; 47286cca1e7SJohn Baldwin else if (f_sizesort) 47386cca1e7SJohn Baldwin sortfcn = sizecmp; 4744b88c807SRodney W. Grimes else if (f_accesstime) 4754b88c807SRodney W. Grimes sortfcn = acccmp; 476fe79420eSJohn Baldwin else if (f_birthtime) 477fe79420eSJohn Baldwin sortfcn = birthcmp; 4784b88c807SRodney W. Grimes else if (f_statustime) 4794b88c807SRodney W. Grimes sortfcn = statcmp; 4804b88c807SRodney W. Grimes else /* Use modification time. */ 4814b88c807SRodney W. Grimes sortfcn = modcmp; 4824b88c807SRodney W. Grimes } 4834b88c807SRodney W. Grimes 4844b88c807SRodney W. Grimes /* Select a print function. */ 4854b88c807SRodney W. Grimes if (f_singlecol) 4864b88c807SRodney W. Grimes printfcn = printscol; 4874b88c807SRodney W. Grimes else if (f_longform) 4884b88c807SRodney W. Grimes printfcn = printlong; 48994274c73STim J. Robbins else if (f_stream) 49094274c73STim J. Robbins printfcn = printstream; 4914b88c807SRodney W. Grimes else 4924b88c807SRodney W. Grimes printfcn = printcol; 4934b88c807SRodney W. Grimes 49452e4a08cSMarcel Moolenaar xo_open_container("file-information"); 4954b88c807SRodney W. Grimes if (argc) 4964b88c807SRodney W. Grimes traverse(argc, argv, fts_options); 4974b88c807SRodney W. Grimes else 4984b88c807SRodney W. Grimes traverse(1, dotav, fts_options); 49952e4a08cSMarcel Moolenaar xo_close_container("file-information"); 50052e4a08cSMarcel Moolenaar xo_finish(); 501fb1000d6SAdam David exit(rval); 5024b88c807SRodney W. Grimes } 5034b88c807SRodney W. Grimes 5044b88c807SRodney W. Grimes static int output; /* If anything output. */ 5054b88c807SRodney W. Grimes 5064b88c807SRodney W. Grimes /* 5074b88c807SRodney W. Grimes * Traverse() walks the logical directory structure specified by the argv list 5084b88c807SRodney W. Grimes * in the order specified by the mastercmp() comparison function. During the 5094b88c807SRodney W. Grimes * traversal it passes linked lists of structures to display() which represent 5104b88c807SRodney W. Grimes * a superset (may be exact set) of the files to be displayed. 5114b88c807SRodney W. Grimes */ 5124b88c807SRodney W. Grimes static void 51346251ddeSWarner Losh traverse(int argc, char *argv[], int options) 5144b88c807SRodney W. Grimes { 5154b88c807SRodney W. Grimes FTS *ftsp; 5164b88c807SRodney W. Grimes FTSENT *p, *chp; 5174b88c807SRodney W. Grimes int ch_options; 51852e4a08cSMarcel Moolenaar int first = 1; 5194b88c807SRodney W. Grimes 5204b88c807SRodney W. Grimes if ((ftsp = 5214b88c807SRodney W. Grimes fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) 52252e4a08cSMarcel Moolenaar xo_err(1, "fts_open"); 5234b88c807SRodney W. Grimes 52470bad4f7SDavid Schultz /* 52570bad4f7SDavid Schultz * We ignore errors from fts_children here since they will be 52670bad4f7SDavid Schultz * replicated and signalled on the next call to fts_read() below. 52770bad4f7SDavid Schultz */ 52870bad4f7SDavid Schultz chp = fts_children(ftsp, 0); 52970bad4f7SDavid Schultz if (chp != NULL) 53070bad4f7SDavid Schultz display(NULL, chp, options); 5314b88c807SRodney W. Grimes if (f_listdir) 5324b88c807SRodney W. Grimes return; 5334b88c807SRodney W. Grimes 5344b88c807SRodney W. Grimes /* 5354b88c807SRodney W. Grimes * If not recursing down this tree and don't need stat info, just get 5364b88c807SRodney W. Grimes * the names. 5374b88c807SRodney W. Grimes */ 5383c3f5f9cSRobert Watson ch_options = !f_recursive && !f_label && 5393c3f5f9cSRobert Watson options & FTS_NOSTAT ? FTS_NAMEONLY : 0; 5404b88c807SRodney W. Grimes 5414b88c807SRodney W. Grimes while ((p = fts_read(ftsp)) != NULL) 5424b88c807SRodney W. Grimes switch (p->fts_info) { 5434b88c807SRodney W. Grimes case FTS_DC: 54452e4a08cSMarcel Moolenaar xo_warnx("%s: directory causes a cycle", p->fts_name); 5454b88c807SRodney W. Grimes break; 5464b88c807SRodney W. Grimes case FTS_DNR: 5474b88c807SRodney W. Grimes case FTS_ERR: 54852e4a08cSMarcel Moolenaar xo_warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 549fb1000d6SAdam David rval = 1; 5504b88c807SRodney W. Grimes break; 5514b88c807SRodney W. Grimes case FTS_D: 5524b88c807SRodney W. Grimes if (p->fts_level != FTS_ROOTLEVEL && 553390a478eSRuslan Ermilov p->fts_name[0] == '.' && !f_listdot) 5544b88c807SRodney W. Grimes break; 5554b88c807SRodney W. Grimes 55652e4a08cSMarcel Moolenaar if (first) { 55752e4a08cSMarcel Moolenaar first = 0; 55852e4a08cSMarcel Moolenaar xo_open_list("directory"); 55952e4a08cSMarcel Moolenaar } 56052e4a08cSMarcel Moolenaar xo_open_instance("directory"); 56152e4a08cSMarcel Moolenaar 5624b88c807SRodney W. Grimes /* 5634b88c807SRodney W. Grimes * If already output something, put out a newline as 5644b88c807SRodney W. Grimes * a separator. If multiple arguments, precede each 5654b88c807SRodney W. Grimes * directory with its name. 5664b88c807SRodney W. Grimes */ 5671656f850STim J. Robbins if (output) { 56852e4a08cSMarcel Moolenaar xo_emit("\n"); 56952e4a08cSMarcel Moolenaar (void)printname("path", p->fts_path); 57052e4a08cSMarcel Moolenaar xo_emit(":\n"); 5711656f850STim J. Robbins } else if (argc > 1) { 57252e4a08cSMarcel Moolenaar (void)printname("path", p->fts_path); 57352e4a08cSMarcel Moolenaar xo_emit(":\n"); 5744b88c807SRodney W. Grimes output = 1; 5754b88c807SRodney W. Grimes } 5764b88c807SRodney W. Grimes chp = fts_children(ftsp, ch_options); 5774d33b62eSRobert Watson display(p, chp, options); 5784b88c807SRodney W. Grimes 57952e4a08cSMarcel Moolenaar xo_close_instance("directory"); 5804b88c807SRodney W. Grimes if (!f_recursive && chp != NULL) 5814b88c807SRodney W. Grimes (void)fts_set(ftsp, p, FTS_SKIP); 5824b88c807SRodney W. Grimes break; 583568dcd5fSBill Fumerola default: 584568dcd5fSBill Fumerola break; 5854b88c807SRodney W. Grimes } 58652e4a08cSMarcel Moolenaar if (!first) 58752e4a08cSMarcel Moolenaar xo_close_list("directory"); 5884b88c807SRodney W. Grimes if (errno) 58952e4a08cSMarcel Moolenaar xo_err(1, "fts_read"); 5904b88c807SRodney W. Grimes } 5914b88c807SRodney W. Grimes 5924b88c807SRodney W. Grimes /* 5934b88c807SRodney W. Grimes * Display() takes a linked list of FTSENT structures and passes the list 5944b88c807SRodney W. Grimes * along with any other necessary information to the print function. P 5954b88c807SRodney W. Grimes * points to the parent directory of the display list. 5964b88c807SRodney W. Grimes */ 5974b88c807SRodney W. Grimes static void 59840feca3aSMark Murray display(const FTSENT *p, FTSENT *list, int options) 5994b88c807SRodney W. Grimes { 6004b88c807SRodney W. Grimes struct stat *sp; 6014b88c807SRodney W. Grimes DISPLAY d; 6024b88c807SRodney W. Grimes FTSENT *cur; 6034b88c807SRodney W. Grimes NAMES *np; 6049052855aSMark Murray off_t maxsize; 60540feca3aSMark Murray long maxblock; 6066db1a7f1SMatthew D Fleming uintmax_t maxinode; 6076db1a7f1SMatthew D Fleming u_long btotal, labelstrlen, maxlen, maxnlink; 6084d33b62eSRobert Watson u_long maxlabelstr; 6099f365aa1SEd Schouten u_int sizelen; 61055926a66SJaakko Heinonen int maxflags; 6119052855aSMark Murray gid_t maxgroup; 6129052855aSMark Murray uid_t maxuser; 6139052855aSMark Murray size_t flen, ulen, glen; 614545f583cSTim Vanderhoek char *initmax; 6154b88c807SRodney W. Grimes int entries, needstats; 6160928a7f1SJuli Mallett const char *user, *group; 6174d33b62eSRobert Watson char *flags, *labelstr = NULL; 618008a4910SSheldon Hearn char ngroup[STRBUF_SIZEOF(uid_t) + 1]; 619008a4910SSheldon Hearn char nuser[STRBUF_SIZEOF(gid_t) + 1]; 6204b88c807SRodney W. Grimes 6214b88c807SRodney W. Grimes needstats = f_inode || f_longform || f_size; 6224b88c807SRodney W. Grimes flen = 0; 623545f583cSTim Vanderhoek btotal = 0; 624545f583cSTim Vanderhoek initmax = getenv("LS_COLWIDTHS"); 625545f583cSTim Vanderhoek /* Fields match -lios order. New ones should be added at the end. */ 6266db1a7f1SMatthew D Fleming maxlabelstr = maxblock = maxlen = maxnlink = 0; 6279052855aSMark Murray maxuser = maxgroup = maxflags = maxsize = 0; 6286db1a7f1SMatthew D Fleming maxinode = 0; 629545f583cSTim Vanderhoek if (initmax != NULL && *initmax != '\0') { 630545f583cSTim Vanderhoek char *initmax2, *jinitmax; 631545f583cSTim Vanderhoek int ninitmax; 632545f583cSTim Vanderhoek 633545f583cSTim Vanderhoek /* Fill-in "::" as "0:0:0" for the sake of scanf. */ 63440feca3aSMark Murray jinitmax = malloc(strlen(initmax) * 2 + 2); 635545f583cSTim Vanderhoek if (jinitmax == NULL) 63652e4a08cSMarcel Moolenaar xo_err(1, "malloc"); 63740feca3aSMark Murray initmax2 = jinitmax; 638545f583cSTim Vanderhoek if (*initmax == ':') 639545f583cSTim Vanderhoek strcpy(initmax2, "0:"), initmax2 += 2; 640545f583cSTim Vanderhoek else 641545f583cSTim Vanderhoek *initmax2++ = *initmax, *initmax2 = '\0'; 642545f583cSTim Vanderhoek for (initmax++; *initmax != '\0'; initmax++) { 643545f583cSTim Vanderhoek if (initmax[-1] == ':' && initmax[0] == ':') { 644545f583cSTim Vanderhoek *initmax2++ = '0'; 645545f583cSTim Vanderhoek *initmax2++ = initmax[0]; 646545f583cSTim Vanderhoek initmax2[1] = '\0'; 647545f583cSTim Vanderhoek } else { 648545f583cSTim Vanderhoek *initmax2++ = initmax[0]; 649545f583cSTim Vanderhoek initmax2[1] = '\0'; 650545f583cSTim Vanderhoek } 651545f583cSTim Vanderhoek } 6525dda5d0dSJosef Karthauser if (initmax2[-1] == ':') 6535dda5d0dSJosef Karthauser strcpy(initmax2, "0"); 654545f583cSTim Vanderhoek 655545f583cSTim Vanderhoek ninitmax = sscanf(jinitmax, 6566db1a7f1SMatthew D Fleming " %ju : %ld : %lu : %u : %u : %i : %jd : %lu : %lu ", 657545f583cSTim Vanderhoek &maxinode, &maxblock, &maxnlink, &maxuser, 6584d33b62eSRobert Watson &maxgroup, &maxflags, &maxsize, &maxlen, &maxlabelstr); 659545f583cSTim Vanderhoek f_notabs = 1; 660545f583cSTim Vanderhoek switch (ninitmax) { 6615dda5d0dSJosef Karthauser case 0: 6625dda5d0dSJosef Karthauser maxinode = 0; 6630d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6645dda5d0dSJosef Karthauser case 1: 6655dda5d0dSJosef Karthauser maxblock = 0; 6660d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6675dda5d0dSJosef Karthauser case 2: 6685dda5d0dSJosef Karthauser maxnlink = 0; 6690d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6705dda5d0dSJosef Karthauser case 3: 6715dda5d0dSJosef Karthauser maxuser = 0; 6720d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6735dda5d0dSJosef Karthauser case 4: 6745dda5d0dSJosef Karthauser maxgroup = 0; 6750d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6765dda5d0dSJosef Karthauser case 5: 6775dda5d0dSJosef Karthauser maxflags = 0; 6780d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6795dda5d0dSJosef Karthauser case 6: 6805dda5d0dSJosef Karthauser maxsize = 0; 6810d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6825dda5d0dSJosef Karthauser case 7: 6835dda5d0dSJosef Karthauser maxlen = 0; 6840d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6855dda5d0dSJosef Karthauser case 8: 6864d33b62eSRobert Watson maxlabelstr = 0; 6870d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 68818d8a22bSAndrey A. Chernov #ifdef COLORLS 68918d8a22bSAndrey A. Chernov if (!f_color) 69022ff3e9eSAndrey A. Chernov #endif 69118d8a22bSAndrey A. Chernov f_notabs = 0; 6920d9f1a69SPhilippe Charnier /* FALLTHROUGH */ 6939052855aSMark Murray default: 694568dcd5fSBill Fumerola break; 695545f583cSTim Vanderhoek } 69640feca3aSMark Murray MAKENINES(maxinode); 69740feca3aSMark Murray MAKENINES(maxblock); 69840feca3aSMark Murray MAKENINES(maxnlink); 69940feca3aSMark Murray MAKENINES(maxsize); 7007fcc4669SLukas Ertl free(jinitmax); 7019052855aSMark Murray } 7029f365aa1SEd Schouten d.s_size = 0; 7039f365aa1SEd Schouten sizelen = 0; 7040fd510b7SJoerg Wunsch flags = NULL; 7054b88c807SRodney W. Grimes for (cur = list, entries = 0; cur; cur = cur->fts_link) { 7064b88c807SRodney W. Grimes if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { 70752e4a08cSMarcel Moolenaar xo_warnx("%s: %s", 7084b88c807SRodney W. Grimes cur->fts_name, strerror(cur->fts_errno)); 7094b88c807SRodney W. Grimes cur->fts_number = NO_PRINT; 710fb1000d6SAdam David rval = 1; 7114b88c807SRodney W. Grimes continue; 7124b88c807SRodney W. Grimes } 7134b88c807SRodney W. Grimes /* 7144b88c807SRodney W. Grimes * P is NULL if list is the argv list, to which different rules 7154b88c807SRodney W. Grimes * apply. 7164b88c807SRodney W. Grimes */ 7174b88c807SRodney W. Grimes if (p == NULL) { 7184b88c807SRodney W. Grimes /* Directories will be displayed later. */ 7194b88c807SRodney W. Grimes if (cur->fts_info == FTS_D && !f_listdir) { 7204b88c807SRodney W. Grimes cur->fts_number = NO_PRINT; 7214b88c807SRodney W. Grimes continue; 7224b88c807SRodney W. Grimes } 7234b88c807SRodney W. Grimes } else { 7244b88c807SRodney W. Grimes /* Only display dot file if -a/-A set. */ 725390a478eSRuslan Ermilov if (cur->fts_name[0] == '.' && !f_listdot) { 7264b88c807SRodney W. Grimes cur->fts_number = NO_PRINT; 7274b88c807SRodney W. Grimes continue; 7284b88c807SRodney W. Grimes } 7294b88c807SRodney W. Grimes } 7304b88c807SRodney W. Grimes if (cur->fts_namelen > maxlen) 7314b88c807SRodney W. Grimes maxlen = cur->fts_namelen; 7320d86878cSDag-Erling Smørgrav if (f_octal || f_octal_escape) { 7336bd042dfSJosef Karthauser u_long t = len_octal(cur->fts_name, cur->fts_namelen); 7345dda5d0dSJosef Karthauser 7355dda5d0dSJosef Karthauser if (t > maxlen) 7365dda5d0dSJosef Karthauser maxlen = t; 7377ea30648SDag-Erling Smørgrav } 7384b88c807SRodney W. Grimes if (needstats) { 7394b88c807SRodney W. Grimes sp = cur->fts_statp; 7404b88c807SRodney W. Grimes if (sp->st_blocks > maxblock) 7414b88c807SRodney W. Grimes maxblock = sp->st_blocks; 7424b88c807SRodney W. Grimes if (sp->st_ino > maxinode) 7434b88c807SRodney W. Grimes maxinode = sp->st_ino; 7444b88c807SRodney W. Grimes if (sp->st_nlink > maxnlink) 7454b88c807SRodney W. Grimes maxnlink = sp->st_nlink; 7464b88c807SRodney W. Grimes if (sp->st_size > maxsize) 7474b88c807SRodney W. Grimes maxsize = sp->st_size; 7484b88c807SRodney W. Grimes 7494b88c807SRodney W. Grimes btotal += sp->st_blocks; 7504b88c807SRodney W. Grimes if (f_longform) { 751f3a6a64eSSheldon Hearn if (f_numericonly) { 752f3a6a64eSSheldon Hearn (void)snprintf(nuser, sizeof(nuser), 753f3a6a64eSSheldon Hearn "%u", sp->st_uid); 754f3a6a64eSSheldon Hearn (void)snprintf(ngroup, sizeof(ngroup), 755f3a6a64eSSheldon Hearn "%u", sp->st_gid); 756f3a6a64eSSheldon Hearn user = nuser; 757f3a6a64eSSheldon Hearn group = ngroup; 758f3a6a64eSSheldon Hearn } else { 7594b88c807SRodney W. Grimes user = user_from_uid(sp->st_uid, 0); 760f3a6a64eSSheldon Hearn group = group_from_gid(sp->st_gid, 0); 761f3a6a64eSSheldon Hearn } 7624b88c807SRodney W. Grimes if ((ulen = strlen(user)) > maxuser) 7634b88c807SRodney W. Grimes maxuser = ulen; 7644b88c807SRodney W. Grimes if ((glen = strlen(group)) > maxgroup) 7654b88c807SRodney W. Grimes maxgroup = glen; 7664b88c807SRodney W. Grimes if (f_flags) { 767141d77b8SJosef Karthauser flags = fflagstostr(sp->st_flags); 768141d77b8SJosef Karthauser if (flags != NULL && *flags == '\0') { 769141d77b8SJosef Karthauser free(flags); 770141d77b8SJosef Karthauser flags = strdup("-"); 771141d77b8SJosef Karthauser } 772141d77b8SJosef Karthauser if (flags == NULL) 77352e4a08cSMarcel Moolenaar xo_err(1, "fflagstostr"); 7749052855aSMark Murray flen = strlen(flags); 7759052855aSMark Murray if (flen > (size_t)maxflags) 7764b88c807SRodney W. Grimes maxflags = flen; 7774b88c807SRodney W. Grimes } else 7784b88c807SRodney W. Grimes flen = 0; 7794d33b62eSRobert Watson labelstr = NULL; 7804d33b62eSRobert Watson if (f_label) { 7814df6dabaSRobert Watson char name[PATH_MAX + 1]; 7824d33b62eSRobert Watson mac_t label; 7834d33b62eSRobert Watson int error; 7844b88c807SRodney W. Grimes 7854d33b62eSRobert Watson error = mac_prepare_file_label(&label); 7864d33b62eSRobert Watson if (error == -1) { 78752e4a08cSMarcel Moolenaar xo_warn("MAC label for %s/%s", 7883c3f5f9cSRobert Watson cur->fts_parent->fts_path, 7893c3f5f9cSRobert Watson cur->fts_name); 7904d33b62eSRobert Watson goto label_out; 7914d33b62eSRobert Watson } 7924d33b62eSRobert Watson 7934df6dabaSRobert Watson if (cur->fts_level == FTS_ROOTLEVEL) 7944df6dabaSRobert Watson snprintf(name, sizeof(name), 7954df6dabaSRobert Watson "%s", cur->fts_name); 7964d33b62eSRobert Watson else 7974df6dabaSRobert Watson snprintf(name, sizeof(name), 7983c3f5f9cSRobert Watson "%s/%s", cur->fts_parent-> 7993c3f5f9cSRobert Watson fts_accpath, cur->fts_name); 8004df6dabaSRobert Watson 8014df6dabaSRobert Watson if (options & FTS_LOGICAL) 8024df6dabaSRobert Watson error = mac_get_file(name, 8034df6dabaSRobert Watson label); 8044df6dabaSRobert Watson else 8054df6dabaSRobert Watson error = mac_get_link(name, 8064df6dabaSRobert Watson label); 8074d33b62eSRobert Watson if (error == -1) { 80852e4a08cSMarcel Moolenaar xo_warn("MAC label for %s/%s", 8093c3f5f9cSRobert Watson cur->fts_parent->fts_path, 8103c3f5f9cSRobert Watson cur->fts_name); 8114d33b62eSRobert Watson mac_free(label); 8124d33b62eSRobert Watson goto label_out; 8134d33b62eSRobert Watson } 8144d33b62eSRobert Watson 8154d33b62eSRobert Watson error = mac_to_text(label, 8164d33b62eSRobert Watson &labelstr); 8174d33b62eSRobert Watson if (error == -1) { 81852e4a08cSMarcel Moolenaar xo_warn("MAC label for %s/%s", 8193c3f5f9cSRobert Watson cur->fts_parent->fts_path, 8203c3f5f9cSRobert Watson cur->fts_name); 8214d33b62eSRobert Watson mac_free(label); 8224d33b62eSRobert Watson goto label_out; 8234d33b62eSRobert Watson } 8244d33b62eSRobert Watson mac_free(label); 8254d33b62eSRobert Watson label_out: 8264d33b62eSRobert Watson if (labelstr == NULL) 827317f1d53SRobert Watson labelstr = strdup("-"); 8284d33b62eSRobert Watson labelstrlen = strlen(labelstr); 8294d33b62eSRobert Watson if (labelstrlen > maxlabelstr) 8304d33b62eSRobert Watson maxlabelstr = labelstrlen; 8314d33b62eSRobert Watson } else 8324d33b62eSRobert Watson labelstrlen = 0; 8334d33b62eSRobert Watson 8344d33b62eSRobert Watson if ((np = malloc(sizeof(NAMES) + labelstrlen + 8357304f61fSBrian Feldman ulen + glen + flen + 4)) == NULL) 83652e4a08cSMarcel Moolenaar xo_err(1, "malloc"); 8374b88c807SRodney W. Grimes 8384b88c807SRodney W. Grimes np->user = &np->data[0]; 8394b88c807SRodney W. Grimes (void)strcpy(np->user, user); 8404b88c807SRodney W. Grimes np->group = &np->data[ulen + 1]; 8414b88c807SRodney W. Grimes (void)strcpy(np->group, group); 8424b88c807SRodney W. Grimes 8439f365aa1SEd Schouten if (S_ISCHR(sp->st_mode) || 8449f365aa1SEd Schouten S_ISBLK(sp->st_mode)) { 8459f365aa1SEd Schouten sizelen = snprintf(NULL, 0, 8469f365aa1SEd Schouten "%#jx", (uintmax_t)sp->st_rdev); 8479f365aa1SEd Schouten if (d.s_size < sizelen) 8489f365aa1SEd Schouten d.s_size = sizelen; 84955926a66SJaakko Heinonen } 8504b88c807SRodney W. Grimes 8514b88c807SRodney W. Grimes if (f_flags) { 8524b88c807SRodney W. Grimes np->flags = &np->data[ulen + glen + 2]; 8534b88c807SRodney W. Grimes (void)strcpy(np->flags, flags); 854141d77b8SJosef Karthauser free(flags); 8554b88c807SRodney W. Grimes } 8564d33b62eSRobert Watson if (f_label) { 8574d33b62eSRobert Watson np->label = &np->data[ulen + glen + 2 8587304f61fSBrian Feldman + (f_flags ? flen + 1 : 0)]; 8594d33b62eSRobert Watson (void)strcpy(np->label, labelstr); 8604d33b62eSRobert Watson free(labelstr); 8617304f61fSBrian Feldman } 8624b88c807SRodney W. Grimes cur->fts_pointer = np; 8634b88c807SRodney W. Grimes } 8644b88c807SRodney W. Grimes } 8654b88c807SRodney W. Grimes ++entries; 8664b88c807SRodney W. Grimes } 8674b88c807SRodney W. Grimes 86870bad4f7SDavid Schultz /* 86970bad4f7SDavid Schultz * If there are no entries to display, we normally stop right 87070bad4f7SDavid Schultz * here. However, we must continue if we have to display the 87170bad4f7SDavid Schultz * total block count. In this case, we display the total only 87270bad4f7SDavid Schultz * on the second (p != NULL) pass. 87370bad4f7SDavid Schultz */ 87470bad4f7SDavid Schultz if (!entries && (!(f_longform || f_size) || p == NULL)) 8754b88c807SRodney W. Grimes return; 8764b88c807SRodney W. Grimes 8774b88c807SRodney W. Grimes d.list = list; 8784b88c807SRodney W. Grimes d.entries = entries; 8794b88c807SRodney W. Grimes d.maxlen = maxlen; 8804b88c807SRodney W. Grimes if (needstats) { 8814b88c807SRodney W. Grimes d.btotal = btotal; 882cf147939SDag-Erling Smørgrav d.s_block = snprintf(NULL, 0, "%lu", howmany(maxblock, blocksize)); 8834b88c807SRodney W. Grimes d.s_flags = maxflags; 8844d33b62eSRobert Watson d.s_label = maxlabelstr; 8854b88c807SRodney W. Grimes d.s_group = maxgroup; 8866db1a7f1SMatthew D Fleming d.s_inode = snprintf(NULL, 0, "%ju", maxinode); 8879f365aa1SEd Schouten d.s_nlink = snprintf(NULL, 0, "%lu", maxnlink); 8889f365aa1SEd Schouten sizelen = f_humanval ? HUMANVALSTR_LEN : 8899f365aa1SEd Schouten snprintf(NULL, 0, "%ju", maxsize); 8909f365aa1SEd Schouten if (d.s_size < sizelen) 8919f365aa1SEd Schouten d.s_size = sizelen; 8924b88c807SRodney W. Grimes d.s_user = maxuser; 8934b88c807SRodney W. Grimes } 8949aa68a3fSGreg Lehey if (f_thousands) /* make space for commas */ 8959aa68a3fSGreg Lehey d.s_size += (d.s_size - 1) / 3; 8964b88c807SRodney W. Grimes printfcn(&d); 8974b88c807SRodney W. Grimes output = 1; 8984b88c807SRodney W. Grimes 8994b88c807SRodney W. Grimes if (f_longform) 9004b88c807SRodney W. Grimes for (cur = list; cur; cur = cur->fts_link) 9014b88c807SRodney W. Grimes free(cur->fts_pointer); 9024b88c807SRodney W. Grimes } 9034b88c807SRodney W. Grimes 9044b88c807SRodney W. Grimes /* 9054b88c807SRodney W. Grimes * Ordering for mastercmp: 9064b88c807SRodney W. Grimes * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories 9074b88c807SRodney W. Grimes * as larger than directories. Within either group, use the sort function. 9084b88c807SRodney W. Grimes * All other levels use the sort function. Error entries remain unsorted. 9094b88c807SRodney W. Grimes */ 9104b88c807SRodney W. Grimes static int 9110d3bcc2eSGarrett Wollman mastercmp(const FTSENT * const *a, const FTSENT * const *b) 9124b88c807SRodney W. Grimes { 9134b88c807SRodney W. Grimes int a_info, b_info; 9144b88c807SRodney W. Grimes 9154b88c807SRodney W. Grimes a_info = (*a)->fts_info; 9164b88c807SRodney W. Grimes if (a_info == FTS_ERR) 9174b88c807SRodney W. Grimes return (0); 9184b88c807SRodney W. Grimes b_info = (*b)->fts_info; 9194b88c807SRodney W. Grimes if (b_info == FTS_ERR) 9204b88c807SRodney W. Grimes return (0); 9214b88c807SRodney W. Grimes 9224b88c807SRodney W. Grimes if (a_info == FTS_NS || b_info == FTS_NS) 9234b88c807SRodney W. Grimes return (namecmp(*a, *b)); 9244b88c807SRodney W. Grimes 92551f26ac5SSean Eric Fagan if (a_info != b_info && 92651f26ac5SSean Eric Fagan (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) { 9274b88c807SRodney W. Grimes if (a_info == FTS_D) 9284b88c807SRodney W. Grimes return (1); 92951f26ac5SSean Eric Fagan if (b_info == FTS_D) 9304b88c807SRodney W. Grimes return (-1); 93151f26ac5SSean Eric Fagan } 9324b88c807SRodney W. Grimes return (sortfcn(*a, *b)); 9334b88c807SRodney W. Grimes } 934