|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)ls.c 5.9 (Berkeley) 10/22/87";
15: #endif not lint
16:
17: /*
18: * ls
19: *
20: * 4.2bsd version for symbolic links, variable length
21: * directory entries, block size in the inode, etc.
22: */
23: #include <sys/param.h>
24: #include <sys/stat.h>
25: #include <sys/dir.h>
26: #include <stdio.h>
27: #include <sgtty.h>
28:
29: #define kbytes(size) (((size) + 1023) / 1024)
30:
31: struct afile {
32: char ftype; /* file type, e.g. 'd', 'c', 'f' */
33: ino_t fnum; /* inode number of file */
34: short fflags; /* mode&~S_IFMT, perhaps ISARG */
35: short fnl; /* number of links */
36: uid_t fuid; /* owner id */
37: gid_t fgid; /* group id */
38: off_t fsize; /* file size */
39: long fblks; /* number of blocks used */
40: time_t fmtime; /* time (modify or access or create) */
41: char *fname; /* file name */
42: char *flinkto; /* symbolic link value */
43: };
44:
45: #define ISARG 0x8000 /* extra ``mode'' */
46:
47: struct subdirs {
48: char *sd_name;
49: struct subdirs *sd_next;
50: } *subdirs;
51:
52: int aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1;
53: int qflg, Aflg, Cflg, Fflg, Lflg, Rflg;
54:
55: int usetabs;
56:
57: time_t now, sixmonthsago;
58:
59: char *dotp = ".";
60:
61: struct winsize win;
62: int twidth;
63:
64: struct afile *gstat();
65: int fcmp();
66: char *cat(), *savestr();
67: char *fmtentry();
68: char *getname(), *getgroup();
69:
70: char *ctime();
71: char *malloc(), *calloc(), *realloc();
72: char *strcpy(), *strcat();
73:
74: main(argc, argv)
75: int argc;
76: char *argv[];
77: {
78: extern int optind;
79: struct afile *fp0, *fplast;
80: register struct afile *fp;
81: struct sgttyb sgbuf;
82: int ch, i;
83: time_t time();
84:
85: Aflg = !getuid();
86: (void) time(&now); sixmonthsago = now - 6L*30L*24L*60L*60L; now += 60;
87: twidth = 80;
88: if (isatty(1)) {
89: qflg = Cflg = 1;
90: (void) gtty(1, &sgbuf);
91: if (ioctl(1, TIOCGWINSZ, &win) != -1)
92: twidth = (win.ws_col == 0 ? 80 : win.ws_col);
93: if ((sgbuf.sg_flags & XTABS) != XTABS)
94: usetabs = 1;
95: } else
96: usetabs = 1;
97: while ((ch = getopt(argc, argv, "1ACLFRacdfgilqrstu")) != EOF)
98: switch((char)ch) {
99: case '1':
100: Cflg = 0; break;
101: case 'A':
102: Aflg++; break;
103: case 'C':
104: Cflg = 1; break;
105: case 'L':
106: Lflg++; break;
107: case 'F':
108: Fflg++; break;
109: case 'R':
110: Rflg++; break;
111: case 'a':
112: aflg++; break;
113: case 'c':
114: cflg++; break;
115: case 'd':
116: dflg++; break;
117: case 'f':
118: fflg++; break;
119: case 'g':
120: gflg++; break;
121: case 'i':
122: iflg++; break;
123: case 'l':
124: lflg++; break;
125: case 'q':
126: qflg = 1; break;
127: case 'r':
128: rflg = -1; break;
129: case 's':
130: sflg++; break;
131: case 't':
132: tflg++; break;
133: case 'u':
134: uflg++; break;
135: case '?':
136: default:
137: fputs("usage: ls [ -1ACLFRacdfgilqrstu ] [ file ]\n", stderr);
138: exit(1);
139: }
140: if (fflg) {
141: aflg++; lflg = 0; sflg = 0; tflg = 0;
142: }
143: if (lflg)
144: Cflg = 0;
145: argc -= optind;
146: argv += optind;
147: if (argc == 0) {
148: argc++;
149: argv = &dotp;
150: }
151: fp = (struct afile *)calloc((u_int)argc, sizeof (struct afile));
152: if (fp == 0) {
153: fputs("ls: out of memory\n", stderr);
154: exit(1);
155: }
156: fp0 = fp;
157: for (i = 0; i < argc; i++) {
158: if (gstat(fp, *argv, 1, (int *)0)) {
159: fp->fname = *argv;
160: fp->fflags |= ISARG;
161: fp++;
162: }
163: argv++;
164: }
165: fplast = fp;
166: qsort(fp0, fplast - fp0, sizeof (struct afile), fcmp);
167: if (dflg) {
168: formatf(fp0, fplast);
169: exit(0);
170: }
171: if (fflg)
172: fp = fp0;
173: else {
174: for (fp = fp0; fp < fplast && fp->ftype != 'd'; fp++)
175: continue;
176: formatf(fp0, fp);
177: }
178: if (fp < fplast) {
179: if (fp > fp0)
180: putchar('\n');
181: for (;;) {
182: formatd(fp->fname, argc > 1);
183: while (subdirs) {
184: struct subdirs *t;
185:
186: t = subdirs; subdirs = t->sd_next;
187: putchar('\n');
188: formatd(t->sd_name, 1);
189: cfree(t->sd_name);
190: cfree((char *)t);
191: }
192: if (++fp == fplast)
193: break;
194: putchar('\n');
195: }
196: }
197: exit(0);
198: }
199:
200: formatd(name, title)
201: char *name;
202: int title;
203: {
204: register struct afile *fp;
205: register struct subdirs *dp;
206: struct afile *dfp0, *dfplast;
207: int nkb;
208:
209: nkb = getdir(name, &dfp0, &dfplast);
210: if (dfp0 == 0)
211: return;
212: if (fflg == 0)
213: qsort(dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
214: if (title)
215: printf("%s:\n", name);
216: if (lflg || sflg)
217: printf("total %d\n", nkb);
218: formatf(dfp0, dfplast);
219: if (Rflg)
220: for (fp = dfplast - 1; fp >= dfp0; fp--) {
221: if (fp->ftype != 'd' ||
222: !strcmp(fp->fname, ".") ||
223: !strcmp(fp->fname, ".."))
224: continue;
225: dp = (struct subdirs *)malloc(sizeof (struct subdirs));
226: dp->sd_name = savestr(cat(name, fp->fname));
227: dp->sd_next = subdirs; subdirs = dp;
228: }
229: for (fp = dfp0; fp < dfplast; fp++) {
230: if ((fp->fflags&ISARG) == 0 && fp->fname)
231: cfree(fp->fname);
232: if (fp->flinkto)
233: cfree(fp->flinkto);
234: }
235: cfree((char *)dfp0);
236: }
237:
238: getdir(dir, pfp0, pfplast)
239: char *dir;
240: struct afile **pfp0, **pfplast;
241: {
242: register struct afile *fp;
243: DIR *dirp;
244: register struct direct *dp;
245: int nb, nent = 20;
246:
247: dirp = opendir(dir);
248: if (dirp == NULL) {
249: *pfp0 = *pfplast = NULL;
250: printf("%s unreadable\n", dir); /* not stderr! */
251: return (0);
252: }
253: fp = *pfp0 = (struct afile *)calloc(nent, sizeof (struct afile));
254: *pfplast = *pfp0 + nent;
255: nb = 0;
256: while (dp = readdir(dirp)) {
257: if (dp->d_ino == 0)
258: continue;
259: if (aflg == 0 && dp->d_name[0]=='.' &&
260: (Aflg == 0 || dp->d_name[1]==0 ||
261: dp->d_name[1]=='.' && dp->d_name[2]==0))
262: continue;
263: if (gstat(fp, cat(dir, dp->d_name), Fflg+Rflg, &nb) == 0)
264: continue;
265: fp->fnum = dp->d_ino;
266: fp->fname = savestr(dp->d_name);
267: fp++;
268: if (fp == *pfplast) {
269: *pfp0 = (struct afile *)realloc((char *)*pfp0,
270: 2 * nent * sizeof (struct afile));
271: if (*pfp0 == 0) {
272: fputs("ls: out of memory\n", stderr);
273: exit(1);
274: }
275: fp = *pfp0 + nent;
276: *pfplast = fp + nent;
277: nent *= 2;
278: }
279: }
280: closedir(dirp);
281: *pfplast = fp;
282: return (kbytes(dbtob(nb)));
283: }
284:
285: int stat(), lstat();
286:
287: struct afile *
288: gstat(fp, file, statarg, pnb)
289: register struct afile *fp;
290: char *file;
291: int statarg, *pnb;
292: {
293: int (*statf)() = Lflg ? stat : lstat;
294: char buf[BUFSIZ]; int cc;
295: static struct afile azerofile;
296:
297: *fp = azerofile;
298: fp->fflags = 0;
299: fp->fnum = 0;
300: fp->ftype = '-';
301: if (statarg || sflg || lflg || tflg) {
302: struct stat stb, stb1;
303:
304: if ((*statf)(file, &stb) < 0) {
305: if (statf == lstat || lstat(file, &stb) < 0) {
306: fprintf(stderr, "%s not found\n", file);
307: return (0);
308: }
309: }
310: fp->fblks = stb.st_blocks;
311: fp->fsize = stb.st_size;
312: switch (stb.st_mode & S_IFMT) {
313:
314: case S_IFDIR:
315: fp->ftype = 'd'; break;
316: case S_IFBLK:
317: fp->ftype = 'b'; fp->fsize = stb.st_rdev; break;
318: case S_IFCHR:
319: fp->ftype = 'c'; fp->fsize = stb.st_rdev; break;
320: case S_IFSOCK:
321: fp->ftype = 's'; fp->fsize = 0; break;
322: case S_IFLNK:
323: fp->ftype = 'l';
324: if (lflg) {
325: cc = readlink(file, buf, BUFSIZ);
326: if (cc >= 0) {
327: buf[cc] = 0;
328: fp->flinkto = savestr(buf);
329: }
330: break;
331: }
332: if (stat(file, &stb1) < 0)
333: break;
334: if ((stb1.st_mode & S_IFMT) == S_IFDIR) {
335: stb = stb1;
336: fp->ftype = 'd';
337: fp->fsize = stb.st_size;
338: fp->fblks = stb.st_blocks;
339: }
340: break;
341: }
342: fp->fnum = stb.st_ino;
343: fp->fflags = stb.st_mode & ~S_IFMT;
344: fp->fnl = stb.st_nlink;
345: fp->fuid = stb.st_uid;
346: fp->fgid = stb.st_gid;
347: if (uflg)
348: fp->fmtime = stb.st_atime;
349: else if (cflg)
350: fp->fmtime = stb.st_ctime;
351: else
352: fp->fmtime = stb.st_mtime;
353: if (pnb)
354: *pnb += stb.st_blocks;
355: }
356: return (fp);
357: }
358:
359: formatf(fp0, fplast)
360: struct afile *fp0, *fplast;
361: {
362: register struct afile *fp;
363: register int i, j, w;
364: int width = 0, nentry = fplast - fp0;
365: int columns, lines;
366: char *cp;
367:
368: if (fp0 == fplast)
369: return;
370: if (lflg || Cflg == 0)
371: columns = 1;
372: else {
373: for (fp = fp0; fp < fplast; fp++) {
374: int len = strlen(fmtentry(fp));
375:
376: if (len > width)
377: width = len;
378: }
379: if (usetabs)
380: width = (width + 8) &~ 7;
381: else
382: width += 2;
383: columns = twidth / width;
384: if (columns == 0)
385: columns = 1;
386: }
387: lines = (nentry + columns - 1) / columns;
388: for (i = 0; i < lines; i++) {
389: for (j = 0; j < columns; j++) {
390: fp = fp0 + j * lines + i;
391: cp = fmtentry(fp);
392: fputs(cp, stdout);
393: if (fp + lines >= fplast) {
394: putchar('\n');
395: break;
396: }
397: w = strlen(cp);
398: while (w < width)
399: if (usetabs) {
400: w = (w + 8) &~ 7;
401: putchar('\t');
402: } else {
403: w++;
404: putchar(' ');
405: }
406: }
407: }
408: }
409:
410: fcmp(f1, f2)
411: register struct afile *f1, *f2;
412: {
413:
414: if (dflg == 0 && fflg == 0) {
415: if ((f1->fflags&ISARG) && f1->ftype == 'd') {
416: if ((f2->fflags&ISARG) == 0 || f2->ftype != 'd')
417: return (1);
418: } else {
419: if ((f2->fflags&ISARG) && f2->ftype == 'd')
420: return (-1);
421: }
422: }
423: if (tflg) {
424: if (f2->fmtime == f1->fmtime)
425: return (0);
426: if (f2->fmtime > f1->fmtime)
427: return (rflg);
428: return (-rflg);
429: }
430: return (rflg * strcmp(f1->fname, f2->fname));
431: }
432:
433: char *
434: cat(dir, file)
435: char *dir, *file;
436: {
437: static char dfile[BUFSIZ];
438: register int dlen;
439:
440: if ((dlen = strlen(dir))+1+strlen(file)+1 > BUFSIZ) {
441: fputs("ls: filename too long\n", stderr);
442: exit(1);
443: }
444: if (!dir[0] || dir[0] == '.' && !dir[1])
445: return(strcpy(dfile, file));
446: (void) strcpy(dfile, dir);
447: if (dir[dlen - 1] != '/' && *file != '/')
448: dfile[dlen++] = '/';
449: (void) strcpy(dfile + dlen, file);
450: return (dfile);
451: }
452:
453: char *
454: savestr(str)
455: char *str;
456: {
457: char *cp = malloc(strlen(str) + 1);
458:
459: if (cp == NULL) {
460: fputs("ls: out of memory\n", stderr);
461: exit(1);
462: }
463: return(strcpy(cp, str));
464: }
465:
466: char *fmtinum(), *fmtsize(), *fmtlstuff(), *fmtmode();
467:
468: char *
469: fmtentry(fp)
470: register struct afile *fp;
471: {
472: static char fmtres[BUFSIZ];
473: register char *cp, *dp;
474:
475: (void) sprintf(fmtres, "%s%s%s",
476: iflg ? fmtinum(fp) : "",
477: sflg ? fmtsize(fp) : "",
478: lflg ? fmtlstuff(fp) : "");
479: dp = &fmtres[strlen(fmtres)];
480: for (cp = fp->fname; *cp; cp++)
481: if (qflg && (*cp < ' ' || *cp >= 0177))
482: *dp++ = '?';
483: else
484: *dp++ = *cp;
485: if (Fflg) {
486: if (fp->ftype == 'd')
487: *dp++ = '/';
488: else if (fp->ftype == 'l')
489: *dp++ = '@';
490: else if (fp->ftype == 's')
491: *dp++ = '=';
492: else if (fp->fflags & 0111)
493: *dp++ = '*';
494: }
495: if (lflg && fp->flinkto) {
496: (void) strcpy(dp, " -> "); dp += 4;
497: for (cp = fp->flinkto; *cp; cp++)
498: if (qflg && (*cp < ' ' || *cp >= 0177))
499: *dp++ = '?';
500: else
501: *dp++ = *cp;
502: }
503: *dp++ = 0;
504: return (fmtres);
505: }
506:
507: char *
508: fmtinum(p)
509: register struct afile *p;
510: {
511: static char inumbuf[8];
512:
513: (void) sprintf(inumbuf, "%6ld ", p->fnum);
514: return (inumbuf);
515: }
516:
517: char *
518: fmtsize(p)
519: register struct afile *p;
520: {
521: static char sizebuf[32];
522:
523: (void) sprintf(sizebuf, "%4ld ", kbytes(dbtob(p->fblks)));
524: return (sizebuf);
525: }
526:
527: char *
528: fmtlstuff(p)
529: register struct afile *p;
530: {
531: static char lstuffbuf[256];
532: char gname[32], uname[32], fsize[32], ftime[32];
533: register char *lp = lstuffbuf;
534:
535: /* type mode uname gname fsize ftime */
536: /* get uname */
537: { char *cp = getname(p->fuid);
538: if (cp)
539: (void) sprintf(uname, "%-9.9s", cp);
540: else
541: (void) sprintf(uname, "%-9u", p->fuid);
542: }
543: /* get gname */
544: if (gflg) {
545: char *cp = getgroup(p->fgid);
546: if (cp)
547: (void) sprintf(gname, "%-9.9s", cp);
548: else
549: (void) sprintf(gname, "%-9u", p->fgid);
550: }
551: /* get fsize */
552: if (p->ftype == 'b' || p->ftype == 'c')
553: (void) sprintf(fsize, "%3d,%4d",
554: major(p->fsize), minor(p->fsize));
555: else if (p->ftype == 's')
556: (void) sprintf(fsize, "%8ld", 0L);
557: else
558: (void) sprintf(fsize, "%8ld", p->fsize);
559: /* get ftime */
560: { char *cp = ctime(&p->fmtime);
561: if ((p->fmtime < sixmonthsago) || (p->fmtime > now))
562: (void) sprintf(ftime, " %-7.7s %-4.4s ", cp+4, cp+20);
563: else
564: (void) sprintf(ftime, " %-12.12s ", cp+4);
565: }
566: /* splat */
567: *lp++ = p->ftype;
568: lp = fmtmode(lp, p->fflags);
569: (void) sprintf(lp, "%3d %s%s%s%s",
570: p->fnl, uname, gflg ? gname : "", fsize, ftime);
571: return (lstuffbuf);
572: }
573:
574: int m1[] = { 1, S_IREAD>>0, 'r', '-' };
575: int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
576: int m3[] = { 3, S_ISUID|(S_IEXEC>>0), 's', S_ISUID, 'S', S_IEXEC>>0, 'x', '-' };
577: int m4[] = { 1, S_IREAD>>3, 'r', '-' };
578: int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
579: int m6[] = { 3, S_ISGID|(S_IEXEC>>3), 's', S_ISGID, 'S', S_IEXEC>>3, 'x', '-' };
580: int m7[] = { 1, S_IREAD>>6, 'r', '-' };
581: int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
582: int m9[] = { 3, S_ISVTX|(S_IEXEC>>6), 't', S_ISVTX, 'T', S_IEXEC>>6, 'x', '-' };
583:
584: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
585:
586: char *
587: fmtmode(lp, flags)
588: char *lp;
589: register int flags;
590: {
591: int **mp;
592:
593: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])]; ) {
594: register int *pairp = *mp++;
595: register int n = *pairp++;
596:
597: while (--n >= 0 && (flags&*pairp) != *pairp)
598: pairp += 2;
599: *lp++ = pairp[n>=0];
600: }
601: return (lp);
602: }
603:
604: /* rest should be done with nameserver or database */
605:
606: #include <pwd.h>
607: #include <grp.h>
608: #include <utmp.h>
609:
610: struct utmp utmp;
611: #define NMAX (sizeof (utmp.ut_name))
612: #define SCPYN(a, b) strncpy(a, b, NMAX)
613:
614: #define NCACHE 64 /* power of 2 */
615: #define CAMASK NCACHE - 1
616:
617: char *
618: getname(uid)
619: uid_t uid;
620: {
621: extern int _pw_stayopen;
622: static struct ncache {
623: uid_t uid;
624: char name[NMAX+1];
625: } c_uid[NCACHE];
626: register struct passwd *pw;
627: register struct ncache *cp;
628:
629: _pw_stayopen = 1;
630: cp = c_uid + (uid & CAMASK);
631: if (cp->uid == uid && *cp->name)
632: return(cp->name);
633: if (!(pw = getpwuid(uid)))
634: return((char *)0);
635: cp->uid = uid;
636: SCPYN(cp->name, pw->pw_name);
637: return(cp->name);
638: }
639:
640: char *
641: getgroup(gid)
642: gid_t gid;
643: {
644: static struct ncache {
645: gid_t gid;
646: char name[NMAX+1];
647: } c_gid[NCACHE];
648: register struct group *gr;
649: register struct ncache *cp;
650:
651: cp = c_gid + (gid & CAMASK);
652: if (cp->gid == gid && *cp->name)
653: return(cp->name);
654: if (!(gr = getgrgid(gid)))
655: return((char *)0);
656: cp->gid = gid;
657: SCPYN(cp->name, gr->gr_name);
658: return(cp->name);
659: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.