|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)find.c 4.20 (Berkeley) 9/28/87";
3: #endif
4:
5: #include <stdio.h>
6: #include <sys/param.h>
7: #include <sys/dir.h>
8: #include <sys/stat.h>
9:
10: #define A_DAY 86400L /* a day full of seconds */
11: #define EQ(x, y) (strcmp(x, y)==0)
12:
13: int Randlast;
14: char Pathname[MAXPATHLEN+1];
15:
16: #define MAXNODES 100
17:
18: struct anode {
19: int (*F)();
20: struct anode *L, *R;
21: } Node[MAXNODES];
22: int Nn; /* number of nodes */
23: char *Fname;
24: long Now;
25: int Argc,
26: Ai,
27: Pi;
28: char **Argv;
29: /* cpio stuff */
30: int Cpio;
31: short *Buf, *Dbuf, *Wp;
32: int Bufsize = 5120;
33: int Wct = 2560;
34:
35: long Newer;
36:
37: int Xdev = 1; /* true if SHOULD cross devices (file systems) */
38: int follow; /* true if SHOULD descend symlinked directories */
39: struct stat Devstat; /* stats of each argument path's file system */
40:
41: struct stat Statb;
42:
43: struct anode *exp(),
44: *e1(),
45: *e2(),
46: *e3(),
47: *mk();
48: char *nxtarg();
49: char Home[MAXPATHLEN + 1];
50: long Blocks;
51: char *rindex();
52: char *sbrk();
53:
54: /*
55: * SEE ALSO: updatedb, bigram.c, code.c
56: * Usenix ;login:, February/March, 1983, p. 8.
57: *
58: * REVISIONS: James A. Woods, Informatics General Corporation,
59: * NASA Ames Research Center, 6/81.
60: *
61: * The second form searches a pre-computed filelist
62: * (constructed nightly by /usr/lib/crontab) which is
63: * compressed by updatedb (v.i.z.) The effect of
64: * find <name>
65: * is similar to
66: * find / +0 -name "*<name>*" -print
67: * but much faster.
68: *
69: * 8/82 faster yet + incorporation of bigram coding -- jaw
70: *
71: * 1/83 incorporate glob-style matching -- jaw
72: */
73: #define AMES 1
74:
75: main(argc, argv)
76: int argc;
77: char *argv[];
78: {
79: struct anode *exlist;
80: int paths;
81: register char *cp, *sp = 0;
82: #ifdef SUID_PWD
83: FILE *pwd, *popen();
84: #endif
85:
86: #ifdef AMES
87: if (argc < 2) {
88: fprintf(stderr,
89: "Usage: find name, or find path-list predicate-list\n");
90: exit(1);
91: }
92: if (argc == 2) {
93: fastfind(argv[1]);
94: exit(0);
95: }
96: #endif
97: time(&Now);
98: #ifdef SUID_PWD
99: pwd = popen("pwd", "r");
100: fgets(Home, sizeof Home, pwd);
101: pclose(pwd);
102: Home[strlen(Home) - 1] = '\0';
103: #else
104: if (getwd(Home) == NULL) {
105: fprintf(stderr, "find: Can't get current working directory\n");
106: exit(1);
107: }
108: #endif
109: Argc = argc; Argv = argv;
110: if(argc<3) {
111: usage: fprintf(stderr, "Usage: find path-list predicate-list\n");
112: exit(1);
113: }
114: for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths)
115: if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!"))
116: break;
117: if(paths == 1) /* no path-list */
118: goto usage;
119: if(!(exlist = exp())) { /* parse and compile the arguments */
120: fprintf(stderr, "find: parsing error\n");
121: exit(1);
122: }
123: if(Ai<argc) {
124: fprintf(stderr, "find: missing conjunction\n");
125: exit(1);
126: }
127: for(Pi = 1; Pi < paths; ++Pi) {
128: sp = 0;
129: chdir(Home);
130: strcpy(Pathname, Argv[Pi]);
131: if(cp = rindex(Pathname, '/')) {
132: sp = cp + 1;
133: *cp = '\0';
134: if(chdir(*Pathname? Pathname: "/") == -1) {
135: fprintf(stderr, "find: bad starting directory\n");
136: exit(2);
137: }
138: *cp = '/';
139: }
140: Fname = sp? sp: Pathname;
141: if (!Xdev)
142: stat(Pathname, &Devstat);
143: descend(Pathname, Fname, exlist); /* to find files that match */
144: }
145: if(Cpio) {
146: strcpy(Pathname, "TRAILER!!!");
147: Statb.st_size = 0;
148: cpio();
149: printf("%D blocks\n", Blocks*10);
150: }
151: exit(0);
152: }
153:
154: /* compile time functions: priority is exp()<e1()<e2()<e3() */
155:
156: struct anode *exp() { /* parse ALTERNATION (-o) */
157: int or();
158: register struct anode * p1;
159:
160: p1 = e1() /* get left operand */ ;
161: if(EQ(nxtarg(), "-o")) {
162: Randlast--;
163: return(mk(or, p1, exp()));
164: }
165: else if(Ai <= Argc) --Ai;
166: return(p1);
167: }
168: struct anode *e1() { /* parse CONCATENATION (formerly -a) */
169: int and();
170: register struct anode * p1;
171: register char *a;
172:
173: p1 = e2();
174: a = nxtarg();
175: if(EQ(a, "-a")) {
176: And:
177: Randlast--;
178: return(mk(and, p1, e1()));
179: } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
180: --Ai;
181: goto And;
182: } else if(Ai <= Argc) --Ai;
183: return(p1);
184: }
185: struct anode *e2() { /* parse NOT (!) */
186: int not();
187:
188: if(Randlast) {
189: fprintf(stderr, "find: operand follows operand\n");
190: exit(1);
191: }
192: Randlast++;
193: if(EQ(nxtarg(), "!"))
194: return(mk(not, e3(), (struct anode *)0));
195: else if(Ai <= Argc) --Ai;
196: return(e3());
197: }
198: struct anode *e3() { /* parse parens and predicates */
199: int exeq(), ok(), glob(), mtime(), atime(), user(),
200: group(), size(), perm(), links(), print(),
201: type(), ino(), cpio(), newer(),
202: nouser(), nogroup(), ls(), dummy();
203: struct anode *p1;
204: int i;
205: register char *a, *b;
206: register int s;
207:
208: a = nxtarg();
209: if(EQ(a, "(")) {
210: Randlast--;
211: p1 = exp();
212: a = nxtarg();
213: if(!EQ(a, ")")) goto err;
214: return(p1);
215: }
216: else if(EQ(a, "-print")) {
217: return(mk(print, (struct anode *)0, (struct anode *)0));
218: }
219: else if (EQ(a, "-nouser")) {
220: return (mk(nouser, (struct anode *)0, (struct anode *)0));
221: }
222: else if (EQ(a, "-nogroup")) {
223: return (mk(nogroup, (struct anode *)0, (struct anode *)0));
224: }
225: else if (EQ(a, "-ls")) {
226: return (mk(ls, (struct anode *)0, (struct anode *)0));
227: }
228: else if (EQ(a, "-xdev")) {
229: Xdev = 0;
230: return (mk(dummy, (struct anode *)0, (struct anode *)0));
231: }
232: else if (EQ(a, "-follow")) {
233: follow=1;
234: return mk(dummy, (struct anode *)0, (struct anode *)0);
235: }
236: b = nxtarg();
237: s = *b;
238: if(s=='+') b++;
239: if(EQ(a, "-name"))
240: return(mk(glob, (struct anode *)b, (struct anode *)0));
241: else if(EQ(a, "-mtime"))
242: return(mk(mtime, (struct anode *)atoi(b), (struct anode *)s));
243: else if(EQ(a, "-atime"))
244: return(mk(atime, (struct anode *)atoi(b), (struct anode *)s));
245: else if(EQ(a, "-user")) {
246: if((i=getuid(b)) == -1) {
247: if(gmatch(b, "[0-9]*"))
248: return mk(user, (struct anode *)atoi(b), (struct anode *)s);
249: fprintf(stderr, "find: cannot find -user name\n");
250: exit(1);
251: }
252: return(mk(user, (struct anode *)i, (struct anode *)s));
253: }
254: else if(EQ(a, "-inum"))
255: return(mk(ino, (struct anode *)atoi(b), (struct anode *)s));
256: else if(EQ(a, "-group")) {
257: if((i=getgid(b)) == -1) {
258: if(gmatch(b, "[0-9]*"))
259: return mk(group, (struct anode *)atoi(b), (struct anode *)s);
260: fprintf(stderr, "find: cannot find -group name\n");
261: exit(1);
262: }
263: return(mk(group, (struct anode *)i, (struct anode *)s));
264: } else if(EQ(a, "-size"))
265: return(mk(size, (struct anode *)atoi(b), (struct anode *)s));
266: else if(EQ(a, "-links"))
267: return(mk(links, (struct anode *)atoi(b), (struct anode *)s));
268: else if(EQ(a, "-perm")) {
269: for(i=0; *b ; ++b) {
270: if(*b=='-') continue;
271: i <<= 3;
272: i = i + (*b - '0');
273: }
274: return(mk(perm, (struct anode *)i, (struct anode *)s));
275: }
276: else if(EQ(a, "-type")) {
277: i = s=='d' ? S_IFDIR :
278: s=='b' ? S_IFBLK :
279: s=='c' ? S_IFCHR :
280: s=='f' ? S_IFREG :
281: s=='l' ? S_IFLNK :
282: s=='s' ? S_IFSOCK :
283: 0;
284: return(mk(type, (struct anode *)i, (struct anode *)0));
285: }
286: else if (EQ(a, "-exec")) {
287: i = Ai - 1;
288: while(!EQ(nxtarg(), ";"));
289: return(mk(exeq, (struct anode *)i, (struct anode *)0));
290: }
291: else if (EQ(a, "-ok")) {
292: i = Ai - 1;
293: while(!EQ(nxtarg(), ";"));
294: return(mk(ok, (struct anode *)i, (struct anode *)0));
295: }
296: else if(EQ(a, "-cpio")) {
297: if((Cpio = creat(b, 0666)) < 0) {
298: fprintf(stderr, "find: cannot create < %s >\n", s);
299: exit(1);
300: }
301: Buf = (short *)sbrk(512);
302: Wp = Dbuf = (short *)sbrk(5120);
303: return(mk(cpio, (struct anode *)0, (struct anode *)0));
304: }
305: else if(EQ(a, "-newer")) {
306: if(stat(b, &Statb) < 0) {
307: fprintf(stderr, "find: cannot access < %s >\n", b);
308: exit(1);
309: }
310: Newer = Statb.st_mtime;
311: return mk(newer, (struct anode *)0, (struct anode *)0);
312: }
313: err: fprintf(stderr, "find: bad option < %s >\n", a);
314: exit(1);
315: }
316: struct anode *mk(f, l, r)
317: int (*f)();
318: struct anode *l, *r;
319: {
320: if (Nn >= MAXNODES) {
321: fprintf(stderr, "find: Too many options\n");
322: exit(1);
323: }
324:
325: Node[Nn].F = f;
326: Node[Nn].L = l;
327: Node[Nn].R = r;
328: return(&(Node[Nn++]));
329: }
330:
331: char *nxtarg() { /* get next arg from command line */
332: static strikes = 0;
333:
334: if(strikes==3) {
335: fprintf(stderr, "find: incomplete statement\n");
336: exit(1);
337: }
338: if(Ai>=Argc) {
339: strikes++;
340: Ai = Argc + 1;
341: return("");
342: }
343: return(Argv[Ai++]);
344: }
345:
346: /* execution time functions */
347: and(p)
348: register struct anode *p;
349: {
350: return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0);
351: }
352: or(p)
353: register struct anode *p;
354: {
355: return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0);
356: }
357: not(p)
358: register struct anode *p;
359: {
360: return( !((*p->L->F)(p->L)));
361: }
362: glob(p)
363: register struct { int f; char *pat; } *p;
364: {
365: return(gmatch(Fname, p->pat));
366: }
367: print(p)
368: struct anode *p;
369: {
370: puts(Pathname);
371: return(1);
372: }
373: mtime(p)
374: register struct { int f, t, s; } *p;
375: {
376: return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s));
377: }
378: atime(p)
379: register struct { int f, t, s; } *p;
380: {
381: return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s));
382: }
383: user(p)
384: register struct { int f, u, s; } *p;
385: {
386: return(scomp(Statb.st_uid, p->u, p->s));
387: }
388: nouser(p)
389: struct anode *p;
390: {
391: char *getname();
392:
393: return (getname(Statb.st_uid) == NULL);
394: }
395: ino(p)
396: register struct { int f, u, s; } *p;
397: {
398: return(scomp((int)Statb.st_ino, p->u, p->s));
399: }
400: group(p)
401: register struct { int f, u; } *p;
402: {
403: return(p->u == Statb.st_gid);
404: }
405: nogroup(p)
406: struct anode *p;
407: {
408: char *getgroup();
409:
410: return (getgroup(Statb.st_gid) == NULL);
411: }
412: links(p)
413: register struct { int f, link, s; } *p;
414: {
415: return(scomp(Statb.st_nlink, p->link, p->s));
416: }
417: size(p)
418: register struct { int f, sz, s; } *p;
419: {
420: return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s));
421: }
422: perm(p)
423: register struct { int f, per, s; } *p;
424: {
425: register i;
426: i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */
427: return((Statb.st_mode & i & 07777) == p->per);
428: }
429: type(p)
430: register struct { int f, per, s; } *p;
431: {
432: return((Statb.st_mode&S_IFMT)==p->per);
433: }
434: exeq(p)
435: register struct { int f, com; } *p;
436: {
437: fflush(stdout); /* to flush possible `-print' */
438: return(doex(p->com));
439: }
440: ok(p)
441: struct { int f, com; } *p;
442: {
443: char c; int yes;
444: yes = 0;
445: fflush(stdout); /* to flush possible `-print' */
446: fprintf(stderr, "< %s ... %s > ? ", Argv[p->com], Pathname);
447: fflush(stderr);
448: if((c=getchar())=='y') yes = 1;
449: while(c!='\n') c = getchar();
450: if(yes) return(doex(p->com));
451: return(0);
452: }
453:
454: #define MKSHORT(v, lv) {U.l=1L;if(U.c[0]) U.l=lv, v[0]=U.s[1], v[1]=U.s[0]; else U.l=lv, v[0]=U.s[0], v[1]=U.s[1];}
455: union { long l; short s[2]; char c[4]; } U;
456: long mklong(v)
457: short v[];
458: {
459: U.l = 1;
460: if(U.c[0] /* VAX */)
461: U.s[0] = v[1], U.s[1] = v[0];
462: else
463: U.s[0] = v[0], U.s[1] = v[1];
464: return U.l;
465: }
466: cpio(p)
467: struct anode *p;
468: {
469: #define MAGIC 070707
470: struct header {
471: short h_magic,
472: h_dev,
473: h_ino,
474: h_mode,
475: h_uid,
476: h_gid,
477: h_nlink,
478: h_rdev;
479: short h_mtime[2];
480: short h_namesize;
481: short h_filesize[2];
482: char h_name[256];
483: } hdr;
484: register ifile, ct;
485: static long fsz;
486: register i;
487:
488: hdr.h_magic = MAGIC;
489: strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname);
490: hdr.h_namesize = strlen(hdr.h_name) + 1;
491: hdr.h_uid = Statb.st_uid;
492: hdr.h_gid = Statb.st_gid;
493: hdr.h_dev = Statb.st_dev;
494: hdr.h_ino = Statb.st_ino;
495: hdr.h_mode = Statb.st_mode;
496: MKSHORT(hdr.h_mtime, Statb.st_mtime);
497: hdr.h_nlink = Statb.st_nlink;
498: fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L;
499: MKSHORT(hdr.h_filesize, fsz);
500: hdr.h_rdev = Statb.st_rdev;
501: if(EQ(hdr.h_name, "TRAILER!!!")) {
502: bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize);
503: for(i = 0; i < 10; ++i)
504: bwrite(Buf, 512);
505: return;
506: }
507: if(!mklong(hdr.h_filesize))
508: return;
509: if((ifile = open(Fname, 0)) < 0) {
510: cerror:
511: fprintf(stderr, "find: cannot copy < %s >\n", hdr.h_name);
512: return;
513: }
514: bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize);
515: for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) {
516: ct = fsz>512? 512: fsz;
517: if(read(ifile, (char *)Buf, ct) < 0)
518: goto cerror;
519: bwrite(Buf, ct);
520: }
521: close(ifile);
522: return;
523: }
524: newer(p)
525: struct anode *p;
526: {
527: return Statb.st_mtime > Newer;
528: }
529: ls(p)
530: struct anode *p;
531: {
532: list(Pathname, &Statb);
533: return (1);
534: }
535: dummy(p)
536: struct anode *p;
537: {
538: /* dummy */
539: return (1);
540: }
541:
542: /* support functions */
543: scomp(a, b, s) /* funny signed compare */
544: register a, b;
545: register char s;
546: {
547: if(s == '+')
548: return(a > b);
549: if(s == '-')
550: return(a < (b * -1));
551: return(a == b);
552: }
553:
554: doex(com)
555: {
556: register np;
557: register char *na;
558: static char *nargv[50];
559: static ccode;
560: register int w, pid, omask;
561:
562: ccode = np = 0;
563: while (na=Argv[com++]) {
564: if(np >= sizeof nargv / sizeof *nargv - 1) break;
565: if(strcmp(na, ";")==0) break;
566: if(strcmp(na, "{}")==0) nargv[np++] = Pathname;
567: else nargv[np++] = na;
568: }
569: nargv[np] = 0;
570: if (np==0) return(9);
571: switch (pid = vfork()) {
572: case -1:
573: perror("find: Can't fork");
574: exit(1);
575: break;
576:
577: case 0:
578: chdir(Home);
579: execvp(nargv[0], nargv, np);
580: write(2, "find: Can't execute ", 20);
581: perror(nargv[0]);
582: /*
583: * Kill ourselves; our exit status will be a suicide
584: * note indicating we couldn't do the "exec".
585: */
586: kill(getpid(), SIGUSR1);
587: break;
588:
589: default:
590: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT));
591: while ((w = wait(&ccode)) != pid && w != -1)
592: ;
593: (void) sigsetmask(omask);
594: if ((ccode & 0177) == SIGUSR1)
595: exit(1);
596: return (ccode != 0 ? 0 : 1);
597: }
598: }
599:
600: getunum(f, s) char *f, *s; { /* find user/group name and return number */
601: register i;
602: register char *sp;
603: register c;
604: char str[20];
605: FILE *pin;
606:
607: i = -1;
608: pin = fopen(f, "r");
609: c = '\n'; /* prime with a CR */
610: do {
611: if(c=='\n') {
612: sp = str;
613: while((c = *sp++ = getc(pin)) != ':')
614: if(c == EOF) goto RET;
615: *--sp = '\0';
616: if(EQ(str, s)) {
617: while((c=getc(pin)) != ':')
618: if(c == EOF) goto RET;
619: sp = str;
620: while((*sp = getc(pin)) != ':') sp++;
621: *sp = '\0';
622: i = atoi(str);
623: goto RET;
624: }
625: }
626: } while((c = getc(pin)) != EOF);
627: RET:
628: fclose(pin);
629: return(i);
630: }
631:
632: descend(name, fname, exlist)
633: struct anode *exlist;
634: char *name, *fname;
635: {
636: DIR *dir = NULL;
637: register struct direct *dp;
638: register char *c1;
639: int rv = 0;
640: char *endofname;
641:
642: if ((follow?stat(fname, &Statb):lstat(fname, &Statb))<0) {
643: fprintf(stderr, "find: bad status < %s >\n", name);
644: return(0);
645: }
646: (*exlist->F)(exlist);
647: if((Statb.st_mode&S_IFMT)!=S_IFDIR ||
648: !Xdev && Devstat.st_dev != Statb.st_dev)
649: return(1);
650:
651: if (Statb.st_nlink == 2 && exlist->F == and &&
652: exlist->L->F == type && ((int) (exlist->L->L)) == S_IFDIR)
653: return(1);
654:
655: for (c1 = name; *c1; ++c1);
656: if (*(c1-1) == '/')
657: --c1;
658: endofname = c1;
659:
660: if (chdir(fname) == -1)
661: return(0);
662: if ((dir = opendir(".")) == NULL) {
663: fprintf(stderr, "find: cannot open < %s >\n", name);
664: rv = 0;
665: goto ret;
666: }
667: for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) {
668: if ((dp->d_name[0]=='.' && dp->d_name[1]=='\0') ||
669: (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
670: continue;
671: c1 = endofname;
672: *c1++ = '/';
673: strcpy(c1, dp->d_name);
674: Fname = endofname+1;
675: if(!descend(name, Fname, exlist)) {
676: *endofname = '\0';
677: chdir(Home);
678: if(chdir(Pathname) == -1) {
679: fprintf(stderr, "find: bad directory tree\n");
680: exit(1);
681: }
682: }
683: }
684: rv = 1;
685: ret:
686: if(dir)
687: closedir(dir);
688: if(chdir("..") == -1) {
689: *endofname = '\0';
690: fprintf(stderr, "find: bad directory <%s>\n", name);
691: rv = 1;
692: }
693: return(rv);
694: }
695:
696: gmatch(s, p) /* string match as in glob */
697: register char *s, *p;
698: {
699: if (*s=='.' && *p!='.') return(0);
700: return amatch(s, p);
701: }
702:
703: amatch(s, p)
704: register char *s, *p;
705: {
706: register cc;
707: int scc, k;
708: int c, lc;
709:
710: scc = *s;
711: lc = 077777;
712: switch (c = *p) {
713:
714: case '[':
715: k = 0;
716: while (cc = *++p) {
717: switch (cc) {
718:
719: case ']':
720: if (k)
721: return(amatch(++s, ++p));
722: else
723: return(0);
724:
725: case '-':
726: cc = p[1];
727: k |= lc <= scc && scc <= cc;
728: }
729: if (scc==(lc=cc)) k++;
730: }
731: return(0);
732:
733: case '?':
734: caseq:
735: if(scc) return(amatch(++s, ++p));
736: return(0);
737: case '*':
738: return(umatch(s, ++p));
739: case 0:
740: return(!scc);
741: }
742: if (c==scc) goto caseq;
743: return(0);
744: }
745:
746: umatch(s, p)
747: register char *s, *p;
748: {
749: if(*p==0) return(1);
750: while(*s)
751: if (amatch(s++, p)) return(1);
752: return(0);
753: }
754:
755: bwrite(rp, c)
756: register short *rp;
757: register c;
758: {
759: register short *wp = Wp;
760:
761: c = (c+1) >> 1;
762: while(c--) {
763: if(!Wct) {
764: again:
765: if(write(Cpio, (char *)Dbuf, Bufsize)<0) {
766: Cpio = chgreel(1, Cpio);
767: goto again;
768: }
769: Wct = Bufsize >> 1;
770: wp = Dbuf;
771: ++Blocks;
772: }
773: *wp++ = *rp++;
774: --Wct;
775: }
776: Wp = wp;
777: }
778: chgreel(x, fl)
779: {
780: register f;
781: char str[22];
782: FILE *devtty;
783: struct stat statb;
784: extern errno;
785:
786: fprintf(stderr, "find: errno: %d, ", errno);
787: fprintf(stderr, "find: can't %s\n", x? "write output": "read input");
788: fstat(fl, &statb);
789: if((statb.st_mode&S_IFMT) != S_IFCHR)
790: exit(1);
791: again:
792: fprintf(stderr, "If you want to go on, type device/file name %s\n",
793: "when ready");
794: devtty = fopen("/dev/tty", "r");
795: fgets(str, 20, devtty);
796: str[strlen(str) - 1] = '\0';
797: if(!*str)
798: exit(1);
799: close(fl);
800: if((f = open(str, x? 1: 0)) < 0) {
801: fprintf(stderr, "That didn't work");
802: fclose(devtty);
803: goto again;
804: }
805: return f;
806: }
807:
808: #ifdef AMES
809: /*
810: * 'fastfind' scans a file list for the full pathname of a file
811: * given only a piece of the name. The list has been processed with
812: * with "front-compression" and bigram coding. Front compression reduces
813: * space by a factor of 4-5, bigram coding by a further 20-25%.
814: * The codes are:
815: *
816: * 0-28 likeliest differential counts + offset to make nonnegative
817: * 30 escape code for out-of-range count to follow in next word
818: * 128-255 bigram codes, (128 most common, as determined by 'updatedb')
819: * 32-127 single character (printable) ascii residue
820: *
821: * A novel two-tiered string search technique is employed:
822: *
823: * First, a metacharacter-free subpattern and partial pathname is
824: * matched BACKWARDS to avoid full expansion of the pathname list.
825: * The time savings is 40-50% over forward matching, which cannot efficiently
826: * handle overlapped search patterns and compressed path residue.
827: *
828: * Then, the actual shell glob-style regular expression (if in this form)
829: * is matched against the candidate pathnames using the slower routines
830: * provided in the standard 'find'.
831: */
832:
833: #define FCODES "/usr/lib/find/find.codes"
834: #define YES 1
835: #define NO 0
836: #define OFFSET 14
837: #define ESCCODE 30
838:
839: fastfind ( pathpart )
840: char pathpart[];
841: {
842: register char *p, *s;
843: register int c;
844: char *q, *index(), *patprep();
845: int i, count = 0, globflag;
846: FILE *fp, *fopen();
847: char *patend, *cutoff;
848: char path[1024];
849: char bigram1[128], bigram2[128];
850: int found = NO;
851:
852: if ( (fp = fopen ( FCODES, "r" )) == NULL ) {
853: fprintf ( stderr, "find: can't open %s\n", FCODES );
854: exit ( 1 );
855: }
856: for ( i = 0; i < 128; i++ )
857: bigram1[i] = getc ( fp ), bigram2[i] = getc ( fp );
858:
859: globflag = index ( pathpart, '*' ) || index ( pathpart, '?' ) ||
860: index ( pathpart, '[' );
861: patend = patprep ( pathpart );
862:
863: c = getc ( fp );
864: for ( ; ; ) {
865:
866: count += ( (c == ESCCODE) ? getw ( fp ) : c ) - OFFSET;
867:
868: for ( p = path + count; (c = getc ( fp )) > ESCCODE; ) /* overlay old path */
869: if ( c < 0200 )
870: *p++ = c;
871: else /* bigrams are parity-marked */
872: *p++ = bigram1[c & 0177], *p++ = bigram2[c & 0177];
873: if ( c == EOF )
874: break;
875: *p-- = NULL;
876: cutoff = ( found ? path : path + count);
877:
878: for ( found = NO, s = p; s >= cutoff; s-- )
879: if ( *s == *patend ) { /* fast first char check */
880: for ( p = patend - 1, q = s - 1; *p != NULL; p--, q-- )
881: if ( *q != *p )
882: break;
883: if ( *p == NULL ) { /* success on fast match */
884: found = YES;
885: if ( globflag == NO || amatch ( path, pathpart ) )
886: puts ( path );
887: break;
888: }
889: }
890: }
891: }
892:
893: /*
894: extract last glob-free subpattern in name for fast pre-match;
895: prepend '\0' for backwards match; return end of new pattern
896: */
897: static char globfree[100];
898:
899: char *
900: patprep ( name )
901: char *name;
902: {
903: register char *p, *endmark;
904: register char *subp = globfree;
905:
906: *subp++ = '\0';
907: p = name + strlen ( name ) - 1;
908: /*
909: skip trailing metacharacters (and [] ranges)
910: */
911: for ( ; p >= name; p-- )
912: if ( index ( "*?", *p ) == 0 )
913: break;
914: if ( p < name )
915: p = name;
916: if ( *p == ']' )
917: for ( p--; p >= name; p-- )
918: if ( *p == '[' ) {
919: p--;
920: break;
921: }
922: if ( p < name )
923: p = name;
924: /*
925: if pattern has only metacharacters,
926: check every path (force '/' search)
927: */
928: if ( (p == name) && index ( "?*[]", *p ) != 0 )
929: *subp++ = '/';
930: else {
931: for ( endmark = p; p >= name; p-- )
932: if ( index ( "]*?", *p ) != 0 )
933: break;
934: for ( ++p; (p <= endmark) && subp < (globfree + sizeof ( globfree )); )
935: *subp++ = *p++;
936: }
937: *subp = '\0';
938: return ( --subp );
939: }
940: #endif
941:
942: /* rest should be done with nameserver or database */
943:
944: #include <pwd.h>
945: #include <grp.h>
946: #include <utmp.h>
947:
948: struct utmp utmp;
949: #define NMAX (sizeof (utmp.ut_name))
950: #define SCPYN(a, b) strncpy(a, b, NMAX)
951:
952: #define NUID 64
953: #define NGID 300
954:
955: struct ncache {
956: int uid;
957: char name[NMAX+1];
958: } nc[NUID];
959: char outrangename[NMAX+1];
960: int outrangeuid = -1;
961: char groups[NGID][NMAX+1];
962: char outrangegroup[NMAX+1];
963: int outrangegid = -1;
964:
965: /*
966: * This function assumes that the password file is hashed
967: * (or some such) to allow fast access based on a name key.
968: * If this isn't true, duplicate the code for getgroup().
969: */
970: char *
971: getname(uid)
972: {
973: register struct passwd *pw;
974: struct passwd *getpwent();
975: register int cp;
976: extern int _pw_stayopen;
977:
978: _pw_stayopen = 1;
979:
980: #if (((NUID) & ((NUID) - 1)) != 0)
981: cp = uid % (NUID);
982: #else
983: cp = uid & ((NUID) - 1);
984: #endif
985: if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
986: return (nc[cp].name);
987: pw = getpwuid(uid);
988: if (!pw)
989: return (0);
990: nc[cp].uid = uid;
991: SCPYN(nc[cp].name, pw->pw_name);
992: return (nc[cp].name);
993: }
994:
995: char *
996: getgroup(gid)
997: {
998: register struct group *gr;
999: static init;
1000: struct group *getgrent();
1001:
1002: if (gid >= 0 && gid < NGID && groups[gid][0])
1003: return (&groups[gid][0]);
1004: if (gid >= 0 && gid == outrangegid)
1005: return (outrangegroup);
1006: rescan:
1007: if (init == 2) {
1008: if (gid < NGID)
1009: return (0);
1010: setgrent();
1011: while (gr = getgrent()) {
1012: if (gr->gr_gid != gid)
1013: continue;
1014: outrangegid = gr->gr_gid;
1015: SCPYN(outrangegroup, gr->gr_name);
1016: endgrent();
1017: return (outrangegroup);
1018: }
1019: endgrent();
1020: return (0);
1021: }
1022: if (init == 0)
1023: setgrent(), init = 1;
1024: while (gr = getgrent()) {
1025: if (gr->gr_gid < 0 || gr->gr_gid >= NGID) {
1026: if (gr->gr_gid == gid) {
1027: outrangegid = gr->gr_gid;
1028: SCPYN(outrangegroup, gr->gr_name);
1029: return (outrangegroup);
1030: }
1031: continue;
1032: }
1033: if (groups[gr->gr_gid][0])
1034: continue;
1035: SCPYN(groups[gr->gr_gid], gr->gr_name);
1036: if (gr->gr_gid == gid)
1037: return (&groups[gid][0]);
1038: }
1039: init = 2;
1040: goto rescan;
1041: }
1042:
1043: int
1044: getuid(username)
1045: char *username;
1046: {
1047: register struct passwd *pw;
1048: struct passwd *getpwnam();
1049: #ifndef NO_PW_STAYOPEN
1050: extern int _pw_stayopen;
1051:
1052: _pw_stayopen = 1;
1053: #endif
1054:
1055: pw = getpwnam(username);
1056: if (pw != NULL)
1057: return (pw->pw_uid);
1058: else
1059: return (-1);
1060: }
1061:
1062: int
1063: getgid(groupname)
1064: char *groupname;
1065: {
1066: register struct group *gr;
1067: struct group *getgrnam();
1068:
1069: gr = getgrnam(groupname);
1070: if (gr != NULL)
1071: return (gr->gr_gid);
1072: else
1073: return (-1);
1074: }
1075:
1076: #define permoffset(who) ((who) * 3)
1077: #define permission(who, type) ((type) >> permoffset(who))
1078: #define kbytes(bytes) (((bytes) + 1023) / 1024)
1079:
1080: list(file, stp)
1081: char *file;
1082: register struct stat *stp;
1083: {
1084: char pmode[32], uname[32], gname[32], fsize[32], ftime[32];
1085: char *getname(), *getgroup(), *ctime();
1086: static long special[] = { S_ISUID, 's', S_ISGID, 's', S_ISVTX, 't' };
1087: static time_t sixmonthsago = -1;
1088: #ifdef S_IFLNK
1089: char flink[MAXPATHLEN + 1];
1090: #endif
1091: register int who;
1092: register char *cp;
1093: time_t now;
1094:
1095: if (file == NULL || stp == NULL)
1096: return (-1);
1097:
1098: time(&now);
1099: if (sixmonthsago == -1)
1100: sixmonthsago = now - 6L*30L*24L*60L*60L;
1101:
1102: switch (stp->st_mode & S_IFMT) {
1103: #ifdef S_IFDIR
1104: case S_IFDIR: /* directory */
1105: pmode[0] = 'd';
1106: break;
1107: #endif
1108: #ifdef S_IFCHR
1109: case S_IFCHR: /* character special */
1110: pmode[0] = 'c';
1111: break;
1112: #endif
1113: #ifdef S_IFBLK
1114: case S_IFBLK: /* block special */
1115: pmode[0] = 'b';
1116: break;
1117: #endif
1118: #ifdef S_IFLNK
1119: case S_IFLNK: /* symbolic link */
1120: pmode[0] = 'l';
1121: break;
1122: #endif
1123: #ifdef S_IFSOCK
1124: case S_IFSOCK: /* socket */
1125: pmode[0] = 's';
1126: break;
1127: #endif
1128: #ifdef S_IFREG
1129: case S_IFREG: /* regular */
1130: #endif
1131: default:
1132: pmode[0] = '-';
1133: break;
1134: }
1135:
1136: for (who = 0; who < 3; who++) {
1137: if (stp->st_mode & permission(who, S_IREAD))
1138: pmode[permoffset(who) + 1] = 'r';
1139: else
1140: pmode[permoffset(who) + 1] = '-';
1141:
1142: if (stp->st_mode & permission(who, S_IWRITE))
1143: pmode[permoffset(who) + 2] = 'w';
1144: else
1145: pmode[permoffset(who) + 2] = '-';
1146:
1147: if (stp->st_mode & special[who * 2])
1148: pmode[permoffset(who) + 3] = special[who * 2 + 1];
1149: else if (stp->st_mode & permission(who, S_IEXEC))
1150: pmode[permoffset(who) + 3] = 'x';
1151: else
1152: pmode[permoffset(who) + 3] = '-';
1153: }
1154: pmode[permoffset(who) + 1] = '\0';
1155:
1156: cp = getname(stp->st_uid);
1157: if (cp != NULL)
1158: sprintf(uname, "%-9.9s", cp);
1159: else
1160: sprintf(uname, "%-9d", stp->st_uid);
1161:
1162: cp = getgroup(stp->st_gid);
1163: if (cp != NULL)
1164: sprintf(gname, "%-9.9s", cp);
1165: else
1166: sprintf(gname, "%-9d", stp->st_gid);
1167:
1168: if (pmode[0] == 'b' || pmode[0] == 'c')
1169: sprintf(fsize, "%3d,%4d",
1170: major(stp->st_rdev), minor(stp->st_rdev));
1171: else {
1172: sprintf(fsize, "%8ld", stp->st_size);
1173: #ifdef S_IFLNK
1174: if (pmode[0] == 'l') {
1175: /*
1176: * Need to get the tail of the file name, since we have
1177: * already chdir()ed into the directory of the file
1178: */
1179: cp = rindex(file, '/');
1180: if (cp == NULL)
1181: cp = file;
1182: else
1183: cp++;
1184: who = readlink(cp, flink, sizeof flink - 1);
1185: if (who >= 0)
1186: flink[who] = '\0';
1187: else
1188: flink[0] = '\0';
1189: }
1190: #endif
1191: }
1192:
1193: cp = ctime(&stp->st_mtime);
1194: if (stp->st_mtime < sixmonthsago || stp->st_mtime > now)
1195: sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20);
1196: else
1197: sprintf(ftime, "%-12.12s", cp + 4);
1198:
1199: printf("%5lu %4ld %s %2d %s%s%s %s %s%s%s\n",
1200: stp->st_ino, /* inode # */
1201: #ifdef S_IFSOCK
1202: (long) kbytes(dbtob(stp->st_blocks)), /* kbytes */
1203: #else
1204: (long) kbytes(stp->st_size), /* kbytes */
1205: #endif
1206: pmode, /* protection */
1207: stp->st_nlink, /* # of links */
1208: uname, /* owner */
1209: gname, /* group */
1210: fsize, /* # of bytes */
1211: ftime, /* modify time */
1212: file, /* name */
1213: #ifdef S_IFLNK
1214: (pmode[0] == 'l') ? " -> " : "",
1215: (pmode[0] == 'l') ? flink : "" /* symlink */
1216: #else
1217: "",
1218: ""
1219: #endif
1220: );
1221:
1222: return (0);
1223: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.