X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/a6fd9866459739100f2ce0484ad3c9593e26d4b9..82567da7811712ec1ac18548a84177600b16690b:/usr/src/bin/ls/ls.c diff --git a/usr/src/bin/ls/ls.c b/usr/src/bin/ls/ls.c index fc357c74ba..22a8772859 100644 --- a/usr/src/bin/ls/ls.c +++ b/usr/src/bin/ls/ls.c @@ -1,705 +1,474 @@ -#ifndef lint -static char *sccsid = "@(#)ls.c 4.22 (Berkeley) %G%"; -#endif - /* - * ls + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. * - * 4.2bsd version for symbolic links, variable length - * directory entries, block size in the inode, etc. + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#include -#include -#include -#include -#include - -#define kbytes(size) (((size) + 1023) / 1024) - -struct afile { - char ftype; /* file type, e.g. 'd', 'c', 'f' */ - ino_t fnum; /* inode number of file */ - short fflags; /* mode&~S_IFMT, perhaps ISARG */ - short fnl; /* number of links */ - short fuid; /* owner id */ - short fgid; /* group id */ - long fsize; /* file size */ - long fblks; /* number of blocks used */ - time_t fmtime; /* time (modify or access or create) */ - char *fname; /* file name */ - char *flinkto; /* symbolic link value */ -}; - -#define ISARG 0x8000 /* extra ``mode'' */ - -struct subdirs { - char *sd_name; - struct subdirs *sd_next; -} *subdirs; -int aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1; -int qflg, Aflg, Cflg, Fflg, Lflg, Rflg; - -int usetabs; - -time_t now, sixmonthsago; - -char *dotp = "."; - -struct winsize win; -int twidth; +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ -struct afile *gstat(); -int fcmp(); -char *cat(), *savestr(); -char *fmtentry(); -char *getname(), *getgroup(); +#ifndef lint +static char sccsid[] = "@(#)ls.c 5.25 (Berkeley) %G%"; +#endif /* not lint */ -char *ctime(); -char *malloc(), *calloc(), *realloc(); -char *sprintf(), *strcpy(), *strcat(); +#include +#include +#include +#include +#include +#include +#include +#include "ls.h" + +int lstat(), strlen(); +char *emalloc(); + +int qflg, Aflg, Cflg, Fflg, Lflg, Rflg, Sflg; + +int termwidth = 80; /* default terminal width */ + +/* flags */ +int f_accesstime; /* use time of last access */ +int f_group; /* show group ownership of a file */ +int f_ignorelink; /* indirect through symbolic link operands */ +int f_inode; /* print inode */ +int f_listalldot; /* list . and .. as well */ +int f_listdir; /* list actual directory, not contents */ +int f_listdot; /* list files beginning with . */ +int f_longform; /* long listing format */ +int f_nonprint; /* show unprintables as ? */ +int f_recursive; /* ls subdirectories also */ +int f_reversesort; /* reverse whatever sort is used */ +int f_singlecol; /* use single column output */ +int f_size; /* list size in short listing */ +int f_specialdir; /* force params to be directories */ +int f_statustime; /* use time of last mode change */ +int f_timesort; /* sort by time vice name */ +int f_type; /* add type character for non-regular files */ main(argc, argv) int argc; - char *argv[]; + char **argv; { - int i; - struct afile *fp0, *fplast; - register struct afile *fp; - struct sgttyb sgbuf; - - argc--, argv++; - if (getuid() == 0) - Aflg++; - (void) time(&now); sixmonthsago = now - 6L*30L*24L*60L*60L; now += 60; - twidth = 80; + extern int optind, stat(); + struct winsize win; + int ch; + char *p, *getenv(); + int namecmp(), revnamecmp(), acccmp(), revacccmp(); + int modcmp(), revmodcmp(), statcmp(), revstatcmp(); + int printcol(), printlong(), printscol(); + + /* + * terminal defaults to -C -q + * non-terminal defaults to -1 + */ if (isatty(1)) { - qflg = Cflg = 1; - (void) gtty(1, &sgbuf); - if (ioctl(1, TIOCGWINSZ, &win) != -1) - twidth = (win.ws_col == 0 ? 80 : win.ws_col); - if ((sgbuf.sg_flags & XTABS) == 0) - usetabs = 1; + f_nonprint = 1; + if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { + if (p = getenv("COLUMNS")) + termwidth = atoi(p); + } + else + termwidth = win.ws_col; } else - usetabs = 1; - while (argc > 0 && **argv == '-') { - (*argv)++; - while (**argv) switch (*(*argv)++) { - - case 'C': - Cflg = 1; break; - case 'q': - qflg = 1; break; + f_singlecol = 1; + + /* root is -A automatically */ + if (!getuid()) + f_listdot = 1; + + while ((ch = getopt(argc, argv, "1ACFLRacdfgilqrstu")) != EOF) { + switch (ch) { + /* + * -1, -C and -l all override each other + * so shell aliasing works right + */ case '1': - Cflg = 0; break; + f_singlecol = 1; + f_longform = 0; + break; + case 'C': + f_longform = f_singlecol = 0; + break; + case 'l': + f_longform = 1; + f_singlecol = 0; + break; + /* -c and -u override each other */ + case 'c': + f_statustime = 1; + f_accesstime = 0; + break; + case 'u': + f_accesstime = 1; + f_statustime = 0; + break; + case 'F': + f_type = 1; + break; + case 'L': + f_ignorelink = 1; + break; + case 'R': + f_recursive = 1; + break; case 'a': - aflg++; break; + f_listalldot = 1; + /* FALLTHROUGH */ case 'A': - Aflg++; break; - case 'c': - cflg++; break; - case 's': - sflg++; break; + f_listdot = 1; + break; + case 'S': + Sflg++; /* fall into... */ case 'd': - dflg++; break; + f_listdir = 1; + break; + case 'f': + f_specialdir = 1; + break; case 'g': - gflg++; break; - case 'l': - lflg++; break; + f_group = 1; + break; + case 'i': + f_inode = 1; + break; + case 'q': + f_nonprint = 1; + break; case 'r': - rflg = -1; break; + f_reversesort = 1; + break; + case 's': + f_size = 1; + break; case 't': - tflg++; break; - case 'u': - uflg++; break; - case 'i': - iflg++; break; - case 'f': - fflg++; break; - case 'L': - Lflg++; break; - case 'F': - Fflg++; break; - case 'R': - Rflg++; break; - } - argc--, argv++; - } - if (fflg) { - aflg++; lflg = 0; sflg = 0; tflg = 0; - } - if (lflg) - Cflg = 0; - if (argc == 0) { - argc++; - argv = &dotp; - } - fp = (struct afile *)calloc(argc, sizeof (struct afile)); - if (fp == 0) { - fprintf(stderr, "ls: out of memory\n"); - exit(1); - } - fp0 = fp; - for (i = 0; i < argc; i++) { - if (gstat(fp, *argv, 1, (int *)0)) { - fp->fname = *argv; - fp->fflags |= ISARG; - fp++; + f_timesort = 1; + break; + default: + case '?': + usage(); } - argv++; - } - fplast = fp; - qsort(fp0, fplast - fp0, sizeof (struct afile), fcmp); - if (dflg) { - formatf(fp0, fplast); - exit(0); } - if (fflg) - fp = fp0; - else { - for (fp = fp0; fp < fplast && fp->ftype != 'd'; fp++) - continue; - formatf(fp0, fp); + argc -= optind; + argv += optind; + + /* -f turns off -F, -R, -l, -t, -s, -r, turns on -a */ + if (f_specialdir) { + f_longform = f_recursive = f_reversesort = f_size = + f_timesort = f_type = 0; + f_listdot = f_listalldot = 1; } - if (fp < fplast) { - if (fp > fp0) - printf("\n"); - for (;;) { - formatd(fp->fname, argc > 1); - while (subdirs) { - struct subdirs *t; - - t = subdirs; subdirs = t->sd_next; - printf("\n"); - formatd(t->sd_name, 1); - cfree(t->sd_name); - cfree((char *)t); - } - if (++fp == fplast) - break; - printf("\n"); - } + + /* -d turns off -R */ + if (f_listdir) + f_recursive = 0; + + /* if need to stat files */ + needstat = f_longform || f_recursive || f_timesort || f_size || f_type; + + /* 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; } - exit(0); -} -formatd(name, title) - char *name; - int title; -{ - register struct afile *fp; - register struct subdirs *dp; - struct afile *dfp0, *dfplast; - int nkb; + /* select a print function */ + if (f_singlecol) + printfcn = printscol; + else if (f_longform) + printfcn = printlong; + else + printfcn = printcol; - nkb = getdir(name, &dfp0, &dfplast); - if (dfp0 == 0) - return; - if (fflg == 0) - qsort(dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); - if (title) - printf("%s:\n", name); - if (lflg || sflg) - printf("total %ld\n", nkb); - formatf(dfp0, dfplast); - if (Rflg) - for (fp = dfplast; fp >= dfp0; fp--) { - if (fp->ftype != 'd' || - !strcmp(fp->fname, ".") || - !strcmp(fp->fname, "..")) - continue; - dp = (struct subdirs *)malloc(sizeof (struct subdirs)); - dp->sd_name = savestr(cat(name, fp->fname)); - dp->sd_next = subdirs; subdirs = dp; - } - for (fp = dfp0; fp < dfplast; fp++) { - if ((fp->fflags&ISARG) == 0 && fp->fname) - cfree(fp->fname); - if (fp->flinkto) - cfree(fp->flinkto); - } - cfree((char *)dfp0); + if (argc) + doargs(argc, argv); + else + dodot(); + exit(0); } -getdir(dir, pfp0, pfplast) - char *dir; - struct afile **pfp0, **pfplast; +dodot() { - register struct afile *fp; - DIR *dirp; - register struct direct *dp; - int nb, nent = 20; - - dirp = opendir(dir); - if (dirp == NULL) { - *pfp0 = *pfplast = NULL; - printf("%s unreadable\n", dir); /* not stderr! */ - return (0); - } - fp = *pfp0 = (struct afile *)calloc(nent, sizeof (struct afile)); - *pfplast = *pfp0 + nent; - nb = 0; - while (dp = readdir(dirp)) { - if (dp->d_ino == 0) - continue; - if (aflg == 0 && dp->d_name[0]=='.' && - (Aflg == 0 || dp->d_name[1]==0 || - dp->d_name[1]=='.' && dp->d_name[2]==0)) - continue; - if (gstat(fp, cat(dir, dp->d_name), Fflg+Rflg, &nb) == 0) - continue; - fp->fnum = dp->d_ino; - fp->fname = savestr(dp->d_name); - fp++; - if (fp == *pfplast) { - *pfp0 = (struct afile *)realloc((char *)*pfp0, - 2 * nent * sizeof (struct afile)); - if (*pfp0 == 0) { - fprintf(stderr, "ls: out of memory\n"); - exit(1); - } - fp = *pfp0 + nent; - *pfplast = fp + nent; - nent *= 2; - } + LS local, *stats; + int num; + char *names; + + if (lstat(local.name = ".", &local.lstat)) { + (void)fprintf(stderr, "ls: .: %s\n", strerror(errno)); + exit(1); } - closedir(dirp); - *pfplast = fp; - return (kbytes(dbtob(nb))); + if (num = tabdir(&local, &stats, &names)) + displaydir(stats, num); } -int stat(), lstat(); +static char path[MAXPATHLEN + 1]; +static char *endofpath = path; -struct afile * -gstat(fp, file, statarg, pnb) - register struct afile *fp; - char *file; - int statarg, *pnb; +doargs(argc, argv) + int argc; + char **argv; { - int (*statf)() = Lflg ? stat : lstat; - char buf[BUFSIZ]; int cc; - static struct afile azerofile; - - *fp = azerofile; - fp->fflags = 0; - fp->fnum = 0; - fp->ftype = '-'; - if (statarg || sflg || lflg || tflg) { - struct stat stb, stb1; - - if ((*statf)(file, &stb) < 0) { - if (statf == lstat || lstat(file, &stb) < 0) { - fprintf(stderr, "%s not found\n", file); - return (0); - } + register LS *dstatp, *rstatp; + LS *dstats, *rstats; + register int cnt, dircnt, regcnt; + struct stat sb; + LS *stats; + int num, (*statfcn)(), stat(), lstat(); + char *names, top[MAXPATHLEN + 1]; + + /* + * walk through the operands, building separate arrays of LS + * structures for directory and non-directory files. + */ + dstats = rstats = NULL; + statfcn = f_ignorelink ? stat : lstat; + for (dircnt = regcnt = 0; *argv; ++argv) { + if (statfcn(*argv, &sb)) { + (void)fprintf(stderr, "ls: %s: %s\n", + *argv, strerror(errno)); + if (errno == ENOENT) + continue; + exit(1); } - fp->fblks = stb.st_blocks; - fp->fsize = stb.st_size; - switch (stb.st_mode & S_IFMT) { - - case S_IFDIR: - fp->ftype = 'd'; break; - case S_IFBLK: - fp->ftype = 'b'; fp->fsize = stb.st_rdev; break; - case S_IFCHR: - fp->ftype = 'c'; fp->fsize = stb.st_rdev; break; - case S_IFSOCK: - fp->ftype = 's'; fp->fsize = 0; break; - case S_IFLNK: - fp->ftype = 'l'; - if (lflg) { - cc = readlink(file, buf, BUFSIZ); - if (cc >= 0) { - buf[cc] = 0; - fp->flinkto = savestr(buf); - } - break; - } - if (stat(file, &stb1) < 0) - break; - if ((stb1.st_mode & S_IFMT) == S_IFDIR) { - stb = stb1; - fp->ftype = 'd'; - fp->fsize = stb.st_size; - fp->fblks = stb.st_blocks; - } - break; + if (!f_specialdir && !f_listdir && S_ISDIR(sb.st_mode)) { + if (!dstats) + dstatp = dstats = (LS *)emalloc((u_int)argc * + (sizeof(LS))); + dstatp->name = *argv; + dstatp->lstat = sb; + ++dstatp; + ++dircnt; } - fp->fnum = stb.st_ino; - fp->fflags = stb.st_mode & ~S_IFMT; - fp->fnl = stb.st_nlink; - fp->fuid = stb.st_uid; - fp->fgid = stb.st_gid; - if (uflg) - fp->fmtime = stb.st_atime; - else if (cflg) - fp->fmtime = stb.st_ctime; - else - fp->fmtime = stb.st_mtime; - if (pnb) - *pnb += stb.st_blocks; - } - return (fp); -} - -formatf(fp0, fplast) - struct afile *fp0, *fplast; -{ - register struct afile *fp; - int width = 0, w, nentry = fplast - fp0; - int i, j, columns, lines; - char *cp; - - if (fp0 == fplast) - return; - if (lflg || Cflg == 0) - columns = 1; - else { - for (fp = fp0; fp < fplast; fp++) { - int len = strlen(fmtentry(fp)); - - if (len > width) - width = len; + else { + if (!rstats) + rstatp = rstats = (LS *)emalloc((u_int)argc * + (sizeof(LS))); + rstatp->name = *argv; + rstatp->lstat = sb; + ++rstatp; + ++regcnt; } - if (usetabs) - width = (width + 8) &~ 7; - else - width += 2; - columns = twidth / width; - if (columns == 0) - columns = 1; } - lines = (nentry + columns - 1) / columns; - for (i = 0; i < lines; i++) { - for (j = 0; j < columns; j++) { - fp = fp0 + j * lines + i; - cp = fmtentry(fp); - printf("%s", cp); - if (fp + lines >= fplast) { - printf("\n"); - break; + /* display regular files */ + if (regcnt) { + /* + * for -f flag -- switch above treats all -f operands as + * regular files; this code uses tabdir() to read + * them as directories. + */ + if (f_specialdir) { + for (cnt = regcnt; cnt--;) { + if (num = tabdir(rstats++, &stats, &names)) + displaydir(stats, num); + (void)free((char *)stats); + (void)free((char *)names); } - w = strlen(cp); - while (w < width) - if (usetabs) { - w = (w + 8) &~ 7; - putchar('\t'); - } else { - w++; - putchar(' '); - } - } + } else + displaydir(rstats, regcnt); } -} - -fcmp(f1, f2) - register struct afile *f1, *f2; -{ + /* display directories */ + if (dircnt) { + register char *p; - if (dflg == 0 && fflg == 0) { - if ((f1->fflags&ISARG) && f1->ftype == 'd') { - if ((f2->fflags&ISARG) == 0 || f2->ftype != 'd') - return (1); - } else { - if ((f2->fflags&ISARG) && f2->ftype == 'd') - return (-1); + if (dircnt > 1) { + (void)getwd(top); + qsort((char *)dstats, dircnt, sizeof(LS), sortfcn); + } + for (cnt = 0; cnt < dircnt; ++dstats) { + for (endofpath = path, p = dstats->name; + *endofpath = *p++; ++endofpath); + subdir(dstats, regcnt, regcnt || dircnt > 1); + if (++cnt < dircnt && chdir(top)) { + (void)fprintf(stderr, "ls: %s: %s\n", + top, strerror(errno)); + exit(1); + } } } - if (tflg) { - if (f2->fmtime == f1->fmtime) - return (0); - if (f2->fmtime > f1->fmtime) - return (rflg); - return (-rflg); - } - return (rflg * strcmp(f1->fname, f2->fname)); } -char * -cat(dir, file) - char *dir, *file; +displaydir(stats, num) + LS *stats; + register int num; { - static char dfile[BUFSIZ]; + register char *p, *savedpath; + LS *lp; - if (strlen(dir)+1+strlen(file)+1 > BUFSIZ) { - fprintf(stderr, "ls: filename too long\n"); - exit(1); - } - if (!strcmp(dir, "") || !strcmp(dir, ".")) { - (void) strcpy(dfile, file); - return (dfile); - } - (void) strcpy(dfile, dir); - if (dir[strlen(dir) - 1] != '/' && *file != '/') - (void) strcat(dfile, "/"); - (void) strcat(dfile, file); - return (dfile); -} - -char * -savestr(str) - char *str; -{ - char *cp = malloc(strlen(str) + 1); + if (num > 1 && !f_specialdir) { + u_long save1, save2; - if (cp == NULL) { - fprintf(stderr, "ls: out of memory\n"); - exit(1); + save1 = stats[0].lstat.st_btotal; + save2 = stats[0].lstat.st_maxlen; + qsort((char *)stats, num, sizeof(LS), sortfcn); + stats[0].lstat.st_btotal = save1; + stats[0].lstat.st_maxlen = save2; } - (void) strcpy(cp, str); - return (cp); -} -char *fmtinum(), *fmtsize(), *fmtlstuff(), *fmtmode(); + printfcn(stats, num); -char * -fmtentry(fp) - register struct afile *fp; -{ - static char fmtres[BUFSIZ]; - register char *cp, *dp; - - (void) sprintf(fmtres, "%s%s%s", - iflg ? fmtinum(fp) : "", - sflg ? fmtsize(fp) : "", - lflg ? fmtlstuff(fp) : ""); - dp = &fmtres[strlen(fmtres)]; - for (cp = fp->fname; *cp; cp++) - if (qflg && (*cp < ' ' || *cp >= 0177)) - *dp++ = '?'; - else - *dp++ = *cp; - if (Fflg) { - if (fp->ftype == 'd') - *dp++ = '/'; - else if (fp->ftype == 'l') - *dp++ = '@'; - else if (fp->ftype == 's') - *dp++ = '='; - else if (fp->fflags & 0111) - *dp++ = '*'; - } - if (lflg && fp->flinkto) { - (void) strcpy(dp, " -> "); dp += 4; - for (cp = fp->flinkto; *cp; cp++) - if (qflg && (*cp < ' ' || *cp >= 0177)) - *dp++ = '?'; - else - *dp++ = *cp; + if (f_recursive) { + savedpath = endofpath; + for (lp = stats; num--; ++lp) { + if (!S_ISDIR(lp->lstat.st_mode)) + continue; + p = lp->name; + if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2])) + continue; + if (endofpath != path && endofpath[-1] != '/') + *endofpath++ = '/'; + for (; *endofpath = *p++; ++endofpath); + subdir(lp, 1, 1); + *(endofpath = savedpath) = '\0'; + } } - *dp++ = 0; - return (fmtres); -} - -char * -fmtinum(p) - register struct afile *p; -{ - static char inumbuf[8]; - - (void) sprintf(inumbuf, "%5d ", p->fnum); - return (inumbuf); -} - -char * -fmtsize(p) - register struct afile *p; -{ - static char sizebuf[32]; - - (void) sprintf(sizebuf, "%4ld ", kbytes(dbtob(p->fblks))); - return (sizebuf); } -char * -fmtlstuff(p) - register struct afile *p; +subdir(lp, newline, tag) + LS *lp; + int newline, tag; { - static char lstuffbuf[256]; - char gname[32], uname[32], fsize[32], ftime[32]; - register char *lp = lstuffbuf; - - /* type mode uname gname fsize ftime */ -/* get uname */ - { char *cp = getname(p->fuid); - if (cp) - (void) sprintf(uname, "%-9.9s", cp); - else - (void) sprintf(uname, "%-9d", p->fuid); - } -/* get gname */ - if (gflg) { - char *cp = getgroup(p->fgid); - if (cp) - (void) sprintf(gname, "%-9.9s", cp); - else - (void) sprintf(gname, "%-9d", p->fgid); + LS *stats; + int num; + char *names; + + /* + * this doesn't really belong here, but it's the only place that + * everybody goes through; the `tag' variable is so that we don't + * print the header for directories unless we're going to display + * more directories, or we've already displayed files or directories. + * The `newline' variable keeps us from inserting a newline before + * we've displayed anything at all. + */ + if (newline) + (void)putchar('\n'); + if (tag) + (void)printf("%s:\n", path); + + if (chdir(lp->name)) { + (void)fprintf(stderr, "ls: %s: %s\n", + lp->name, strerror(errno)); + return; } -/* get fsize */ - if (p->ftype == 'b' || p->ftype == 'c') - (void) sprintf(fsize, "%3d,%4d", - major(p->fsize), minor(p->fsize)); - else if (p->ftype == 's') - (void) sprintf(fsize, "%8ld", 0); - else - (void) sprintf(fsize, "%8ld", p->fsize); -/* get ftime */ - { char *cp = ctime(&p->fmtime); - if ((p->fmtime < sixmonthsago) || (p->fmtime > now)) - (void) sprintf(ftime, " %-7.7s %-4.4s ", cp+4, cp+20); - else - (void) sprintf(ftime, " %-12.12s ", cp+4); + if (num = tabdir(lp, &stats, &names)) + displaydir(stats, num); + (void)free((char *)stats); + (void)free((char *)names); + if (chdir("..")) { + (void)fprintf(stderr, "ls: ..: %s\n", strerror(errno)); + exit(1); } -/* splat */ - *lp++ = p->ftype; - lp = fmtmode(lp, p->fflags); - (void) sprintf(lp, "%3d %s%s%s%s", - p->fnl, uname, gflg ? gname : "", fsize, ftime); - return (lstuffbuf); } -int m1[] = { 1, S_IREAD>>0, 'r', '-' }; -int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; -int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; -int m4[] = { 1, S_IREAD>>3, 'r', '-' }; -int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; -int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' }; -int m7[] = { 1, S_IREAD>>6, 'r', '-' }; -int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; -int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' }; - -int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; - -char * -fmtmode(lp, flags) - char *lp; - int flags; +tabdir(lp, s_stats, s_names) + LS *lp, **s_stats; + char **s_names; { - int **mp; - - for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])]; ) { - register int *pairp = *mp++; - register int n = *pairp++; - - while (--n >= 0 && (flags&*pairp++) == 0) - pairp++; - *lp++ = *pairp; + register DIR *dirp; + register int cnt, maxentry, maxlen; + register char *p, *names; + struct dirent *dp; + u_long blocks; + LS *stats; + + /* + * allocate space for array of LS structures and the file names + * the name field will point to. Make it big so we don't have + * to realloc often. + */ +#define DEFNUM 256 + maxentry = DEFNUM; + *s_stats = stats = (LS *)emalloc((u_int)DEFNUM * sizeof(LS)); + *s_names = names = emalloc((u_int)lp->lstat.st_size); + + if (!(dirp = opendir(f_specialdir ? lp->name : "."))) { + (void)fprintf(stderr, "ls: %s: %s\n", lp->name, + strerror(errno)); + return(0); } - return (lp); -} - -/* rest should be done with nameserver or database */ - -#include -#include -#include - -struct utmp utmp; -#define NMAX (sizeof (utmp.ut_name)) -#define SCPYN(a, b) strncpy(a, b, NMAX) - -#define NUID 2048 -#define NGID 300 - -char names[NUID][NMAX+1]; -char outrangename[NMAX+1]; -int outrangeuid = -1; -char groups[NGID][NMAX+1]; -char outrangegroup[NMAX+1]; -int outrangegid = -1; - -char * -getname(uid) -{ - register struct passwd *pw; - static init; - struct passwd *getpwent(); - - if (uid >= 0 && uid < NUID && names[uid][0]) - return (&names[uid][0]); - if (uid >= 0 && uid == outrangeuid) - return (outrangename); -rescan: - if (init == 2) { - if (uid < NUID) - return (0); - setpwent(); - while (pw = getpwent()) { - if (pw->pw_uid != uid) + blocks = 0; + maxlen = -1; + for (cnt = 0; dp = readdir(dirp);) { + /* this does -A and -a */ + p = dp->d_name; + if (p[0] == '.') { + if (!f_listdot) + continue; + if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2])) continue; - outrangeuid = pw->pw_uid; - SCPYN(outrangename, pw->pw_name); - endpwent(); - return (outrangename); } - endpwent(); - return (0); - } - if (init == 0) - setpwent(), init = 1; - while (pw = getpwent()) { - if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { - if (pw->pw_uid == uid) { - outrangeuid = pw->pw_uid; - SCPYN(outrangename, pw->pw_name); - return (outrangename); - } - continue; + if (cnt == maxentry) { + maxentry += DEFNUM; + if (!(stats = (LS *)realloc((char *)stats, + (u_int)maxentry * sizeof(LS)))) + nomem(); } - if (names[pw->pw_uid][0]) - continue; - SCPYN(names[pw->pw_uid], pw->pw_name); - if (pw->pw_uid == uid) - return (&names[uid][0]); - } - init = 2; - goto rescan; -} - -char * -getgroup(gid) -{ - register struct group *gr; - static init; - struct group *getgrent(); - - if (gid >= 0 && gid < NGID && groups[gid][0]) - return (&groups[gid][0]); - if (gid >= 0 && gid == outrangegid) - return (outrangegroup); -rescan: - if (init == 2) { - if (gid < NGID) - return (0); - setgrent(); - while (gr = getgrent()) { - if (gr->gr_gid != gid) + if (needstat && lstat(dp->d_name, &stats[cnt].lstat)) { + (void)fprintf(stderr, "ls: %s: %s\n", + dp->d_name, strerror(errno)); + if (errno == ENOENT) continue; - outrangegid = gr->gr_gid; - SCPYN(outrangegroup, gr->gr_name); - endgrent(); - return (outrangegroup); + exit(1); } - endgrent(); - return (0); - } - if (init == 0) - setgrent(), init = 1; - while (gr = getgrent()) { - if (gr->gr_gid < 0 || gr->gr_gid >= NGID) { - if (gr->gr_gid == gid) { - outrangegid = gr->gr_gid; - SCPYN(outrangegroup, gr->gr_name); - return (outrangegroup); - } - continue; - } - if (groups[gr->gr_gid][0]) - continue; - SCPYN(groups[gr->gr_gid], gr->gr_name); - if (gr->gr_gid == gid) - return (&groups[gid][0]); + stats[cnt].name = names; + + /* strip out unprintables */ + if (f_nonprint) + prcopy(dp->d_name, names, (int)dp->d_namlen); + else + bcopy(dp->d_name, names, (int)dp->d_namlen); + names += dp->d_namlen; + *names++ = '\0'; + + /* + * get the inode from the directory, so the -f flag + * works right. + */ + stats[cnt].lstat.st_ino = dp->d_ino; + + /* save name length for -C format */ + stats[cnt].len = dp->d_namlen; + /* calculate number of blocks if -l format */ + if (f_longform || f_size) + blocks += stats[cnt].lstat.st_blocks; + /* save max length if -C format */ + if (!f_longform && !f_singlecol && maxlen < (int)dp->d_namlen) + maxlen = dp->d_namlen; + ++cnt; } - init = 2; - goto rescan; + stats[0].lstat.st_btotal = blocks; + stats[0].lstat.st_maxlen = maxlen; + closedir(dirp); + return(cnt); }