X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2b84abb596f52ab2068d52108adc96838ad4340a..31cef89cb428866f787983e68246030321893df4:/usr/src/cmd/ls/ucbls.c diff --git a/usr/src/cmd/ls/ucbls.c b/usr/src/cmd/ls/ucbls.c index 118bee5466..bf090cd6be 100644 --- a/usr/src/cmd/ls/ucbls.c +++ b/usr/src/cmd/ls/ucbls.c @@ -1,11 +1,14 @@ -/* Copyright (c) 1979 Regents of the University of California */ -# +#define UCB /* Controls output format for -F */ +/* #define UCB_PWHASH /* If have hashed password file */ + /* * ls - list file or directory * * Modified by Bill Joy UCB May/August 1977 + * Modified by Dave Presotto BTL Feb/80 + * Modified by Bill Joy and Mark Horton Summer 1980 * - * This version of ls is designed for graphic terminals and to + * this version of ls is designed for graphic terminals and to * list directories with lots of files in them compactly. * It supports three variants for listings: * @@ -34,10 +37,15 @@ * * -q force non-printings to be '?'s, e.g. to a file * - * -c force columnar output, e.g. into a file + * -C force columnar output, e.g. into a file * * -n like -l, but user/group id's in decimal rather than * looking in /etc/passwd to save time + * + * -F turns on the "flagging" of executables and directories + * + * -R causes ls to recurse through the branches of the subtree + * ala find */ #include @@ -45,9 +53,15 @@ #include #include #include +#include +#include +#include +struct utmp utmp; +#define NMAX (sizeof utmp.ut_name) -#define NFILES 1024 +#define MAXFILEWIDTH 14 +#define NFILES 1024 FILE *pwdf, *dirf; struct lbuf { @@ -56,7 +70,7 @@ struct lbuf { char *namep; } ln; char ltype; - short lnum; + ino_t lnum; short lflags; short lnl; short luid; @@ -65,17 +79,26 @@ struct lbuf { long lmtime; }; -int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; -int Aflg, nflg, qflg, across; +struct dchain { + char *dc_name; /* the path name */ + struct dchain *dc_next; /* the next directory on the chain */ +}; + +struct dchain *dfirst; /* the start of the directory chain */ +struct dchain *cdfirst; /* the start of the current directory chain */ +struct dchain *dtemp; /* temporary used when linking */ +char *curdir; /* the current directory */ + +int aflg, bflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; +int Aflg, nflg, qflg, Fflg, Rflg, across, Cflg; int nopad; -char buff[32]; +int tabflg; int rflg = 1; long year; int flags; -int lastuid = -1; -char tbuf[16]; long tblocks; int statreq; +int xtraent; /* for those switches which print out a total */ struct lbuf *flist[NFILES]; struct lbuf **lastp = flist; struct lbuf **firstp = flist; @@ -85,30 +108,43 @@ char *makename(); struct lbuf *gstat(); char *ctime(); long nblock(); +char *getname(); -#define ISARG 0100000 -int colwidth = 15; +#define ISARG 0100000 +int colwidth; +int filewidth; +int fixedwidth; int outcol; char obuf[BUFSIZ]; main(argc, argv) +int argc; char *argv[]; { - int i; - register struct lbuf *ep, **ep1; +#include + + int i, width; + register struct lbuf *ep; register struct lbuf **slastp; struct lbuf **epp; struct lbuf lb; char *t; char *cp; int compar(); + struct sgttyb sgbuf; + Fflg = 0; + tabflg = 0; Aflg = getuid() == 0; setbuf(stdout, obuf); - time(&lb.lmtime); + lb.lmtime = time((long *) 0); year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */ - qflg = gtty(1, buff) == 0; + qflg = gtty(1, &sgbuf) == 0; + + /* guarantee at least on column width */ + fixedwidth = 2; + /* * If the standard output is not a teletype, * then we default to one-per-line format @@ -116,36 +152,57 @@ char *argv[]; * columnar based on our name. */ if (qflg) { - cflg = 1; + Cflg = 1; + if ((sgbuf.sg_flags & XTABS) == 0) + tabflg++; for (cp = argv[0]; cp[0] && cp[1]; cp++) continue; /* - * Name ends in l => stream + * Certain kinds of links (l, ll, lr, lf, lx) cause some + * various options to be turned on. */ - if (cp[0] == 'l') - nopad = 1, cflg = 0; - /* - * ... if doesn't end in l or s ==> columns sorted across - * - else if (cp[0] == 'x') + switch (cp[0]) { + case 'l': + if (cp[-1] == 'l') { + /* ll => -l */ + lflg = 1; + statreq++; + xtraent++; + } else { + /* l => -m */ + nopad = 1; + Cflg = 0; + } + break; + case 'x': /* lx => -x */ across = 1; - */ + break; + case 'f': /* lf => -F */ + Fflg = 1; + break; + case 'r': /* lr => -R */ + Rflg = 1; + break; + } + } else { + tabflg++; } - if (--argc > 0 && *argv[1] == '-') { + + while (--argc > 0 && *argv[1] == '-') { argv++; while (*++*argv) switch (**argv) { /* - * c - force columnar output + * C - force columnar output */ - case 'c': - cflg = 1; + case 'C': + Cflg = 1; nopad = 0; continue; /* * m - force stream output */ case 'm': - cflg = 0; + Cflg = 0; nopad = 1; continue; /* @@ -154,19 +211,27 @@ char *argv[]; case 'x': across = 1; nopad = 0; - cflg = 1; + Cflg = 1; continue; /* * q - force ?'s in output */ case 'q': qflg = 1; + bflg = 0; + continue; + /* + * b - force octal value in output + */ + case 'b': + bflg = 1; + qflg = 0; continue; /* * 1 - force 1/line in output */ case '1': - cflg = 0; + Cflg = 0; nopad = 0; continue; /* STANDARD FLAGS */ @@ -178,10 +243,15 @@ char *argv[]; Aflg = !Aflg; continue; + case 'c': + cflg++; + continue; + case 's': - colwidth += 5; + fixedwidth += 5; sflg++; statreq++; + xtraent++; continue; case 'd': @@ -196,6 +266,7 @@ char *argv[]; case 'l': lflg++; statreq++; + xtraent++; continue; case 'r': @@ -212,7 +283,7 @@ char *argv[]; continue; case 'i': - colwidth += 5; + fixedwidth += 6; iflg++; continue; @@ -224,25 +295,40 @@ char *argv[]; gflg++; continue; - default: + case 'F': + Fflg++; + continue; + + case 'R': + Rflg++; continue; + + default: + fprintf (stderr, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n"); + exit(1); } - argc--; } + if (Fflg) +#ifdef UCB + fixedwidth++; +#else + fixedwidth += 2; +#endif if (fflg) { aflg++; lflg = 0; sflg = 0; tflg = 0; statreq = 0; + xtraent = 0; } if(lflg) { - cflg = 0; + Cflg = 0; t = "/etc/passwd"; if (gflg) t = "/etc/group"; nopad = 0; - colwidth = 70; + fixedwidth = 70; pwdf = fopen(t, "r"); } if (argc==0) { @@ -250,42 +336,126 @@ char *argv[]; argv = &dotp - 1; } for (i=0; i < argc; i++) { - if ((ep = gstat(*++argv, 1))==NULL) + argv++; + if (Cflg) { + width = strlen (*argv); + if (width > filewidth) + filewidth = width; + } + if ((ep = gstat(*argv, 1))==NULL) continue; ep->ln.namep = *argv; ep->lflags |= ISARG; } + if (!Cflg) + filewidth = MAXFILEWIDTH; + else + colwidth = fixedwidth + filewidth; qsort(firstp, lastp - firstp, sizeof *lastp, compar); slastp = lastp; + /* For each argument user typed */ for (epp=firstp; eppltype=='d' && dflg==0 || fflg) { - if (argc>1) - printf("\n%s:\n", ep->ln.namep); - lastp = slastp; - readdir(ep->ln.namep); - if (fflg==0) - qsort(slastp,lastp - slastp,sizeof *lastp,compar); - if (lflg || sflg) - printf("total %D", tblocks); - pem(slastp, lastp); - newline(); - } else + if (ep->ltype=='d' && dflg==0 || fflg) + pdirectory(ep->ln.namep, (argc>1), slastp); + else pentry(ep); + + /* -R: print subdirectories found */ + while (dfirst || cdfirst) { + /* Place direct subdirs on front in right order */ + while (cdfirst) { + /* reverse cdfirst onto front of dfirst */ + dtemp = cdfirst; + cdfirst = cdfirst -> dc_next; + dtemp -> dc_next = dfirst; + dfirst = dtemp; + } + /* take off first dir on dfirst & print it */ + dtemp = dfirst; + dfirst = dfirst->dc_next; + pdirectory (dtemp->dc_name, 1, firstp); + cfree (dtemp->dc_name); + cfree (dtemp); + } } if (outcol) putc('\n', stdout); fflush(stdout); } +/* + * pdirectory: print the directory name, labelling it if title is + * nonzero, using lp as the place to start reading in the dir. + */ +pdirectory (name, title, lp) +char *name; +int title; +struct lbuf **lp; +{ + register struct dchain *dp; + register struct lbuf *ap; + register char *pname; + struct lbuf **app; + + filewidth = 0; + curdir = name; + if (title) + printf("\n%s:\n", name); + lastp = lp; + readdir(name); + if (!Cflg) + filewidth = MAXFILEWIDTH; + colwidth = fixedwidth + filewidth; +#ifdef notdef + /* Taken out because it appears this is done below in pem. */ + if (tabflg) { + if (colwidth <= 8) + colwidth = 8; + else + if (colwidth <= 16) + colwidth = 16; + } +#endif + if (fflg==0) + qsort(lp,lastp - lp,sizeof *lastp,compar); + if (Rflg) for (app=lastp-1; app>=lp; app--) { + ap = *app; + if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && + strcmp(ap->ln.lname, "..")) { + dp = (struct dchain *) calloc(1, sizeof(struct dchain)); + pname = makename (curdir, ap->ln.lname); + dp->dc_name = (char *) calloc(1, strlen(pname)+1); + strcpy(dp->dc_name, pname); + dp -> dc_next = dfirst; + dfirst = dp; + } + } + if (lflg || sflg) + printf("total %D", tblocks); + pem(lp, lastp); + newline(); +} + +/* + * pem: print 'em. Print a list of files (e.g. a directory) bounded + * by slp and lp. + */ pem(slp, lp) register struct lbuf **slp, **lp; { int ncols, nrows, row, col; register struct lbuf **ep; + if (tabflg) { + if (colwidth <= 9) + colwidth = 8; + else + if (colwidth <= 17) + colwidth = 16; + } ncols = 80 / colwidth; - if (ncols == 1 || cflg == 0) { + if (ncols == 1 || Cflg == 0) { for (ep = slp; ep < lp; ep++) pentry(*ep); return; @@ -295,11 +465,11 @@ pem(slp, lp) pentry(*ep); return; } - if (statreq) + if (xtraent) slp--; nrows = (lp - slp - 1) / ncols + 1; for (row = 0; row < nrows; row++) { - col = row == 0 && statreq; + col = row == 0 && xtraent; for (; col < ncols; col++) { ep = slp + (nrows * col) + row; if (ep < lp) @@ -310,9 +480,17 @@ pem(slp, lp) } } +/* + * pputchar: like putchar but knows how to handle control chars. + * CAUTION: if you make ctrl chars print in ^x notation, or any + * other notation which is wider than one character, the column + * nature of things (such as files with 14 letter names) will be + * messed up. Weigh this carefully! + */ pputchar(c) char c; { + char cc; switch (c) { case '\t': @@ -322,8 +500,19 @@ pputchar(c) outcol = 0; break; default: - if (qflg && (c < ' ' || c >= 0177)) - c = '?'; + if (c < ' ' || c >= 0177) { + if (qflg) + c = '?'; + else if (bflg) { + outcol += 3; + putc ('\\', stdout); + cc = '0' + (c>>6 & 07); + putc (cc, stdout); + cc = '0' + (c>>3 & 07); + putc (cc, stdout); + c = '0' + (c & 07); + } + } outcol++; break; } @@ -337,6 +526,9 @@ newline() outcol = 0; } +/* + * column: get to the beginning of the next column. + */ column() { @@ -354,7 +546,7 @@ column() outcol++; return; } - if (cflg == 0) { + if (Cflg == 0) { putc('\n', stdout); return; } @@ -363,6 +555,16 @@ column() outcol = 0; return; } + if (tabflg && (colwidth <= 16)) { + if (colwidth > 8) + if ((outcol % 16) < 8) { + outcol += 8 - (outcol % 8); + putc ('\t', stdout); + } + outcol += 8 - (outcol % 8); + putc ('\t', stdout); + return; + } do { outcol++; putc(' ', stdout); @@ -370,40 +572,10 @@ column() } -getname(uid, buf) -int uid; -char buf[]; -{ - int j, c, n, i; - - if (uid==lastuid) - return(0); - if(pwdf == NULL) - return(-1); - rewind(pwdf); - lastuid = -1; - do { - i = 0; - j = 0; - n = 0; - while((c=fgetc(pwdf)) != '\n') { - if (c==EOF) - return(-1); - if (c==':') { - j++; - c = '0'; - } - if (j==0) - buf[i++] = c; - if (j==2) - n = n*10 + c - '0'; - } - } while (n != uid); - buf[i++] = '\0'; - lastuid = uid; - return(0); -} - +/* + * nblock: the number of 512 byte blocks a size byte file takes up. + * (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.) + */ long nblock(size) long size; @@ -411,6 +583,10 @@ long size; return((size+511)>>9); } +/* + * This code handles the rwx- business. + * You figure it out. + */ int m1[] = { 1, S_IREAD>>0, 'r', '-' }; int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; @@ -443,6 +619,9 @@ register int *pairp; pputchar(*pairp); } +/* + * returns cat(dir, "/", file), unless dir ends in /, when it doesn't // + */ char * makename(dir, file) char *dir, *file; @@ -455,6 +634,7 @@ char *dir, *file; fp = dir; while (*fp) *dp++ = *fp++; + if (*(dp-1) != '/') *dp++ = '/'; fp = file; for (i=0; i filewidth) + filewidth = width; + } + ep = gstat(makename(dir, dentry.d_name), Fflg || Rflg); if (ep==NULL) continue; if (ep->lnum != -1) @@ -495,6 +684,11 @@ char *dir; fclose(dirf); } +/* + * stat the given file and return an lbuf containing it. + * argfl is nonzero if a stat is required because the file is + * an argument, rather than having been found in a directory. + */ struct lbuf * gstat(file, argfl) char *file; @@ -551,6 +745,16 @@ char *file; rep->ltype = 'c'; rep->lsize = statb.st_rdev; break; + + case S_IFMPB: + rep->ltype = 'M'; + rep->lsize = statb.st_rdev; + break; + + case S_IFMPC: + rep->ltype = 'm'; + rep->lsize = statb.st_rdev; + break; } rep->lflags = statb.st_mode & ~S_IFMT; rep->luid = statb.st_uid; @@ -567,6 +771,10 @@ char *file; return(rep); } +/* + * decide whether to print pp1 before or after pp2, based on their + * names, various times, and the r flag. + */ compar(pp1, pp2) struct lbuf **pp1, **pp2; { @@ -593,14 +801,24 @@ struct lbuf **pp1, **pp2; return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname, p2->lflags&ISARG? p2->ln.namep: p2->ln.lname)); } + +/* + * print the entry pointed at by ap + */ pentry(ap) struct lbuf *ap; { struct { char dminor, dmajor;}; - register t; register struct lbuf *p; register char *cp; + char fname[100]; + char *pname; + struct passwd *getpwuid(); + struct passwd *pwptr; + struct group *getgrgid(); + struct group *grptr; + fname[0] = 0; p = ap; if (p->lnum == -1) return; @@ -619,41 +837,94 @@ struct lbuf *ap; pputchar(p->ltype); pmode(p->lflags); printf("%2d ", p->lnl); - t = p->luid; - if(gflg) - t = p->lgid; - if (nflg == 0 && getname(t, tbuf)==0) - printf("%-8.8s", tbuf); - else - printf("%-8d", t); - if (p->ltype=='b' || p->ltype=='c') - printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize)); - else + if(gflg) { + grptr = getgrgid(p->lgid); + if (nflg == 0 && grptr != 0) + printf("%-8.8s", grptr->gr_name); + else + printf("%-8d", p->lgid); + } else { +#ifndef UCB_PWHASH + char *name; + if (nflg == 0 && (name = getname(p->luid))) { + printf("%-8.8s", name); + } +#else + pwptr = getpwuid(p->luid); + if (nflg == 0 && pwptr != 0) + printf("%-8.8s", pwptr->pw_name); +#endif + else + printf("%-8d", p->luid); + } + switch (p->ltype) { + + case 'b': + case 'c': + case 'm': + case 'M': + printf("%3d,%3d", + major((int)p->lsize), minor((int)p->lsize)); + break; + default: printf("%7ld", p->lsize); + } cp = ctime(&p->lmtime); if(p->lmtime < year) printf(" %-7.7s %-4.4s ", cp+4, cp+20); else printf(" %-12.12s ", cp+4); } - if (p->lflags&ISARG) - printf("%s", p->ln.namep); +#ifndef UCB + if (Fflg) { + if (p->ltype == 'd') + strcat (fname, "["); + else if (p->lflags & 0111) + strcat (fname, "*"); + else if (!nopad) + strcat (fname, " "); + } +#endif + if (p->lflags & ISARG) + strncat (fname, p->ln.namep, 98); else - printf("%.14s", p->ln.lname); + strncat (fname, p->ln.lname, 14); +#ifndef UCB + if (Fflg) { + if (p->ltype == 'd') + strcat (fname, "]"); + else if (!nopad) + strcat (fname, " "); + } +#else + if (Fflg) { + if (p->ltype == 'd') + strcat (fname, "/"); + else if (p->lflags & 0111) + strcat (fname, "*"); + else if (!nopad) + strcat (fname, " "); + } +#endif + printf ("%s", fname); + free(ap); } + /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/ + #include "varargs.h" -/* This version of printf is compatible with the Version 7 C + +/* + * This version of printf is compatible with the Version 7 C * printf. The differences are only minor except that this * printf assumes it is to print through pputchar. Version 7 * printf is more general (and is much larger) and includes * provisions for floating point. */ - -#define MAXOCT 11 /* Maximum octal digits in a long */ -#define MAXINT 32767 /* largest normal length positive integer */ +#define MAXOCT 11 /* Maximum octal digits in a long */ +#define MAXINT 32767 /* largest normal length positive integer */ #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ -#define MAXDIGS 10 /* number of digits in BIG */ +#define MAXDIGS 10 /* number of digits in BIG */ static int width, sign, fill; @@ -799,7 +1070,7 @@ printf(va_alist) /* shift and mask for speed */ do if (((int) num & mask1) < 10) - *--bptr = ((int) num & mask1) + 060; + *--bptr = ((int) num & mask1) + 060; else *--bptr = ((int) num & mask1) + 0127; while (num = (num >> nbits) & mask2); @@ -824,7 +1095,8 @@ printf(va_alist) case 'U': case 'I': length = 1; - fcode = fcode + 'a' - 'A'; + + fcode = fcode + 'a' - 'A'; /* no break */ case 'd': case 'i': @@ -979,3 +1251,36 @@ b_emit(s, send) while (--npad >= 0) pputchar(cfill); } + +#ifndef UCB_PWHASH +#define NUID 2048 + +char names[NUID][NMAX+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 (init == 2) + return (0); + if (init == 0) + setpwent(), init = 1; + while (pw = getpwent()) { + if (pw->pw_uid < 0 || pw->pw_uid >= NUID) + continue; + if (names[pw->pw_uid][0]) + continue; + strncpy(names[pw->pw_uid], pw->pw_name, NMAX); + if (pw->pw_uid == uid) + return (&names[uid][0]); + } + init = 2; + endpwent(); + return (0); +} +#endif