X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2fd18a0a9295d45d4c2a5a2300218c7488712eda..d662a9c36c88e3aca3cebd9ede5fc7af570de16f:/usr/src/bin/ls/ls.c diff --git a/usr/src/bin/ls/ls.c b/usr/src/bin/ls/ls.c index 4a010dbfb1..9628f7cf25 100644 --- a/usr/src/bin/ls/ls.c +++ b/usr/src/bin/ls/ls.c @@ -1,795 +1,482 @@ /* - * Written by Michael Fischbein, currently with Sun Microsystems, Inc. - * (sun!sunbow!msf) - * 16 June 1989 18:41 + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * %sccs.include.redist.c% */ -#include + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ls.c 8.5 (Berkeley) %G%"; +#endif /* not lint */ + #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int getopt(); -extern char *optarg; -extern int optind, opterr; -extern int stat(), lstat(); - -int namecmp(); /* name comparison for qsort */ -int revnamecmp(); -int acccmp(); /* access time comparison for qsort */ -int revacccmp(); -int modcmp(); /* modify time comparixon for qsort */ -int revmodcmp(); -int statcmp(); /* status time comparixon for qsort */ -int revstatcmp(); -int printfancy(); -int prablelen(); -char *emalloc(); - -typedef struct lsstruct { - char *name; /* pointer to filename */ - struct stat lstat; -} lsstruct; - - -int qflg, Aflg, Cflg, Fflg, Lflg, Rflg, Sflg; +#include -/* - * entry point for ls. - * Parse options and call appropriate subroutines - */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ls.h" +#include "extern.h" + +static void display __P((FTSENT *, FTSENT *)); +static int mastercmp __P((const FTSENT **, const FTSENT **)); +static void traverse __P((int, char **, int)); + +static void (*printfcn) __P((DISPLAY *)); +static int (*sortfcn) __P((const FTSENT *, const FTSENT *)); + +long blocksize; /* block size units */ +int termwidth = 80; /* default terminal width */ + +/* flags */ +int f_accesstime; /* use time of last access */ +int f_column; /* columnated format */ +int f_flags; /* show flags associated with a file */ +int f_inode; /* print inode */ +int f_listdir; /* list actual directory, not contents */ +int f_listdot; /* list files beginning with . */ +int f_longform; /* long listing format */ +int f_newline; /* if precede with newline */ +int f_nonprint; /* show unprintables as ? */ +int f_nosort; /* don't sort output */ +int f_recursive; /* ls subdirectories also */ +int f_reversesort; /* reverse whatever sort is used */ +int f_sectime; /* print the real time for all files */ +int f_singlecol; /* use single column output */ +int f_size; /* list size in short listing */ +int f_statustime; /* use time of last mode change */ +int f_dirname; /* if precede with directory name */ +int f_timesort; /* sort by time vice name */ +int f_type; /* add type character for non-regular files */ + +int main(argc, argv) -int argc; -char *argv[]; - + int argc; + char *argv[]; { - static char options[] = "aAcCdfFgilLqrRstu1"; - int inch; /* input character */ - - /* set up defaults for terminal/nonterminal stdout */ - firsttimethruflag = 1; - if (isatty(1)) { - singlecolflag = 0; - sortacrossflag = 0; - nonprintflag++; - lengthfcn = prablelen; - } else { - singlecolflag++; - } - - if (getuid() == 0) { - listallflag++; - } - while ((inch = getopt(argc, argv, options)) != -1) { - switch (inch) { - case 'a': - listallflag++; - listalwaysflag++; + static char dot[] = ".", *dotav[] = { dot, NULL }; + struct winsize win; + int ch, fts_options, notused; + char *p; + + /* Terminal defaults to -Cq, non-terminal defaults to -1. */ + if (isatty(STDOUT_FILENO)) { + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 || + !win.ws_col) { + if ((p = getenv("COLUMNS")) != NULL) + termwidth = atoi(p); + } + else + termwidth = win.ws_col; + f_column = f_nonprint = 1; + } else + f_singlecol = 1; + + /* Root is -A automatically. */ + if (!getuid()) + f_listdot = 1; + + fts_options = FTS_PHYSICAL; + while ((ch = getopt(argc, argv, "1ACFLRTacdfgiloqrstu")) != EOF) { + switch (ch) { + /* + * The -1, -C and -l options all override each other so shell + * aliasing works right. + */ + case '1': + f_singlecol = 1; + f_column = f_longform = 0; break; - case 'A': - listallflag++; + case 'C': + f_column = 1; + f_longform = f_singlecol = 0; break; + case 'l': + f_longform = 1; + f_column = f_singlecol = 0; + break; + /* The -c and -u options override each other. */ case 'c': - statustimeflag++; - modtimeflag = 0; - accesstimeflag = 0; + f_statustime = 1; + f_accesstime = 0; break; - case 'C': - singlecolflag = 0; - sortacrossflag = 0; + case 'u': + f_accesstime = 1; + f_statustime = 0; break; + case 'F': + f_type = 1; + break; + case 'L': + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + break; + case 'R': + f_recursive = 1; + break; + case 'a': + fts_options |= FTS_SEEDOT; + /* FALLTHROUGH */ + case 'A': + f_listdot = 1; + break; + /* The -d option turns off the -R option. */ case 'S': Sflg++; /* fall into... */ case 'd': - listdirflag++; + f_listdir = 1; + f_recursive = 0; break; case 'f': - longformflag = 0; - timesortflag = 0; - sizeflag = 0; - reversesortflag = 0; - listallflag++; - listalwaysflag++; - specialdirflag++; - break; - case 'F': - fancyflag++; + f_nosort = 1; break; - case 'g': - groupflag++; + case 'g': /* Compatibility with 4.3BSD. */ break; case 'i': - inodeflag++; - break; - case 'l': - longformflag++; - numberflag = 0; - singlecolflag = 0; - statfcn = lstat; - if (accesstimeflag == 0 && statustimeflag == 0) { - modtimeflag++; - } + f_inode = 1; break; - case 'L': - statfcn = stat; + case 'o': + f_flags = 1; break; case 'q': - nonprintflag++; - lengthfcn = prablelen; + f_nonprint = 1; break; case 'r': - reversesortflag++; - break; - case 'R': - recursiveflag++; - statfcn = lstat; + f_reversesort = 1; break; case 's': - sizeflag++; - statfcn = lstat; + f_size = 1; break; - case 't': - timesortflag++; - if (accesstimeflag == 0 && statustimeflag == 0) { - modtimeflag++; - } - break; - case 'u': - accesstimeflag++; - modtimeflag = 0; - statustimeflag = 0; + case 'T': + f_sectime = 1; break; - case '1': - singlecolflag++; + case 't': + f_timesort = 1; break; default: case '?': - (void) fprintf(stderr, "Usage: %s [-%s] [file ...]\n", argv[0], options); - exit(1); + usage(); } - } /* end of option loop */ - /* do the work */ - if (argc > optind) { - lsdir(argc - optind, &argv[optind]); - } else { - char *defname = "."; - - lsdir(1, &defname); } -} - -/* - * list the files in a directory - */ - - -extern int errno; - -int lsdir(argc, argv) -int argc; /* count of file names passed */ -char *argv[]; /* array of file names */ - -{ - int curname; - int goodcount = 0; - lsstruct *stats; - int i; - static char curpath[MAXPATHLEN + 1]; - char *midpt; - - /* allocate memory to proceed. Lint complains, but emalloc is aligned */ - stats = (lsstruct *) emalloc((unsigned) argc * (sizeof(struct lsstruct))); - - for (curname = 0; curname < argc; ++curname) { - if (!firsttimethruflag) { + argc -= optind; + argv += optind; + + /* + * If not -F, -i, -l, -s or -t options, don't require stat + * information. + */ + if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type) + fts_options |= FTS_NOSTAT; + + /* + * If not -F, -d or -l options, follow any symbolic links listed on + * the command line. + */ + if (!f_longform && !f_listdir && !f_type) + fts_options |= FTS_COMFOLLOW; + + /* If -l or -s, figure out block size. */ + if (f_longform || f_size) { + (void)getbsize(¬used, &blocksize); + blocksize /= 512; + } - /* - * check for .xxx files. Note can't get listalways without - * listall being set - */ - if (argv[curname][0] == '.' && !listallflag) { - continue; - } - /* and now for listalways: . and .. */ - if ((argv[curname][0] == '.' && argv[curname][1] == '\0') || - (argv[curname][0] == '.' && argv[curname][1] == '.' && - argv[curname][2] == '\0')) { - if (!listalwaysflag) - continue; - } - } /* end of not firsttimethru test */ - if (firsttimethruflag || longformflag || recursiveflag || timesortflag || sizeflag || inodeflag || fancyflag) { - if (statfcn(argv[curname], &stats[goodcount].lstat) == -1) { - if (errno == ENOENT) { - (void) fprintf(stderr, "%s not found\n", argv[curname]); - continue; - } else { - perror(argv[curname]); - exit(1); - } - } /* end of stat error check */ - } - stats[goodcount].name = argv[curname]; - goodcount++; - } /* end of per name loop */ - - /* sort the names */ - if (goodcount > 1 && !specialdirflag) { - if (reversesortflag) { - if (!timesortflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), revnamecmp); - } else { - if (accesstimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), revacccmp); - } else { - if (modtimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), revmodcmp); - } else { - if (statustimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), revstatcmp); - } else { - } - } - } - } - } else { - if (!timesortflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), namecmp); - } else { - if (accesstimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), acccmp); - } else { - if (modtimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), modcmp); - } else { - if (statustimeflag) { - qsort((char *) stats, goodcount, sizeof(struct lsstruct), statcmp); - } else { - } - } - } - } - } - } /* end of sort conditionals */ - prindir(stats, goodcount); - - if ((firsttimethruflag && !listdirflag) || recursiveflag) { - for (i = 0; i < goodcount; ++i) { - /* recurse on directories */ - if ((stats[i].lstat.st_mode & S_IFMT) == S_IFDIR) { - /* don't recurse on . or .. */ - if ((stats[i].name[0] == '.' && stats[i].name[1] == '\0') || - (stats[i].name[0] == '.' && stats[i].name[1] == '.' && stats[i].name[2] == '\0')) { - if (!firsttimethruflag) { - continue; - } - } - if (chdir(stats[i].name) == -1) { - perror(stats[i].name); - break; - } - if (goodcount > 1 || !firsttimethruflag || recursiveflag) { - /* add current name to path */ - if ((midpt = strchr(curpath, (int) '\0')) != curpath) { - if (midpt[-1] != '/') { - *midpt++ = '/'; - } - } - (void) strcpy(midpt, stats[i].name); - - if (goodcount > 1 || !firsttimethruflag) { - (void) printf("\n%s:\n", curpath); - } - } - recursedir(&stats[i]); - if (goodcount > 1 || !firsttimethruflag) { - *midpt = '\0'; - } - if (chdir("..") == -1) { - perror(stats[i].name); - } - } - } /* end of for loop looking for directories */ - firsttimethruflag = 0; + /* Select a sort function. */ + if (f_reversesort) { + if (!f_timesort) + sortfcn = revnamecmp; + else if (f_accesstime) + sortfcn = revacccmp; + else if (f_statustime) + sortfcn = revstatcmp; + else /* Use modification time. */ + sortfcn = revmodcmp; + } else { + if (!f_timesort) + sortfcn = namecmp; + else if (f_accesstime) + sortfcn = acccmp; + else if (f_statustime) + sortfcn = statcmp; + else /* Use modification time. */ + sortfcn = modcmp; } - free((char *) stats); + + /* Select a print function. */ + if (f_singlecol) + printfcn = printscol; + else if (f_longform) + printfcn = printlong; + else + printfcn = printcol; + + if (argc) + traverse(argc, argv, fts_options); + else + traverse(1, dotav, fts_options); + exit(0); } +static int output; /* If anything output. */ + /* - * set up the call to lsdir (lsdir(count, argv-type array)) - * mutually recursive with lsdir + * Traverse() walks the logical directory structure specified by the argv list + * in the order specified by the mastercmp() comparison function. During the + * traversal it passes linked lists of structures to display() which represent + * a superset (may be exact set) of the files to be displayed. */ +static void +traverse(argc, argv, options) + int argc, options; + char *argv[]; +{ + FTS *ftsp; + FTSENT *p, *chp; + int ch_options; + if ((ftsp = + fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) + err(1, NULL); -recursedir(orig) -lsstruct *orig; -{ - DIR *dirp; - struct dirent *entry; - char *argvblock; - char **argv; - int blocksub = 0; - int vsub = 0; - int oldfirsttimeflag; - - if ((dirp = opendir(".")) == NULL) { - /* perror(orig->name); more info, less compatible */ - (void) fprintf(stderr, "%s unreadable\n", orig->name); + display(NULL, fts_children(ftsp, 0)); + if (f_listdir) return; - } - /* wildly overestimate dynamic amount of memory needed */ - /* lint complains about casting off_t to unsigned int. */ - argvblock = emalloc((unsigned) orig->lstat.st_size); - /* lint also complains about this alignment. It's OK */ - argv = (char **) emalloc((unsigned) orig->lstat.st_size); - - while ((entry = readdir(dirp)) != NULL) { - argv[vsub++] = strncpy(&argvblock[blocksub], entry->d_name, (int) entry->d_namlen); - blocksub += entry->d_namlen; - argvblock[blocksub++] = '\0'; - } - (void) closedir(dirp); - oldfirsttimeflag = firsttimethruflag; - firsttimethruflag = 0; + /* + * If not recursing down this tree and don't need stat info, just get + * the names. + */ + ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; - lsdir(vsub, argv); + while ((p = fts_read(ftsp)) != NULL) + switch (p->fts_info) { + case FTS_DC: + warnx("%s: directory causes a cycle", p->fts_name); + break; + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + break; + case FTS_D: + if (p->fts_level != FTS_ROOTLEVEL && + p->fts_name[0] == '.' && !f_listdot) + break; + + /* + * If already output something, put out a newline as + * a separator. If multiple arguments, precede each + * directory with its name. + */ + if (output) + (void)printf("\n%s:\n", p->fts_path); + else if (argc > 1) { + (void)printf("%s:\n", p->fts_path); + output = 1; + } - firsttimethruflag = oldfirsttimeflag; + chp = fts_children(ftsp, ch_options); + display(p, chp); - free(argvblock); - free((char *) argv); + if (!f_recursive && chp != NULL) + (void)fts_set(ftsp, p, FTS_SKIP); + break; + } + if (errno) + err(1, "fts_read"); } /* - * print a statted (if necessary), sorted directory by listing option + * Display() takes a linked list of FTSENT structures and passes the list + * along with any other necessary information to the print function. P + * points to the parent directory of the display list. */ - -int printaname(); - -prindir(stats, endcount) -lsstruct stats[]; /* the statted, sorted directory */ -int endcount; - +static void +display(p, list) + FTSENT *p, *list; { - int i; /* subscript to stats */ - int maxlen; /* length of longest name string */ - int colwidth; /* width of a printing column */ - int numcols; /* number of columns */ - int collength; /* lines in longest column */ - int base; /* subscript for leftmost column */ - int offset; /* delta from base to next column */ - int chcnt; /* character count printed */ - long blocks; /* sum of blocks in longform listing */ - - if (endcount <= 0) { /* sanity check; also if only bad names given */ + struct stat *sp; + DISPLAY d; + FTSENT *cur; + NAMES *np; + u_quad_t maxsize; + u_long btotal, maxblock, maxinode, maxlen, maxnlink; + int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; + int entries, needstats; + char *user, *group, *flags, buf[20]; /* 32 bits == 10 digits */ + + /* + * If list is NULL there are two possibilities: that the parent + * directory p has no children, or that fts_children() returned an + * error. We ignore the error case since it will be replicated + * on the next call to fts_read() on the post-order visit to the + * directory p, and will be signalled in traverse(). + */ + if (list == NULL) return; - } -/* don't print out a single directory name as argument first time around */ - if (!((firsttimethruflag && !listdirflag) && (endcount == 1) && ((stats[0].lstat.st_mode & S_IFMT) == S_IFDIR))) { - if (singlecolflag) { - for (i = 0; i < endcount; ++i) { - (void) printaname(&stats[i]); - (void) putchar('\n'); - } - } else if (longformflag) { - for (i = 0, blocks = 0; i < endcount; ++i) { - blocks += stats[i].lstat.st_blocks; - } - (void) printf("total %ld\n", blocks / 2); - for (i = 0; i < endcount; ++i) { - if (inodeflag) { - (void) printf("%6d ", stats[i].lstat.st_ino); - } - if (sizeflag) { - (void) printf("%4d ", stats[i].lstat.st_blocks / 2); - } - printperms(stats[i].lstat.st_mode); - (void) printf("%3d ", stats[i].lstat.st_nlink); - printowner(stats[i].lstat.st_uid); - if (groupflag) { - printgrp(stats[i].lstat.st_gid); - } - if (((stats[i].lstat.st_mode & S_IFMT) == S_IFCHR) || - ((stats[i].lstat.st_mode & S_IFMT) == S_IFBLK)) { - (void) printf("%3d,%4d ", major(stats[i].lstat.st_rdev), minor(stats[i].lstat.st_rdev)); - } else { - (void) printf("%8d ", stats[i].lstat.st_size); - } - if (accesstimeflag) { - printtime(stats[i].lstat.st_atime); - } else if (statustimeflag) { - printtime(stats[i].lstat.st_ctime); - } else { - printtime(stats[i].lstat.st_mtime); - } - (void) printf("%s", stats[i].name); - if (fancyflag) { - (void) printfancy(stats[i].lstat.st_mode); - } - if ((stats[i].lstat.st_mode & S_IFMT) == S_IFLNK) { - char buf[MAXPATHLEN + 1]; - int j; - - if ((j = readlink(stats[i].name, buf, MAXPATHLEN)) == -1) { - perror(stats[i].name); - (void) putchar('\n'); - continue; - } - buf[j + 1] = '\0'; - (void) printf(" -> %s", buf); - } - (void) putchar('\n'); - } - } else { + + needstats = f_inode || f_longform || f_size; + flen = 0; + btotal = maxblock = maxinode = maxlen = maxnlink = 0; + bcfile = 0; + maxuser = maxgroup = maxflags = 0; + maxsize = 0; + for (cur = list, entries = 0; cur; cur = cur->fts_link) { + if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { + warnx("%s: %s", + cur->fts_name, strerror(cur->fts_errno)); + cur->fts_number = NO_PRINT; + continue; + } /* - * assume tabs every 8 columns WARNING: bad code (hard coded - * constants) follows: + * P is NULL if list is the argv list, to which different rules + * apply. */ - - /* figure out max width */ - maxlen = 0; - for (i = 0; i < endcount; ++i) { - if (maxlen < lengthfcn(stats[i].name)) { - maxlen = lengthfcn(stats[i].name); - } - } /* end of determining max width of name */ - - /* add fudge factors to max name length */ - if (inodeflag) { - maxlen += 6; - } - if (sizeflag) { - maxlen += 5; + if (p == NULL) { + /* Directories will be displayed later. */ + if (cur->fts_info == FTS_D && !f_listdir) { + cur->fts_number = NO_PRINT; + continue; } - if (fancyflag) { - maxlen += 1; + } else { + /* Only display dot file if -a/-A set. */ + if (cur->fts_name[0] == '.' && !f_listdot) { + cur->fts_number = NO_PRINT; + continue; } - colwidth = (maxlen + 9) & ~0x7; /* one tab after maxlen */ - numcols = (80 + colwidth - maxlen) / colwidth; - collength = (int) ((float) endcount / (float) numcols + 0.999); - - for (base = 0; base < collength; base++) { - for (offset = 0, i = 0; i < numcols; ++i, offset += collength) { - - if ((base + offset) >= endcount) { - break; - } - chcnt = printaname(&stats[base + offset]); - - if ((base + offset + collength) < endcount) { - while (chcnt + 8 < colwidth) { - (void) putchar('\t'); - chcnt += 8; - } - if (chcnt < colwidth) { - (void) putchar('\t'); - } - chcnt = (chcnt + 8) & ~0x7; - } - } - if (base + offset < endcount) { - (void) printaname(&stats[base + offset]); + } + if (f_nonprint) + prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen); + if (cur->fts_namelen > maxlen) + maxlen = cur->fts_namelen; + if (needstats) { + sp = cur->fts_statp; + if (sp->st_blocks > maxblock) + maxblock = sp->st_blocks; + if (sp->st_ino > maxinode) + maxinode = sp->st_ino; + if (sp->st_nlink > maxnlink) + maxnlink = sp->st_nlink; + if (sp->st_size > maxsize) + maxsize = sp->st_size; + + btotal += sp->st_blocks; + if (f_longform) { + user = user_from_uid(sp->st_uid, 0); + if ((ulen = strlen(user)) > maxuser) + maxuser = ulen; + group = group_from_gid(sp->st_gid, 0); + if ((glen = strlen(group)) > maxgroup) + maxgroup = glen; + if (f_flags) { + flags = + flags_to_string(sp->st_flags, "-"); + if ((flen = strlen(flags)) > maxflags) + maxflags = flen; + } else + flen = 0; + + if ((np = malloc(sizeof(NAMES) + + ulen + glen + flen + 3)) == NULL) + err(1, NULL); + + np->user = &np->data[0]; + (void)strcpy(np->user, user); + np->group = &np->data[ulen + 1]; + (void)strcpy(np->group, group); + + if (S_ISCHR(sp->st_mode) || + S_ISBLK(sp->st_mode)) + bcfile = 1; + + if (f_flags) { + np->flags = &np->data[ulen + glen + 2]; + (void)strcpy(np->flags, flags); } - (void) printf("\n"); - } /* end of base and offset loop */ + cur->fts_pointer = np; + } } + ++entries; } -} - -/* - * print [inode] [size] name - * return # of characters printed - * no trailing characters - */ -int printaname(entry) -lsstruct *entry; -{ - int chcnt = 0; - - if (inodeflag) { - chcnt += printf("%5d ", entry->lstat.st_ino); - } - if (sizeflag) { - chcnt += printf("%4d ", entry->lstat.st_blocks / 2); - } - chcnt += printf("%s", entry->name); - - if (fancyflag) { - return (chcnt + printfancy(entry->lstat.st_mode)); - } - return chcnt; -} - -/* - * print group and user name - */ - - - -printgrp(groupid) -short groupid; -{ - struct group *groupentry; - - if ((groupentry = getgrgid((int) groupid)) == NULL) { - /* can't find group, print out number instead */ - (void) printf("%-9d ", groupid); - return; - } - (void) printf("%-9s", groupentry->gr_name); - (void) getgrent(); /* to rewind group file */ -} - - -printowner(uid) -short uid; -{ - struct passwd *pwentry; - if ((pwentry = getpwuid((int) uid)) == NULL) { - /* can't find owner, print out number instead */ - (void) printf("%-9d ", uid); + if (!entries) return; - } - (void) printf("%-9s", pwentry->pw_name); - (void) getpwent(); -} - -#define SIXMONTHS 6l*30l*24l*3600l -time_t time(); - -printtime(ftime) -time_t ftime; -{ - int i; - char *longstring; - - longstring = ctime((long *) &ftime); - - for (i = 4; i < 11; ++i) { - (void) putchar(longstring[i]); - } - - if (ftime + SIXMONTHS > time((time_t *) NULL)) { - for (i = 11; i < 16; ++i) { - (void) putchar(longstring[i]); - } - } else { - (void) putchar(' '); - for (i = 20; i < 24; ++i) { - (void) putchar(longstring[i]); - } - } - (void) putchar(' '); -} - -/* - * act like strlen, but also translate non-printing chars to '?' - */ - - -int prablelen(cp) -char *cp; -{ - register int len = 0; - while (*cp != '\0') { - if (!isprint(*cp)) { - *cp = '?'; - } - ++len; - ++cp; + d.list = list; + d.entries = entries; + d.maxlen = maxlen; + if (needstats) { + d.bcfile = bcfile; + d.btotal = btotal; + (void)snprintf(buf, sizeof(buf), "%lu", maxblock); + d.s_block = strlen(buf); + d.s_flags = maxflags; + d.s_group = maxgroup; + (void)snprintf(buf, sizeof(buf), "%lu", maxinode); + d.s_inode = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); + d.s_nlink = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%qu", maxsize); + d.s_size = strlen(buf); + d.s_user = maxuser; } - return len; -} -/* - * do the permissions printing, passed the mode - */ - -printperms(mode) -u_short mode; -{ - /* print type */ - switch (mode & S_IFMT) { - case S_IFDIR: /* directory */ - (void) putchar('d'); - break; - case S_IFCHR: /* character special */ - (void) putchar('c'); - break; - case S_IFBLK: /* block special */ - (void) putchar('b'); - break; - case S_IFREG: /* regular */ - (void) putchar('-'); - break; - case S_IFLNK: /* symbolic link */ - (void) putchar('l'); - break; - case S_IFSOCK: /* socket */ - (void) putchar('s'); - break; -#ifdef S_IFIFO - case S_IFIFO: /* fifo */ - (void) putchar('p'); - break; -#endif - default: /* unknown */ - (void) putchar('?'); - break; - } - /* usr */ - if (mode & S_IRUSR) { - (void) putchar('r'); - } else { - (void) putchar('-'); - } - if (mode & S_IWUSR) { - (void) putchar('w'); - } else { - (void) putchar('-'); - } - switch (mode & (S_IXUSR | S_ISUID)) { - case 0: - (void) putchar('-'); - break; - case S_IXUSR: - (void) putchar('x'); - break; - case S_ISUID: - (void) putchar('S'); - break; - case S_IXUSR | S_ISUID: - (void) putchar('s'); - break; - } - /* group */ - if (mode & S_IRGRP) { - (void) putchar('r'); - } else { - (void) putchar('-'); - } - if (mode & S_IWGRP) { - (void) putchar('w'); - } else { - (void) putchar('-'); - } - switch (mode & (S_IXGRP | S_ISGID)) { - case 0: - (void) putchar('-'); - break; - case S_IXGRP: - (void) putchar('x'); - break; - case S_ISGID: - (void) putchar('S'); - break; - case S_IXGRP | S_ISGID: - (void) putchar('s'); - break; - } - /* other */ - if (mode & S_IROTH) { - (void) putchar('r'); - } else { - (void) putchar('-'); - } - if (mode & S_IWOTH) { - (void) putchar('w'); - } else { - (void) putchar('-'); - } - switch (mode & (S_IXOTH | S_ISVTX)) { - case 0: - (void) putchar('-'); - break; - case S_IXOTH: - (void) putchar('x'); - break; - case S_ISVTX: - (void) putchar('T'); - break; - case S_IXOTH | S_ISVTX: - (void) putchar('t'); - break; - } -} + printfcn(&d); + output = 1; -int printfancy(mode) -u_short mode; -{ - if ((mode & S_IFMT) == S_IFDIR) { - (void) putchar('/'); - return 1; - } - if ((mode & S_IFMT) == S_IFLNK && !longformflag) { - (void) putchar('@'); - return 1; - } - if ((mode & S_IFMT) == S_IFSOCK) { - (void) putchar('='); - return 1; - } - if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { - (void) putchar('*'); - return 1; - } - return 0; + if (f_longform) + for (cur = list; cur; cur = cur->fts_link) + free(cur->fts_pointer); } /* - * error checks for dynamic memory; - * comparison routines for various calls to qsort(3) + * Ordering for mastercmp: + * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories + * as larger than directories. Within either group, use the sort function. + * All other levels use the sort function. Error entries remain unsorted. */ - -int namecmp(a, b) -lsstruct *a, *b; -{ - return strcmp(a->name, b->name); -} - -int revnamecmp(a, b) -lsstruct *a, *b; -{ - return strcmp(b->name, a->name); -} - -int modcmp(a, b) -lsstruct *a, *b; -{ - return (a->lstat.st_mtime < b->lstat.st_mtime); -} - -int revmodcmp(a, b) -lsstruct *a, *b; -{ - return (b->lstat.st_mtime < a->lstat.st_mtime); -} - -int acccmp(a, b) -lsstruct *a, *b; -{ - return (a->lstat.st_atime < b->lstat.st_atime); -} - -int revacccmp(a, b) -lsstruct *a, *b; -{ - return (b->lstat.st_atime < a->lstat.st_atime); -} - -int statcmp(a, b) -lsstruct *a, *b; -{ - return (a->lstat.st_ctime < b->lstat.st_ctime); -} - -int revstatcmp(a, b) -lsstruct *a, *b; +static int +mastercmp(a, b) + const FTSENT **a, **b; { - return (b->lstat.st_ctime < a->lstat.st_ctime); -} - -char *malloc(); - -char *emalloc(size) -unsigned size; -{ - register char *retval; - - if ((retval = malloc(size)) == NULL) { - perror("Can't find memory"); - exit(1); - } - return retval; + int a_info, b_info; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR) + return (0); + + if (a_info == FTS_NS || b_info == FTS_NS) + return (namecmp(*a, *b)); + + if (a_info == b_info) + return (sortfcn(*a, *b)); + + if ((*a)->fts_level == FTS_ROOTLEVEL) + if (a_info == FTS_D) + return (1); + else if (b_info == FTS_D) + return (-1); + else + return (sortfcn(*a, *b)); + else + return (sortfcn(*a, *b)); }