home *** CD-ROM | disk | FTP | other *** search
- /* find COMPILE: cc -o find -s -O -i find.c -lS */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/dir.h>
- #include <sys/stat.h>
- #define A_DAY 86400L /* a day full of seconds */
- #define EQ(x, y) (strcmp(x, y)==0)
-
- int Randlast;
- char Pathname[200];
-
- struct anode {
- int (*F)();
- struct anode *L, *R;
- } Node[100];
- 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;
-
- struct anode *exp(),
- *e1(),
- *e2(),
- *e3(),
- *mk();
- char *nxtarg();
- char Home[128];
- long Blocks;
- char *rindex();
- char *sbrk();
- main(argc, argv) char *argv[];
- {
- struct anode *exlist;
- int paths;
- register char *cp, *sp = 0;
- FILE *pwd, *popen();
-
- time(&Now);
- pwd = popen("pwd", "r");
- fgets(Home, 128, pwd);
- pclose(pwd);
- Home[strlen(Home) - 1] = '\0';
- 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) {
- pr("find: missing conjunction\n");
- exit(1);
- }
- for(Pi = 1; Pi < paths; ++Pi) {
- sp = 0;
- chdir(Home);
- strcpy(Pathname, Argv[Pi]);
- if(cp = rindex(Pathname, '/')) {
- sp = cp + 1;
- *cp = '\0';
- if(chdir(*Pathname? Pathname: "/") == -1) {
- pr("find: bad starting directory\n");
- exit(2);
- }
- *cp = '/';
- }
- Fname = sp? sp: Pathname;
- descend(Pathname, Fname, exlist); /* to find files that match */
- }
- if(Cpio) {
- strcpy(Pathname, "TRAILER!!!");
- Statb.st_size = 0;
- cpio();
- }
- exit(0);
- }
-
- /* compile time functions: priority is exp()<e1()<e2()<e3() */
-
- struct anode *exp() { /* parse ALTERNATION (-o) */
- int or();
- register struct anode * p1;
-
- p1 = e1() /* get left operand */ ;
- if(EQ(nxtarg(), "-o")) {
- Randlast--;
- return(mk(or, p1, exp()));
- }
- else if(Ai <= Argc) --Ai;
- return(p1);
- }
- struct anode *e1() { /* parse CONCATENATION (formerly -a) */
- int and();
- register struct anode * p1;
- register char *a;
-
- p1 = e2();
- a = nxtarg();
- if(EQ(a, "-a")) {
- And:
- Randlast--;
- return(mk(and, p1, e1()));
- } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
- --Ai;
- goto And;
- } else if(Ai <= Argc) --Ai;
- return(p1);
- }
- struct anode *e2() { /* parse NOT (!) */
- int not();
-
- if(Randlast) {
- pr("find: operand follows operand\n");
- exit(1);
- }
- Randlast++;
- if(EQ(nxtarg(), "!"))
- return(mk(not, e3(), (struct anode *)0));
- else if(Ai <= Argc) --Ai;
- return(e3());
- }
- struct anode *e3() { /* parse parens and predicates */
- int exeq(), ok(), glob(), mtime(), atime(), ctime(), user(),
- group(), size(), perm(), links(), print(),
- type(), ino(), cpio(), newer();
- struct anode *p1;
- int i;
- register char *a, *b, s;
-
- a = nxtarg();
- if(EQ(a, "(")) {
- Randlast--;
- p1 = exp();
- a = nxtarg();
- if(!EQ(a, ")")) goto err;
- return(p1);
- }
- else if(EQ(a, "-print")) {
- return(mk(print, (struct anode *)0, (struct anode *)0));
- }
- b = nxtarg();
- s = *b;
- if(s=='+') b++;
- if(EQ(a, "-name"))
- return(mk(glob, (struct anode *)b, (struct anode *)0));
- else if(EQ(a, "-mtime"))
- return(mk(mtime, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-atime"))
- return(mk(atime, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-ctime"))
- return(mk(ctime, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-user")) {
- if((i=getunum("/etc/passwd", b)) == -1) {
- if(gmatch(b, "[0-9][0-9][0-9]*")
- || gmatch(b, "[0-9][0-9]")
- || gmatch(b, "[0-9]"))
- return mk(user, (struct anode *)atoi(b), (struct anode *)s);
- pr("find: cannot find -user name\n");
- exit(1);
- }
- return(mk(user, (struct anode *)i, (struct anode *)s));
- }
- else if(EQ(a, "-inum"))
- return(mk(ino, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-group")) {
- if((i=getunum("/etc/group", b)) == -1) {
- if(gmatch(b, "[0-9][0-9][0-9]*")
- || gmatch(b, "[0-9][0-9]")
- || gmatch(b, "[0-9]"))
- return mk(group, (struct anode *)atoi(b), (struct anode *)s);
- pr("find: cannot find -group name\n");
- exit(1);
- }
- return(mk(group, (struct anode *)i, (struct anode *)s));
- } else if(EQ(a, "-size"))
- return(mk(size, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-links"))
- return(mk(links, (struct anode *)atoi(b), (struct anode *)s));
- else if(EQ(a, "-perm")) {
- for(i=0; *b ; ++b) {
- if(*b=='-') continue;
- i <<= 3;
- i = i + (*b - '0');
- }
- return(mk(perm, (struct anode *)i, (struct anode *)s));
- }
- else if(EQ(a, "-type")) {
- i = s=='d' ? S_IFDIR :
- s=='b' ? S_IFBLK :
- s=='c' ? S_IFCHR :
- s=='f' ? 0100000 :
- 0;
- return(mk(type, (struct anode *)i, (struct anode *)0));
- }
- else if (EQ(a, "-exec")) {
- i = Ai - 1;
- while(!EQ(nxtarg(), ";"));
- return(mk(exeq, (struct anode *)i, (struct anode *)0));
- }
- else if (EQ(a, "-ok")) {
- i = Ai - 1;
- while(!EQ(nxtarg(), ";"));
- return(mk(ok, (struct anode *)i, (struct anode *)0));
- }
- else if(EQ(a, "-cpio")) {
- if((Cpio = creat(b, 0666)) < 0) {
- pr("find: cannot create "), pr(s), pr("\n");
- exit(1);
- }
- Buf = (short *)sbrk(512);
- Wp = Dbuf = (short *)sbrk(5120);
- return(mk(cpio, (struct anode *)0, (struct anode *)0));
- }
- else if(EQ(a, "-newer")) {
- if(stat(b, &Statb) < 0) {
- pr("find: cannot access "), pr(b), pr("\n");
- exit(1);
- }
- Newer = Statb.st_mtime;
- return mk(newer, (struct anode *)0, (struct anode *)0);
- }
- err: pr("find: bad option "), pr(a), pr("\n");
- exit(1);
- }
- struct anode *mk(f, l, r)
- int (*f)();
- struct anode *l, *r;
- {
- Node[Nn].F = f;
- Node[Nn].L = l;
- Node[Nn].R = r;
- return(&(Node[Nn++]));
- }
-
- char *nxtarg() { /* get next arg from command line */
- static strikes = 0;
-
- if(strikes==3) {
- pr("find: incomplete statement\n");
- exit(1);
- }
- if(Ai>=Argc) {
- strikes++;
- Ai = Argc + 1;
- return("");
- }
- return(Argv[Ai++]);
- }
-
- /* execution time functions */
- and(p)
- register struct anode *p;
- {
- return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0);
- }
- or(p)
- register struct anode *p;
- {
- return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0);
- }
- not(p)
- register struct anode *p;
- {
- return( !((*p->L->F)(p->L)));
- }
- glob(p)
- register struct { int f; char *pat; } *p;
- {
- return(gmatch(Fname, p->pat));
- }
- print()
- {
- puts(Pathname);
- return(1);
- }
- mtime(p)
- register struct { int f, t, s; } *p;
- {
- return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s));
- }
- atime(p)
- register struct { int f, t, s; } *p;
- {
- return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s));
- }
- ctime(p)
- register struct { int f, t, s; } *p;
- {
- return(scomp((int)((Now - Statb.st_ctime) / A_DAY), p->t, p->s));
- }
- user(p)
- register struct { int f, u, s; } *p;
- {
- return(scomp(Statb.st_uid, p->u, p->s));
- }
- ino(p)
- register struct { int f, u, s; } *p;
- {
- return(scomp((int)Statb.st_ino, p->u, p->s));
- }
- group(p)
- register struct { int f, u; } *p;
- {
- return(p->u == Statb.st_gid);
- }
- links(p)
- register struct { int f, link, s; } *p;
- {
- return(scomp(Statb.st_nlink, p->link, p->s));
- }
- size(p)
- register struct { int f, sz, s; } *p;
- {
- return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s));
- }
- perm(p)
- register struct { int f, per, s; } *p;
- {
- register i;
- i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */
- return((Statb.st_mode & i & 07777) == p->per);
- }
- type(p)
- register struct { int f, per, s; } *p;
- {
- return((Statb.st_mode&S_IFMT)==p->per);
- }
- exeq(p)
- register struct { int f, com; } *p;
- {
- fflush(stdout); /* to flush possible `-print' */
- return(doex(p->com));
- }
- ok(p)
- struct { int f, com; } *p;
- {
- int c; int yes;
- yes = 0;
- fflush(stdout); /* to flush possible `-print' */
- pr("< "), pr(Argv[p->com]), 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(p->com));
- 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(v)
- 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;
- }
- cpio()
- {
- #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 ifile, ct;
- static long fsz;
- register 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;
- }
- newer()
- {
- return Statb.st_mtime > Newer;
- }
-
- /* support functions */
- scomp(a, b, s) /* funny signed compare */
- register a, b;
- register char s;
- {
- if(s == '+')
- return(a > b);
- if(s == '-')
- return(a < (b * -1));
- return(a == b);
- }
-
- doex(com)
- {
- register np;
- register char *na;
- static char *nargv[50];
- static ccode;
-
- 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(fork()) /*parent*/ wait(&ccode);
- else { /*child*/
- chdir(Home);
- execvp(nargv[0], nargv, np);
- exit(1);
- }
- return(ccode ? 0:1);
- }
-
- getunum(f, s) char *f, *s; { /* find user/group name and return number */
- register i;
- register char *sp;
- register 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);
- }
-
- descend(name, fname, exlist)
- struct anode *exlist;
- char *name, *fname;
- {
- int dir = 0, /* open directory */
- offset,
- dsize,
- entries,
- dirsize;
- struct direct dentry[32];
- register struct direct *dp;
- register char *c1, *c2;
- int i;
- int rv = 0;
- char *endofname;
-
- if(stat(fname, &Statb)<0) {
- pr("find: bad status-- "), pr(name), pr("\n");
- return(0);
- }
- (*exlist->F)(exlist);
- if((Statb.st_mode&S_IFMT)!=S_IFDIR)
- return(1);
-
- for(c1 = name; *c1; ++c1);
- if(*(c1-1) == '/')
- --c1;
- endofname = c1;
- dirsize = Statb.st_size;
-
- if(chdir(fname) == -1)
- return(0);
- for(offset=0 ; offset < dirsize ; offset += 512) { /* each block */
- dsize = 512<(dirsize-offset)? 512: (dirsize-offset);
- if(!dir) {
- if((dir=open(".", 0))<0) {
- pr("find: cannot open "), pr(name), pr("\n");
- rv = 0;
- goto ret;
- }
- if(offset) lseek(dir, (long)offset, 0);
- if(read(dir, (char *)dentry, dsize)<0) {
- pr("find: cannot read "), pr(name), pr("\n");
- rv = 0;
- goto ret;
- }
- if(dir > 10) {
- close(dir);
- dir = 0;
- }
- } else
- if(read(dir, (char *)dentry, dsize)<0) {
- pr("find: cannot read "), pr(name), pr("\n");
- rv = 0;
- goto ret;
- }
- for(dp=dentry, entries=dsize>>4; entries; --entries, ++dp) { /* each directory entry */
- if(dp->d_ino==0
- || (dp->d_name[0]=='.' && dp->d_name[1]=='\0')
- || (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
- continue;
- c1 = endofname;
- *c1++ = '/';
- c2 = dp->d_name;
- for(i=0; i<14; ++i)
- if(*c2)
- *c1++ = *c2++;
- else
- break;
- *c1 = '\0';
- if(c1 == endofname) { /* ?? */
- rv = 0;
- goto ret;
- }
- Fname = endofname+1;
- if(!descend(name, Fname, exlist)) {
- *endofname = '\0';
- chdir(Home);
- if(chdir(Pathname) == -1) {
- pr("find: bad directory tree\n");
- exit(1);
- }
- }
- }
- }
- rv = 1;
- ret:
- if(dir)
- close(dir);
- if(chdir("..") == -1) {
- *endofname = '\0';
- pr("find: bad directory "), pr(name), pr("\n");
- rv = 1;
- }
- return(rv);
- }
-
- gmatch(s, p) /* string match as in glob */
- register char *s, *p;
- {
- if (*s=='.' && *p!='.') return(0);
- return amatch(s, p);
- }
-
- amatch(s, p)
- register char *s, *p;
- {
- register cc;
- int scc, k;
- int c, lc;
-
- scc = *s;
- lc = 077777;
- switch (c = *p) {
-
- case '[':
- k = 0;
- while (cc = *++p) {
- switch (cc) {
-
- case ']':
- if (k)
- return(amatch(++s, ++p));
- else
- return(0);
-
- case '-':
- k |= lc <= scc & scc <= (cc=p[1]);
- }
- if (scc==(lc=cc)) k++;
- }
- return(0);
-
- case '?':
- caseq:
- if(scc) return(amatch(++s, ++p));
- return(0);
- case '*':
- return(umatch(s, ++p));
- case 0:
- return(!scc);
- }
- if (c==scc) goto caseq;
- return(0);
- }
-
- umatch(s, p)
- register char *s, *p;
- {
- if(*p==0) return(1);
- while(*s)
- if (amatch(s++, p)) return(1);
- return(0);
- }
-
- bwrite(rp, c)
- register short *rp;
- register c;
- {
- register short *wp = Wp;
-
- c = (c+1) >> 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;
- }
- chgreel(x, fl)
- {
- register 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;
- }
- pr(s)
- char *s;
- {
- fputs(s, stderr);
- }
-