ls.c revision 7165
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. 353044Sdg * 367165Sjoerg * $Id: ls.c,v 1.4 1994/12/18 19:00:01 joerg Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 401556Srgrimesstatic char copyright[] = 411556Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 421556Srgrimes The Regents of the University of California. All rights reserved.\n"; 431556Srgrimes#endif /* not lint */ 441556Srgrimes 451556Srgrimes#ifndef lint 461556Srgrimesstatic char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94"; 471556Srgrimes#endif /* not lint */ 481556Srgrimes 491556Srgrimes#include <sys/types.h> 501556Srgrimes#include <sys/stat.h> 511556Srgrimes#include <sys/ioctl.h> 521556Srgrimes 531556Srgrimes#include <dirent.h> 541556Srgrimes#include <err.h> 551556Srgrimes#include <errno.h> 561556Srgrimes#include <fts.h> 571556Srgrimes#include <stdio.h> 581556Srgrimes#include <stdlib.h> 591556Srgrimes#include <string.h> 601556Srgrimes#include <unistd.h> 611556Srgrimes 621556Srgrimes#include "ls.h" 631556Srgrimes#include "extern.h" 641556Srgrimes 651556Srgrimesstatic void display __P((FTSENT *, FTSENT *)); 661556Srgrimesstatic int mastercmp __P((const FTSENT **, const FTSENT **)); 671556Srgrimesstatic void traverse __P((int, char **, int)); 681556Srgrimes 691556Srgrimesstatic void (*printfcn) __P((DISPLAY *)); 701556Srgrimesstatic int (*sortfcn) __P((const FTSENT *, const FTSENT *)); 711556Srgrimes 721556Srgrimeslong blocksize; /* block size units */ 731556Srgrimesint termwidth = 80; /* default terminal width */ 741556Srgrimes 751556Srgrimes/* flags */ 761556Srgrimesint f_accesstime; /* use time of last access */ 771556Srgrimesint f_column; /* columnated format */ 781556Srgrimesint f_flags; /* show flags associated with a file */ 791556Srgrimesint f_inode; /* print inode */ 802889Spstint f_kblocks; /* print size in kilobytes */ 811556Srgrimesint f_listdir; /* list actual directory, not contents */ 821556Srgrimesint f_listdot; /* list files beginning with . */ 831556Srgrimesint f_longform; /* long listing format */ 841556Srgrimesint f_newline; /* if precede with newline */ 851556Srgrimesint f_nonprint; /* show unprintables as ? */ 861556Srgrimesint f_nosort; /* don't sort output */ 871556Srgrimesint f_recursive; /* ls subdirectories also */ 881556Srgrimesint f_reversesort; /* reverse whatever sort is used */ 891556Srgrimesint f_sectime; /* print the real time for all files */ 901556Srgrimesint f_singlecol; /* use single column output */ 911556Srgrimesint f_size; /* list size in short listing */ 921556Srgrimesint f_statustime; /* use time of last mode change */ 931556Srgrimesint f_dirname; /* if precede with directory name */ 941556Srgrimesint f_timesort; /* sort by time vice name */ 951556Srgrimesint f_type; /* add type character for non-regular files */ 961556Srgrimes 971556Srgrimesint 981556Srgrimesmain(argc, argv) 991556Srgrimes int argc; 1001556Srgrimes char *argv[]; 1011556Srgrimes{ 1021556Srgrimes static char dot[] = ".", *dotav[] = { dot, NULL }; 1031556Srgrimes struct winsize win; 1041556Srgrimes int ch, fts_options, notused; 1051556Srgrimes char *p; 1061556Srgrimes 1071556Srgrimes /* Terminal defaults to -Cq, non-terminal defaults to -1. */ 1081556Srgrimes if (isatty(STDOUT_FILENO)) { 1091556Srgrimes if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 || 1101556Srgrimes !win.ws_col) { 1111556Srgrimes if ((p = getenv("COLUMNS")) != NULL) 1121556Srgrimes termwidth = atoi(p); 1131556Srgrimes } 1141556Srgrimes else 1151556Srgrimes termwidth = win.ws_col; 1161556Srgrimes f_column = f_nonprint = 1; 1175158Sjoerg } else { 1181556Srgrimes f_singlecol = 1; 1195158Sjoerg /* retrieve environment variable, in case of explicit -C */ 1207165Sjoerg if ((p = getenv("COLUMNS"))) 1215158Sjoerg termwidth = atoi(p); 1225158Sjoerg } 1231556Srgrimes 1241556Srgrimes /* Root is -A automatically. */ 1251556Srgrimes if (!getuid()) 1261556Srgrimes f_listdot = 1; 1271556Srgrimes 1281556Srgrimes fts_options = FTS_PHYSICAL; 1292889Spst while ((ch = getopt(argc, argv, "1ACFLRTacdfgikloqrstu")) != EOF) { 1301556Srgrimes switch (ch) { 1311556Srgrimes /* 1321556Srgrimes * The -1, -C and -l options all override each other so shell 1331556Srgrimes * aliasing works right. 1341556Srgrimes */ 1351556Srgrimes case '1': 1361556Srgrimes f_singlecol = 1; 1371556Srgrimes f_column = f_longform = 0; 1381556Srgrimes break; 1391556Srgrimes case 'C': 1401556Srgrimes f_column = 1; 1411556Srgrimes f_longform = f_singlecol = 0; 1421556Srgrimes break; 1431556Srgrimes case 'l': 1441556Srgrimes f_longform = 1; 1451556Srgrimes f_column = f_singlecol = 0; 1461556Srgrimes break; 1471556Srgrimes /* The -c and -u options override each other. */ 1481556Srgrimes case 'c': 1491556Srgrimes f_statustime = 1; 1501556Srgrimes f_accesstime = 0; 1511556Srgrimes break; 1521556Srgrimes case 'u': 1531556Srgrimes f_accesstime = 1; 1541556Srgrimes f_statustime = 0; 1551556Srgrimes break; 1561556Srgrimes case 'F': 1571556Srgrimes f_type = 1; 1581556Srgrimes break; 1591556Srgrimes case 'L': 1601556Srgrimes fts_options &= ~FTS_PHYSICAL; 1611556Srgrimes fts_options |= FTS_LOGICAL; 1621556Srgrimes break; 1631556Srgrimes case 'R': 1641556Srgrimes f_recursive = 1; 1651556Srgrimes break; 1661556Srgrimes case 'a': 1671556Srgrimes fts_options |= FTS_SEEDOT; 1681556Srgrimes /* FALLTHROUGH */ 1691556Srgrimes case 'A': 1701556Srgrimes f_listdot = 1; 1711556Srgrimes break; 1721556Srgrimes /* The -d option turns off the -R option. */ 1731556Srgrimes case 'd': 1741556Srgrimes f_listdir = 1; 1751556Srgrimes f_recursive = 0; 1761556Srgrimes break; 1771556Srgrimes case 'f': 1781556Srgrimes f_nosort = 1; 1791556Srgrimes break; 1801556Srgrimes case 'g': /* Compatibility with 4.3BSD. */ 1811556Srgrimes break; 1821556Srgrimes case 'i': 1831556Srgrimes f_inode = 1; 1841556Srgrimes break; 1852889Spst case 'k': 1862889Spst f_kblocks = 1; 1872889Spst break; 1881556Srgrimes case 'o': 1891556Srgrimes f_flags = 1; 1901556Srgrimes break; 1911556Srgrimes case 'q': 1921556Srgrimes f_nonprint = 1; 1931556Srgrimes break; 1941556Srgrimes case 'r': 1951556Srgrimes f_reversesort = 1; 1961556Srgrimes break; 1971556Srgrimes case 's': 1981556Srgrimes f_size = 1; 1991556Srgrimes break; 2001556Srgrimes case 'T': 2011556Srgrimes f_sectime = 1; 2021556Srgrimes break; 2031556Srgrimes case 't': 2041556Srgrimes f_timesort = 1; 2051556Srgrimes break; 2061556Srgrimes default: 2071556Srgrimes case '?': 2081556Srgrimes usage(); 2091556Srgrimes } 2101556Srgrimes } 2111556Srgrimes argc -= optind; 2121556Srgrimes argv += optind; 2131556Srgrimes 2141556Srgrimes /* 2151556Srgrimes * If not -F, -i, -l, -s or -t options, don't require stat 2161556Srgrimes * information. 2171556Srgrimes */ 2181556Srgrimes if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type) 2191556Srgrimes fts_options |= FTS_NOSTAT; 2201556Srgrimes 2211556Srgrimes /* 2221556Srgrimes * If not -F, -d or -l options, follow any symbolic links listed on 2231556Srgrimes * the command line. 2241556Srgrimes */ 2251556Srgrimes if (!f_longform && !f_listdir && !f_type) 2261556Srgrimes fts_options |= FTS_COMFOLLOW; 2271556Srgrimes 2281556Srgrimes /* If -l or -s, figure out block size. */ 2291556Srgrimes if (f_longform || f_size) { 2301556Srgrimes (void)getbsize(¬used, &blocksize); 2312889Spst blocksize /= 512; 2322889Spst if (f_kblocks) 2332889Spst blocksize *= 2; 2341556Srgrimes } 2351556Srgrimes 2361556Srgrimes /* Select a sort function. */ 2371556Srgrimes if (f_reversesort) { 2381556Srgrimes if (!f_timesort) 2391556Srgrimes sortfcn = revnamecmp; 2401556Srgrimes else if (f_accesstime) 2411556Srgrimes sortfcn = revacccmp; 2421556Srgrimes else if (f_statustime) 2431556Srgrimes sortfcn = revstatcmp; 2441556Srgrimes else /* Use modification time. */ 2451556Srgrimes sortfcn = revmodcmp; 2461556Srgrimes } else { 2471556Srgrimes if (!f_timesort) 2481556Srgrimes sortfcn = namecmp; 2491556Srgrimes else if (f_accesstime) 2501556Srgrimes sortfcn = acccmp; 2511556Srgrimes else if (f_statustime) 2521556Srgrimes sortfcn = statcmp; 2531556Srgrimes else /* Use modification time. */ 2541556Srgrimes sortfcn = modcmp; 2551556Srgrimes } 2561556Srgrimes 2571556Srgrimes /* Select a print function. */ 2581556Srgrimes if (f_singlecol) 2591556Srgrimes printfcn = printscol; 2601556Srgrimes else if (f_longform) 2611556Srgrimes printfcn = printlong; 2621556Srgrimes else 2631556Srgrimes printfcn = printcol; 2641556Srgrimes 2651556Srgrimes if (argc) 2661556Srgrimes traverse(argc, argv, fts_options); 2671556Srgrimes else 2681556Srgrimes traverse(1, dotav, fts_options); 2691556Srgrimes exit(0); 2701556Srgrimes} 2711556Srgrimes 2721556Srgrimesstatic int output; /* If anything output. */ 2731556Srgrimes 2741556Srgrimes/* 2751556Srgrimes * Traverse() walks the logical directory structure specified by the argv list 2761556Srgrimes * in the order specified by the mastercmp() comparison function. During the 2771556Srgrimes * traversal it passes linked lists of structures to display() which represent 2781556Srgrimes * a superset (may be exact set) of the files to be displayed. 2791556Srgrimes */ 2801556Srgrimesstatic void 2811556Srgrimestraverse(argc, argv, options) 2821556Srgrimes int argc, options; 2831556Srgrimes char *argv[]; 2841556Srgrimes{ 2851556Srgrimes FTS *ftsp; 2861556Srgrimes FTSENT *p, *chp; 2871556Srgrimes int ch_options; 2881556Srgrimes 2891556Srgrimes if ((ftsp = 2901556Srgrimes fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) 2911556Srgrimes err(1, NULL); 2921556Srgrimes 2931556Srgrimes display(NULL, fts_children(ftsp, 0)); 2941556Srgrimes if (f_listdir) 2951556Srgrimes return; 2961556Srgrimes 2971556Srgrimes /* 2981556Srgrimes * If not recursing down this tree and don't need stat info, just get 2991556Srgrimes * the names. 3001556Srgrimes */ 3011556Srgrimes ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; 3021556Srgrimes 3031556Srgrimes while ((p = fts_read(ftsp)) != NULL) 3041556Srgrimes switch (p->fts_info) { 3051556Srgrimes case FTS_DC: 3061556Srgrimes warnx("%s: directory causes a cycle", p->fts_name); 3071556Srgrimes break; 3081556Srgrimes case FTS_DNR: 3091556Srgrimes case FTS_ERR: 3101556Srgrimes warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); 3111556Srgrimes break; 3121556Srgrimes case FTS_D: 3131556Srgrimes if (p->fts_level != FTS_ROOTLEVEL && 3141556Srgrimes p->fts_name[0] == '.' && !f_listdot) 3151556Srgrimes break; 3161556Srgrimes 3171556Srgrimes /* 3181556Srgrimes * If already output something, put out a newline as 3191556Srgrimes * a separator. If multiple arguments, precede each 3201556Srgrimes * directory with its name. 3211556Srgrimes */ 3221556Srgrimes if (output) 3231556Srgrimes (void)printf("\n%s:\n", p->fts_path); 3241556Srgrimes else if (argc > 1) { 3251556Srgrimes (void)printf("%s:\n", p->fts_path); 3261556Srgrimes output = 1; 3271556Srgrimes } 3281556Srgrimes 3291556Srgrimes chp = fts_children(ftsp, ch_options); 3301556Srgrimes display(p, chp); 3311556Srgrimes 3321556Srgrimes if (!f_recursive && chp != NULL) 3331556Srgrimes (void)fts_set(ftsp, p, FTS_SKIP); 3341556Srgrimes break; 3351556Srgrimes } 3361556Srgrimes if (errno) 3371556Srgrimes err(1, "fts_read"); 3381556Srgrimes} 3391556Srgrimes 3401556Srgrimes/* 3411556Srgrimes * Display() takes a linked list of FTSENT structures and passes the list 3421556Srgrimes * along with any other necessary information to the print function. P 3431556Srgrimes * points to the parent directory of the display list. 3441556Srgrimes */ 3451556Srgrimesstatic void 3461556Srgrimesdisplay(p, list) 3471556Srgrimes FTSENT *p, *list; 3481556Srgrimes{ 3491556Srgrimes struct stat *sp; 3501556Srgrimes DISPLAY d; 3511556Srgrimes FTSENT *cur; 3521556Srgrimes NAMES *np; 3531556Srgrimes u_quad_t maxsize; 3541556Srgrimes u_long btotal, maxblock, maxinode, maxlen, maxnlink; 3551556Srgrimes int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; 3561556Srgrimes int entries, needstats; 3571556Srgrimes char *user, *group, *flags, buf[20]; /* 32 bits == 10 digits */ 3581556Srgrimes 3591556Srgrimes /* 3601556Srgrimes * If list is NULL there are two possibilities: that the parent 3611556Srgrimes * directory p has no children, or that fts_children() returned an 3621556Srgrimes * error. We ignore the error case since it will be replicated 3631556Srgrimes * on the next call to fts_read() on the post-order visit to the 3641556Srgrimes * directory p, and will be signalled in traverse(). 3651556Srgrimes */ 3661556Srgrimes if (list == NULL) 3671556Srgrimes return; 3681556Srgrimes 3691556Srgrimes needstats = f_inode || f_longform || f_size; 3701556Srgrimes flen = 0; 3711556Srgrimes btotal = maxblock = maxinode = maxlen = maxnlink = 0; 3721556Srgrimes bcfile = 0; 3731556Srgrimes maxuser = maxgroup = maxflags = 0; 3747165Sjoerg flags = NULL; 3751556Srgrimes maxsize = 0; 3761556Srgrimes for (cur = list, entries = 0; cur; cur = cur->fts_link) { 3771556Srgrimes if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { 3781556Srgrimes warnx("%s: %s", 3791556Srgrimes cur->fts_name, strerror(cur->fts_errno)); 3801556Srgrimes cur->fts_number = NO_PRINT; 3811556Srgrimes continue; 3821556Srgrimes } 3831556Srgrimes 3841556Srgrimes /* 3851556Srgrimes * P is NULL if list is the argv list, to which different rules 3861556Srgrimes * apply. 3871556Srgrimes */ 3881556Srgrimes if (p == NULL) { 3891556Srgrimes /* Directories will be displayed later. */ 3901556Srgrimes if (cur->fts_info == FTS_D && !f_listdir) { 3911556Srgrimes cur->fts_number = NO_PRINT; 3921556Srgrimes continue; 3931556Srgrimes } 3941556Srgrimes } else { 3951556Srgrimes /* Only display dot file if -a/-A set. */ 3961556Srgrimes if (cur->fts_name[0] == '.' && !f_listdot) { 3971556Srgrimes cur->fts_number = NO_PRINT; 3981556Srgrimes continue; 3991556Srgrimes } 4001556Srgrimes } 4011556Srgrimes if (f_nonprint) 4021556Srgrimes prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen); 4031556Srgrimes if (cur->fts_namelen > maxlen) 4041556Srgrimes maxlen = cur->fts_namelen; 4051556Srgrimes if (needstats) { 4061556Srgrimes sp = cur->fts_statp; 4071556Srgrimes if (sp->st_blocks > maxblock) 4081556Srgrimes maxblock = sp->st_blocks; 4091556Srgrimes if (sp->st_ino > maxinode) 4101556Srgrimes maxinode = sp->st_ino; 4111556Srgrimes if (sp->st_nlink > maxnlink) 4121556Srgrimes maxnlink = sp->st_nlink; 4131556Srgrimes if (sp->st_size > maxsize) 4141556Srgrimes maxsize = sp->st_size; 4151556Srgrimes 4161556Srgrimes btotal += sp->st_blocks; 4171556Srgrimes if (f_longform) { 4181556Srgrimes user = user_from_uid(sp->st_uid, 0); 4191556Srgrimes if ((ulen = strlen(user)) > maxuser) 4201556Srgrimes maxuser = ulen; 4211556Srgrimes group = group_from_gid(sp->st_gid, 0); 4221556Srgrimes if ((glen = strlen(group)) > maxgroup) 4231556Srgrimes maxgroup = glen; 4241556Srgrimes if (f_flags) { 4251556Srgrimes flags = 4261556Srgrimes flags_to_string(sp->st_flags, "-"); 4271556Srgrimes if ((flen = strlen(flags)) > maxflags) 4281556Srgrimes maxflags = flen; 4291556Srgrimes } else 4301556Srgrimes flen = 0; 4311556Srgrimes 4321556Srgrimes if ((np = malloc(sizeof(NAMES) + 4331556Srgrimes ulen + glen + flen + 3)) == NULL) 4341556Srgrimes err(1, NULL); 4351556Srgrimes 4361556Srgrimes np->user = &np->data[0]; 4371556Srgrimes (void)strcpy(np->user, user); 4381556Srgrimes np->group = &np->data[ulen + 1]; 4391556Srgrimes (void)strcpy(np->group, group); 4401556Srgrimes 4411556Srgrimes if (S_ISCHR(sp->st_mode) || 4421556Srgrimes S_ISBLK(sp->st_mode)) 4431556Srgrimes bcfile = 1; 4441556Srgrimes 4451556Srgrimes if (f_flags) { 4461556Srgrimes np->flags = &np->data[ulen + glen + 2]; 4471556Srgrimes (void)strcpy(np->flags, flags); 4481556Srgrimes } 4491556Srgrimes cur->fts_pointer = np; 4501556Srgrimes } 4511556Srgrimes } 4521556Srgrimes ++entries; 4531556Srgrimes } 4541556Srgrimes 4551556Srgrimes if (!entries) 4561556Srgrimes return; 4571556Srgrimes 4581556Srgrimes d.list = list; 4591556Srgrimes d.entries = entries; 4601556Srgrimes d.maxlen = maxlen; 4611556Srgrimes if (needstats) { 4621556Srgrimes d.bcfile = bcfile; 4631556Srgrimes d.btotal = btotal; 4641556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxblock); 4651556Srgrimes d.s_block = strlen(buf); 4661556Srgrimes d.s_flags = maxflags; 4671556Srgrimes d.s_group = maxgroup; 4681556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxinode); 4691556Srgrimes d.s_inode = strlen(buf); 4701556Srgrimes (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); 4711556Srgrimes d.s_nlink = strlen(buf); 4721556Srgrimes (void)snprintf(buf, sizeof(buf), "%qu", maxsize); 4731556Srgrimes d.s_size = strlen(buf); 4741556Srgrimes d.s_user = maxuser; 4751556Srgrimes } 4761556Srgrimes 4771556Srgrimes printfcn(&d); 4781556Srgrimes output = 1; 4791556Srgrimes 4801556Srgrimes if (f_longform) 4811556Srgrimes for (cur = list; cur; cur = cur->fts_link) 4821556Srgrimes free(cur->fts_pointer); 4831556Srgrimes} 4841556Srgrimes 4851556Srgrimes/* 4861556Srgrimes * Ordering for mastercmp: 4871556Srgrimes * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories 4881556Srgrimes * as larger than directories. Within either group, use the sort function. 4891556Srgrimes * All other levels use the sort function. Error entries remain unsorted. 4901556Srgrimes */ 4911556Srgrimesstatic int 4921556Srgrimesmastercmp(a, b) 4931556Srgrimes const FTSENT **a, **b; 4941556Srgrimes{ 4951556Srgrimes int a_info, b_info; 4961556Srgrimes 4971556Srgrimes a_info = (*a)->fts_info; 4981556Srgrimes if (a_info == FTS_ERR) 4991556Srgrimes return (0); 5001556Srgrimes b_info = (*b)->fts_info; 5011556Srgrimes if (b_info == FTS_ERR) 5021556Srgrimes return (0); 5031556Srgrimes 5041556Srgrimes if (a_info == FTS_NS || b_info == FTS_NS) 5051556Srgrimes return (namecmp(*a, *b)); 5061556Srgrimes 5071556Srgrimes if (a_info == b_info) 5081556Srgrimes return (sortfcn(*a, *b)); 5091556Srgrimes 5101556Srgrimes if ((*a)->fts_level == FTS_ROOTLEVEL) 5111556Srgrimes if (a_info == FTS_D) 5121556Srgrimes return (1); 5131556Srgrimes else if (b_info == FTS_D) 5141556Srgrimes return (-1); 5151556Srgrimes else 5161556Srgrimes return (sortfcn(*a, *b)); 5171556Srgrimes else 5181556Srgrimes return (sortfcn(*a, *b)); 5191556Srgrimes} 520