ls.c revision 61271
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[] = 4850471Speter "$FreeBSD: head/bin/ls/ls.c 61271 2000-06-05 03:51:29Z joe $"; 4927967Ssteve#endif 501556Srgrimes#endif /* not lint */ 511556Srgrimes 521556Srgrimes#include <sys/types.h> 531556Srgrimes#include <sys/stat.h> 541556Srgrimes#include <sys/ioctl.h> 551556Srgrimes 5661268Sjoe#ifdef COLORLS 5761268Sjoe#include <curses.h> 5861268Sjoe#endif 591556Srgrimes#include <dirent.h> 601556Srgrimes#include <err.h> 611556Srgrimes#include <errno.h> 621556Srgrimes#include <fts.h> 6350050Ssheldonh#include <limits.h> 6450050Ssheldonh#include <locale.h> 651556Srgrimes#include <stdio.h> 661556Srgrimes#include <stdlib.h> 671556Srgrimes#include <string.h> 6861268Sjoe#ifdef COLORLS 6961268Sjoe#include <term.h> 7061268Sjoe#endif 711556Srgrimes#include <unistd.h> 721556Srgrimes 731556Srgrimes#include "ls.h" 741556Srgrimes#include "extern.h" 751556Srgrimes 7650050Ssheldonh/* 7750050Ssheldonh * Upward approximation of the maximum number of characters needed to 7850050Ssheldonh * represent a value of integral type t as a string, excluding the 7950050Ssheldonh * NUL terminator, with provision for a sign. 8050050Ssheldonh */ 8150051Ssheldonh#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) 8250050Ssheldonh 8357003Sjoechar *getflags __P((u_long, char *)); 8457003Sjoe 851556Srgrimesstatic void display __P((FTSENT *, FTSENT *)); 8637932Shoekstatic u_quad_t makenines __P((u_long)); 871556Srgrimesstatic int mastercmp __P((const FTSENT **, const FTSENT **)); 881556Srgrimesstatic void traverse __P((int, char **, int)); 891556Srgrimes 901556Srgrimesstatic void (*printfcn) __P((DISPLAY *)); 911556Srgrimesstatic int (*sortfcn) __P((const FTSENT *, const FTSENT *)); 921556Srgrimes 931556Srgrimeslong blocksize; /* block size units */ 941556Srgrimesint termwidth = 80; /* default terminal width */ 951556Srgrimes 961556Srgrimes/* flags */ 971556Srgrimesint f_accesstime; /* use time of last access */ 981556Srgrimesint f_column; /* columnated format */ 991556Srgrimesint f_flags; /* show flags associated with a file */ 1001556Srgrimesint f_inode; /* print inode */ 1012889Spstint f_kblocks; /* print size in kilobytes */ 1021556Srgrimesint f_listdir; /* list actual directory, not contents */ 1031556Srgrimesint f_listdot; /* list files beginning with . */ 1041556Srgrimesint f_longform; /* long listing format */ 1051556Srgrimesint f_nonprint; /* show unprintables as ? */ 1061556Srgrimesint f_nosort; /* don't sort output */ 10750050Ssheldonhint f_notabs; /* don't use tab-separated multi-col output */ 10849373Ssheldonhint f_numericonly; /* don't convert uid/gid to name */ 10935373Sdesint f_octal; /* show unprintables as \xxx */ 11035417Sdesint f_octal_escape; /* like f_octal but use C escapes if possible */ 1111556Srgrimesint f_recursive; /* ls subdirectories also */ 1121556Srgrimesint f_reversesort; /* reverse whatever sort is used */ 1131556Srgrimesint f_sectime; /* print the real time for all files */ 1141556Srgrimesint f_singlecol; /* use single column output */ 1151556Srgrimesint f_size; /* list size in short listing */ 1161556Srgrimesint f_statustime; /* use time of last mode change */ 1171556Srgrimesint f_timesort; /* sort by time vice name */ 1181556Srgrimesint f_type; /* add type character for non-regular files */ 11920417Ssteveint f_whiteout; /* show whiteout entries */ 12061268Sjoe#ifdef COLORLS 12161178Sjoeint f_color; /* add type in color for non-regular files */ 12261271Sjoe 12361271Sjoechar *ansi_bgcol; /* ANSI sequence to set background colour */ 12461271Sjoechar *ansi_fgcol; /* ANSI sequence to set foreground colour */ 12561271Sjoechar *ansi_coloff; /* ANSI sequence to reset colours */ 12661268Sjoe#endif 1271556Srgrimes 12817852Sadamint rval; 12917852Sadam 1301556Srgrimesint 1311556Srgrimesmain(argc, argv) 1321556Srgrimes int argc; 1331556Srgrimes char *argv[]; 1341556Srgrimes{ 1351556Srgrimes static char dot[] = ".", *dotav[] = { dot, NULL }; 1361556Srgrimes struct winsize win; 1371556Srgrimes int ch, fts_options, notused; 1381556Srgrimes char *p; 1391556Srgrimes 14061271Sjoe#ifdef COLORLS 14161271Sjoe char termcapbuf[1024]; /* termcap definition buffer */ 14261271Sjoe char tcapbuf[512]; /* capability buffer */ 14361271Sjoe char *bp = tcapbuf; 14461271Sjoe#endif 14561271Sjoe 14611808Sache (void) setlocale(LC_ALL, ""); 14711808Sache 1481556Srgrimes /* Terminal defaults to -Cq, non-terminal defaults to -1. */ 1491556Srgrimes if (isatty(STDOUT_FILENO)) { 1501556Srgrimes if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 || 1511556Srgrimes !win.ws_col) { 1521556Srgrimes if ((p = getenv("COLUMNS")) != NULL) 1531556Srgrimes termwidth = atoi(p); 1541556Srgrimes } 1551556Srgrimes else 1561556Srgrimes termwidth = win.ws_col; 1571556Srgrimes f_column = f_nonprint = 1; 1585158Sjoerg } else { 1591556Srgrimes f_singlecol = 1; 1605158Sjoerg /* retrieve environment variable, in case of explicit -C */ 1617165Sjoerg if ((p = getenv("COLUMNS"))) 1625158Sjoerg termwidth = atoi(p); 1635158Sjoerg } 1641556Srgrimes 1651556Srgrimes /* Root is -A automatically. */ 1661556Srgrimes if (!getuid()) 1671556Srgrimes f_listdot = 1; 1681556Srgrimes 1691556Srgrimes fts_options = FTS_PHYSICAL; 17061178Sjoe while ((ch = getopt(argc, argv, "1ABCFGHLPRTWabcdfgiklnoqrstu")) != -1) { 1711556Srgrimes switch (ch) { 1721556Srgrimes /* 1731556Srgrimes * The -1, -C and -l options all override each other so shell 1741556Srgrimes * aliasing works right. 1751556Srgrimes */ 1761556Srgrimes case '1': 1771556Srgrimes f_singlecol = 1; 1781556Srgrimes f_column = f_longform = 0; 1791556Srgrimes break; 18035417Sdes case 'B': 18135417Sdes f_nonprint = 0; 18235417Sdes f_octal = 1; 18335417Sdes f_octal_escape = 0; 18435417Sdes break; 1851556Srgrimes case 'C': 1861556Srgrimes f_column = 1; 1871556Srgrimes f_longform = f_singlecol = 0; 1881556Srgrimes break; 1891556Srgrimes case 'l': 1901556Srgrimes f_longform = 1; 1911556Srgrimes f_column = f_singlecol = 0; 1921556Srgrimes break; 1931556Srgrimes /* The -c and -u options override each other. */ 1941556Srgrimes case 'c': 1951556Srgrimes f_statustime = 1; 1961556Srgrimes f_accesstime = 0; 1971556Srgrimes break; 1981556Srgrimes case 'u': 1991556Srgrimes f_accesstime = 1; 2001556Srgrimes f_statustime = 0; 2011556Srgrimes break; 2021556Srgrimes case 'F': 2031556Srgrimes f_type = 1; 2041556Srgrimes break; 20535426Sdes case 'H': 20635426Sdes fts_options |= FTS_COMFOLLOW; 20735426Sdes break; 20861178Sjoe case 'G': 20961178Sjoe if (isatty(STDOUT_FILENO)) 21061268Sjoe#ifdef COLORLS 21161271Sjoe if (tgetent(termcapbuf, getenv("TERM")) == 1) { 21261271Sjoe ansi_fgcol = tgetstr("AF", &bp); 21361271Sjoe ansi_bgcol = tgetstr("AB", &bp); 21461271Sjoe 21561271Sjoe /* To switch colours off use 'op' if 21661271Sjoe * available, otherwise use 'oc', or 21761271Sjoe * don't do colours at all. */ 21861271Sjoe ansi_coloff = tgetstr("op", &bp); 21961271Sjoe if (!ansi_coloff) 22061271Sjoe ansi_coloff = tgetstr("oc", &bp); 22161271Sjoe if (ansi_fgcol && ansi_bgcol && ansi_coloff) 22261271Sjoe f_color = 1; 22361271Sjoe } 22461268Sjoe#else 22561268Sjoe (void)fprintf(stderr, "Color support not compiled in.\n"); 22661268Sjoe#endif 22761178Sjoe break; 2281556Srgrimes case 'L': 2291556Srgrimes fts_options &= ~FTS_PHYSICAL; 2301556Srgrimes fts_options |= FTS_LOGICAL; 2311556Srgrimes break; 23235426Sdes case 'P': 23335426Sdes fts_options &= ~FTS_COMFOLLOW; 23435426Sdes fts_options &= ~FTS_LOGICAL; 23535426Sdes fts_options |= FTS_PHYSICAL; 23635426Sdes break; 2371556Srgrimes case 'R': 2381556Srgrimes f_recursive = 1; 2391556Srgrimes break; 2401556Srgrimes case 'a': 2411556Srgrimes fts_options |= FTS_SEEDOT; 2421556Srgrimes /* FALLTHROUGH */ 2431556Srgrimes case 'A': 2441556Srgrimes f_listdot = 1; 2451556Srgrimes break; 2461556Srgrimes /* The -d option turns off the -R option. */ 2471556Srgrimes case 'd': 2481556Srgrimes f_listdir = 1; 2491556Srgrimes f_recursive = 0; 2501556Srgrimes break; 2511556Srgrimes case 'f': 2521556Srgrimes f_nosort = 1; 2531556Srgrimes break; 2541556Srgrimes case 'g': /* Compatibility with 4.3BSD. */ 2551556Srgrimes break; 2561556Srgrimes case 'i': 2571556Srgrimes f_inode = 1; 2581556Srgrimes break; 2592889Spst case 'k': 2602889Spst f_kblocks = 1; 2612889Spst break; 26249373Ssheldonh case 'n': 26349373Ssheldonh f_numericonly = 1; 26449373Ssheldonh break; 2651556Srgrimes case 'o': 2661556Srgrimes f_flags = 1; 2671556Srgrimes break; 2681556Srgrimes case 'q': 2691556Srgrimes f_nonprint = 1; 27035373Sdes f_octal = 0; 27135417Sdes f_octal_escape = 0; 2721556Srgrimes break; 2731556Srgrimes case 'r': 2741556Srgrimes f_reversesort = 1; 2751556Srgrimes break; 2761556Srgrimes case 's': 2771556Srgrimes f_size = 1; 2781556Srgrimes break; 2791556Srgrimes case 'T': 2801556Srgrimes f_sectime = 1; 2811556Srgrimes break; 2821556Srgrimes case 't': 2831556Srgrimes f_timesort = 1; 2841556Srgrimes break; 28520417Ssteve case 'W': 28620417Ssteve f_whiteout = 1; 28720417Ssteve break; 28835373Sdes case 'b': 28935373Sdes f_nonprint = 0; 29035417Sdes f_octal = 0; 29135417Sdes f_octal_escape = 1; 29235373Sdes break; 2931556Srgrimes default: 2941556Srgrimes case '?': 2951556Srgrimes usage(); 2961556Srgrimes } 2971556Srgrimes } 2981556Srgrimes argc -= optind; 2991556Srgrimes argv += optind; 3001556Srgrimes 30161268Sjoe#ifdef COLORLS 30261178Sjoe if (f_color) 30361178Sjoe parsecolors(getenv("LSCOLORS")); 30461268Sjoe#endif 30561178Sjoe 3061556Srgrimes /* 3071556Srgrimes * If not -F, -i, -l, -s or -t options, don't require stat 30861178Sjoe * information, unless in color mode in which case we do 30961178Sjoe * need this to determine which colors to display. 3101556Srgrimes */ 31161178Sjoe if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type 31261268Sjoe#ifdef COLORLS 31361268Sjoe && !f_color 31461268Sjoe#endif 31561268Sjoe ) 3161556Srgrimes fts_options |= FTS_NOSTAT; 3171556Srgrimes 3181556Srgrimes /* 3191556Srgrimes * If not -F, -d or -l options, follow any symbolic links listed on 3201556Srgrimes * the command line. 3211556Srgrimes */ 3221556Srgrimes if (!f_longform && !f_listdir && !f_type) 3231556Srgrimes fts_options |= FTS_COMFOLLOW; 3241556Srgrimes 32520417Ssteve /* 32620417Ssteve * If -W, show whiteout entries 32720417Ssteve */ 32820417Ssteve#ifdef FTS_WHITEOUT 32920417Ssteve if (f_whiteout) 33020417Ssteve fts_options |= FTS_WHITEOUT; 33120417Ssteve#endif 33220417Ssteve 3331556Srgrimes /* If -l or -s, figure out block size. */ 3341556Srgrimes if (f_longform || f_size) { 3352889Spst if (f_kblocks) 3367282Sphk blocksize = 2; 3377282Sphk else { 3387282Sphk (void)getbsize(¬used, &blocksize); 3397282Sphk blocksize /= 512; 3407282Sphk } 3411556Srgrimes } 3421556Srgrimes 3431556Srgrimes /* Select a sort function. */ 3441556Srgrimes if (f_reversesort) { 3451556Srgrimes if (!f_timesort) 3461556Srgrimes sortfcn = revnamecmp; 3471556Srgrimes else if (f_accesstime) 3481556Srgrimes sortfcn = revacccmp; 3491556Srgrimes else if (f_statustime) 3501556Srgrimes sortfcn = revstatcmp; 3511556Srgrimes else /* Use modification time. */ 3521556Srgrimes sortfcn = revmodcmp; 3531556Srgrimes } else { 3541556Srgrimes if (!f_timesort) 3551556Srgrimes sortfcn = namecmp; 3561556Srgrimes else if (f_accesstime) 3571556Srgrimes sortfcn = acccmp; 3581556Srgrimes else if (f_statustime) 3591556Srgrimes sortfcn = statcmp; 3601556Srgrimes else /* Use modification time. */ 3611556Srgrimes sortfcn = modcmp; 3621556Srgrimes } 3631556Srgrimes 3641556Srgrimes /* Select a print function. */ 3651556Srgrimes if (f_singlecol) 3661556Srgrimes printfcn = printscol; 3671556Srgrimes else if (f_longform) 3681556Srgrimes printfcn = printlong; 3691556Srgrimes else 3701556Srgrimes printfcn = printcol; 3711556Srgrimes 3721556Srgrimes if (argc) 3731556Srgrimes traverse(argc, argv, fts_options); 3741556Srgrimes else 3751556Srgrimes traverse(1, dotav, fts_options); 37617852Sadam exit(rval); 3771556Srgrimes} 3781556Srgrimes 3791556Srgrimesstatic int output; /* If anything output. */ 3801556Srgrimes 3811556Srgrimes/* 3821556Srgrimes * Traverse() walks the logical directory structure specified by the argv list 3831556Srgrimes * in the order specified by the mastercmp() comparison function. During the 3841556Srgrimes * traversal it passes linked lists of structures to display() which represent 3851556Srgrimes * a superset (may be exact set) of the files to be displayed. 3861556Srgrimes */ 3871556Srgrimesstatic void 3881556Srgrimestraverse(argc, argv, options) 3891556Srgrimes int argc, options; 3901556Srgrimes char *argv[]; 3911556Srgrimes{ 3921556Srgrimes FTS *ftsp; 3931556Srgrimes FTSENT *p, *chp; 3941556Srgrimes int ch_options; 3951556Srgrimes 3961556Srgrimes if ((ftsp = 3971556Srgrimes fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) 3981556Srgrimes err(1, NULL); 3991556Srgrimes 4001556Srgrimes display(NULL, fts_children(ftsp, 0)); 4011556Srgrimes if (f_listdir) 4021556Srgrimes return; 4031556Srgrimes 4041556Srgrimes /* 4051556Srgrimes * If not recursing down this tree and don't need stat info, just get 4061556Srgrimes * the names. 4071556Srgrimes */ 4081556Srgrimes ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; 4091556Srgrimes 4101556Srgrimes while ((p = fts_read(ftsp)) != NULL) 4111556Srgrimes switch (p->fts_info) { 4121556Srgrimes case FTS_DC: 4131556Srgrimes warnx("%s: directory causes a cycle", p->fts_name); 4141556Srgrimes break; 4151556Srgrimes case FTS_DNR: 4161556Srgrimes case FTS_ERR: 4171556Srgrimes warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); 41817852Sadam rval = 1; 4191556Srgrimes break; 4201556Srgrimes case FTS_D: 4211556Srgrimes if (p->fts_level != FTS_ROOTLEVEL && 4221556Srgrimes p->fts_name[0] == '.' && !f_listdot) 4231556Srgrimes break; 4241556Srgrimes 4251556Srgrimes /* 4261556Srgrimes * If already output something, put out a newline as 4271556Srgrimes * a separator. If multiple arguments, precede each 4281556Srgrimes * directory with its name. 4291556Srgrimes */ 4301556Srgrimes if (output) 4311556Srgrimes (void)printf("\n%s:\n", p->fts_path); 4321556Srgrimes else if (argc > 1) { 4331556Srgrimes (void)printf("%s:\n", p->fts_path); 4341556Srgrimes output = 1; 4351556Srgrimes } 4361556Srgrimes 4371556Srgrimes chp = fts_children(ftsp, ch_options); 4381556Srgrimes display(p, chp); 4391556Srgrimes 4401556Srgrimes if (!f_recursive && chp != NULL) 4411556Srgrimes (void)fts_set(ftsp, p, FTS_SKIP); 4421556Srgrimes break; 4431556Srgrimes } 4441556Srgrimes if (errno) 4451556Srgrimes err(1, "fts_read"); 4461556Srgrimes} 4471556Srgrimes 4481556Srgrimes/* 4491556Srgrimes * Display() takes a linked list of FTSENT structures and passes the list 4501556Srgrimes * along with any other necessary information to the print function. P 4511556Srgrimes * points to the parent directory of the display list. 4521556Srgrimes */ 4531556Srgrimesstatic void 4541556Srgrimesdisplay(p, list) 4551556Srgrimes FTSENT *p, *list; 4561556Srgrimes{ 4571556Srgrimes struct stat *sp; 4581556Srgrimes DISPLAY d; 4591556Srgrimes FTSENT *cur; 4601556Srgrimes NAMES *np; 4611556Srgrimes u_quad_t maxsize; 4621556Srgrimes u_long btotal, maxblock, maxinode, maxlen, maxnlink; 4631556Srgrimes int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; 46437932Shoek char *initmax; 4651556Srgrimes int entries, needstats; 46649373Ssheldonh char *user, *group, *flags; 46750050Ssheldonh char buf[STRBUF_SIZEOF(u_quad_t) + 1]; 46850050Ssheldonh char ngroup[STRBUF_SIZEOF(uid_t) + 1]; 46950050Ssheldonh char nuser[STRBUF_SIZEOF(gid_t) + 1]; 4701556Srgrimes 4711556Srgrimes /* 4721556Srgrimes * If list is NULL there are two possibilities: that the parent 4731556Srgrimes * directory p has no children, or that fts_children() returned an 4741556Srgrimes * error. We ignore the error case since it will be replicated 4751556Srgrimes * on the next call to fts_read() on the post-order visit to the 47646684Skris * directory p, and will be signaled in traverse(). 4771556Srgrimes */ 4781556Srgrimes if (list == NULL) 4791556Srgrimes return; 4801556Srgrimes 4811556Srgrimes needstats = f_inode || f_longform || f_size; 4821556Srgrimes flen = 0; 48337932Shoek btotal = 0; 48437932Shoek initmax = getenv("LS_COLWIDTHS"); 48537932Shoek /* Fields match -lios order. New ones should be added at the end. */ 48637932Shoek if (initmax != NULL && *initmax != '\0') { 48737932Shoek char *initmax2, *jinitmax; 48837932Shoek int ninitmax; 48937932Shoek 49037932Shoek /* Fill-in "::" as "0:0:0" for the sake of scanf. */ 49137932Shoek jinitmax = initmax2 = malloc(strlen(initmax) * 2 + 2); 49237932Shoek if (jinitmax == NULL) 49337932Shoek err(1, NULL); 49437932Shoek if (*initmax == ':') 49537932Shoek strcpy(initmax2, "0:"), initmax2 += 2; 49637932Shoek else 49737932Shoek *initmax2++ = *initmax, *initmax2 = '\0'; 49837932Shoek for (initmax++; *initmax != '\0'; initmax++) { 49937932Shoek if (initmax[-1] == ':' && initmax[0] == ':') { 50037932Shoek *initmax2++ = '0'; 50137932Shoek *initmax2++ = initmax[0]; 50237932Shoek initmax2[1] = '\0'; 50337932Shoek } else { 50437932Shoek *initmax2++ = initmax[0]; 50537932Shoek initmax2[1] = '\0'; 50637932Shoek } 50737932Shoek } 50837932Shoek if (initmax2[-1] == ':') strcpy(initmax2, "0"); 50937932Shoek 51037932Shoek ninitmax = sscanf(jinitmax, 51137932Shoek " %lu : %lu : %lu : %i : %i : %i : %qu : %lu ", 51237932Shoek &maxinode, &maxblock, &maxnlink, &maxuser, 51337932Shoek &maxgroup, &maxflags, &maxsize, &maxlen); 51437932Shoek f_notabs = 1; 51537932Shoek switch (ninitmax) { 51637932Shoek case 0: maxinode = 0; 51737932Shoek case 1: maxblock = 0; 51837932Shoek case 2: maxnlink = 0; 51937932Shoek case 3: maxuser = 0; 52037932Shoek case 4: maxgroup = 0; 52137932Shoek case 5: maxflags = 0; 52237932Shoek case 6: maxsize = 0; 52337932Shoek case 7: maxlen = 0, f_notabs = 0; 52437932Shoek } 52537932Shoek maxinode = makenines(maxinode); 52637932Shoek maxblock = makenines(maxblock); 52737932Shoek maxnlink = makenines(maxnlink); 52837932Shoek maxsize = makenines(maxsize); 52938026Shoek } else if (initmax == NULL || *initmax == '\0') 53037932Shoek maxblock = maxinode = maxlen = maxnlink = 53138026Shoek maxuser = maxgroup = maxflags = maxsize = 0; 5321556Srgrimes bcfile = 0; 5337165Sjoerg flags = NULL; 5341556Srgrimes for (cur = list, entries = 0; cur; cur = cur->fts_link) { 5351556Srgrimes if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { 5361556Srgrimes warnx("%s: %s", 5371556Srgrimes cur->fts_name, strerror(cur->fts_errno)); 5381556Srgrimes cur->fts_number = NO_PRINT; 53917852Sadam rval = 1; 5401556Srgrimes continue; 5411556Srgrimes } 5421556Srgrimes 5431556Srgrimes /* 5441556Srgrimes * P is NULL if list is the argv list, to which different rules 5451556Srgrimes * apply. 5461556Srgrimes */ 5471556Srgrimes if (p == NULL) { 5481556Srgrimes /* Directories will be displayed later. */ 5491556Srgrimes if (cur->fts_info == FTS_D && !f_listdir) { 5501556Srgrimes cur->fts_number = NO_PRINT; 5511556Srgrimes continue; 5521556Srgrimes } 5531556Srgrimes } else { 5541556Srgrimes /* Only display dot file if -a/-A set. */ 5551556Srgrimes if (cur->fts_name[0] == '.' && !f_listdot) { 5561556Srgrimes cur->fts_number = NO_PRINT; 5571556Srgrimes continue; 5581556Srgrimes } 5591556Srgrimes } 5601556Srgrimes if (f_nonprint) 5611556Srgrimes prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen); 5621556Srgrimes if (cur->fts_namelen > maxlen) 5631556Srgrimes maxlen = cur->fts_namelen; 56435417Sdes if (f_octal || f_octal_escape) { 56535373Sdes int t = len_octal(cur->fts_name, cur->fts_namelen); 56635373Sdes if (t > maxlen) maxlen = t; 56737932Shoek } 5681556Srgrimes if (needstats) { 5691556Srgrimes sp = cur->fts_statp; 5701556Srgrimes if (sp->st_blocks > maxblock) 5711556Srgrimes maxblock = sp->st_blocks; 5721556Srgrimes if (sp->st_ino > maxinode) 5731556Srgrimes maxinode = sp->st_ino; 5741556Srgrimes if (sp->st_nlink > maxnlink) 5751556Srgrimes maxnlink = sp->st_nlink; 5761556Srgrimes if (sp->st_size > maxsize) 5771556Srgrimes maxsize = sp->st_size; 5781556Srgrimes 5791556Srgrimes btotal += sp->st_blocks; 5801556Srgrimes if (f_longform) { 58149373Ssheldonh if (f_numericonly) { 58249373Ssheldonh (void)snprintf(nuser, sizeof(nuser), 58349373Ssheldonh "%u", sp->st_uid); 58449373Ssheldonh (void)snprintf(ngroup, sizeof(ngroup), 58549373Ssheldonh "%u", sp->st_gid); 58649373Ssheldonh user = nuser; 58749373Ssheldonh group = ngroup; 58849373Ssheldonh } else { 58949373Ssheldonh user = user_from_uid(sp->st_uid, 0); 59049373Ssheldonh group = group_from_gid(sp->st_gid, 0); 59149373Ssheldonh } 5921556Srgrimes if ((ulen = strlen(user)) > maxuser) 5931556Srgrimes maxuser = ulen; 5941556Srgrimes if ((glen = strlen(group)) > maxgroup) 5951556Srgrimes maxgroup = glen; 5961556Srgrimes if (f_flags) { 59756692Sjoe flags = getflags(sp->st_flags, "-"); 5981556Srgrimes if ((flen = strlen(flags)) > maxflags) 5991556Srgrimes maxflags = flen; 6001556Srgrimes } else 6011556Srgrimes flen = 0; 6021556Srgrimes 6031556Srgrimes if ((np = malloc(sizeof(NAMES) + 6041556Srgrimes ulen + glen + flen + 3)) == NULL) 6051556Srgrimes err(1, NULL); 6061556Srgrimes 6071556Srgrimes np->user = &np->data[0]; 6081556Srgrimes (void)strcpy(np->user, user); 6091556Srgrimes np->group = &np->data[ulen + 1]; 6101556Srgrimes (void)strcpy(np->group, group); 6111556Srgrimes 6121556Srgrimes if (S_ISCHR(sp->st_mode) || 6131556Srgrimes S_ISBLK(sp->st_mode)) 6141556Srgrimes bcfile = 1; 6151556Srgrimes 6161556Srgrimes if (f_flags) { 6171556Srgrimes np->flags = &np->data[ulen + glen + 2]; 6181556Srgrimes (void)strcpy(np->flags, flags); 6191556Srgrimes } 6201556Srgrimes cur->fts_pointer = np; 6211556Srgrimes } 6221556Srgrimes } 6231556Srgrimes ++entries; 6241556Srgrimes } 6251556Srgrimes 6261556Srgrimes if (!entries) 6271556Srgrimes return; 6281556Srgrimes 6291556Srgrimes d.list = list; 6301556Srgrimes d.entries = entries; 6311556Srgrimes d.maxlen = maxlen; 6321556Srgrimes if (needstats) { 6331556Srgrimes d.bcfile = bcfile; 6341556Srgrimes d.btotal = btotal; 6351556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxblock); 6361556Srgrimes d.s_block = strlen(buf); 6371556Srgrimes d.s_flags = maxflags; 6381556Srgrimes d.s_group = maxgroup; 6391556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxinode); 6401556Srgrimes d.s_inode = strlen(buf); 6411556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); 6421556Srgrimes d.s_nlink = strlen(buf); 6431556Srgrimes (void)snprintf(buf, sizeof(buf), "%qu", maxsize); 6441556Srgrimes d.s_size = strlen(buf); 6451556Srgrimes d.s_user = maxuser; 6461556Srgrimes } 6471556Srgrimes 6481556Srgrimes printfcn(&d); 6491556Srgrimes output = 1; 6501556Srgrimes 6511556Srgrimes if (f_longform) 6521556Srgrimes for (cur = list; cur; cur = cur->fts_link) 6531556Srgrimes free(cur->fts_pointer); 6541556Srgrimes} 6551556Srgrimes 6561556Srgrimes/* 6571556Srgrimes * Ordering for mastercmp: 6581556Srgrimes * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories 6591556Srgrimes * as larger than directories. Within either group, use the sort function. 6601556Srgrimes * All other levels use the sort function. Error entries remain unsorted. 6611556Srgrimes */ 6621556Srgrimesstatic int 6631556Srgrimesmastercmp(a, b) 6641556Srgrimes const FTSENT **a, **b; 6651556Srgrimes{ 6661556Srgrimes int a_info, b_info; 6671556Srgrimes 6681556Srgrimes a_info = (*a)->fts_info; 6691556Srgrimes if (a_info == FTS_ERR) 6701556Srgrimes return (0); 6711556Srgrimes b_info = (*b)->fts_info; 6721556Srgrimes if (b_info == FTS_ERR) 6731556Srgrimes return (0); 6741556Srgrimes 6751556Srgrimes if (a_info == FTS_NS || b_info == FTS_NS) 6761556Srgrimes return (namecmp(*a, *b)); 6771556Srgrimes 67829560Ssef if (a_info != b_info && 67929560Ssef (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) { 6801556Srgrimes if (a_info == FTS_D) 6811556Srgrimes return (1); 68229560Ssef if (b_info == FTS_D) 6831556Srgrimes return (-1); 68429560Ssef } 68529560Ssef return (sortfcn(*a, *b)); 6861556Srgrimes} 68737932Shoek 68837932Shoek/* 68937932Shoek * Makenines() returns (10**n)-1. This is useful for converting a width 69037932Shoek * into a number that wide in decimal. 69137932Shoek */ 69237932Shoekstatic u_quad_t 69337932Shoekmakenines(n) 69437932Shoek u_long n; 69537932Shoek{ 69637932Shoek u_long i; 69737932Shoek u_quad_t reg; 69837932Shoek 69937932Shoek reg = 1; 70037932Shoek /* Use a loop instead of pow(), since all values of n are small. */ 70137932Shoek for (i = 0; i < n; i++) 70237932Shoek reg *= 10; 70337932Shoek reg--; 70437932Shoek 70537932Shoek return reg; 70637932Shoek} 707