ls.c revision 50051
11556Srgrimes/* 21556Srgrimes * Copyright (c) 1989, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Michael Fischbein. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 3827958Sstevestatic const char copyright[] = 391556Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 401556Srgrimes The Regents of the University of California. All rights reserved.\n"; 4127967Ssteve#endif /* not lint */ 4227967Ssteve 4327967Ssteve#ifndef lint 4427967Ssteve#if 0 4527967Sstevestatic char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94"; 4627967Ssteve#else 4727958Sstevestatic const char rcsid[] = 4850051Ssheldonh "$Id: ls.c,v 1.26 1999/08/19 11:36:12 sheldonh Exp $"; 4927967Ssteve#endif 501556Srgrimes#endif /* not lint */ 511556Srgrimes 521556Srgrimes#include <sys/types.h> 531556Srgrimes#include <sys/stat.h> 541556Srgrimes#include <sys/ioctl.h> 551556Srgrimes 561556Srgrimes#include <dirent.h> 571556Srgrimes#include <err.h> 581556Srgrimes#include <errno.h> 591556Srgrimes#include <fts.h> 6050050Ssheldonh#include <limits.h> 6150050Ssheldonh#include <locale.h> 621556Srgrimes#include <stdio.h> 631556Srgrimes#include <stdlib.h> 641556Srgrimes#include <string.h> 651556Srgrimes#include <unistd.h> 661556Srgrimes 671556Srgrimes#include "ls.h" 681556Srgrimes#include "extern.h" 691556Srgrimes 7050050Ssheldonh/* 7150050Ssheldonh * Upward approximation of the maximum number of characters needed to 7250050Ssheldonh * represent a value of integral type t as a string, excluding the 7350050Ssheldonh * NUL terminator, with provision for a sign. 7450050Ssheldonh */ 7550051Ssheldonh#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) 7650050Ssheldonh 771556Srgrimesstatic void display __P((FTSENT *, FTSENT *)); 7837932Shoekstatic u_quad_t makenines __P((u_long)); 791556Srgrimesstatic int mastercmp __P((const FTSENT **, const FTSENT **)); 801556Srgrimesstatic void traverse __P((int, char **, int)); 811556Srgrimes 821556Srgrimesstatic void (*printfcn) __P((DISPLAY *)); 831556Srgrimesstatic int (*sortfcn) __P((const FTSENT *, const FTSENT *)); 841556Srgrimes 851556Srgrimeslong blocksize; /* block size units */ 861556Srgrimesint termwidth = 80; /* default terminal width */ 871556Srgrimes 881556Srgrimes/* flags */ 891556Srgrimesint f_accesstime; /* use time of last access */ 901556Srgrimesint f_column; /* columnated format */ 911556Srgrimesint f_flags; /* show flags associated with a file */ 921556Srgrimesint f_inode; /* print inode */ 932889Spstint f_kblocks; /* print size in kilobytes */ 941556Srgrimesint f_listdir; /* list actual directory, not contents */ 951556Srgrimesint f_listdot; /* list files beginning with . */ 961556Srgrimesint f_longform; /* long listing format */ 971556Srgrimesint f_nonprint; /* show unprintables as ? */ 981556Srgrimesint f_nosort; /* don't sort output */ 9950050Ssheldonhint f_notabs; /* don't use tab-separated multi-col output */ 10049373Ssheldonhint f_numericonly; /* don't convert uid/gid to name */ 10135373Sdesint f_octal; /* show unprintables as \xxx */ 10235417Sdesint f_octal_escape; /* like f_octal but use C escapes if possible */ 1031556Srgrimesint f_recursive; /* ls subdirectories also */ 1041556Srgrimesint f_reversesort; /* reverse whatever sort is used */ 1051556Srgrimesint f_sectime; /* print the real time for all files */ 1061556Srgrimesint f_singlecol; /* use single column output */ 1071556Srgrimesint f_size; /* list size in short listing */ 1081556Srgrimesint f_statustime; /* use time of last mode change */ 1091556Srgrimesint f_timesort; /* sort by time vice name */ 1101556Srgrimesint f_type; /* add type character for non-regular files */ 11120417Ssteveint f_whiteout; /* show whiteout entries */ 1121556Srgrimes 11317852Sadamint rval; 11417852Sadam 1151556Srgrimesint 1161556Srgrimesmain(argc, argv) 1171556Srgrimes int argc; 1181556Srgrimes char *argv[]; 1191556Srgrimes{ 1201556Srgrimes static char dot[] = ".", *dotav[] = { dot, NULL }; 1211556Srgrimes struct winsize win; 1221556Srgrimes int ch, fts_options, notused; 1231556Srgrimes char *p; 1241556Srgrimes 12511808Sache (void) setlocale(LC_ALL, ""); 12611808Sache 1271556Srgrimes /* Terminal defaults to -Cq, non-terminal defaults to -1. */ 1281556Srgrimes if (isatty(STDOUT_FILENO)) { 1291556Srgrimes if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 || 1301556Srgrimes !win.ws_col) { 1311556Srgrimes if ((p = getenv("COLUMNS")) != NULL) 1321556Srgrimes termwidth = atoi(p); 1331556Srgrimes } 1341556Srgrimes else 1351556Srgrimes termwidth = win.ws_col; 1361556Srgrimes f_column = f_nonprint = 1; 1375158Sjoerg } else { 1381556Srgrimes f_singlecol = 1; 1395158Sjoerg /* retrieve environment variable, in case of explicit -C */ 1407165Sjoerg if ((p = getenv("COLUMNS"))) 1415158Sjoerg termwidth = atoi(p); 1425158Sjoerg } 1431556Srgrimes 1441556Srgrimes /* Root is -A automatically. */ 1451556Srgrimes if (!getuid()) 1461556Srgrimes f_listdot = 1; 1471556Srgrimes 1481556Srgrimes fts_options = FTS_PHYSICAL; 14949373Ssheldonh while ((ch = getopt(argc, argv, "1ABCFHLPRTWabcdfgiklnoqrstu")) != -1) { 1501556Srgrimes switch (ch) { 1511556Srgrimes /* 1521556Srgrimes * The -1, -C and -l options all override each other so shell 1531556Srgrimes * aliasing works right. 1541556Srgrimes */ 1551556Srgrimes case '1': 1561556Srgrimes f_singlecol = 1; 1571556Srgrimes f_column = f_longform = 0; 1581556Srgrimes break; 15935417Sdes case 'B': 16035417Sdes f_nonprint = 0; 16135417Sdes f_octal = 1; 16235417Sdes f_octal_escape = 0; 16335417Sdes break; 1641556Srgrimes case 'C': 1651556Srgrimes f_column = 1; 1661556Srgrimes f_longform = f_singlecol = 0; 1671556Srgrimes break; 1681556Srgrimes case 'l': 1691556Srgrimes f_longform = 1; 1701556Srgrimes f_column = f_singlecol = 0; 1711556Srgrimes break; 1721556Srgrimes /* The -c and -u options override each other. */ 1731556Srgrimes case 'c': 1741556Srgrimes f_statustime = 1; 1751556Srgrimes f_accesstime = 0; 1761556Srgrimes break; 1771556Srgrimes case 'u': 1781556Srgrimes f_accesstime = 1; 1791556Srgrimes f_statustime = 0; 1801556Srgrimes break; 1811556Srgrimes case 'F': 1821556Srgrimes f_type = 1; 1831556Srgrimes break; 18435426Sdes case 'H': 18535426Sdes fts_options |= FTS_COMFOLLOW; 18635426Sdes break; 1871556Srgrimes case 'L': 1881556Srgrimes fts_options &= ~FTS_PHYSICAL; 1891556Srgrimes fts_options |= FTS_LOGICAL; 1901556Srgrimes break; 19135426Sdes case 'P': 19235426Sdes fts_options &= ~FTS_COMFOLLOW; 19335426Sdes fts_options &= ~FTS_LOGICAL; 19435426Sdes fts_options |= FTS_PHYSICAL; 19535426Sdes break; 1961556Srgrimes case 'R': 1971556Srgrimes f_recursive = 1; 1981556Srgrimes break; 1991556Srgrimes case 'a': 2001556Srgrimes fts_options |= FTS_SEEDOT; 2011556Srgrimes /* FALLTHROUGH */ 2021556Srgrimes case 'A': 2031556Srgrimes f_listdot = 1; 2041556Srgrimes break; 2051556Srgrimes /* The -d option turns off the -R option. */ 2061556Srgrimes case 'd': 2071556Srgrimes f_listdir = 1; 2081556Srgrimes f_recursive = 0; 2091556Srgrimes break; 2101556Srgrimes case 'f': 2111556Srgrimes f_nosort = 1; 2121556Srgrimes break; 2131556Srgrimes case 'g': /* Compatibility with 4.3BSD. */ 2141556Srgrimes break; 2151556Srgrimes case 'i': 2161556Srgrimes f_inode = 1; 2171556Srgrimes break; 2182889Spst case 'k': 2192889Spst f_kblocks = 1; 2202889Spst break; 22149373Ssheldonh case 'n': 22249373Ssheldonh f_numericonly = 1; 22349373Ssheldonh break; 2241556Srgrimes case 'o': 2251556Srgrimes f_flags = 1; 2261556Srgrimes break; 2271556Srgrimes case 'q': 2281556Srgrimes f_nonprint = 1; 22935373Sdes f_octal = 0; 23035417Sdes f_octal_escape = 0; 2311556Srgrimes break; 2321556Srgrimes case 'r': 2331556Srgrimes f_reversesort = 1; 2341556Srgrimes break; 2351556Srgrimes case 's': 2361556Srgrimes f_size = 1; 2371556Srgrimes break; 2381556Srgrimes case 'T': 2391556Srgrimes f_sectime = 1; 2401556Srgrimes break; 2411556Srgrimes case 't': 2421556Srgrimes f_timesort = 1; 2431556Srgrimes break; 24420417Ssteve case 'W': 24520417Ssteve f_whiteout = 1; 24620417Ssteve break; 24735373Sdes case 'b': 24835373Sdes f_nonprint = 0; 24935417Sdes f_octal = 0; 25035417Sdes f_octal_escape = 1; 25135373Sdes break; 2521556Srgrimes default: 2531556Srgrimes case '?': 2541556Srgrimes usage(); 2551556Srgrimes } 2561556Srgrimes } 2571556Srgrimes argc -= optind; 2581556Srgrimes argv += optind; 2591556Srgrimes 2601556Srgrimes /* 2611556Srgrimes * If not -F, -i, -l, -s or -t options, don't require stat 2621556Srgrimes * information. 2631556Srgrimes */ 2641556Srgrimes if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type) 2651556Srgrimes fts_options |= FTS_NOSTAT; 2661556Srgrimes 2671556Srgrimes /* 2681556Srgrimes * If not -F, -d or -l options, follow any symbolic links listed on 2691556Srgrimes * the command line. 2701556Srgrimes */ 2711556Srgrimes if (!f_longform && !f_listdir && !f_type) 2721556Srgrimes fts_options |= FTS_COMFOLLOW; 2731556Srgrimes 27420417Ssteve /* 27520417Ssteve * If -W, show whiteout entries 27620417Ssteve */ 27720417Ssteve#ifdef FTS_WHITEOUT 27820417Ssteve if (f_whiteout) 27920417Ssteve fts_options |= FTS_WHITEOUT; 28020417Ssteve#endif 28120417Ssteve 2821556Srgrimes /* If -l or -s, figure out block size. */ 2831556Srgrimes if (f_longform || f_size) { 2842889Spst if (f_kblocks) 2857282Sphk blocksize = 2; 2867282Sphk else { 2877282Sphk (void)getbsize(¬used, &blocksize); 2887282Sphk blocksize /= 512; 2897282Sphk } 2901556Srgrimes } 2911556Srgrimes 2921556Srgrimes /* Select a sort function. */ 2931556Srgrimes if (f_reversesort) { 2941556Srgrimes if (!f_timesort) 2951556Srgrimes sortfcn = revnamecmp; 2961556Srgrimes else if (f_accesstime) 2971556Srgrimes sortfcn = revacccmp; 2981556Srgrimes else if (f_statustime) 2991556Srgrimes sortfcn = revstatcmp; 3001556Srgrimes else /* Use modification time. */ 3011556Srgrimes sortfcn = revmodcmp; 3021556Srgrimes } else { 3031556Srgrimes if (!f_timesort) 3041556Srgrimes sortfcn = namecmp; 3051556Srgrimes else if (f_accesstime) 3061556Srgrimes sortfcn = acccmp; 3071556Srgrimes else if (f_statustime) 3081556Srgrimes sortfcn = statcmp; 3091556Srgrimes else /* Use modification time. */ 3101556Srgrimes sortfcn = modcmp; 3111556Srgrimes } 3121556Srgrimes 3131556Srgrimes /* Select a print function. */ 3141556Srgrimes if (f_singlecol) 3151556Srgrimes printfcn = printscol; 3161556Srgrimes else if (f_longform) 3171556Srgrimes printfcn = printlong; 3181556Srgrimes else 3191556Srgrimes printfcn = printcol; 3201556Srgrimes 3211556Srgrimes if (argc) 3221556Srgrimes traverse(argc, argv, fts_options); 3231556Srgrimes else 3241556Srgrimes traverse(1, dotav, fts_options); 32517852Sadam exit(rval); 3261556Srgrimes} 3271556Srgrimes 3281556Srgrimesstatic int output; /* If anything output. */ 3291556Srgrimes 3301556Srgrimes/* 3311556Srgrimes * Traverse() walks the logical directory structure specified by the argv list 3321556Srgrimes * in the order specified by the mastercmp() comparison function. During the 3331556Srgrimes * traversal it passes linked lists of structures to display() which represent 3341556Srgrimes * a superset (may be exact set) of the files to be displayed. 3351556Srgrimes */ 3361556Srgrimesstatic void 3371556Srgrimestraverse(argc, argv, options) 3381556Srgrimes int argc, options; 3391556Srgrimes char *argv[]; 3401556Srgrimes{ 3411556Srgrimes FTS *ftsp; 3421556Srgrimes FTSENT *p, *chp; 3431556Srgrimes int ch_options; 3441556Srgrimes 3451556Srgrimes if ((ftsp = 3461556Srgrimes fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) 3471556Srgrimes err(1, NULL); 3481556Srgrimes 3491556Srgrimes display(NULL, fts_children(ftsp, 0)); 3501556Srgrimes if (f_listdir) 3511556Srgrimes return; 3521556Srgrimes 3531556Srgrimes /* 3541556Srgrimes * If not recursing down this tree and don't need stat info, just get 3551556Srgrimes * the names. 3561556Srgrimes */ 3571556Srgrimes ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; 3581556Srgrimes 3591556Srgrimes while ((p = fts_read(ftsp)) != NULL) 3601556Srgrimes switch (p->fts_info) { 3611556Srgrimes case FTS_DC: 3621556Srgrimes warnx("%s: directory causes a cycle", p->fts_name); 3631556Srgrimes break; 3641556Srgrimes case FTS_DNR: 3651556Srgrimes case FTS_ERR: 3661556Srgrimes warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); 36717852Sadam rval = 1; 3681556Srgrimes break; 3691556Srgrimes case FTS_D: 3701556Srgrimes if (p->fts_level != FTS_ROOTLEVEL && 3711556Srgrimes p->fts_name[0] == '.' && !f_listdot) 3721556Srgrimes break; 3731556Srgrimes 3741556Srgrimes /* 3751556Srgrimes * If already output something, put out a newline as 3761556Srgrimes * a separator. If multiple arguments, precede each 3771556Srgrimes * directory with its name. 3781556Srgrimes */ 3791556Srgrimes if (output) 3801556Srgrimes (void)printf("\n%s:\n", p->fts_path); 3811556Srgrimes else if (argc > 1) { 3821556Srgrimes (void)printf("%s:\n", p->fts_path); 3831556Srgrimes output = 1; 3841556Srgrimes } 3851556Srgrimes 3861556Srgrimes chp = fts_children(ftsp, ch_options); 3871556Srgrimes display(p, chp); 3881556Srgrimes 3891556Srgrimes if (!f_recursive && chp != NULL) 3901556Srgrimes (void)fts_set(ftsp, p, FTS_SKIP); 3911556Srgrimes break; 3921556Srgrimes } 3931556Srgrimes if (errno) 3941556Srgrimes err(1, "fts_read"); 3951556Srgrimes} 3961556Srgrimes 3971556Srgrimes/* 3981556Srgrimes * Display() takes a linked list of FTSENT structures and passes the list 3991556Srgrimes * along with any other necessary information to the print function. P 4001556Srgrimes * points to the parent directory of the display list. 4011556Srgrimes */ 4021556Srgrimesstatic void 4031556Srgrimesdisplay(p, list) 4041556Srgrimes FTSENT *p, *list; 4051556Srgrimes{ 4061556Srgrimes struct stat *sp; 4071556Srgrimes DISPLAY d; 4081556Srgrimes FTSENT *cur; 4091556Srgrimes NAMES *np; 4101556Srgrimes u_quad_t maxsize; 4111556Srgrimes u_long btotal, maxblock, maxinode, maxlen, maxnlink; 4121556Srgrimes int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; 41337932Shoek char *initmax; 4141556Srgrimes int entries, needstats; 41549373Ssheldonh char *user, *group, *flags; 41650050Ssheldonh char buf[STRBUF_SIZEOF(u_quad_t) + 1]; 41750050Ssheldonh char ngroup[STRBUF_SIZEOF(uid_t) + 1]; 41850050Ssheldonh char nuser[STRBUF_SIZEOF(gid_t) + 1]; 4191556Srgrimes 4201556Srgrimes /* 4211556Srgrimes * If list is NULL there are two possibilities: that the parent 4221556Srgrimes * directory p has no children, or that fts_children() returned an 4231556Srgrimes * error. We ignore the error case since it will be replicated 4241556Srgrimes * on the next call to fts_read() on the post-order visit to the 42546684Skris * directory p, and will be signaled in traverse(). 4261556Srgrimes */ 4271556Srgrimes if (list == NULL) 4281556Srgrimes return; 4291556Srgrimes 4301556Srgrimes needstats = f_inode || f_longform || f_size; 4311556Srgrimes flen = 0; 43237932Shoek btotal = 0; 43337932Shoek initmax = getenv("LS_COLWIDTHS"); 43437932Shoek /* Fields match -lios order. New ones should be added at the end. */ 43537932Shoek if (initmax != NULL && *initmax != '\0') { 43637932Shoek char *initmax2, *jinitmax; 43737932Shoek int ninitmax; 43837932Shoek 43937932Shoek /* Fill-in "::" as "0:0:0" for the sake of scanf. */ 44037932Shoek jinitmax = initmax2 = malloc(strlen(initmax) * 2 + 2); 44137932Shoek if (jinitmax == NULL) 44237932Shoek err(1, NULL); 44337932Shoek if (*initmax == ':') 44437932Shoek strcpy(initmax2, "0:"), initmax2 += 2; 44537932Shoek else 44637932Shoek *initmax2++ = *initmax, *initmax2 = '\0'; 44737932Shoek for (initmax++; *initmax != '\0'; initmax++) { 44837932Shoek if (initmax[-1] == ':' && initmax[0] == ':') { 44937932Shoek *initmax2++ = '0'; 45037932Shoek *initmax2++ = initmax[0]; 45137932Shoek initmax2[1] = '\0'; 45237932Shoek } else { 45337932Shoek *initmax2++ = initmax[0]; 45437932Shoek initmax2[1] = '\0'; 45537932Shoek } 45637932Shoek } 45737932Shoek if (initmax2[-1] == ':') strcpy(initmax2, "0"); 45837932Shoek 45937932Shoek ninitmax = sscanf(jinitmax, 46037932Shoek " %lu : %lu : %lu : %i : %i : %i : %qu : %lu ", 46137932Shoek &maxinode, &maxblock, &maxnlink, &maxuser, 46237932Shoek &maxgroup, &maxflags, &maxsize, &maxlen); 46337932Shoek f_notabs = 1; 46437932Shoek switch (ninitmax) { 46537932Shoek case 0: maxinode = 0; 46637932Shoek case 1: maxblock = 0; 46737932Shoek case 2: maxnlink = 0; 46837932Shoek case 3: maxuser = 0; 46937932Shoek case 4: maxgroup = 0; 47037932Shoek case 5: maxflags = 0; 47137932Shoek case 6: maxsize = 0; 47237932Shoek case 7: maxlen = 0, f_notabs = 0; 47337932Shoek } 47437932Shoek maxinode = makenines(maxinode); 47537932Shoek maxblock = makenines(maxblock); 47637932Shoek maxnlink = makenines(maxnlink); 47737932Shoek maxsize = makenines(maxsize); 47838026Shoek } else if (initmax == NULL || *initmax == '\0') 47937932Shoek maxblock = maxinode = maxlen = maxnlink = 48038026Shoek maxuser = maxgroup = maxflags = maxsize = 0; 4811556Srgrimes bcfile = 0; 4827165Sjoerg flags = NULL; 4831556Srgrimes for (cur = list, entries = 0; cur; cur = cur->fts_link) { 4841556Srgrimes if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { 4851556Srgrimes warnx("%s: %s", 4861556Srgrimes cur->fts_name, strerror(cur->fts_errno)); 4871556Srgrimes cur->fts_number = NO_PRINT; 48817852Sadam rval = 1; 4891556Srgrimes continue; 4901556Srgrimes } 4911556Srgrimes 4921556Srgrimes /* 4931556Srgrimes * P is NULL if list is the argv list, to which different rules 4941556Srgrimes * apply. 4951556Srgrimes */ 4961556Srgrimes if (p == NULL) { 4971556Srgrimes /* Directories will be displayed later. */ 4981556Srgrimes if (cur->fts_info == FTS_D && !f_listdir) { 4991556Srgrimes cur->fts_number = NO_PRINT; 5001556Srgrimes continue; 5011556Srgrimes } 5021556Srgrimes } else { 5031556Srgrimes /* Only display dot file if -a/-A set. */ 5041556Srgrimes if (cur->fts_name[0] == '.' && !f_listdot) { 5051556Srgrimes cur->fts_number = NO_PRINT; 5061556Srgrimes continue; 5071556Srgrimes } 5081556Srgrimes } 5091556Srgrimes if (f_nonprint) 5101556Srgrimes prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen); 5111556Srgrimes if (cur->fts_namelen > maxlen) 5121556Srgrimes maxlen = cur->fts_namelen; 51335417Sdes if (f_octal || f_octal_escape) { 51435373Sdes int t = len_octal(cur->fts_name, cur->fts_namelen); 51535373Sdes if (t > maxlen) maxlen = t; 51637932Shoek } 5171556Srgrimes if (needstats) { 5181556Srgrimes sp = cur->fts_statp; 5191556Srgrimes if (sp->st_blocks > maxblock) 5201556Srgrimes maxblock = sp->st_blocks; 5211556Srgrimes if (sp->st_ino > maxinode) 5221556Srgrimes maxinode = sp->st_ino; 5231556Srgrimes if (sp->st_nlink > maxnlink) 5241556Srgrimes maxnlink = sp->st_nlink; 5251556Srgrimes if (sp->st_size > maxsize) 5261556Srgrimes maxsize = sp->st_size; 5271556Srgrimes 5281556Srgrimes btotal += sp->st_blocks; 5291556Srgrimes if (f_longform) { 53049373Ssheldonh if (f_numericonly) { 53149373Ssheldonh (void)snprintf(nuser, sizeof(nuser), 53249373Ssheldonh "%u", sp->st_uid); 53349373Ssheldonh (void)snprintf(ngroup, sizeof(ngroup), 53449373Ssheldonh "%u", sp->st_gid); 53549373Ssheldonh user = nuser; 53649373Ssheldonh group = ngroup; 53749373Ssheldonh } else { 53849373Ssheldonh user = user_from_uid(sp->st_uid, 0); 53949373Ssheldonh group = group_from_gid(sp->st_gid, 0); 54049373Ssheldonh } 5411556Srgrimes if ((ulen = strlen(user)) > maxuser) 5421556Srgrimes maxuser = ulen; 5431556Srgrimes if ((glen = strlen(group)) > maxgroup) 5441556Srgrimes maxgroup = glen; 5451556Srgrimes if (f_flags) { 5461556Srgrimes flags = 5471556Srgrimes flags_to_string(sp->st_flags, "-"); 5481556Srgrimes if ((flen = strlen(flags)) > maxflags) 5491556Srgrimes maxflags = flen; 5501556Srgrimes } else 5511556Srgrimes flen = 0; 5521556Srgrimes 5531556Srgrimes if ((np = malloc(sizeof(NAMES) + 5541556Srgrimes ulen + glen + flen + 3)) == NULL) 5551556Srgrimes err(1, NULL); 5561556Srgrimes 5571556Srgrimes np->user = &np->data[0]; 5581556Srgrimes (void)strcpy(np->user, user); 5591556Srgrimes np->group = &np->data[ulen + 1]; 5601556Srgrimes (void)strcpy(np->group, group); 5611556Srgrimes 5621556Srgrimes if (S_ISCHR(sp->st_mode) || 5631556Srgrimes S_ISBLK(sp->st_mode)) 5641556Srgrimes bcfile = 1; 5651556Srgrimes 5661556Srgrimes if (f_flags) { 5671556Srgrimes np->flags = &np->data[ulen + glen + 2]; 5681556Srgrimes (void)strcpy(np->flags, flags); 5691556Srgrimes } 5701556Srgrimes cur->fts_pointer = np; 5711556Srgrimes } 5721556Srgrimes } 5731556Srgrimes ++entries; 5741556Srgrimes } 5751556Srgrimes 5761556Srgrimes if (!entries) 5771556Srgrimes return; 5781556Srgrimes 5791556Srgrimes d.list = list; 5801556Srgrimes d.entries = entries; 5811556Srgrimes d.maxlen = maxlen; 5821556Srgrimes if (needstats) { 5831556Srgrimes d.bcfile = bcfile; 5841556Srgrimes d.btotal = btotal; 5851556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxblock); 5861556Srgrimes d.s_block = strlen(buf); 5871556Srgrimes d.s_flags = maxflags; 5881556Srgrimes d.s_group = maxgroup; 5891556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxinode); 5901556Srgrimes d.s_inode = strlen(buf); 5911556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); 5921556Srgrimes d.s_nlink = strlen(buf); 5931556Srgrimes (void)snprintf(buf, sizeof(buf), "%qu", maxsize); 5941556Srgrimes d.s_size = strlen(buf); 5951556Srgrimes d.s_user = maxuser; 5961556Srgrimes } 5971556Srgrimes 5981556Srgrimes printfcn(&d); 5991556Srgrimes output = 1; 6001556Srgrimes 6011556Srgrimes if (f_longform) 6021556Srgrimes for (cur = list; cur; cur = cur->fts_link) 6031556Srgrimes free(cur->fts_pointer); 6041556Srgrimes} 6051556Srgrimes 6061556Srgrimes/* 6071556Srgrimes * Ordering for mastercmp: 6081556Srgrimes * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories 6091556Srgrimes * as larger than directories. Within either group, use the sort function. 6101556Srgrimes * All other levels use the sort function. Error entries remain unsorted. 6111556Srgrimes */ 6121556Srgrimesstatic int 6131556Srgrimesmastercmp(a, b) 6141556Srgrimes const FTSENT **a, **b; 6151556Srgrimes{ 6161556Srgrimes int a_info, b_info; 6171556Srgrimes 6181556Srgrimes a_info = (*a)->fts_info; 6191556Srgrimes if (a_info == FTS_ERR) 6201556Srgrimes return (0); 6211556Srgrimes b_info = (*b)->fts_info; 6221556Srgrimes if (b_info == FTS_ERR) 6231556Srgrimes return (0); 6241556Srgrimes 6251556Srgrimes if (a_info == FTS_NS || b_info == FTS_NS) 6261556Srgrimes return (namecmp(*a, *b)); 6271556Srgrimes 62829560Ssef if (a_info != b_info && 62929560Ssef (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) { 6301556Srgrimes if (a_info == FTS_D) 6311556Srgrimes return (1); 63229560Ssef if (b_info == FTS_D) 6331556Srgrimes return (-1); 63429560Ssef } 63529560Ssef return (sortfcn(*a, *b)); 6361556Srgrimes} 63737932Shoek 63837932Shoek/* 63937932Shoek * Makenines() returns (10**n)-1. This is useful for converting a width 64037932Shoek * into a number that wide in decimal. 64137932Shoek */ 64237932Shoekstatic u_quad_t 64337932Shoekmakenines(n) 64437932Shoek u_long n; 64537932Shoek{ 64637932Shoek u_long i; 64737932Shoek u_quad_t reg; 64837932Shoek 64937932Shoek reg = 1; 65037932Shoek /* Use a loop instead of pow(), since all values of n are small. */ 65137932Shoek for (i = 0; i < n; i++) 65237932Shoek reg *= 10; 65337932Shoek reg--; 65437932Shoek 65537932Shoek return reg; 65637932Shoek} 657