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