Research V7 development
authorDick Haight <haight@research.uucp>
Sat, 5 May 1979 07:00:35 +0000 (02:00 -0500)
committerDick Haight <haight@research.uucp>
Sat, 5 May 1979 07:00:35 +0000 (02:00 -0500)
Work on file usr/src/cmd/find.c

Synthesized-from: v7

usr/src/cmd/find.c [new file with mode: 0644]

diff --git a/usr/src/cmd/find.c b/usr/src/cmd/find.c
new file mode 100644 (file)
index 0000000..d0aea47
--- /dev/null
@@ -0,0 +1,723 @@
+/*     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);
+}