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