1: /* find -- find files in a pathname. 2: Use of find is documented in /usr/man/man1/find.1 . 3: 4: In addition, find has a secret first arg "+" which 5: causes each file name to be printed along with a period 6: if the predicates succeed. 7: */ 8: int randlast; 9: char *pathname; 10: int verbose; 11: struct anode { 12: int (*F)(); 13: struct anode *L, *R; 14: } node[100]; 15: int nn; /* number of nodes */ 16: char *fname, *path; 17: int now[2]; 18: int ap, ac; 19: char **av; 20: 21: struct ibuf { 22: int idev; 23: int inum; 24: int iflags; 25: char inl; 26: char iuid; 27: char igid; 28: char isize0; 29: char *isize; 30: int iaddr[8]; 31: int iatime[2]; 32: int imtime[2]; 33: } statb; 34: 35: main(argc,argv) char *argv[]; { 36: 37: struct anode *exlist; 38: int find(); 39: 40: time(&now); 41: ac = argc; av = argv; ap = 2; 42: pathname = argv[1]; 43: if(compstr(argv[1],"+")==0) { 44: verbose++; 45: ap++; 46: pathname = argv[2]; 47: } else verbose = 0; 48: argv[argc] = 0; 49: if(argc<3) { 50: printf("Insufficient args\n"); 51: exit(9); 52: } 53: if(!(exlist = exp())) { /* parse and compile the arguments */ 54: printf("Odd usage\n"); 55: exit(9); 56: } 57: if(ap<argc) { 58: printf("Missing conjunction\n"); 59: exit(9); 60: } 61: descend(pathname,'f',find,exlist); /* to find files that match */ 62: } 63: 64: /* compile time functions: priority is exp()<e1()<e2()<e3() */ 65: 66: struct anode *exp() { /* parse -o ... */ 67: int or(); 68: int p1; 69: char *na; 70: p1 = e1() /* get left operand */ ; 71: if(compstr(na=nxtarg(),"-o")==0) { 72: randlast--; 73: return(mk(&or,p1,exp())); 74: } 75: else if(*na!=0) --ap; 76: return(p1); 77: } 78: struct anode *e1() { /* parse -a */ 79: int and(); 80: int p1; 81: char *na; 82: p1 = e2(); 83: if(compstr(na=nxtarg(),"-a")==0) { 84: randlast--; 85: return(mk(&and,p1,e1())); 86: } 87: else if(*na!=0) --ap; 88: return(p1); 89: } 90: struct anode *e2() { /* parse not (!) */ 91: int not(); 92: char *na; 93: if(randlast) { 94: printf("operand follows operand.\n"); 95: exit(9); 96: } 97: randlast++; 98: if(compstr(na=nxtarg(),"!")==0) 99: return(mk(¬,e3(),0)); 100: else if(*na!=0) --ap; 101: return(e3()); 102: } 103: struct anode *e3() { /* parse parens and predicates */ 104: int exeq(), ok(), glob(), mtime(), atime(), user(), 105: group(), size(), perm(), links(), print(), 106: type(); 107: int p1, i; 108: char *a, *b, s; 109: a = nxtarg(); 110: if(compstr(a,"(")==0) { 111: randlast--; 112: p1 = exp(); 113: a = nxtarg(); 114: if(compstr(a,")")!=0) goto err; 115: return(p1); 116: } 117: else if(compstr(a,"-print")==0) { 118: return(mk(&print,0,0)); 119: } 120: b = nxtarg(); 121: s = *b; 122: if(s=='+') b++; 123: if(compstr(a,"-name")==0) 124: return(mk(&glob,b,0)); 125: else if(compstr(a,"-mtime")==0) 126: return(mk(&mtime,atoi(b),s)); 127: else if(compstr(a,"-atime")==0) 128: return(mk(&atime,atoi(b),s)); 129: else if(compstr(a,"-user")==0) { 130: if((i=getunum(b)) == -1) { 131: printf("Cannot find user \"%s\"\n",b); 132: exit(9); 133: } 134: return(mk(&user,i,s)); 135: } 136: else if(compstr(a,"-group")==0) 137: return(mk(&group,atoi(b),s)); 138: else if(compstr(a,"-size")==0) 139: return(mk(&size,atoi(b),s)); 140: else if(compstr(a,"-links")==0) 141: return(mk(&links,atoi(b),s)); 142: else if(compstr(a,"-perm")==0) { 143: for(i=0; *b ; ++b) { 144: if(*b=='-') continue; 145: i =<< 3; 146: i = i + (*b - '0'); 147: } 148: return(mk(&perm,i,s)); 149: } 150: else if(compstr(a,"-type")==0) { 151: i = s=='d' ? 040000 : 152: s=='b' ? 060000 : 153: s=='c' ? 020000 : 154: 000000; 155: return(mk(&type,i,0)); 156: } 157: else if (compstr(a,"-exec")==0) { 158: i = ap - 1; 159: while(compstr(nxtarg(),";")!=0); 160: return(mk(&exeq,i,0)); 161: } 162: else if (compstr(a,"-ok")==0) { 163: i = ap - 1; 164: while(compstr(nxtarg(),";")!=0); 165: return(mk(&ok,i,0)); 166: } 167: err: printf("Bad option: \"%s\" \"%s\"\n",a,b); 168: exit(9); 169: } 170: struct anode *mk(f,l,r) struct anode *l,*r; { /*make an expression node*/ 171: node[nn].F = f; 172: node[nn].L = l; 173: node[nn].R = r; 174: return(&(node[nn++])); 175: } 176: 177: nxtarg() { /* get next arg from command line */ 178: if(ap>=ac) return(""); 179: return(av[ap++]); 180: } 181: 182: find(exlist,fullname) /* execute predicat list with current file */ 183: struct anode *exlist; 184: char *fullname; 185: { 186: register int i; 187: path = fullname; 188: if(verbose) printf("%s",path); 189: for(i=0;fullname[i];++i) 190: if(fullname[i]=='/') fname = &fullname[i+1]; 191: i = (*exlist->F)(exlist); 192: if(verbose) 193: if(i) printf(".\n"); 194: else printf("\n"); 195: } 196: 197: /* execution time functions */ 198: and(p) struct anode *p; { 199: return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0); 200: } 201: or(p) struct anode *p; { 202: return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0); 203: } 204: not(p) struct anode *p; { 205: return( !((*p->L->F)(p->L))); 206: } 207: glob(p) struct { int f; char *pat; } *p; { 208: return(gmatch(fname,p->pat)); 209: } 210: print() { 211: printf("%s\n",path); 212: return(1); 213: } 214: mtime(p) struct { int f, t, s; } *p; { 215: return(scomp((now[0]-statb.imtime[0])*3/4,p->t,p->s)); 216: } 217: atime(p) struct { int f, t, s; } *p; { 218: return(scomp((now[0]-statb.iatime[0])*3/4,p->t,p->s)); 219: } 220: user(p) struct { int f, u, s; } *p; { 221: return(scomp(statb.iuid,p->u,p->s)); 222: } 223: group(p) struct { int f, u; } *p; { 224: return(p->u == statb.igid); 225: } 226: links(p) struct { int f, link, s; } *p; { 227: return(scomp(statb.inl,p->link,p->s)); 228: } 229: size(p) struct { int f, sz, s; } *p; { 230: register int i; 231: i = statb.isize0 << 7; 232: i = i | ((statb.isize>>9) & 0177); 233: return(scomp(i,p->sz,p->s)); 234: } 235: perm(p) struct { int f, per, s; } *p; { 236: int i; 237: i = (p->s=='-') ? p->per : 03777; /* '-' means only arg bits */ 238: return((statb.iflags & i & 017777) == p->per); 239: } 240: type(p) struct { int f, per, s; } *p; { 241: return((statb.iflags&060000)==p->per); 242: } 243: exeq(p) struct { int f, com; } *p; { 244: return(doex(p->com)); 245: } 246: ok(p) struct { int f, com; } *p; { 247: char c; int yes; 248: yes = 0; 249: printf("%s ... %s ...? ",av[p->com],path); 250: if((c=getchar())=='y') yes = 1; 251: while(c!='\n') c = getchar(); 252: if(yes) return(doex(p->com)); 253: return(0); 254: } 255: 256: /* support functions */ 257: scomp(a,b,s) char s; { /* funny signed compare */ 258: if(s == '+') 259: return(a > b); 260: if(s == '-') 261: return(a < (b * -1)); 262: return(a == b); 263: } 264: doex(com) { 265: int ccode; 266: int np, i, c; 267: char *nargv[50], *ncom, *na; 268: 269: ccode = np = 0; 270: while (na=av[com++]) { 271: if(compstr(na,";")==0) break; 272: if(compstr(na,"{}")==0) nargv[np++] = path; 273: else nargv[np++] = na; 274: } 275: nargv[np] = 0; 276: if (np==0) return(9); 277: if(fork()) /*parent*/ wait(&ccode); 278: else { /*child*/ 279: execv(nargv[0], nargv, np); 280: i = 0; 281: ncom = "/usr/bin/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 282: while(c=nargv[0][i]) { 283: ncom[9+i++] = c; 284: } 285: ncom[9+i] = '\0'; 286: execv(ncom+4, nargv, np); 287: execv(ncom, nargv, np); 288: exit(9); 289: } 290: return(ccode ? 0:1); 291: } 292: 293: char fin[518]; 294: getunum(s) char *s; { /* find username in /etc/passwd & return num. */ 295: int i; 296: char str[20], *sp, c; 297: i = -1; 298: fin[0] = open("/etc/passwd",0); 299: while(c = getchar()) { 300: if(c=='\n') { 301: sp = str; 302: while((*sp = getchar()) != ':') 303: if(! *sp++) goto RET; 304: *sp = '\0'; 305: if(compstr(str,s)==0) { 306: while((c=getchar()) != ':') 307: if(! c) goto RET; 308: sp = str; 309: while((*sp = getchar()) != ':') sp++; 310: *sp = '\0'; 311: i = atoi(str); 312: break; 313: } 314: } 315: } 316: RET: 317: close(fin); 318: fin[0] = 0; 319: return(i); 320: } 321: 322: compstr(s1,s2) char s1[], s2[]; { /* compare strings: */ 323: register char *c1, *c2; 324: c1 = s1; c2 = s2; 325: while(*c1 == *c2) 326: if(*c1++ == '\0') 327: return(0); /* s1 == s2 */ 328: else c2++; 329: return(*c1 > *c2 ? 1 : -1); 330: } 331: 332: int descend(name,goal,func,arg) 333: int (*func)(); 334: char *name, goal; 335: { 336: int dir /* open directory */, offset /* in directory */; 337: int dsize, top; 338: struct { 339: int dinode; 340: char dname[14]; 341: } dentry[32]; 342: register int i, j, k; 343: char aname[128]; 344: 345: if(stat(name,&statb)<0) { 346: printf("--bad status %s\n",name); 347: return(0); 348: } 349: /* 350: if((statb.iflags&060000)!=040000){ /*not a directory*/ 351: /* 352: if(goal=='f'||goal=='b') /* search goal for files */ 353: /* 354: (*func)(arg,name); 355: return(1); 356: } else if(goal=='d' || goal=='b') /* search goal is directories */ 357: /* 358: (*func)(arg,name); 359: */ 360: (*func)(arg,name); 361: if((statb.iflags&060000)!=040000) 362: return(1); 363: 364: top = statb.isize; 365: for(offset=0 ; offset < top ; offset =+ 512) { /* each block */ 366: dsize = 512<(top-offset) ? 512 : (top-offset); 367: if((dir=open(name,0))<0) { 368: printf("--cannot open %s\n",name); 369: return(0); 370: } 371: if(offset) seek(dir,offset,0); 372: if(read(dir,&dentry,dsize)<0) { 373: printf("--cannot read %s\n",name); 374: return(0); 375: } 376: close(dir); 377: for(i = 0; i < (dsize>>4); ++i) { /* each dir. entry */ 378: if(dentry[i].dinode==0 || 379: compstr(dentry[i].dname,".")==0 || 380: compstr(dentry[i].dname,"..")==0) 381: continue; 382: if (dentry[i].dinode == -1) break; 383: for(j=0;aname[j]=name[j];++j); 384: if(aname[j-1]!='/') aname[j++] = '/'; 385: for(k=0; (aname[j++]=dentry[i].dname[k]) && 386: k<13; ++k); 387: aname[j] = '\0'; 388: if(descend(aname,goal,func,arg)==0) 389: printf("--%s\n",name); 390: } 391: } 392: return(1); 393: } 394: 395: gmatch(s, p) /* string match as in glob */ 396: char *s, *p; { 397: if (*s=='.' && *p!='.') return(0); 398: return(amatch(s, p)); 399: } 400: 401: amatch(s, p) 402: char *s, *p; 403: { 404: register int cc, scc, k; 405: int c, lc; 406: 407: scc = *s; 408: lc = 077777; 409: switch (c = *p) { 410: 411: case '[': 412: k = 0; 413: while (cc = *++p) { 414: switch (cc) { 415: 416: case ']': 417: if (k) 418: return(amatch(++s, ++p)); 419: else 420: return(0); 421: 422: case '-': 423: k =| lc <= scc & scc <= (cc=p[1]); 424: } 425: if (scc==(lc=cc)) k++; 426: } 427: return(0); 428: 429: case '?': 430: caseq: 431: if(scc) return(amatch(++s, ++p)); 432: return(0); 433: case '*': 434: return(umatch(s, ++p)); 435: case 0: 436: return(!scc); 437: } 438: if (c==scc) goto caseq; 439: return(0); 440: } 441: 442: umatch(s, p) 443: char *s, *p; 444: { 445: if(*p==0) return(1); 446: while(*s) 447: if (amatch(s++,p)) return(1); 448: return(0); 449: }