|
|
1.1 root 1: /*
2: * ls
3: */
4:
5: #include <sys/param.h>
6: #include <sys/stat.h>
7: #include <ndir.h>
8: #include <stdio.h>
9: #include <sgtty.h>
10: #include "/usr/jerq/include/jioctl.h"
11:
12: #define kbytes(size) ((size + 1023) / 1024)
13:
14: struct afile {
15: char ftype; /* file type, e.g. 'd', 'c', 'f' */
16: char flink; /* 'L' for symlinks, ' ' otherwise */
17: ino_t fnum; /* inode number of file */
18: short fflags; /* mode&~S_IFMT, perhaps ISARG */
19: short fnl; /* number of links */
20: short fuid; /* owner id */
21: short fgid; /* group id */
22: long fsize; /* file size */
23: time_t fmtime; /* time (modify or access or create) */
24: char *fname; /* file name */
25: char *flinkto; /* symbolic link value */
26: };
27:
28: #define ISARG 0x8000 /* extra ``mode'' */
29:
30: struct subdirs {
31: char *sd_name;
32: struct subdirs *sd_next;
33: } *subdirs;
34:
35: int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1;
36: int qflg, Cflg, Fflg, Lflg, Rflg;
37:
38: #ifdef AFLG
39: int Aflg;
40: #endif
41:
42: int usetabs;
43: int screenwidth = 80; /* default */
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: char buf[BUFSIZ];
67: struct sgttyb sgbuf;
68:
69: setbuf(stderr, buf);
70: argc--, argv++;
71:
72: #ifdef AFLG
73: if (getuid() == 0)
74: Aflg++;
75: #endif
76:
77: (void) time(&now); sixmonthsago = now - 6L*30L*24L*60L*60L; now += 60;
78: if (isatty(1)) {
79: if (ioctl(1,JMUX,0) >= 0) {
80: struct winsize win;
81: if (ioctl(1,JWINSIZE,&win) >= 0) {
82: screenwidth = win.bytesx;
83: if (screenwidth == 0)
84: screenwidth++;
85: }
86: }
87:
88: qflg = Cflg = 1;
89: (void) gtty(1, &sgbuf);
90: if ((sgbuf.sg_flags & XTABS) == 0)
91: usetabs = 1;
92: } else
93: usetabs = 1;
94: while (argc > 0 && **argv == '-') {
95: (*argv)++;
96: while (**argv) switch (*(*argv)++) {
97:
98: case 'C':
99: Cflg = 1; break;
100: case 'q':
101: qflg = 1; break;
102: case '1':
103: Cflg = 0; break;
104: case 'a':
105: aflg++; break;
106:
107: #ifdef AFLG
108: case 'A':
109: Aflg++; break;
110: #endif
111:
112: case 'c':
113: cflg++; break;
114: case 's':
115: sflg++; break;
116: case 'd':
117: dflg++; break;
118: case 'l':
119: lflg++; break;
120: case 'r':
121: rflg = -1; break;
122: case 't':
123: tflg++; break;
124: case 'u':
125: uflg++; break;
126: case 'i':
127: iflg++; break;
128: case 'f':
129: fflg++; break;
130: case 'L':
131: Lflg++; break;
132: case 'F':
133: Fflg++; break;
134: case 'R':
135: Rflg++; break;
136: }
137: argc--, argv++;
138: }
139: if (fflg) {
140: aflg++; lflg = 0; sflg = 0; tflg = 0;
141: }
142: if (lflg)
143: Cflg = 0;
144: if (argc == 0) {
145: argc++;
146: argv = &dotp;
147: }
148: fp = (struct afile *)calloc(argc, sizeof (struct afile));
149: if (fp == 0) {
150: dprintf("ls: out of memory\n");
151: exit(1);
152: }
153: fp0 = fp;
154: for (i = 0; i < argc; i++) {
155: if (gstat(fp, *argv, 1, (int *)0)) {
156: fp->fname = *argv;
157: fp->fflags |= ISARG;
158: fp++;
159: }
160: argv++;
161: }
162: fplast = fp;
163: qsort(fp0, fplast - fp0, sizeof (struct afile), fcmp);
164: if (dflg) {
165: formatf(fp0, fplast);
166: exit(0);
167: }
168: if (fflg)
169: fp = fp0;
170: else {
171: for (fp = fp0; fp < fplast && fp->ftype != 'd'; fp++)
172: continue;
173: formatf(fp0, fp);
174: }
175: if (fp < fplast) {
176: if (fp > fp0)
177: printf("\n");
178: for (;;) {
179: formatd(fp->fname, argc > 1);
180: while (subdirs) {
181: struct subdirs *t;
182:
183: t = subdirs; subdirs = t->sd_next;
184: printf("\n");
185: formatd(t->sd_name, 1);
186: cfree(t->sd_name);
187: cfree((char *)t);
188: }
189: if (++fp == fplast)
190: break;
191: printf("\n");
192: }
193: }
194: exit(0);
195: }
196:
197: formatd(name, title)
198: char *name;
199: int title;
200: {
201: register struct afile *fp;
202: register struct subdirs *dp;
203: struct afile *dfp0, *dfplast;
204: int nkb;
205:
206: nkb = getdir(name, &dfp0, &dfplast);
207: if (dfp0 == 0)
208: return;
209: if (fflg == 0)
210: qsort(dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
211: if (title)
212: printf("%s:\n", name);
213: if (lflg || sflg)
214: printf("total %ld\n", nkb);
215: formatf(dfp0, dfplast);
216: if (Rflg)
217: for (fp = dfplast; fp >= dfp0; fp--) {
218: if (fp->ftype != 'd' ||
219: (fp->flink=='L' && (fp->fflags&ISARG)==0) ||
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 nkb, 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: nkb = 0;
254: while (dp = readdir(dirp)) {
255: if (dp->d_ino == 0)
256: continue;
257: if (aflg == 0 && dp->d_name[0]=='.' && (
258:
259: #ifdef AFLG
260: Aflg == 0 ||
261: #endif
262:
263: dp->d_name[1]==0 || dp->d_name[1]=='.' && dp->d_name[2]==0))
264: continue;
265: if (gstat(fp, cat(dir, dp->d_name), 0, &nkb) == 0)
266: continue;
267: fp->fnum = dp->d_ino;
268: fp->fname = savestr(dp->d_name);
269: fp++;
270: if (fp == *pfplast) {
271: *pfp0 = (struct afile *)realloc((char *)*pfp0,
272: 2 * nent * sizeof (struct afile));
273: if (*pfp0 == 0) {
274: dprintf("ls: out of memory\n");
275: exit(1);
276: }
277: fp = *pfp0 + nent;
278: *pfplast = fp + nent;
279: nent *= 2;
280: }
281: }
282: closedir(dirp);
283: *pfplast = fp;
284: return (nkb);
285: }
286:
287: int stat(), lstat();
288:
289: struct afile *
290: gstat(fp, file, statarg, pnkb)
291: register struct afile *fp;
292: char *file;
293: int statarg, *pnkb;
294: {
295: char buf[BUFSIZ]; int cc;
296: static struct afile azerofile = { 0, ' ' };
297: static struct afile azerolink = { 0, 'L' };
298:
299: *fp = azerofile;
300: fp->fflags = 0;
301: fp->fnum = 0;
302: fp->ftype = '-';
303: if (statarg || sflg || lflg || tflg || Fflg || Rflg) {
304: struct stat stb;
305:
306: if (lstat(file, &stb) < 0) {
307: if (statarg) {
308: dprintf("%s not found\n", file);
309: return (0);
310: }
311: return (&azerofile);
312: }
313: fp->flink = ' ';
314: if (Lflg==0 && (stb.st_mode&S_IFMT)==S_IFLNK) {
315: fp->flink = 'L';
316: if (stat(file, &stb) < 0)
317: return (&azerolink);
318: }
319: fp->fsize = stb.st_size;
320: switch (stb.st_mode & S_IFMT) {
321:
322: case S_IFDIR:
323: fp->ftype = 'd'; break;
324: case S_IFBLK:
325: fp->ftype = 'b'; fp->fsize = stb.st_rdev; break;
326: case S_IFCHR:
327: fp->ftype = 'c'; fp->fsize = stb.st_rdev; break;
328: case S_IFLNK:
329: fp->ftype = 'l';
330: if (lflg) {
331: cc = readlink(file, buf, BUFSIZ);
332: if (cc >= 0) {
333: buf[cc] = 0;
334: fp->flinkto = savestr(buf);
335: }
336: }
337: break;
338: }
339: fp->fnum = stb.st_ino;
340: fp->fflags = stb.st_mode & ~S_IFMT;
341: fp->fnl = stb.st_nlink;
342: fp->fuid = stb.st_uid;
343: fp->fgid = stb.st_gid;
344: if (uflg)
345: fp->fmtime = stb.st_atime;
346: else if (cflg)
347: fp->fmtime = stb.st_ctime;
348: else
349: fp->fmtime = stb.st_mtime;
350: if (pnkb)
351: if (fp->ftype != 'b' && fp->ftype != 'c')
352: *pnkb += kbytes(fp->fsize);
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 = screenwidth / 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: dprintf("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: dprintf("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: dprintf(a, b, c)
468: char *a, *b, *c;
469: {
470: fprintf(stderr, a, b, c);
471: fflush(stderr);
472: }
473:
474: char *
475: fmtentry(fp)
476: register struct afile *fp;
477: {
478: static char fmtres[BUFSIZ];
479: register char *cp, *dp;
480:
481: (void) sprintf(fmtres, "%s%s%s",
482: iflg ? fmtinum(fp) : "",
483: sflg ? fmtsize(fp) : "",
484: lflg ? fmtlstuff(fp) : "");
485: dp = &fmtres[strlen(fmtres)];
486: for (cp = fp->fname; *cp; cp++)
487: if (qflg && (*cp < ' ' || *cp >= 0177))
488: *dp++ = '?';
489: else
490: *dp++ = *cp;
491: if (Fflg) {
492: if (fp->ftype == 'd')
493: *dp++ = '/';
494: else if (fp->ftype == 'l')
495: *dp++ = '@';
496: else if (fp->fflags & 0111)
497: *dp++ = '*';
498: }
499: if (lflg && fp->flinkto) {
500: (void) strcpy(dp, " -> "); dp += 4;
501: for (cp = fp->flinkto; *cp; cp++)
502: if (qflg && (*cp < ' ' || *cp >= 0177))
503: *dp++ = '?';
504: else
505: *dp++ = *cp;
506: }
507: *dp++ = 0;
508: return (fmtres);
509: }
510:
511: char *
512: fmtinum(p)
513: register struct afile *p;
514: {
515: static char inumbuf[8];
516:
517: (void) sprintf(inumbuf, "%5d ", p->fnum);
518: return (inumbuf);
519: }
520:
521: char *
522: fmtsize(p)
523: register struct afile *p;
524: {
525: static char sizebuf[32];
526:
527: switch (p->ftype) {
528:
529: case 'b':
530: case 'c':
531: (void) sprintf(sizebuf, "%4ld ", 0);
532: break;
533:
534: default:
535: (void) sprintf(sizebuf, "%4ld ", kbytes(p->fsize));
536: break;
537: }
538: return (sizebuf);
539: }
540:
541: char *
542: fmtlstuff(p)
543: register struct afile *p;
544: {
545: static char lstuffbuf[256];
546: char gname[32], uname[32], fsize[32], ftime[32];
547: register char *lp = lstuffbuf;
548: extern char *ngs();
549:
550: /* type mode uname gname fsize ftime */
551: /* get uname */
552: { char *cp = getname(p->fuid);
553: if (cp)
554: (void) sprintf(uname, "%s", cp);
555: else
556: (void) sprintf(uname, "%d", p->fuid);
557: }
558: /* get gname */
559: {
560: char *cp = getgroup(p->fgid);
561: if (cp)
562: (void) sprintf(gname, "%s", cp);
563: else
564: (void) sprintf(gname, "%d", p->fgid);
565: }
566: /* get fsize */
567: if (p->ftype == 'b' || p->ftype == 'c')
568: (void) sprintf(fsize, "%d,%3d",
569: major(p->fsize), minor(p->fsize));
570: else
571: (void) sprintf(fsize, "%ld", p->fsize);
572: /* get ftime */
573: { char *cp = ctime(&p->fmtime);
574: if ((p->fmtime < sixmonthsago) || (p->fmtime > now))
575: (void) sprintf(ftime, " %-7.7s %-4.4s ", cp+4, cp+20);
576: else
577: (void) sprintf(ftime, " %-12.12s ", cp+4);
578: }
579: /* splat */
580: *lp++ = p->ftype;
581: lp = fmtmode(lp, p->fflags);
582: (void) sprintf(lp, "%3d%c %s%s",
583: p->fnl, p->flink, ngs(uname, gname, fsize), ftime);
584: return (lstuffbuf);
585: }
586:
587: /* format username, group, size in small space */
588: char *
589: ngs(name, group, size)
590: char *name, *group, *size;
591: {
592: static char r[64];
593: register s1, s2;
594: register sn=strlen(name), sg=strlen(group), ss=strlen(size);
595:
596: s1 = 8-sn;
597: s2 = 12-(sg+ss);
598: if (s2<1) {
599: s1 -= 1-s2;
600: s2 = 1;
601: }
602: if (s1<1) {
603: s2 -= 1-s1;
604: s1 = 1;
605: }
606: if (s2<1)
607: s2 = 1;
608: sprintf(r, "%s%*s%s%*s%s", name, s1, "", group, s2, "", size);
609: return(r);
610: }
611:
612:
613: int m1[] = { 1, S_IREAD>>0, 'r', '-' };
614: int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
615: int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
616: int m4[] = { 1, S_IREAD>>3, 'r', '-' };
617: int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
618: int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
619: int m7[] = { 1, S_IREAD>>6, 'r', '-' };
620: int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
621: int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
622:
623: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
624:
625: char *
626: fmtmode(lp, flags)
627: char *lp;
628: int flags;
629: {
630: int **mp;
631:
632: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])]; ) {
633: register int *pairp = *mp++;
634: register int n = *pairp++;
635:
636: while (--n >= 0 && (flags&*pairp++) == 0)
637: pairp++;
638: *lp++ = *pairp;
639: }
640: return (lp);
641: }
642:
643: /* rest should be done with nameserver or database */
644:
645: #include <pwd.h>
646: #include <grp.h>
647: #include <utmp.h>
648:
649: struct utmp utmp;
650:
651: #define NUID 2048
652: #define NGID 300
653: #define NMAX (sizeof (utmp.ut_name))
654:
655: char names[NUID][NMAX+1];
656: char groups[NGID][NMAX+1];
657:
658: char *
659: getname(uid)
660: {
661: register struct passwd *pw;
662: static init;
663: struct passwd *getpwent();
664:
665: if (uid >= 0 && uid < NUID && names[uid][0])
666: return (&names[uid][0]);
667: if (init == 2)
668: return (0);
669: if (init == 0)
670: setpwent(), init = 1;
671: while (pw = getpwent()) {
672: if (pw->pw_uid < 0 || pw->pw_uid >= NUID)
673: continue;
674: if (names[pw->pw_uid][0])
675: continue;
676: strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
677: if (pw->pw_uid == uid) {
678: return (&names[uid][0]);
679: }
680: }
681: init = 2;
682: endpwent();
683: return (0);
684: }
685:
686: char *
687: getgroup(gid)
688: {
689: register struct group *gr;
690: static init;
691: struct group *getgrent();
692:
693: if (gid >= 0 && gid < NGID && groups[gid][0])
694: return (&groups[gid][0]);
695: if (init == 2)
696: return (0);
697: if (init == 0)
698: setgrent(), init = 1;
699: while (gr = getgrent()) {
700: if (gr->gr_gid < 0 || gr->gr_gid >= NGID)
701: continue;
702: if (groups[gr->gr_gid][0])
703: continue;
704: strncpy(groups[gr->gr_gid], gr->gr_name, NMAX);
705: if (gr->gr_gid == gid) {
706: return (&groups[gid][0]);
707: }
708: }
709: init = 2;
710: endgrent();
711: return (0);
712: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.