find.c

Go to the documentation of this file.
00001 /* find - look for files satisfying a predicate       Author: E. Baalbergen */
00002 
00003 /* Original author: Erik Baalbergen; POSIX compliant version: Bert Laverman */
00004 
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <sys/wait.h>
00008 #include <fcntl.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <unistd.h>
00012 #include <time.h>
00013 #include <pwd.h>
00014 #include <grp.h>
00015 #include <dirent.h>
00016 #include <limits.h>
00017 #include <stdio.h>
00018 
00019 /*######################## DEFINITIONS ##############################*/
00020 
00021 #ifdef S_IFLNK
00022 #define LSTAT lstat
00023 #else
00024 #define LSTAT stat
00025 #endif
00026 
00027 #define SHELL "/bin/sh"
00028 #define MAXARG          256     /* maximum length for an argv for -exec  */
00029 #define BSIZE           512     /* POSIX wants 512 byte blocks           */
00030 #define SECS_PER_DAY    (24L*60L*60L)   /* check your planet             */
00031 
00032 #define OP_NAME          1      /* match name                            */
00033 #define OP_PERM          2      /* check file permission bits            */
00034 #define OP_TYPE          3      /* check file type bits                  */
00035 #define OP_LINKS         4      /* check link count                      */
00036 #define OP_USER          5      /* check owner                           */
00037 #define OP_GROUP         6      /* check group ownership                 */
00038 #define OP_SIZE          7      /* check size, blocks or bytes           */
00039 #define OP_SIZEC         8      /* this is a fake for -size with 'c'     */
00040 #define OP_INUM          9      /* compare inode number                  */
00041 #define OP_ATIME        10      /* check last access time                */
00042 #define OP_CTIME        11      /* check creation time                   */
00043 #define OP_MTIME        12      /* check last modification time          */
00044 #define OP_EXEC         13      /* execute command                       */
00045 #define OP_OK           14      /* execute with confirmation             */
00046 #define OP_PRINT        15      /* print name                            */
00047 #define OP_PRINT0       16      /* print name null terminated            */
00048 #define OP_NEWER        17      /* compare modification times            */
00049 #define OP_CNEWER       18      /* compare modification times            */
00050 #define OP_AND          19      /* logical and (short circuit)           */
00051 #define OP_OR           20      /* logical or (short circuit)            */
00052 #define OP_XDEV         21      /* do not cross file-system boundaries   */
00053 #define OP_DEPTH        22      /* descend directory before testing      */
00054 #define OP_PRUNE        23      /* don't descend into current directory  */
00055 #define OP_NOUSER       24      /* check validity of user id             */
00056 #define OP_NOGROUP      25      /* check validity of group id            */
00057 #define LPAR            26      /* left parenthesis                      */
00058 #define RPAR            27      /* right parenthesis                     */
00059 #define NOT             28      /* logical not                           */
00060 
00061 /* Some return values: */
00062 #define EOI             -1      /* end of expression                     */
00063 #define NONE             0      /* not a valid predicate                 */
00064 
00065 /* For -perm with symbolic modes: */
00066 #define ISWHO(c)        ((c == 'u') || (c == 'g') || (c == 'o') || (c == 'a'))
00067 #define ISOPER(c)       ((c == '-') || (c == '=') || (c == '+'))
00068 #define ISMODE(c)       ((c == 'r') || (c == 'w') || (c == 'x') || \
00069                          (c == 's') || (c == 't'))
00070 #define MUSER           1
00071 #define MGROUP          2
00072 #define MOTHERS         4
00073 
00074 
00075 struct exec {
00076   int e_cnt;
00077   char *e_vec[MAXARG];
00078 };
00079 
00080 struct node {
00081   int n_type;                   /* any OP_ or NOT */
00082   union {
00083         char *n_str;
00084         struct {
00085                 long n_val;
00086                 int n_sign;
00087         } n_int;
00088         struct exec *n_exec;
00089         struct {
00090                 struct node *n_left, *n_right;
00091         } n_opnd;
00092   } n_info;
00093 };
00094 
00095 struct oper {
00096   char *op_str;
00097   int op_val;
00098 } ops[] = {
00099 
00100   {
00101         "name", OP_NAME
00102   },
00103   {
00104         "perm", OP_PERM
00105   },
00106   {
00107         "type", OP_TYPE
00108   },
00109   {
00110         "links", OP_LINKS
00111   },
00112   {
00113         "user", OP_USER
00114   },
00115   {
00116         "group", OP_GROUP
00117   },
00118   {
00119         "size", OP_SIZE
00120   },
00121   {
00122         "inum", OP_INUM
00123   },
00124   {
00125         "atime", OP_ATIME
00126   },
00127   {
00128         "ctime", OP_CTIME
00129   },
00130   {
00131         "mtime", OP_MTIME
00132   },
00133   {
00134         "exec", OP_EXEC
00135   },
00136   {
00137         "ok", OP_OK
00138   },
00139   {
00140         "print", OP_PRINT
00141   },
00142   {
00143         "print0", OP_PRINT0
00144   },
00145   {
00146         "newer", OP_NEWER
00147   },
00148   {
00149         "cnewer", OP_CNEWER
00150   },
00151   {
00152         "a", OP_AND
00153   },
00154   {
00155         "o", OP_OR
00156   },
00157   {
00158         "xdev", OP_XDEV
00159   },
00160   {
00161         "depth", OP_DEPTH
00162   },
00163   {
00164         "prune", OP_PRUNE
00165   },
00166   {
00167         "nouser", OP_NOUSER
00168   },
00169   {
00170         "nogroup", OP_NOGROUP
00171   },
00172   {
00173         0, 0
00174   }
00175 };
00176 
00177 
00178 char **ipp;                     /* pointer to next argument during parsing       */
00179 char *prog;                     /* program name (== argv [0])                    */
00180 char *epath;                    /* value of PATH environment string              */
00181 long current_time;              /* for computing age                             */
00182 int tty;                        /* fd for /dev/tty when using -ok                */
00183 int xdev_flag = 0;              /* cross device boundaries?                      */
00184 int devnr;                      /* device nr of first inode                      */
00185 int depth_flag = 0;             /* descend before check?                         */
00186 int prune_here;                 /* This is Baaaad! Don't ever do this again!     */
00187 int um;                         /* current umask()                               */
00188 int needprint = 1;              /* implicit -print needed?                       */
00189 
00190 
00191 /* The prototypes: */
00192 _PROTOTYPE(int main, (int argc, char **argv));
00193 _PROTOTYPE(char *Malloc, (int n));
00194 _PROTOTYPE(char *Salloc, (char *s));
00195 _PROTOTYPE(void find, (char *path, struct node * pred, char *last));
00196 _PROTOTYPE(int check, (char *path, struct stat * st, struct node * n, char *last));
00197 _PROTOTYPE(int ichk, (long val, struct node * n));
00198 _PROTOTYPE(int lex, (char *str));
00199 _PROTOTYPE(struct node * newnode, (int t));
00200 _PROTOTYPE(int isnumber, (char *str, int base, int sign));
00201 _PROTOTYPE(void number, (char *str, int base, long *pl, int *ps));
00202 _PROTOTYPE(void fmode, (char *str, long *pl, int *ps));
00203 _PROTOTYPE(struct node * expr, (int t));
00204 _PROTOTYPE(struct node * primary, (int t));
00205 _PROTOTYPE(struct node * secondary, (int t));
00206 _PROTOTYPE(void checkarg, (char *arg));
00207 _PROTOTYPE(struct node * simple, (int t));
00208 _PROTOTYPE(void nonfatal, (char *s1, char *s2));
00209 _PROTOTYPE(void fatal, (char *s1, char *s2));
00210 _PROTOTYPE(int smatch, (char *s, char *t));
00211 _PROTOTYPE(char *find_bin, (char *s));
00212 _PROTOTYPE(int execute, (int op, struct exec * e, char *path));
00213 _PROTOTYPE(void domode, (int op, int *mode, int bits));
00214 
00215 
00216 /* Malloc: a certified malloc */
00217 char *Malloc(n)
00218 int n;
00219 {
00220   char *m;
00221 
00222   if ((m = (char *) malloc(n)) == (char *) NULL) fatal("out of memory", "");
00223   return m;
00224 }
00225 
00226 /* Salloc: allocate space for a string */
00227 char *Salloc(s)
00228 char *s;
00229 {
00230   return strcpy(Malloc(strlen(s) + 1), s);
00231 }
00232 
00233 
00234 /* Main: the main body */
00235 int main(argc, argv)
00236 int argc;
00237 char *argv[];
00238 {
00239   char **pathlist, *path, *last;
00240   int pathcnt = 0, i;
00241   struct node *pred;
00242 
00243   prog = *argv++;               /* set program name (for diagnostics)    */
00244   if ((epath = getenv("PATH")) == (char *) NULL)
00245         fatal("Can't get path from environment", "");
00246   (void) umask(um = umask(0));  /* non-destructive get-umask :-)         */
00247   time(&current_time);          /* get current time                      */
00248 
00249   pathlist= argv;
00250   while (--argc > 0 && lex(*argv) == NONE) {    /* find paths            */
00251         pathcnt++;
00252         argv++;
00253   }
00254   if (pathcnt == 0)             /* there must be at least one path       */
00255         fatal("Usage: path-list [predicate-list]", "");
00256 
00257   ipp = argv;                   /* prepare for parsing                   */
00258   if (argc != 0) {              /* If there is anything to parse,        */
00259         pred = expr(lex(*ipp)); /* then do so                            */
00260         if (lex(*++ipp) != EOI) /* Make sure there's nothing left        */
00261                 fatal("syntax error: garbage at end of predicate", "");
00262   } else                        /* No predicate list                     */
00263         pred = (struct node *) NULL;
00264 
00265   for (i = 0; i < pathcnt; i++) {
00266         if (xdev_flag) xdev_flag = 2;
00267         path = pathlist[i];
00268         if ((last = strrchr(path, '/')) == NULL) last = path; else last++;
00269         find(path, pred, last);
00270   }
00271   return 0;
00272 }
00273 
00274 void find(path, pred, last)
00275 char *path, *last;
00276 struct node *pred;
00277 {
00278   char spath[PATH_MAX];
00279   register char *send = spath, *p;
00280   struct stat st;
00281   DIR *dp;
00282   struct dirent *de;
00283 
00284   if (path[1] == '\0' && *path == '/') {
00285         *send++ = '/';
00286         *send = '\0';
00287   } else
00288         while (*send++ = *path++) {
00289         }
00290 
00291   if (LSTAT(spath, &st) == -1)
00292         nonfatal("can't get status of ", spath);
00293   else {
00294         switch (xdev_flag) {
00295           case 0:
00296                 break;
00297           case 1:
00298                 if (st.st_dev != devnr) return;
00299                 break;
00300           case 2:               /* set current device number */
00301                 xdev_flag = 1;
00302                 devnr = st.st_dev;
00303                 break;
00304         }
00305 
00306         prune_here = 0;
00307         if (!depth_flag && check(spath, &st, pred, last) && needprint)
00308                 printf("%s\n", spath);
00309         if (!prune_here && (st.st_mode & S_IFMT) == S_IFDIR) {
00310                 if ((dp = opendir(spath)) == NULL) {
00311                         nonfatal("can't read directory ", spath);
00312                         perror( "Error" );
00313                         return;
00314                 }
00315                 send[-1] = '/';
00316                 while ((de = readdir(dp)) != NULL) {
00317                         p = de->d_name;
00318                         if ((de->d_name[0] != '.') || ((de->d_name[1])
00319                                           && ((de->d_name[1] != '.')
00320                                               || (de->d_name[2])))) {
00321                                 strcpy(send, de->d_name);
00322                                 find(spath, pred, send);
00323                         }
00324                 }
00325                 closedir(dp);
00326         }
00327         if (depth_flag) {
00328                 send[-1] = '\0';
00329                 if (check(spath, &st, pred, last) && needprint)
00330                         printf("%s\n", spath);
00331         }
00332   }
00333 }
00334 
00335 int check(path, st, n, last)
00336 char *path, *last;
00337 register struct stat *st;
00338 register struct node *n;
00339 {
00340   if (n == (struct node *) NULL) return 1;
00341   switch (n->n_type) {
00342     case OP_AND:
00343         return check(path, st, n->n_info.n_opnd.n_left, last) &&
00344                 check(path, st, n->n_info.n_opnd.n_right, last);
00345     case OP_OR:
00346         return check(path, st, n->n_info.n_opnd.n_left, last) ||
00347                 check(path, st, n->n_info.n_opnd.n_right, last);
00348     case NOT:
00349         return !check(path, st, n->n_info.n_opnd.n_left, last);
00350     case OP_NAME:
00351         return smatch(last, n->n_info.n_str);
00352     case OP_PERM:
00353         if (n->n_info.n_int.n_sign < 0)
00354                 return(st->st_mode & (int) n->n_info.n_int.n_val) ==
00355                         (int) n->n_info.n_int.n_val;
00356         return(st->st_mode & 07777) == (int) n->n_info.n_int.n_val;
00357     case OP_NEWER:
00358         return st->st_mtime > n->n_info.n_int.n_val;
00359     case OP_CNEWER:
00360         return st->st_ctime > n->n_info.n_int.n_val;
00361     case OP_TYPE:
00362         return(st->st_mode & S_IFMT) == (mode_t) n->n_info.n_int.n_val;
00363     case OP_LINKS:
00364         return ichk((long) (st->st_nlink), n);
00365     case OP_USER:
00366         return st->st_uid == n->n_info.n_int.n_val;
00367     case OP_GROUP:
00368         return st->st_gid == n->n_info.n_int.n_val;
00369     case OP_SIZE:
00370         return ichk((st->st_size == 0) ? 0L :
00371                     (long) ((st->st_size - 1) / BSIZE + 1), n);
00372     case OP_SIZEC:
00373         return ichk((long) st->st_size, n);
00374     case OP_INUM:
00375         return ichk((long) (st->st_ino), n);
00376     case OP_ATIME:
00377         return ichk(st->st_atime, n);
00378     case OP_CTIME:
00379         return ichk(st->st_ctime, n);
00380     case OP_MTIME:
00381         return ichk(st->st_mtime, n);
00382     case OP_EXEC:
00383     case OP_OK:
00384         return execute(n->n_type, n->n_info.n_exec, path);
00385     case OP_PRINT:
00386         printf("%s\n", path);
00387         return 1;
00388     case OP_PRINT0:
00389         printf("%s", path); putchar(0);
00390         return 1;
00391     case OP_XDEV:
00392     case OP_DEPTH:
00393         return 1;
00394     case OP_PRUNE:
00395         prune_here = 1;
00396         return 1;
00397     case OP_NOUSER:
00398         return(getpwuid(st->st_uid) == (struct passwd *) NULL);
00399     case OP_NOGROUP:
00400         return(getgrgid(st->st_gid) == (struct group *) NULL);
00401   }
00402   fatal("ILLEGAL NODE", "");
00403   return 0;                     /* Never reached */
00404 }
00405 
00406 int ichk(val, n)
00407 long val;
00408 struct node *n;
00409 {
00410   switch (n->n_info.n_int.n_sign) {
00411     case 0:
00412         return val == n->n_info.n_int.n_val;
00413     case 1:
00414         return val > n->n_info.n_int.n_val;
00415     case -1:    return val < n->n_info.n_int.n_val;
00416 }
00417   fatal("internal: bad n_sign", "");
00418   return 0;                     /* Never reached */
00419 }
00420 
00421 int lex(str)
00422 char *str;
00423 {
00424   if (str == (char *) NULL) return EOI;
00425   if (*str == '-') {
00426         register struct oper *op;
00427 
00428         str++;
00429         for (op = ops; op->op_str; op++)
00430                 if (strcmp(str, op->op_str) == 0) break;
00431         return op->op_val;
00432   }
00433   if (str[1] == 0) {
00434         switch (*str) {
00435           case '(':
00436                 return LPAR;
00437           case ')':
00438                 return RPAR;
00439           case '!':     return NOT;
00440         }
00441   }
00442   return NONE;
00443 }
00444 
00445 struct node *
00446  newnode(t)
00447 int t;
00448 {
00449   struct node *n = (struct node *) Malloc(sizeof(struct node));
00450 
00451   n->n_type = t;
00452   return n;
00453 }
00454 
00455 /*########################### PARSER ###################################*/
00456 /* Grammar:
00457  * expr        : primary | primary OR expr;
00458  * primary     : secondary | secondary AND primary | secondary primary;
00459  * secondary   : NOT secondary | LPAR expr RPAR | simple;
00460  * simple      : -OP args...
00461  */
00462 
00463 /* Isnumber checks correct number syntax. A sign is allowed, but the '+'
00464  * only if the number is to be in decimal.
00465  */
00466 int isnumber(str, base, sign)
00467 register char *str;
00468 int base;
00469 int sign;
00470 {
00471   if (sign && ((*str == '-') || ((base == 8) && (*str == '+')))) str++;
00472   while ((*str >= '0') && (*str < ('0' + base))) str++;
00473   return(*str == '\0' ? 1 : 0);
00474 }
00475 
00476 /* Convert a string to an integer, storing sign info in *ps. */
00477 void number(str, base, pl, ps)
00478 char *str;
00479 int base;
00480 long *pl;
00481 int *ps;
00482 {
00483   int up = '0' + base - 1;
00484   long val = 0;
00485 
00486   *ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
00487   while (*str >= '0' && *str <= up) val = base * val + *str++ - '0';
00488   if (*str) fatal("syntax error: illegal numeric value", "");
00489   *pl = val;
00490 }
00491 
00492 
00493 void domode(op, mode, bits)
00494 int op;
00495 int *mode;
00496 int bits;
00497 {
00498   switch (op) {
00499     case '-':
00500         *mode &= ~bits;
00501         break;                  /* clear bits */
00502     case '=':
00503         *mode |= bits;
00504         break;                  /* set bits */
00505     case '+':
00506         *mode |= (bits & ~um);  /* set, but take umask in account */
00507   }
00508 }
00509 
00510 void fmode(str, pl, ps)
00511 char *str;
00512 long *pl;
00513 int *ps;
00514 {
00515   int m = 0, w, op;
00516   char *p = str;
00517 
00518   if (*p == '-') {
00519         *ps = -1;
00520         p++;
00521   } else
00522         *ps = 0;
00523 
00524   while (*p) {
00525         w = 0;
00526         if (ISOPER(*p))
00527                 w = MUSER | MGROUP | MOTHERS;
00528         else if (!ISWHO(*p))
00529                 fatal("u, g, o, or a expected: ", p);
00530         else {
00531                 while (ISWHO(*p)) {
00532                         switch (*p) {
00533                           case 'u':
00534                                 w |= MUSER;
00535                                 break;
00536                           case 'g':
00537                                 w |= MGROUP;
00538                                 break;
00539                           case 'o':
00540                                 w |= MOTHERS;
00541                                 break;
00542                           case 'a':
00543                                 w = MUSER | MGROUP | MOTHERS;
00544                         }
00545                         p++;
00546                 }
00547                 if (!ISOPER(*p)) fatal("-, + or = expected: ", p);
00548         }
00549         op = *p++;
00550         while (ISMODE(*p)) {
00551                 switch (*p) {
00552                   case 'r':
00553                         if (w & MUSER) domode(op, &m, S_IRUSR);
00554                         if (w & MGROUP) domode(op, &m, S_IRGRP);
00555                         if (w & MOTHERS) domode(op, &m, S_IROTH);
00556                         break;
00557                   case 'w':
00558                         if (w & MUSER) domode(op, &m, S_IWUSR);
00559                         if (w & MGROUP) domode(op, &m, S_IWGRP);
00560                         if (w & MOTHERS) domode(op, &m, S_IWOTH);
00561                         break;
00562                   case 'x':
00563                         if (w & MUSER) domode(op, &m, S_IXUSR);
00564                         if (w & MGROUP) domode(op, &m, S_IXGRP);
00565                         if (w & MOTHERS) domode(op, &m, S_IXOTH);
00566                         break;
00567                   case 's':
00568                         if (w & MUSER) domode(op, &m, S_ISUID);
00569                         if (w & MGROUP) domode(op, &m, S_ISGID);
00570                         break;
00571                   case 't':
00572                         domode(op, &m, S_ISVTX);
00573                 }
00574                 p++;
00575         }
00576         if (*p) {
00577                 if (*p == ',')
00578                         p++;
00579                 else
00580                         fatal("garbage at end of mode string: ", p);
00581         }
00582   }
00583   *pl = m;
00584 }
00585 
00586 struct node *
00587  expr(t)
00588 int t;
00589 {
00590   struct node *nd, *p, *nd2;
00591 
00592   nd = primary(t);
00593   if ((t = lex(*++ipp)) == OP_OR) {
00594         nd2 = expr(lex(*++ipp));
00595         p = newnode(OP_OR);
00596         p->n_info.n_opnd.n_left = nd;
00597         p->n_info.n_opnd.n_right = nd2;
00598         return p;
00599   }
00600   ipp--;
00601   return nd;
00602 }
00603 
00604 struct node *
00605  primary(t)
00606 int t;
00607 {
00608   struct node *nd, *p, *nd2;
00609 
00610   nd = secondary(t);
00611   if ((t = lex(*++ipp)) != OP_AND) {
00612         ipp--;
00613         if (t == EOI || t == RPAR || t == OP_OR) return nd;
00614   }
00615   nd2 = primary(lex(*++ipp));
00616   p = newnode(OP_AND);
00617   p->n_info.n_opnd.n_left = nd;
00618   p->n_info.n_opnd.n_right = nd2;
00619   return p;
00620 }
00621 
00622 struct node *
00623  secondary(t)
00624 int t;
00625 {
00626   struct node *n, *p;
00627 
00628   if (t == LPAR) {
00629         n = expr(lex(*++ipp));
00630         if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
00631         return n;
00632   }
00633   if (t == NOT) {
00634         n = secondary(lex(*++ipp));
00635         p = newnode(NOT);
00636         p->n_info.n_opnd.n_left = n;
00637         return p;
00638   }
00639   return simple(t);
00640 }
00641 
00642 void checkarg(arg)
00643 char *arg;
00644 {
00645   if (arg == 0) fatal("syntax error, argument expected", "");
00646 }
00647 
00648 struct node *
00649  simple(t)
00650 int t;
00651 {
00652   struct node *p = newnode(t);
00653   struct exec *e;
00654   struct stat est;
00655   struct passwd *pw;
00656   struct group *gr;
00657   long l;
00658   int i;
00659 
00660   switch (t) {
00661     case OP_TYPE:
00662         checkarg(*++ipp);
00663         switch (**ipp) {
00664           case 'b':
00665                 p->n_info.n_int.n_val = S_IFBLK;
00666                 break;
00667           case 'c':
00668                 p->n_info.n_int.n_val = S_IFCHR;
00669                 break;
00670           case 'd':
00671                 p->n_info.n_int.n_val = S_IFDIR;
00672                 break;
00673           case 'f':
00674                 p->n_info.n_int.n_val = S_IFREG;
00675                 break;
00676           case 'p':
00677                 p->n_info.n_int.n_val = S_IFIFO;
00678                 break;
00679           case 's':
00680                 p->n_info.n_int.n_val = ~0;
00681                 break;
00682           case 'l':
00683 #ifdef S_IFLNK
00684                 p->n_info.n_int.n_val = S_IFLNK;
00685 #else
00686                 p->n_info.n_int.n_val = ~0;     /* Always unequal. */
00687 #endif
00688                 break;
00689           default:
00690                 fatal("-type needs b, c, d, f, p, s or l", "");
00691         }
00692         break;
00693     case OP_USER:
00694         checkarg(*++ipp);
00695         if (((pw = getpwnam(*ipp)) == NULL)
00696             && isnumber(*ipp, 10, 0))
00697                 number(*ipp, 10, &(p->n_info.n_int.n_val),
00698                        &(p->n_info.n_int.n_sign));
00699         else {
00700                 if (pw == NULL)
00701                         fatal("unknown user: ", *ipp);
00702                 p->n_info.n_int.n_val = pw->pw_uid;
00703                 p->n_info.n_int.n_sign = 0;
00704         }
00705         break;
00706     case OP_GROUP:
00707         checkarg(*++ipp);
00708         if (((gr = getgrnam(*ipp)) == NULL)
00709             && isnumber(*ipp, 10, 0))
00710                 number(*ipp, 10, &(p->n_info.n_int.n_val),
00711                        &(p->n_info.n_int.n_sign));
00712         else {
00713                 if (gr == NULL)
00714                         fatal("unknown group: ", *ipp);
00715                 p->n_info.n_int.n_val = gr->gr_gid;
00716                 p->n_info.n_int.n_sign = 0;
00717         }
00718         break;
00719     case OP_SIZE:
00720         checkarg(*++ipp);
00721         i = strlen(*ipp) - 1;
00722         if ((*ipp)[i] == 'c') {
00723                 p->n_type = OP_SIZEC;   /* Count in bytes i.s.o. blocks */
00724                 (*ipp)[i] = '\0';
00725         }
00726         number(*ipp, 10, &(p->n_info.n_int.n_val),
00727                &(p->n_info.n_int.n_sign));
00728         break;
00729     case OP_LINKS:
00730     case OP_INUM:
00731         checkarg(*++ipp);
00732         number(*ipp, 10, &(p->n_info.n_int.n_val),
00733                &(p->n_info.n_int.n_sign));
00734         break;
00735     case OP_PERM:
00736         checkarg(*++ipp);
00737         if (isnumber(*ipp, 8, 1)) number(*ipp, 8, &(p->n_info.n_int.n_val),
00738                        &(p->n_info.n_int.n_sign));
00739         else
00740                 fmode(*ipp, &(p->n_info.n_int.n_val),
00741                       &(p->n_info.n_int.n_sign));
00742         break;
00743     case OP_ATIME:
00744     case OP_CTIME:
00745     case OP_MTIME:
00746         checkarg(*++ipp);
00747         number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
00748         p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
00749         /* More than n days old means less than the absolute time */
00750         p->n_info.n_int.n_sign *= -1;
00751         break;
00752     case OP_EXEC:
00753     case OP_OK:
00754         checkarg(*++ipp);
00755         e = (struct exec *) Malloc(sizeof(struct exec));
00756         e->e_cnt = 2;
00757         e->e_vec[0] = SHELL;
00758         p->n_info.n_exec = e;
00759         while (*ipp) {
00760                 if (**ipp == ';' && (*ipp)[1] == '\0') {
00761                         e->e_vec[e->e_cnt] = 0;
00762                         break;
00763                 }
00764                 e->e_vec[(e->e_cnt)++] =
00765                         (**ipp == '{' && (*ipp)[1] == '}'
00766                        && (*ipp)[2] == '\0') ? (char *) (-1) : *ipp;
00767                 ipp++;
00768         }
00769         if (*ipp == 0) fatal("-exec/-ok: ; missing", "");
00770         if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
00771                 fatal("can't find program ", e->e_vec[2]);
00772         if (t == OP_OK)
00773                 if ((tty = open("/dev/tty", O_RDWR)) < 0)
00774                         fatal("can't open /dev/tty", "");
00775         break;
00776     case OP_CNEWER:
00777     case OP_NEWER:
00778         checkarg(*++ipp);
00779         if (LSTAT(*ipp, &est) == -1)
00780                 fatal("-newer: can't get status of ", *ipp);
00781         p->n_info.n_int.n_val = est.st_mtime;
00782         break;
00783     case OP_NAME:
00784         checkarg(*++ipp);
00785         p->n_info.n_str = *ipp;
00786         break;
00787     case OP_XDEV:       xdev_flag = 1;  break;
00788     case OP_DEPTH:      depth_flag = 1; break;
00789     case OP_PRUNE:
00790     case OP_PRINT:
00791     case OP_PRINT0:
00792     case OP_NOUSER:     case OP_NOGROUP:        break;
00793           default:
00794         fatal("syntax error, operator expected", "");
00795   }
00796   if ((t == OP_PRINT) || (t == OP_PRINT0) || (t == OP_EXEC) || (t == OP_OK))
00797         needprint = 0;
00798 
00799   return p;
00800 }
00801 
00802 /*######################## DIAGNOSTICS ##############################*/
00803 
00804 void nonfatal(s1, s2)
00805 char *s1, *s2;
00806 {
00807   fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
00808 }
00809 
00810 void fatal(s1, s2)
00811 char *s1, *s2;
00812 {
00813   nonfatal(s1, s2);
00814   exit(1);
00815 }
00816 
00817 /*################### SMATCH #########################*/
00818 /* Don't try to understand the following one... */
00819 int smatch(s, t)                /* shell-like matching */
00820 char *s, *t;
00821 {
00822   register n;
00823 
00824   if (*t == '\0') return *s == '\0';
00825   if (*t == '*') {
00826         ++t;
00827         do
00828                 if (smatch(s, t)) return 1;
00829         while (*s++ != '\0');
00830         return 0;
00831   }
00832   if (*s == '\0') return 0;
00833   if (*t == '\\') return (*s == *++t) ? smatch(++s, ++t) : 0;
00834   if (*t == '?') return smatch(++s, ++t);
00835   if (*t == '[') {
00836         while (*++t != ']') {
00837                 if (*t == '\\') ++t;
00838                 if (*(t + 1) != '-')
00839                         if (*t == *s) {
00840                                 while (*++t != ']')
00841                                         if (*t == '\\') ++t;
00842                                 return smatch(++s, ++t);
00843                         } else
00844                                 continue;
00845                 if (*(t + 2) == ']') return(*s == *t || *s == '-');
00846                 n = (*(t + 2) == '\\') ? 3 : 2;
00847                 if (*s >= *t && *s <= *(t + n)) {
00848                         while (*++t != ']')
00849                                 if (*t == '\\') ++t;
00850                         return smatch(++s, ++t);
00851                 }
00852                 t += n;
00853         }
00854         return 0;
00855   }
00856   return(*s == *t) ? smatch(++s, ++t) : 0;
00857 }
00858 
00859 /*####################### EXECUTE ###########################*/
00860 /* Do -exec or -ok */
00861 
00862 char *
00863  find_bin(s)
00864 char *s;
00865 {
00866   char *f, *l, buf[PATH_MAX];
00867 
00868   if (*s == '/')                /* absolute path name */
00869         return(access(s, 1) == 0) ? s : 0;
00870   l = f = epath;
00871   for (;;) {
00872         if (*l == ':' || *l == 0) {
00873                 if (l == f) {
00874                         if (access(s, 1) == 0) return Salloc(s);
00875                         f++;
00876                 } else {
00877                         register char *p = buf, *q = s;
00878 
00879                         while (f != l) *p++ = *f++;
00880                         f++;
00881                         *p++ = '/';
00882                         while (*p++ = *q++) {
00883                         }
00884                         if (access(buf, 1) == 0) return Salloc(buf);
00885                 }
00886                 if (*l == 0) break;
00887         }
00888         l++;
00889   }
00890   return 0;
00891 }
00892 
00893 int execute(op, e, path)
00894 int op;
00895 struct exec *e;
00896 char *path;
00897 {
00898   int s, pid;
00899   char *argv[MAXARG];
00900   register char **p, **q;
00901 
00902   for (p = e->e_vec, q = argv; *p;)     /* replace the {}s */
00903         if ((*q++ = *p++) == (char *) -1) q[-1] = path;
00904   *q = '\0';
00905   if (op == OP_OK) {
00906         char answer[10];
00907 
00908         for (p = &argv[2]; *p; p++) {
00909                 write(tty, *p, strlen(*p));
00910                 write(tty, " ", 1);
00911         }
00912         write(tty, "? ", 2);
00913         if (read(tty, answer, 10) < 2 || *answer != 'y') return 0;
00914   }
00915   if ((pid = fork()) == -1) fatal("can't fork", "");
00916   if (pid == 0) {
00917         register i = 3;
00918 
00919         while (close(i++) == 0) {
00920         }                       /* wow!!! */
00921         execv(argv[1], &argv[2]);       /* binary itself? */
00922         execv(argv[0], &argv[1]);       /* shell command? */
00923         fatal("exec failure: ", argv[1]);       /* none of them! */
00924         exit(127);
00925   }
00926   return wait(&s) == pid && s == 0;
00927 }

Generated on Fri Apr 14 22:57:06 2006 for minix by  doxygen 1.4.6