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