|
|
1.1 root 1: static char *sccsid = "@(#)find.c 4.5 (Berkeley) 3/31/82";
2: /* find COMPILE: cc -o find -s -O -i find.c -lS */
3: #include <stdio.h>
4: #include <sys/types.h>
5: #include <sys/stat.h>
6: #include <errno.h>
7: #define A_DAY 86400L /* a day full of seconds */
8: #define EQ(x, y) (strcmp(x, y)==0)
9: #define MINUSINF (int)~((unsigned)-1>>1)
10:
11: int Randlast;
12: char Pathname[200];
13:
14: struct anode {
15: int (*F)();
16: struct anode *L, *R;
17: } Node[100];
18: int Nn; /* number of nodes */
19: char *Fname;
20: long Now;
21: int Argc,
22: Ai,
23: Pi;
24: char **Argv;
25: /* cpio stuff */
26: int Cpio;
27: short *Buf, *Dbuf, *Wp;
28: int Bufsize = 5120;
29: int Wct = 2560;
30:
31: long Newer;
32:
33: struct stat Statb;
34: int Status;
35: int Statusqueried;
36:
37: struct anode *exp(),
38: *e1(),
39: *e2(),
40: *e3(),
41: *mk();
42: char *nxtarg();
43: char Home[128];
44: long Blocks;
45: char *strrchr();
46: char *sbrk();
47: main(argc, argv) char *argv[];
48: {
49: int or(), and(), errchk();
50: struct anode *exlist, *errchklist;
51: int paths;
52: register char *cp, *sp = 0;
53: FILE *pwd, *popen();
54:
55: time(&Now);
56: pwd = popen("pwd", "r");
57: fgets(Home, 128, pwd);
58: pclose(pwd);
59: Home[strlen(Home) - 1] = '\0';
60: Argc = argc; Argv = argv;
61: if(argc<3) {
62: usage: fprintf(stderr, "Usage: find path-list predicate-list\n");
63: exit(1);
64: }
65: for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths)
66: if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!"))
67: break;
68: if(paths == 1) /* no path-list */
69: goto usage;
70: if(!(exlist = exp())) { /* parse and compile the arguments */
71: fprintf(stderr, "find: parsing error\n");
72: exit(1);
73: }
74: errchklist = mk(errchk, (struct anode*)0, (struct anode*)0);
75: exlist = mk(or, mk(and, exlist, errchklist), errchklist);
76: if(Ai<argc) {
77: fprintf(stderr, "find: missing conjunction\n");
78: exit(1);
79: }
80: for(Pi = 1; Pi < paths; ++Pi) {
81: sp = 0;
82: chdir(Home);
83: strcpy(Pathname, Argv[Pi]);
84: if(cp = strrchr(Pathname, '/')) {
85: sp = cp + 1;
86: *cp = '\0';
87: if(chdir(*Pathname? Pathname: "/") == -1) {
88: fprintf(stderr, "find: bad starting directory\n");
89: exit(2);
90: }
91: *cp = '/';
92: }
93: Fname = sp? sp: Pathname;
94: descend(Pathname, Fname, exlist); /* to find files that match */
95: }
96: if(Cpio) {
97: strcpy(Pathname, "TRAILER!!!");
98: Statb.st_size = 0;
99: cpio();
100: printf("%D blocks\n", Blocks*10);
101: }
102: exit(0);
103: }
104:
105: /* compile time functions: priority is exp()<e1()<e2()<e3() */
106:
107: struct anode *exp() { /* parse ALTERNATION (-o) */
108: int or();
109: register struct anode * p1;
110:
111: p1 = e1() /* get left operand */ ;
112: if(EQ(nxtarg(), "-o")) {
113: Randlast--;
114: return(mk(or, p1, exp()));
115: }
116: else if(Ai <= Argc) --Ai;
117: return(p1);
118: }
119: struct anode *e1() { /* parse CONCATENATION (formerly -a) */
120: int and();
121: register struct anode * p1;
122: register char *a;
123:
124: p1 = e2();
125: a = nxtarg();
126: if(EQ(a, "-a")) {
127: And:
128: Randlast--;
129: return(mk(and, p1, e1()));
130: } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
131: --Ai;
132: goto And;
133: } else if(Ai <= Argc) --Ai;
134: return(p1);
135: }
136: struct anode *e2() { /* parse NOT (!) */
137: int not();
138:
139: if(Randlast) {
140: fprintf(stderr, "find: operand follows operand\n");
141: exit(1);
142: }
143: Randlast++;
144: if(EQ(nxtarg(), "!"))
145: return(mk(not, e3(), (struct anode *)0));
146: else if(Ai <= Argc) --Ai;
147: return(e3());
148: }
149: struct anode *e3() { /* parse parens and predicates */
150: int exeq(), ok(), glob(), ctime(), mtime(), atime(), user(),
151: group(), size(), perm(), links(), print(),
152: type(), ino(), cpio(), newer(), status(), errchk();
153: struct anode *p1;
154: int i;
155: register char *a, *b, s;
156:
157: a = nxtarg();
158: if(EQ(a, "(")) {
159: Randlast--;
160: p1 = exp();
161: a = nxtarg();
162: if(!EQ(a, ")")) goto err;
163: return(p1);
164: }
165: else if(EQ(a, "-print")) {
166: return(mk(print, (struct anode *)0, (struct anode *)0));
167: }
168: b = nxtarg();
169: s = *b;
170: if(s=='+') b++;
171: if(EQ(a, "-name"))
172: return(mk(glob, (struct anode *)b, (struct anode *)0));
173: else if(EQ(a, "-ctime"))
174: return(mk(ctime, (struct anode *)atoi(b), (struct anode *)s));
175: else if(EQ(a, "-mtime"))
176: return(mk(mtime, (struct anode *)atoi(b), (struct anode *)s));
177: else if(EQ(a, "-atime"))
178: return(mk(atime, (struct anode *)atoi(b), (struct anode *)s));
179: else if(EQ(a, "-user")) {
180: if((i=getunum("/etc/passwd", b)) == -1) {
181: if(amatch(b, "[0-9]*"))
182: return mk(user, (struct anode *)atoi(b), (struct anode *)s);
183: fprintf(stderr, "find: cannot find -user name\n");
184: exit(1);
185: }
186: return(mk(user, (struct anode *)i, (struct anode *)s));
187: }
188: else if(EQ(a, "-inum"))
189: return(mk(ino, (struct anode *)atoi(b), (struct anode *)s));
190: else if(EQ(a, "-group")) {
191: if((i=getunum("/etc/group", b)) == -1) {
192: if(amatch(b, "[0-9]*"))
193: return mk(group, (struct anode *)atoi(b), (struct anode *)s);
194: fprintf(stderr, "find: cannot find -group name\n");
195: exit(1);
196: }
197: return(mk(group, (struct anode *)i, (struct anode *)s));
198: } else if(EQ(a, "-size"))
199: return(mk(size, (struct anode *)atoi(b), (struct anode *)s));
200: else if(EQ(a, "-links"))
201: return(mk(links, (struct anode *)atoi(b), (struct anode *)s));
202: else if(EQ(a, "-status"))
203: return(mk(status, (struct anode *)atoi(b), (struct anode *)s));
204: else if(EQ(a, "-perm")) {
205: for(i=0; *b ; ++b) {
206: if(*b=='-') continue;
207: i <<= 3;
208: i = i + (*b - '0');
209: }
210: return(mk(perm, (struct anode *)i, (struct anode *)s));
211: }
212: else if(EQ(a, "-type")) {
213: i = s=='d' ? S_IFDIR :
214: s=='b' ? S_IFBLK :
215: s=='c' ? S_IFCHR :
216: s=='L' ? S_IFLNK :
217: s=='f' ? 0100000 :
218: 0;
219: return(mk(type, (struct anode *)i, (struct anode *)0));
220: }
221: else if (EQ(a, "-exec")) {
222: i = Ai - 1;
223: while(!EQ(nxtarg(), ";"));
224: return(mk(exeq, (struct anode *)i, (struct anode *)0));
225: }
226: else if (EQ(a, "-ok")) {
227: i = Ai - 1;
228: while(!EQ(nxtarg(), ";"));
229: return(mk(ok, (struct anode *)i, (struct anode *)0));
230: }
231: else if(EQ(a, "-cpio")) {
232: if((Cpio = creat(b, 0666)) < 0) {
233: fprintf(stderr, "find: cannot create < %s >\n", s);
234: exit(1);
235: }
236: Buf = (short *)sbrk(512);
237: Wp = Dbuf = (short *)sbrk(5120);
238: return(mk(cpio, (struct anode *)0, (struct anode *)0));
239: }
240: else if(EQ(a, "-newer")) {
241: if(stat(b, &Statb) < 0) {
242: fprintf(stderr, "find: cannot access < %s >\n", b);
243: exit(1);
244: }
245: Newer = Statb.st_mtime;
246: return mk(newer, (struct anode *)0, (struct anode *)0);
247: }
248: err: fprintf(stderr, "find: bad option < %s >\n", a);
249: exit(1);
250: }
251: struct anode *mk(f, l, r)
252: int (*f)();
253: struct anode *l, *r;
254: {
255: Node[Nn].F = f;
256: Node[Nn].L = l;
257: Node[Nn].R = r;
258: return(&(Node[Nn++]));
259: }
260:
261: char *nxtarg() { /* get next arg from command line */
262: static strikes = 0;
263:
264: if(strikes==3) {
265: fprintf(stderr, "find: incomplete statement\n");
266: exit(1);
267: }
268: if(Ai>=Argc) {
269: strikes++;
270: Ai = Argc + 1;
271: return("");
272: }
273: return(Argv[Ai++]);
274: }
275:
276: /* execution time functions */
277: and(p)
278: register struct anode *p;
279: {
280: return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0);
281: }
282: or(p)
283: register struct anode *p;
284: {
285: return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0);
286: }
287: not(p)
288: register struct anode *p;
289: {
290: return( !((*p->L->F)(p->L)));
291: }
292: glob(p)
293: register struct { int f; char *pat; } *p;
294: {
295: return(amatch(Fname, p->pat));
296: }
297: print()
298: {
299: puts(Pathname);
300: return(1);
301: }
302: mtime(p)
303: register struct { int f, t, s; } *p;
304: {
305: if(Status != 0) return 0;
306: return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s));
307: }
308: ctime(p)
309: register struct { int f, t, s; } *p;
310: {
311: if(Status != 0) return 0;
312: return(scomp((int)((Now - Statb.st_ctime) / A_DAY), p->t, p->s));
313: }
314: atime(p)
315: register struct { int f, t, s; } *p;
316: {
317: if(Status != 0) return 0;
318: return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s));
319: }
320: user(p)
321: register struct { int f, u, s; } *p;
322: {
323: if(Status != 0) return 0;
324: return(scomp(Statb.st_uid, p->u, p->s));
325: }
326: ino(p)
327: register struct { int f, u, s; } *p;
328: {
329: if(Status != 0) return 0;
330: return(scomp((int)Statb.st_ino, p->u, p->s));
331: }
332: group(p)
333: register struct { int f, u; } *p;
334: {
335: if(Status != 0) return 0;
336: return(p->u == Statb.st_gid);
337: }
338: links(p)
339: register struct { int f, link, s; } *p;
340: {
341: if(Status != 0) return 0;
342: return(scomp(Statb.st_nlink, p->link, p->s));
343: }
344: size(p)
345: register struct { int f, sz, s; } *p;
346: {
347: if(Status != 0) return 0;
348: return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s));
349: }
350: perm(p)
351: register struct { int f, per, s; } *p;
352: {
353: register i;
354: if(Status != 0) return 0;
355: i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */
356: return((Statb.st_mode & i & 07777) == p->per);
357: }
358: type(p)
359: register struct { int f, per, s; } *p;
360: {
361: if(Status != 0) return 0;
362: return((Statb.st_mode&S_IFMT)==p->per);
363: }
364: exeq(p)
365: register struct { int f, com; } *p;
366: {
367: fflush(stdout); /* to flush possible `-print' */
368: return(doex(p->com));
369: }
370: ok(p)
371: struct { int f, com; } *p;
372: {
373: char c; int yes;
374: yes = 0;
375: fflush(stdout); /* to flush possible `-print' */
376: fprintf(stderr, "< %s ... %s > ? ", Argv[p->com], Pathname);
377: fflush(stderr);
378: if((c=getchar())=='y') yes = 1;
379: while(c!='\n') c = getchar();
380: if(yes) return(doex(p->com));
381: return(0);
382: }
383:
384: #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];}
385: union { long l; short s[2]; char c[4]; } U;
386: long mklong(v)
387: short v[];
388: {
389: U.l = 1;
390: if(U.c[0] /* VAX */)
391: U.s[0] = v[1], U.s[1] = v[0];
392: else
393: U.s[0] = v[0], U.s[1] = v[1];
394: return U.l;
395: }
396: cpio()
397: {
398: #define MAGIC 070707
399: struct header {
400: short h_magic,
401: h_dev,
402: h_ino,
403: h_mode,
404: h_uid,
405: h_gid,
406: h_nlink,
407: h_rdev;
408: short h_mtime[2];
409: short h_namesize;
410: short h_filesize[2];
411: char h_name[256];
412: } hdr;
413: register ifile, ct;
414: static long fsz;
415: register i;
416:
417: hdr.h_magic = MAGIC;
418: strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname);
419: hdr.h_namesize = strlen(hdr.h_name) + 1;
420: hdr.h_uid = Statb.st_uid;
421: hdr.h_gid = Statb.st_gid;
422: hdr.h_dev = Statb.st_dev;
423: hdr.h_ino = Statb.st_ino;
424: hdr.h_mode = Statb.st_mode;
425: MKSHORT(hdr.h_mtime, Statb.st_mtime);
426: hdr.h_nlink = Statb.st_nlink;
427: fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L;
428: MKSHORT(hdr.h_filesize, fsz);
429: hdr.h_rdev = Statb.st_rdev;
430: if(EQ(hdr.h_name, "TRAILER!!!")) {
431: bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize);
432: for(i = 0; i < 10; ++i)
433: bwrite(Buf, 512);
434: return;
435: }
436: if(!mklong(hdr.h_filesize))
437: return;
438: if((ifile = open(Fname, 0)) < 0) {
439: cerror:
440: fprintf(stderr, "find: cannot copy < %s >\n", hdr.h_name);
441: return;
442: }
443: bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize);
444: for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) {
445: ct = fsz>512? 512: fsz;
446: if(read(ifile, (char *)Buf, ct) < 0)
447: goto cerror;
448: bwrite(Buf, ct);
449: }
450: close(ifile);
451: return;
452: }
453: newer()
454: {
455: if(Status != 0) return 0;
456: return Statb.st_mtime > Newer;
457: }
458: status(p)
459: register struct { int f, st, s; } *p;
460: {
461: Statusqueried = 1;
462: return scomp(Status, p->st, p->s);
463: }
464: errchk()
465: {
466: if(Status && !Statusqueried) {
467: fflush(stdout);
468: fprintf(stderr, "find: ");
469: perror(Pathname);
470: }
471: return 1;
472: }
473:
474: /* support functions */
475: scomp(a, b, s) /* funny signed compare */
476: register a, b;
477: register char s;
478: {
479: if(s == '+')
480: return(a > b);
481: if(s == '-')
482: return(a < (b * -1));
483: return(a == b);
484: }
485:
486: doex(com)
487: {
488: register np;
489: register char *na;
490: static char *nargv[50];
491: static ccode;
492:
493: ccode = np = 0;
494: while (na=Argv[com++]) {
495: if(strcmp(na, ";")==0) break;
496: if(strcmp(na, "{}")==0) nargv[np++] = Pathname;
497: else nargv[np++] = na;
498: }
499: nargv[np] = 0;
500: if (np==0) return(9);
501: if(fork()) /*parent*/ {
502: #include <signal.h>
503: int (*old)() = signal(SIGINT, SIG_IGN);
504: int (*oldq)() = signal(SIGQUIT, SIG_IGN);
505: wait(&ccode);
506: signal(SIGINT, old);
507: signal(SIGQUIT, oldq);
508: } else { /*child*/
509: chdir(Home);
510: execvp(nargv[0], nargv, np);
511: exit(1);
512: }
513: return(ccode ? 0:1);
514: }
515:
516: getunum(f, s) char *f, *s; { /* find user/group name and return number */
517: register i;
518: register char *sp;
519: register c;
520: char str[20];
521: FILE *pin;
522:
523: i = -1;
524: pin = fopen(f, "r");
525: c = '\n'; /* prime with a CR */
526: do {
527: if(c=='\n') {
528: sp = str;
529: while((c = *sp++ = getc(pin)) != ':')
530: if(c == EOF) goto RET;
531: *--sp = '\0';
532: if(EQ(str, s)) {
533: while((c=getc(pin)) != ':')
534: if(c == EOF) goto RET;
535: sp = str;
536: while((*sp = getc(pin)) != ':') sp++;
537: *sp = '\0';
538: i = atoi(str);
539: goto RET;
540: }
541: }
542: } while((c = getc(pin)) != EOF);
543: RET:
544: fclose(pin);
545: return(i);
546: }
547:
548: #include <ndir.h>
549:
550:
551: descend(name, fname, exlist)
552: struct anode *exlist;
553: char *name, *fname;
554: {
555: DIR *dir = 0;
556: register struct direct *dp;
557: register char *c1, *c2;
558: int i;
559: int rv = 0;
560: char *endofname;
561:
562: errno = 0;
563: if (lstat(fname, &Statb) == -1) {
564: fprintf(stderr, "find: bad status < %s >\n", name);
565: return 0;
566: }
567: Status = errno;
568: Statusqueried = 0;
569: (*exlist->F)(exlist);
570: if((Statb.st_mode&S_IFMT)!=S_IFDIR)
571: return(1);
572: for(c1 = name; *c1; ++c1);
573: if(*(c1-1) == '/')
574: --c1;
575: endofname = c1;
576:
577: if(chdir(fname) == -1)
578: return(0);
579: if ((dir = opendir(".")) == 0) {
580: fprintf(stderr, "find: cannot open < %s >\n", name);
581: rv = 0;
582: goto ret;
583: }
584: for (dp = readdir(dir); dp; dp = readdir(dir)) {
585: if ((dp->d_name[0]=='.' && dp->d_name[1]=='\0') ||
586: (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
587: continue;
588: c1 = endofname;
589: *c1++ = '/';
590: strcpy(c1, dp->d_name);
591: Fname = endofname+1;
592: if(!descend(name, Fname, exlist)) {
593: *endofname = '\0';
594: chdir(Home);
595: if(chdir(Pathname) == -1) {
596: fprintf(stderr, "find: bad directory tree\n");
597: exit(1);
598: }
599: }
600: }
601: rv = 1;
602: closedir(dir);
603: ret:
604: if(chdir("..") == -1) {
605: *endofname = '\0';
606: fprintf(stderr, "find: bad directory <%s>\n", name);
607: rv = 1;
608: }
609: return(rv);
610: }
611:
612: amatch(s, p)
613: register char *s, *p;
614: {
615: register cc;
616: int scc, k;
617: int c, lc;
618:
619: scc = *s;
620: lc = 077777;
621: switch (c = *p) {
622:
623: case '[':
624: k = 0;
625: while (cc = *++p) {
626: switch (cc) {
627:
628: case ']':
629: if (k)
630: return(amatch(++s, ++p));
631: else
632: return(0);
633:
634: case '-':
635: k |= lc <= scc & scc <= (cc=p[1]);
636: }
637: if (scc==(lc=cc)) k++;
638: }
639: return(0);
640:
641: case '?':
642: caseq:
643: if(scc) return(amatch(++s, ++p));
644: return(0);
645: case '*':
646: return(umatch(s, ++p));
647: case 0:
648: return(!scc);
649: }
650: if (c==scc) goto caseq;
651: return(0);
652: }
653:
654: umatch(s, p)
655: register char *s, *p;
656: {
657: if(*p==0) return(1);
658: while(*s)
659: if (amatch(s++, p)) return(1);
660: return(0);
661: }
662:
663: bwrite(rp, c)
664: register short *rp;
665: register c;
666: {
667: register short *wp = Wp;
668:
669: c = (c+1) >> 1;
670: while(c--) {
671: if(!Wct) {
672: again:
673: if(write(Cpio, (char *)Dbuf, Bufsize)<0) {
674: Cpio = chgreel(1, Cpio);
675: goto again;
676: }
677: Wct = Bufsize >> 1;
678: wp = Dbuf;
679: ++Blocks;
680: }
681: *wp++ = *rp++;
682: --Wct;
683: }
684: Wp = wp;
685: }
686: chgreel(x, fl)
687: {
688: register f;
689: char str[22];
690: FILE *devtty;
691: struct stat statb;
692: extern errno;
693:
694: fprintf(stderr, "find: errno: %d, ", errno);
695: fprintf(stderr, "find: can't %s\n", x? "write output": "read input");
696: fstat(fl, &statb);
697: if((statb.st_mode&S_IFMT) != S_IFCHR)
698: exit(1);
699: again:
700: fprintf(stderr, "If you want to go on, type device/file name %s\n",
701: "when ready");
702: devtty = fopen("/dev/tty", "r");
703: fgets(str, 20, devtty);
704: str[strlen(str) - 1] = '\0';
705: if(!*str)
706: exit(1);
707: close(fl);
708: if((f = open(str, x? 1: 0)) < 0) {
709: fprintf(stderr, "That didn't work");
710: fclose(devtty);
711: goto again;
712: }
713: return f;
714: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.