forget difference between big and small commands - obsolete with vm.
[minix.git] / commands / simple / find.c
blobd0072c7ed19c2fe4436bb6abae99109f6eb93684
1 /* find - look for files satisfying a predicate Author: E. Baalbergen */
3 /* Original author: Erik Baalbergen; POSIX compliant version: Bert Laverman */
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/wait.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <pwd.h>
14 #include <grp.h>
15 #include <dirent.h>
16 #include <limits.h>
17 #include <stdio.h>
19 /*######################## DEFINITIONS ##############################*/
21 #ifdef S_IFLNK
22 #define LSTAT lstat
23 #else
24 #define LSTAT stat
25 #endif
27 #define SHELL "/bin/sh"
28 #define MAXARG 256 /* maximum length for an argv for -exec */
29 #define BSIZE 512 /* POSIX wants 512 byte blocks */
30 #define SECS_PER_DAY (24L*60L*60L) /* check your planet */
32 #define OP_NAME 1 /* match name */
33 #define OP_PERM 2 /* check file permission bits */
34 #define OP_TYPE 3 /* check file type bits */
35 #define OP_LINKS 4 /* check link count */
36 #define OP_USER 5 /* check owner */
37 #define OP_GROUP 6 /* check group ownership */
38 #define OP_SIZE 7 /* check size, blocks or bytes */
39 #define OP_SIZEC 8 /* this is a fake for -size with 'c' */
40 #define OP_INUM 9 /* compare inode number */
41 #define OP_ATIME 10 /* check last access time */
42 #define OP_CTIME 11 /* check creation time */
43 #define OP_MTIME 12 /* check last modification time */
44 #define OP_EXEC 13 /* execute command */
45 #define OP_OK 14 /* execute with confirmation */
46 #define OP_PRINT 15 /* print name */
47 #define OP_PRINT0 16 /* print name null terminated */
48 #define OP_NEWER 17 /* compare modification times */
49 #define OP_CNEWER 18 /* compare modification times */
50 #define OP_AND 19 /* logical and (short circuit) */
51 #define OP_OR 20 /* logical or (short circuit) */
52 #define OP_XDEV 21 /* do not cross file-system boundaries */
53 #define OP_DEPTH 22 /* descend directory before testing */
54 #define OP_PRUNE 23 /* don't descend into current directory */
55 #define OP_NOUSER 24 /* check validity of user id */
56 #define OP_NOGROUP 25 /* check validity of group id */
57 #define LPAR 26 /* left parenthesis */
58 #define RPAR 27 /* right parenthesis */
59 #define NOT 28 /* logical not */
61 /* Some return values: */
62 #define EOI -1 /* end of expression */
63 #define NONE 0 /* not a valid predicate */
65 /* For -perm with symbolic modes: */
66 #define ISWHO(c) ((c == 'u') || (c == 'g') || (c == 'o') || (c == 'a'))
67 #define ISOPER(c) ((c == '-') || (c == '=') || (c == '+'))
68 #define ISMODE(c) ((c == 'r') || (c == 'w') || (c == 'x') || \
69 (c == 's') || (c == 't'))
70 #define MUSER 1
71 #define MGROUP 2
72 #define MOTHERS 4
75 struct exec {
76 int e_cnt;
77 char *e_vec[MAXARG];
80 struct node {
81 int n_type; /* any OP_ or NOT */
82 union {
83 char *n_str;
84 struct {
85 long n_val;
86 int n_sign;
87 } n_int;
88 struct exec *n_exec;
89 struct {
90 struct node *n_left, *n_right;
91 } n_opnd;
92 } n_info;
95 struct oper {
96 char *op_str;
97 int op_val;
98 } ops[] = {
101 "name", OP_NAME
104 "perm", OP_PERM
107 "type", OP_TYPE
110 "links", OP_LINKS
113 "user", OP_USER
116 "group", OP_GROUP
119 "size", OP_SIZE
122 "inum", OP_INUM
125 "atime", OP_ATIME
128 "ctime", OP_CTIME
131 "mtime", OP_MTIME
134 "exec", OP_EXEC
137 "ok", OP_OK
140 "print", OP_PRINT
143 "print0", OP_PRINT0
146 "newer", OP_NEWER
149 "cnewer", OP_CNEWER
152 "a", OP_AND
155 "o", OP_OR
158 "xdev", OP_XDEV
161 "depth", OP_DEPTH
164 "prune", OP_PRUNE
167 "nouser", OP_NOUSER
170 "nogroup", OP_NOGROUP
173 0, 0
178 char **ipp; /* pointer to next argument during parsing */
179 char *prog; /* program name (== argv [0]) */
180 char *epath; /* value of PATH environment string */
181 long current_time; /* for computing age */
182 int tty; /* fd for /dev/tty when using -ok */
183 int xdev_flag = 0; /* cross device boundaries? */
184 int devnr; /* device nr of first inode */
185 int depth_flag = 0; /* descend before check? */
186 int prune_here; /* This is Baaaad! Don't ever do this again! */
187 int um; /* current umask() */
188 int needprint = 1; /* implicit -print needed? */
191 /* The prototypes: */
192 _PROTOTYPE(int main, (int argc, char **argv));
193 _PROTOTYPE(char *Malloc, (int n));
194 _PROTOTYPE(char *Salloc, (char *s));
195 _PROTOTYPE(void find, (char *path, struct node * pred, char *last));
196 _PROTOTYPE(int check, (char *path, struct stat * st, struct node * n, char *last));
197 _PROTOTYPE(int ichk, (long val, struct node * n));
198 _PROTOTYPE(int lex, (char *str));
199 _PROTOTYPE(struct node * newnode, (int t));
200 _PROTOTYPE(int isnumber, (char *str, int base, int sign));
201 _PROTOTYPE(void number, (char *str, int base, long *pl, int *ps));
202 _PROTOTYPE(void fmode, (char *str, long *pl, int *ps));
203 _PROTOTYPE(struct node * expr, (int t));
204 _PROTOTYPE(struct node * primary, (int t));
205 _PROTOTYPE(struct node * secondary, (int t));
206 _PROTOTYPE(void checkarg, (char *arg));
207 _PROTOTYPE(struct node * simple, (int t));
208 _PROTOTYPE(void nonfatal, (char *s1, char *s2));
209 _PROTOTYPE(void fatal, (char *s1, char *s2));
210 _PROTOTYPE(int smatch, (char *s, char *t));
211 _PROTOTYPE(char *find_bin, (char *s));
212 _PROTOTYPE(int execute, (int op, struct exec * e, char *path));
213 _PROTOTYPE(void domode, (int op, int *mode, int bits));
216 /* Malloc: a certified malloc */
217 char *Malloc(n)
218 int n;
220 char *m;
222 if ((m = (char *) malloc(n)) == (char *) NULL) fatal("out of memory", "");
223 return m;
226 /* Salloc: allocate space for a string */
227 char *Salloc(s)
228 char *s;
230 return strcpy(Malloc(strlen(s) + 1), s);
234 /* Main: the main body */
235 int main(argc, argv)
236 int argc;
237 char *argv[];
239 char **pathlist, *path, *last;
240 int pathcnt = 0, i;
241 struct node *pred;
243 prog = *argv++; /* set program name (for diagnostics) */
244 if ((epath = getenv("PATH")) == (char *) NULL)
245 fatal("Can't get path from environment", "");
246 (void) umask(um = umask(0)); /* non-destructive get-umask :-) */
247 time(&current_time); /* get current time */
249 pathlist= argv;
250 while (--argc > 0 && lex(*argv) == NONE) { /* find paths */
251 pathcnt++;
252 argv++;
254 if (pathcnt == 0) /* there must be at least one path */
255 fatal("Usage: path-list [predicate-list]", "");
257 ipp = argv; /* prepare for parsing */
258 if (argc != 0) { /* If there is anything to parse, */
259 pred = expr(lex(*ipp)); /* then do so */
260 if (lex(*++ipp) != EOI) /* Make sure there's nothing left */
261 fatal("syntax error: garbage at end of predicate", "");
262 } else /* No predicate list */
263 pred = (struct node *) NULL;
265 for (i = 0; i < pathcnt; i++) {
266 if (xdev_flag) xdev_flag = 2;
267 path = pathlist[i];
268 if ((last = strrchr(path, '/')) == NULL) last = path; else last++;
269 find(path, pred, last);
271 return 0;
274 void find(path, pred, last)
275 char *path, *last;
276 struct node *pred;
278 char spath[PATH_MAX];
279 register char *send = spath, *p;
280 struct stat st;
281 DIR *dp;
282 struct dirent *de;
284 if (path[1] == '\0' && *path == '/') {
285 *send++ = '/';
286 *send = '\0';
287 } else
288 while (*send++ = *path++) {
291 if (LSTAT(spath, &st) == -1)
292 nonfatal("can't get status of ", spath);
293 else {
294 switch (xdev_flag) {
295 case 0:
296 break;
297 case 1:
298 if (st.st_dev != devnr) return;
299 break;
300 case 2: /* set current device number */
301 xdev_flag = 1;
302 devnr = st.st_dev;
303 break;
306 prune_here = 0;
307 if (!depth_flag && check(spath, &st, pred, last) && needprint)
308 printf("%s\n", spath);
309 if (!prune_here && (st.st_mode & S_IFMT) == S_IFDIR) {
310 if ((dp = opendir(spath)) == NULL) {
311 nonfatal("can't read directory ", spath);
312 perror( "Error" );
313 return;
315 send[-1] = '/';
316 while ((de = readdir(dp)) != NULL) {
317 p = de->d_name;
318 if ((de->d_name[0] != '.') || ((de->d_name[1])
319 && ((de->d_name[1] != '.')
320 || (de->d_name[2])))) {
321 strcpy(send, de->d_name);
322 find(spath, pred, send);
325 closedir(dp);
327 if (depth_flag) {
328 send[-1] = '\0';
329 if (check(spath, &st, pred, last) && needprint)
330 printf("%s\n", spath);
335 int check(path, st, n, last)
336 char *path, *last;
337 register struct stat *st;
338 register struct node *n;
340 if (n == (struct node *) NULL) return 1;
341 switch (n->n_type) {
342 case OP_AND:
343 return check(path, st, n->n_info.n_opnd.n_left, last) &&
344 check(path, st, n->n_info.n_opnd.n_right, last);
345 case OP_OR:
346 return check(path, st, n->n_info.n_opnd.n_left, last) ||
347 check(path, st, n->n_info.n_opnd.n_right, last);
348 case NOT:
349 return !check(path, st, n->n_info.n_opnd.n_left, last);
350 case OP_NAME:
351 return smatch(last, n->n_info.n_str);
352 case OP_PERM:
353 if (n->n_info.n_int.n_sign < 0)
354 return(st->st_mode & (int) n->n_info.n_int.n_val) ==
355 (int) n->n_info.n_int.n_val;
356 return(st->st_mode & 07777) == (int) n->n_info.n_int.n_val;
357 case OP_NEWER:
358 return st->st_mtime > n->n_info.n_int.n_val;
359 case OP_CNEWER:
360 return st->st_ctime > n->n_info.n_int.n_val;
361 case OP_TYPE:
362 return(st->st_mode & S_IFMT) == (mode_t) n->n_info.n_int.n_val;
363 case OP_LINKS:
364 return ichk((long) (st->st_nlink), n);
365 case OP_USER:
366 return st->st_uid == n->n_info.n_int.n_val;
367 case OP_GROUP:
368 return st->st_gid == n->n_info.n_int.n_val;
369 case OP_SIZE:
370 return ichk((st->st_size == 0) ? 0L :
371 (long) ((st->st_size - 1) / BSIZE + 1), n);
372 case OP_SIZEC:
373 return ichk((long) st->st_size, n);
374 case OP_INUM:
375 return ichk((long) (st->st_ino), n);
376 case OP_ATIME:
377 return ichk(st->st_atime, n);
378 case OP_CTIME:
379 return ichk(st->st_ctime, n);
380 case OP_MTIME:
381 return ichk(st->st_mtime, n);
382 case OP_EXEC:
383 case OP_OK:
384 return execute(n->n_type, n->n_info.n_exec, path);
385 case OP_PRINT:
386 printf("%s\n", path);
387 return 1;
388 case OP_PRINT0:
389 printf("%s", path); putchar(0);
390 return 1;
391 case OP_XDEV:
392 case OP_DEPTH:
393 return 1;
394 case OP_PRUNE:
395 prune_here = 1;
396 return 1;
397 case OP_NOUSER:
398 return(getpwuid(st->st_uid) == (struct passwd *) NULL);
399 case OP_NOGROUP:
400 return(getgrgid(st->st_gid) == (struct group *) NULL);
402 fatal("ILLEGAL NODE", "");
403 return 0; /* Never reached */
406 int ichk(val, n)
407 long val;
408 struct node *n;
410 switch (n->n_info.n_int.n_sign) {
411 case 0:
412 return val == n->n_info.n_int.n_val;
413 case 1:
414 return val > n->n_info.n_int.n_val;
415 case -1: return val < n->n_info.n_int.n_val;
417 fatal("internal: bad n_sign", "");
418 return 0; /* Never reached */
421 int lex(str)
422 char *str;
424 if (str == (char *) NULL) return EOI;
425 if (*str == '-') {
426 register struct oper *op;
428 str++;
429 for (op = ops; op->op_str; op++)
430 if (strcmp(str, op->op_str) == 0) break;
431 return op->op_val;
433 if (str[1] == 0) {
434 switch (*str) {
435 case '(':
436 return LPAR;
437 case ')':
438 return RPAR;
439 case '!': return NOT;
442 return NONE;
445 struct node *
446 newnode(t)
447 int t;
449 struct node *n = (struct node *) Malloc(sizeof(struct node));
451 n->n_type = t;
452 return n;
455 /*########################### PARSER ###################################*/
456 /* Grammar:
457 * expr : primary | primary OR expr;
458 * primary : secondary | secondary AND primary | secondary primary;
459 * secondary : NOT secondary | LPAR expr RPAR | simple;
460 * simple : -OP args...
463 /* Isnumber checks correct number syntax. A sign is allowed, but the '+'
464 * only if the number is to be in decimal.
466 int isnumber(str, base, sign)
467 register char *str;
468 int base;
469 int sign;
471 if (sign && ((*str == '-') || ((base == 8) && (*str == '+')))) str++;
472 while ((*str >= '0') && (*str < ('0' + base))) str++;
473 return(*str == '\0' ? 1 : 0);
476 /* Convert a string to an integer, storing sign info in *ps. */
477 void number(str, base, pl, ps)
478 char *str;
479 int base;
480 long *pl;
481 int *ps;
483 int up = '0' + base - 1;
484 long val = 0;
486 *ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
487 while (*str >= '0' && *str <= up) val = base * val + *str++ - '0';
488 if (*str) fatal("syntax error: illegal numeric value", "");
489 *pl = val;
493 void domode(op, mode, bits)
494 int op;
495 int *mode;
496 int bits;
498 switch (op) {
499 case '-':
500 *mode &= ~bits;
501 break; /* clear bits */
502 case '=':
503 *mode |= bits;
504 break; /* set bits */
505 case '+':
506 *mode |= (bits & ~um); /* set, but take umask in account */
510 void fmode(str, pl, ps)
511 char *str;
512 long *pl;
513 int *ps;
515 int m = 0, w, op;
516 char *p = str;
518 if (*p == '-') {
519 *ps = -1;
520 p++;
521 } else
522 *ps = 0;
524 while (*p) {
525 w = 0;
526 if (ISOPER(*p))
527 w = MUSER | MGROUP | MOTHERS;
528 else if (!ISWHO(*p))
529 fatal("u, g, o, or a expected: ", p);
530 else {
531 while (ISWHO(*p)) {
532 switch (*p) {
533 case 'u':
534 w |= MUSER;
535 break;
536 case 'g':
537 w |= MGROUP;
538 break;
539 case 'o':
540 w |= MOTHERS;
541 break;
542 case 'a':
543 w = MUSER | MGROUP | MOTHERS;
545 p++;
547 if (!ISOPER(*p)) fatal("-, + or = expected: ", p);
549 op = *p++;
550 while (ISMODE(*p)) {
551 switch (*p) {
552 case 'r':
553 if (w & MUSER) domode(op, &m, S_IRUSR);
554 if (w & MGROUP) domode(op, &m, S_IRGRP);
555 if (w & MOTHERS) domode(op, &m, S_IROTH);
556 break;
557 case 'w':
558 if (w & MUSER) domode(op, &m, S_IWUSR);
559 if (w & MGROUP) domode(op, &m, S_IWGRP);
560 if (w & MOTHERS) domode(op, &m, S_IWOTH);
561 break;
562 case 'x':
563 if (w & MUSER) domode(op, &m, S_IXUSR);
564 if (w & MGROUP) domode(op, &m, S_IXGRP);
565 if (w & MOTHERS) domode(op, &m, S_IXOTH);
566 break;
567 case 's':
568 if (w & MUSER) domode(op, &m, S_ISUID);
569 if (w & MGROUP) domode(op, &m, S_ISGID);
570 break;
571 case 't':
572 domode(op, &m, S_ISVTX);
574 p++;
576 if (*p) {
577 if (*p == ',')
578 p++;
579 else
580 fatal("garbage at end of mode string: ", p);
583 *pl = m;
586 struct node *
587 expr(t)
588 int t;
590 struct node *nd, *p, *nd2;
592 nd = primary(t);
593 if ((t = lex(*++ipp)) == OP_OR) {
594 nd2 = expr(lex(*++ipp));
595 p = newnode(OP_OR);
596 p->n_info.n_opnd.n_left = nd;
597 p->n_info.n_opnd.n_right = nd2;
598 return p;
600 ipp--;
601 return nd;
604 struct node *
605 primary(t)
606 int t;
608 struct node *nd, *p, *nd2;
610 nd = secondary(t);
611 if ((t = lex(*++ipp)) != OP_AND) {
612 ipp--;
613 if (t == EOI || t == RPAR || t == OP_OR) return nd;
615 nd2 = primary(lex(*++ipp));
616 p = newnode(OP_AND);
617 p->n_info.n_opnd.n_left = nd;
618 p->n_info.n_opnd.n_right = nd2;
619 return p;
622 struct node *
623 secondary(t)
624 int t;
626 struct node *n, *p;
628 if (t == LPAR) {
629 n = expr(lex(*++ipp));
630 if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
631 return n;
633 if (t == NOT) {
634 n = secondary(lex(*++ipp));
635 p = newnode(NOT);
636 p->n_info.n_opnd.n_left = n;
637 return p;
639 return simple(t);
642 void checkarg(arg)
643 char *arg;
645 if (arg == 0) fatal("syntax error, argument expected", "");
648 struct node *
649 simple(t)
650 int t;
652 struct node *p = newnode(t);
653 struct exec *e;
654 struct stat est;
655 struct passwd *pw;
656 struct group *gr;
657 long l;
658 int i;
660 switch (t) {
661 case OP_TYPE:
662 checkarg(*++ipp);
663 switch (**ipp) {
664 case 'b':
665 p->n_info.n_int.n_val = S_IFBLK;
666 break;
667 case 'c':
668 p->n_info.n_int.n_val = S_IFCHR;
669 break;
670 case 'd':
671 p->n_info.n_int.n_val = S_IFDIR;
672 break;
673 case 'f':
674 p->n_info.n_int.n_val = S_IFREG;
675 break;
676 case 'p':
677 p->n_info.n_int.n_val = S_IFIFO;
678 break;
679 case 's':
680 p->n_info.n_int.n_val = ~0;
681 break;
682 case 'l':
683 #ifdef S_IFLNK
684 p->n_info.n_int.n_val = S_IFLNK;
685 #else
686 p->n_info.n_int.n_val = ~0; /* Always unequal. */
687 #endif
688 break;
689 default:
690 fatal("-type needs b, c, d, f, p, s or l", "");
692 break;
693 case OP_USER:
694 checkarg(*++ipp);
695 if (((pw = getpwnam(*ipp)) == NULL)
696 && isnumber(*ipp, 10, 0))
697 number(*ipp, 10, &(p->n_info.n_int.n_val),
698 &(p->n_info.n_int.n_sign));
699 else {
700 if (pw == NULL)
701 fatal("unknown user: ", *ipp);
702 p->n_info.n_int.n_val = pw->pw_uid;
703 p->n_info.n_int.n_sign = 0;
705 break;
706 case OP_GROUP:
707 checkarg(*++ipp);
708 if (((gr = getgrnam(*ipp)) == NULL)
709 && isnumber(*ipp, 10, 0))
710 number(*ipp, 10, &(p->n_info.n_int.n_val),
711 &(p->n_info.n_int.n_sign));
712 else {
713 if (gr == NULL)
714 fatal("unknown group: ", *ipp);
715 p->n_info.n_int.n_val = gr->gr_gid;
716 p->n_info.n_int.n_sign = 0;
718 break;
719 case OP_SIZE:
720 checkarg(*++ipp);
721 i = strlen(*ipp) - 1;
722 if ((*ipp)[i] == 'c') {
723 p->n_type = OP_SIZEC; /* Count in bytes i.s.o. blocks */
724 (*ipp)[i] = '\0';
726 number(*ipp, 10, &(p->n_info.n_int.n_val),
727 &(p->n_info.n_int.n_sign));
728 break;
729 case OP_LINKS:
730 case OP_INUM:
731 checkarg(*++ipp);
732 number(*ipp, 10, &(p->n_info.n_int.n_val),
733 &(p->n_info.n_int.n_sign));
734 break;
735 case OP_PERM:
736 checkarg(*++ipp);
737 if (isnumber(*ipp, 8, 1)) number(*ipp, 8, &(p->n_info.n_int.n_val),
738 &(p->n_info.n_int.n_sign));
739 else
740 fmode(*ipp, &(p->n_info.n_int.n_val),
741 &(p->n_info.n_int.n_sign));
742 break;
743 case OP_ATIME:
744 case OP_CTIME:
745 case OP_MTIME:
746 checkarg(*++ipp);
747 number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
748 p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
749 /* More than n days old means less than the absolute time */
750 p->n_info.n_int.n_sign *= -1;
751 break;
752 case OP_EXEC:
753 case OP_OK:
754 checkarg(*++ipp);
755 e = (struct exec *) Malloc(sizeof(struct exec));
756 e->e_cnt = 2;
757 e->e_vec[0] = SHELL;
758 p->n_info.n_exec = e;
759 while (*ipp) {
760 if (**ipp == ';' && (*ipp)[1] == '\0') {
761 e->e_vec[e->e_cnt] = 0;
762 break;
764 e->e_vec[(e->e_cnt)++] =
765 (**ipp == '{' && (*ipp)[1] == '}'
766 && (*ipp)[2] == '\0') ? (char *) (-1) : *ipp;
767 ipp++;
769 if (*ipp == 0) fatal("-exec/-ok: ; missing", "");
770 if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
771 fatal("can't find program ", e->e_vec[2]);
772 if (t == OP_OK)
773 if ((tty = open("/dev/tty", O_RDWR)) < 0)
774 fatal("can't open /dev/tty", "");
775 break;
776 case OP_CNEWER:
777 case OP_NEWER:
778 checkarg(*++ipp);
779 if (LSTAT(*ipp, &est) == -1)
780 fatal("-newer: can't get status of ", *ipp);
781 p->n_info.n_int.n_val = est.st_mtime;
782 break;
783 case OP_NAME:
784 checkarg(*++ipp);
785 p->n_info.n_str = *ipp;
786 break;
787 case OP_XDEV: xdev_flag = 1; break;
788 case OP_DEPTH: depth_flag = 1; break;
789 case OP_PRUNE:
790 case OP_PRINT:
791 case OP_PRINT0:
792 case OP_NOUSER: case OP_NOGROUP: break;
793 default:
794 fatal("syntax error, operator expected", "");
796 if ((t == OP_PRINT) || (t == OP_PRINT0) || (t == OP_EXEC) || (t == OP_OK))
797 needprint = 0;
799 return p;
802 /*######################## DIAGNOSTICS ##############################*/
804 void nonfatal(s1, s2)
805 char *s1, *s2;
807 fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
810 void fatal(s1, s2)
811 char *s1, *s2;
813 nonfatal(s1, s2);
814 exit(1);
817 /*################### SMATCH #########################*/
818 /* Don't try to understand the following one... */
819 int smatch(s, t) /* shell-like matching */
820 char *s, *t;
822 register n;
824 if (*t == '\0') return *s == '\0';
825 if (*t == '*') {
826 ++t;
828 if (smatch(s, t)) return 1;
829 while (*s++ != '\0');
830 return 0;
832 if (*s == '\0') return 0;
833 if (*t == '\\') return (*s == *++t) ? smatch(++s, ++t) : 0;
834 if (*t == '?') return smatch(++s, ++t);
835 if (*t == '[') {
836 while (*++t != ']') {
837 if (*t == '\\') ++t;
838 if (*(t + 1) != '-')
839 if (*t == *s) {
840 while (*++t != ']')
841 if (*t == '\\') ++t;
842 return smatch(++s, ++t);
843 } else
844 continue;
845 if (*(t + 2) == ']') return(*s == *t || *s == '-');
846 n = (*(t + 2) == '\\') ? 3 : 2;
847 if (*s >= *t && *s <= *(t + n)) {
848 while (*++t != ']')
849 if (*t == '\\') ++t;
850 return smatch(++s, ++t);
852 t += n;
854 return 0;
856 return(*s == *t) ? smatch(++s, ++t) : 0;
859 /*####################### EXECUTE ###########################*/
860 /* Do -exec or -ok */
862 char *
863 find_bin(s)
864 char *s;
866 char *f, *l, buf[PATH_MAX];
868 if (*s == '/') /* absolute path name */
869 return(access(s, 1) == 0) ? s : 0;
870 l = f = epath;
871 for (;;) {
872 if (*l == ':' || *l == 0) {
873 if (l == f) {
874 if (access(s, 1) == 0) return Salloc(s);
875 f++;
876 } else {
877 register char *p = buf, *q = s;
879 while (f != l) *p++ = *f++;
880 f++;
881 *p++ = '/';
882 while (*p++ = *q++) {
884 if (access(buf, 1) == 0) return Salloc(buf);
886 if (*l == 0) break;
888 l++;
890 return 0;
893 int execute(op, e, path)
894 int op;
895 struct exec *e;
896 char *path;
898 int s, pid;
899 char *argv[MAXARG];
900 register char **p, **q;
902 for (p = e->e_vec, q = argv; *p;) /* replace the {}s */
903 if ((*q++ = *p++) == (char *) -1) q[-1] = path;
904 *q = '\0';
905 if (op == OP_OK) {
906 char answer[10];
908 for (p = &argv[2]; *p; p++) {
909 write(tty, *p, strlen(*p));
910 write(tty, " ", 1);
912 write(tty, "? ", 2);
913 if (read(tty, answer, 10) < 2 || *answer != 'y') return 0;
915 if ((pid = fork()) == -1) fatal("can't fork", "");
916 if (pid == 0) {
917 register i = 3;
919 while (close(i++) == 0) {
920 } /* wow!!! */
921 execv(argv[1], &argv[2]); /* binary itself? */
922 execv(argv[0], &argv[1]); /* shell command? */
923 fatal("exec failure: ", argv[1]); /* none of them! */
924 exit(127);
926 return wait(&s) == pid && s == 0;