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 header {
 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: }

Defined functions

amatch defined in line 694; used 5 times
and defined in line 342; used 2 times
atime defined in line 373; used 2 times
bwrite defined in line 746; used 4 times
chgreel defined in line 769; used 1 times
cpio defined in line 461; used 3 times
descend defined in line 627; used 2 times
doex defined in line 549; used 2 times
dummy defined in line 530; used 2 times
e1 defined in line 167; used 3 times
e2 defined in line 184; used 2 times
e3 defined in line 197; used 3 times
exeq defined in line 429; used 2 times
exp defined in line 155; used 4 times
fastfind defined in line 830; used 1 times
  • in line 92
getgid defined in line 1053; used 1 times
getgroup defined in line 986; used 4 times
getname defined in line 961; used 4 times
getuid defined in line 1034; used 1 times
getunum defined in line 595; never used
glob defined in line 357; used 2 times
gmatch defined in line 687; used 3 times
group defined in line 395; used 3 times
ino defined in line 390; used 2 times
links defined in line 407; used 2 times
list defined in line 1071; used 1 times
ls defined in line 524; used 2 times
main defined in line 74; never used
mk defined in line 311; used 25 times
mklong defined in line 451; used 2 times
mtime defined in line 368; used 2 times
newer defined in line 519; used 2 times
nogroup defined in line 400; used 2 times
not defined in line 352; used 2 times
nouser defined in line 383; used 2 times
nxtarg defined in line 326; used 9 times
ok defined in line 435; used 2 times
or defined in line 347; used 2 times
patprep defined in line 890; used 2 times
perm defined in line 417; used 2 times
print defined in line 362; used 2 times
scomp defined in line 538; used 6 times
size defined in line 412; used 2 times
type defined in line 424; used 4 times
umatch defined in line 737; used 1 times
user defined in line 378; used 3 times

Defined variables

Ai defined in line 26; used 19 times
Argc defined in line 25; used 6 times
Argv defined in line 28; used 8 times
Blocks defined in line 49; used 2 times
Buf defined in line 31; used 4 times
Bufsize defined in line 32; used 2 times
Cpio defined in line 30; used 5 times
Dbuf defined in line 31; used 3 times
Devstat defined in line 38; used 2 times
Fname defined in line 23; used 6 times
Home defined in line 48; used 8 times
Newer defined in line 35; used 2 times
Nn defined in line 22; used 5 times
Node defined in line 21; used 4 times
Now defined in line 24; used 3 times
Pathname defined in line 14; used 16 times
Pi defined in line 27; used 4 times
Randlast defined in line 13; used 5 times
Statb defined in line 40; used 28 times
Wct defined in line 33; used 3 times
Wp defined in line 31; used 3 times
Xdev defined in line 37; used 3 times
globfree defined in line 888; used 3 times
groups defined in line 952; used 5 times
nc defined in line 949; used 6 times
outrangegid defined in line 954; used 3 times
outrangegroup defined in line 953; used 5 times
outrangename defined in line 950; never used
outrangeuid defined in line 951; never used
sccsid defined in line 2; never used
utmp defined in line 939; used 1 times

Defined struct's

anode defined in line 18; used 132 times
header defined in line 465; never used
ncache defined in line 946; never used

Defined macros

AMES defined in line 72; used 2 times
A_DAY defined in line 10; used 2 times
EQ defined in line 11; used 33 times
ESCCODE defined in line 828; used 2 times
FCODES defined in line 824; used 2 times
MAGIC defined in line 464; used 1 times
MAXNODES defined in line 16; used 2 times
MKSHORT defined in line 449; used 2 times
NGID defined in line 944; used 4 times
NMAX defined in line 940; used 5 times
NO defined in line 826; used 3 times
NUID defined in line 943; used 5 times
OFFSET defined in line 827; used 1 times
SCPYN defined in line 941; used 4 times
YES defined in line 825; used 2 times
kbytes defined in line 1069; used 2 times
permission defined in line 1068; used 3 times
permoffset defined in line 1067; used 9 times
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4175
Valid CSS Valid XHTML 1.0 Strict