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