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