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