/* find COMPILE: cc -o find -s -O -i find.c -lS */ #pragma debug 8+64 /* No ORCA/C stack fixup */ #include #include #include #include #include #include #include #include #include #include #include #include #define FNAMELEN 255 #define A_DAY 86400L /* a day full of seconds */ #define EQ(x, y) (strcmp(x, y)==0) time_t time(time_t*); struct anode { int (*F)(void *); void *L, *R; } Node[100]; int Randlast; char Pathname[MAXPATHLEN]; int Nn; /* number of nodes */ char *Fname; long Now; int Argc, Ai, Pi; char **Argv; /* cpio stuff */ int Cpio; short *Buf, *Dbuf, *Wp; int Bufsize = 5120; int Wct = 2560; long Newer; struct stat Statb; char Home[MAXPATHLEN]; long Blocks; int main(int argc, char *argv[]); struct anode *_exp(void); struct anode *e1(void); struct anode *e2(void); struct anode *e3(void); struct anode *mk(void *f, void *l, void *r); char *nxtarg(void); int and(register struct anode *p); int or(register struct anode *p); int not(register struct anode *p); int _glob(register struct anode *p); int print(void); int mtime(register struct anode *p); int atime(register struct anode *p); int _ctime(register struct anode *p); int user(register struct anode *p); int ino(register struct anode *p); int group(register struct anode *p); int links(register struct anode *p); int size(register struct anode *p); int perm(register struct anode *p); int type(register struct anode *p); int exeq(register struct anode *p); int ok(register struct anode *p); long mklong(short v[]); void cpio(void); int newer(void); int scomp(register int a, register int b, register char s); int doex(int com); int getunum(char *f, char *s); int descend(char *name, char *fname, struct anode *exlist); int gmatch(register char *s, register char *p); int amatch(register char *s, register char *p); int umatch(register char *s, register char *p); void bwrite(register short *rp, register int c); int chgreel(int x, int fl); void pr(char *s); int main(int argc, char *argv[]) { struct anode *exlist; int paths; register char *cp, *sp = 0; FILE *pwd; time(&Now); getcwd(Home, MAXPATHLEN); Argc = argc; Argv = argv; if(argc<3) { usage: pr("Usage: find path-list predicate-list\n"); exit(1); } for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths) if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!")) break; if(paths == 1) /* no path-list */ goto usage; if(!(exlist = _exp())) { /* parse and compile the arguments */ pr("find: parsing error\n"); exit(1); } if(Ai=Argc) { strikes++; Ai = Argc + 1; return(""); } return(Argv[Ai++]); } /* execution time functions */ int and(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(((*L->F)(p->L)) && ((*R->F)(R))?1:0); } int or(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(((*L->F)(L)) || ((*R->F)(R))?1:0); } int not(register struct anode *p) { struct anode *L = p->L; return( !((*L->F)(L))); } int _glob(register struct anode *p) { struct anode *L = p->L; return(gmatch(Fname, (char*)L)); } int print(void) { puts(Pathname); return(1); } int mtime(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp((int)((Now - Statb.st_mtime) / A_DAY), (int)L, (char)R)); } int atime(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp((int)((Now - Statb.st_atime) / A_DAY), (int)L, (char)R)); } int _ctime(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp((int)((Now - Statb.st_ctime) / A_DAY), (int)L, (char)R)); } int user(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp(Statb.st_uid, (int)L, (char)R)); } int ino(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp((int)Statb.st_ino, (int)L, (char)R)); } int group(register struct anode *p) { struct anode *L = p->L; return((int)L == Statb.st_gid); } int links(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp(Statb.st_nlink, (int)L, (char)R)); } int size(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; return(scomp((int)((Statb.st_size+511)>>9), (int)L, (char)R)); } int perm(register struct anode *p) { struct anode *L = p->L; struct anode *R = p->R; register int i; i = ((char)R=='-') ? (int)L : 07777; /* '-' means only arg bits */ return((Statb.st_mode & i & 07777) == (int)L); } int type(register struct anode *p) { struct anode *L = p->L; return((Statb.st_mode&S_IFMT)==(int)L); } int exeq(register struct anode *p) { struct anode *L = p->L; fflush(stdout); /* to flush possible `-print' */ return(doex((int)L)); } int ok(register struct anode *p) { struct anode *L = p->L; int c; int yes; yes = 0; fflush(stdout); /* to flush possible `-print' */ pr("< "), pr(Argv[(int)L]), pr(" ... "), pr(Pathname), pr(" >? "); fflush(stderr); if((c=getchar())=='y') yes = 1; while(c!='\n') if(c==EOF) exit(2); else c = getchar(); if(yes) return(doex((int)L)); return(0); } #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];} union { long l; short s[2]; char c[4]; } U; long mklong(short v[]) { U.l = 1; if(U.c[0] /* VAX */) U.s[0] = v[1], U.s[1] = v[0]; else U.s[0] = v[0], U.s[1] = v[1]; return U.l; } void cpio(void) { #define MAGIC 070707 struct header { short h_magic, h_dev, h_ino, h_mode, h_uid, h_gid, h_nlink, h_rdev; short h_mtime[2]; short h_namesize; short h_filesize[2]; char h_name[256]; } hdr; register int ifile, ct; static long fsz; register int i; hdr.h_magic = MAGIC; strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname); hdr.h_namesize = strlen(hdr.h_name) + 1; hdr.h_uid = Statb.st_uid; hdr.h_gid = Statb.st_gid; hdr.h_dev = Statb.st_dev; hdr.h_ino = Statb.st_ino; hdr.h_mode = Statb.st_mode; MKSHORT(hdr.h_mtime, Statb.st_mtime); hdr.h_nlink = Statb.st_nlink; fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L; MKSHORT(hdr.h_filesize, fsz); hdr.h_rdev = Statb.st_rdev; if(EQ(hdr.h_name, "TRAILER!!!")) { bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); for(i = 0; i < 10; ++i) bwrite(Buf, 512); return; } if(!mklong(hdr.h_filesize)) { bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); return; } if((ifile = open(Fname, 0)) < 0) { cerror: pr("find: cannot copy "), pr(hdr.h_name), pr("\n"); return; } bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) { ct = fsz>512? 512: fsz; if(read(ifile, (char *)Buf, ct) < 0) goto cerror; bwrite(Buf, ct); } close(ifile); return; } int newer(void) { return Statb.st_mtime > Newer; } /* support functions */ int scomp(register int a, register int b, register char s) /* funny signed compare */ { if(s == '+') return(a > b); if(s == '-') return(a < (b * -1)); return(a == b); } /* Child entry point for GNO fork2() */ void child(char **nargv) { int rc; chdir(Home); rc = execvp(nargv[0], nargv); if (rc == -1) fprintf(stderr, "find: cannot execute '%s'\n", nargv[0]); } int doex(int com) { static char *nargv[50]; register int np; register char *na; union wait ccode; np = 0; while ((na=Argv[com++])) { if(strcmp(na, ";")==0) break; if(strcmp(na, "{}")==0) nargv[np++] = Pathname; else nargv[np++] = na; } nargv[np] = 0; if (np==0) return(9); if(fork2(child, 1024, 0, "find", 2, nargv)) wait(&ccode); return(*((int*)&ccode) ? 0:1); } int getunum(char *f, char *s) { /* find user/group name and return number */ register int i; register char *sp; register int c; char str[20]; FILE *pin; i = -1; pin = fopen(f, "r"); c = '\n'; /* prime with a CR */ do { if(c=='\n') { sp = str; while((c = *sp++ = getc(pin)) != ':') if(c == EOF) goto RET; *--sp = '\0'; if(EQ(str, s)) { while((c=getc(pin)) != ':') if(c == EOF) goto RET; sp = str; while((*sp = getc(pin)) != ':') sp++; *sp = '\0'; i = atoi(str); goto RET; } } } while((c = getc(pin)) != EOF); RET: fclose(pin); return(i); } /* * name - Full pathname of current file or directory ("/foo/bar/baz") * fname - Name of leaf node file or directory ("baz") * exlist - Expression list * Returns 0 if we are done with subtree, 1 if we should continue */ int descend(char *name, char *fname, struct anode *exlist) { DIR *dp; struct dirent *entry; int rv = 0, i; char *c1, *c2, *endofname; if (lstat(fname, &Statb) < 0) { printf("find: bad status-- %s\n", name); return 0; } (*exlist->F)(exlist); /* If it's a symlink we are done */ if ((Statb.st_mode & S_IFMT) == S_IFLNK) { return 1; } /* If it's not a directory we are done */ if ((Statb.st_mode & S_IFMT) != S_IFDIR) return 1; /* Find first '/' in name */ for (c1 = name; *c1; ++c1); if (*(c1-1) == '/') --c1; endofname = c1; /* If we can't enter & open directory we are done */ if (chdir(fname) == -1) return 0; dp = opendir("."); if (!dp) { printf("find: cannot open %s\n", name); rv = 0; goto done; } errno = 0; for (;;) { entry = readdir(dp); if (!entry) { if (errno != 0) { printf("find: cannot read %s (%d)\n", name, errno); } rv = 0; goto done; } /* Skip . and .. */ if (strcmp(entry->d_name, ".") == 0) continue; if (strcmp(entry->d_name, "..") == 0) continue; c1 = endofname; *c1++ = '/'; c2 = entry->d_name; for (i=0; i> 1; while(c--) { if(!Wct) { again: if(write(Cpio, (char *)Dbuf, Bufsize)<0) { Cpio = chgreel(1, Cpio); goto again; } Wct = Bufsize >> 1; wp = Dbuf; ++Blocks; } *wp++ = *rp++; --Wct; } Wp = wp; } int chgreel(int x, int fl) { register int f; char str[22]; FILE *devtty; struct stat statb; pr("find: can't "), pr(x? "write output": "read input"), pr("\n"); fstat(fl, &statb); if((statb.st_mode&S_IFMT) != S_IFCHR) exit(1); again: pr("If you want to go on, type device/file name when ready\n"); devtty = fopen("/dev/tty", "r"); fgets(str, 20, devtty); str[strlen(str) - 1] = '\0'; if(!*str) exit(1); close(fl); if((f = open(str, x? 1: 0)) < 0) { pr("That didn't work"); fclose(devtty); goto again; } return f; } void pr(char *s) { fputs(s, stderr); }