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