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