source: trunk/minix/commands/simple/find.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 21.2 KB
RevLine 
[9]1/* find - look for files satisfying a predicate Author: E. Baalbergen */
2
3/* Original author: Erik Baalbergen; POSIX compliant version: Bert Laverman */
4
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>
18
19/*######################## DEFINITIONS ##############################*/
20
21#ifdef S_IFLNK
22#define LSTAT lstat
23#else
24#define LSTAT stat
25#endif
26
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 */
31
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 */
60
61/* Some return values: */
62#define EOI -1 /* end of expression */
63#define NONE 0 /* not a valid predicate */
64
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
73
74
75struct exec {
76 int e_cnt;
77 char *e_vec[MAXARG];
78};
79
80struct 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;
93};
94
95struct oper {
96 char *op_str;
97 int op_val;
98} ops[] = {
99
100 {
101 "name", OP_NAME
102 },
103 {
104 "perm", OP_PERM
105 },
106 {
107 "type", OP_TYPE
108 },
109 {
110 "links", OP_LINKS
111 },
112 {
113 "user", OP_USER
114 },
115 {
116 "group", OP_GROUP
117 },
118 {
119 "size", OP_SIZE
120 },
121 {
122 "inum", OP_INUM
123 },
124 {
125 "atime", OP_ATIME
126 },
127 {
128 "ctime", OP_CTIME
129 },
130 {
131 "mtime", OP_MTIME
132 },
133 {
134 "exec", OP_EXEC
135 },
136 {
137 "ok", OP_OK
138 },
139 {
140 "print", OP_PRINT
141 },
142 {
143 "print0", OP_PRINT0
144 },
145 {
146 "newer", OP_NEWER
147 },
148 {
149 "cnewer", OP_CNEWER
150 },
151 {
152 "a", OP_AND
153 },
154 {
155 "o", OP_OR
156 },
157 {
158 "xdev", OP_XDEV
159 },
160 {
161 "depth", OP_DEPTH
162 },
163 {
164 "prune", OP_PRUNE
165 },
166 {
167 "nouser", OP_NOUSER
168 },
169 {
170 "nogroup", OP_NOGROUP
171 },
172 {
173 0, 0
174 }
175};
176
177
178char **ipp; /* pointer to next argument during parsing */
179char *prog; /* program name (== argv [0]) */
180char *epath; /* value of PATH environment string */
181long current_time; /* for computing age */
182int tty; /* fd for /dev/tty when using -ok */
183int xdev_flag = 0; /* cross device boundaries? */
184int devnr; /* device nr of first inode */
185int depth_flag = 0; /* descend before check? */
186int prune_here; /* This is Baaaad! Don't ever do this again! */
187int um; /* current umask() */
188int needprint = 1; /* implicit -print needed? */
189
190
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));
214
215
216/* Malloc: a certified malloc */
217char *Malloc(n)
218int n;
219{
220 char *m;
221
222 if ((m = (char *) malloc(n)) == (char *) NULL) fatal("out of memory", "");
223 return m;
224}
225
226/* Salloc: allocate space for a string */
227char *Salloc(s)
228char *s;
229{
230 return strcpy(Malloc(strlen(s) + 1), s);
231}
232
233
234/* Main: the main body */
235int main(argc, argv)
236int argc;
237char *argv[];
238{
239 char **pathlist, *path, *last;
240 int pathcnt = 0, i;
241 struct node *pred;
242
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 */
248
249 pathlist= argv;
250 while (--argc > 0 && lex(*argv) == NONE) { /* find paths */
251 pathcnt++;
252 argv++;
253 }
254 if (pathcnt == 0) /* there must be at least one path */
255 fatal("Usage: path-list [predicate-list]", "");
256
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;
264
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);
270 }
271 return 0;
272}
273
274void find(path, pred, last)
275char *path, *last;
276struct node *pred;
277{
278 char spath[PATH_MAX];
279 register char *send = spath, *p;
280 struct stat st;
281 DIR *dp;
282 struct dirent *de;
283
284 if (path[1] == '\0' && *path == '/') {
285 *send++ = '/';
286 *send = '\0';
287 } else
288 while (*send++ = *path++) {
289 }
290
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;
304 }
305
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;
314 }
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);
323 }
324 }
325 closedir(dp);
326 }
327 if (depth_flag) {
328 send[-1] = '\0';
329 if (check(spath, &st, pred, last) && needprint)
330 printf("%s\n", spath);
331 }
332 }
333}
334
335int check(path, st, n, last)
336char *path, *last;
337register struct stat *st;
338register struct node *n;
339{
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);
401 }
402 fatal("ILLEGAL NODE", "");
403 return 0; /* Never reached */
404}
405
406int ichk(val, n)
407long val;
408struct node *n;
409{
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;
416}
417 fatal("internal: bad n_sign", "");
418 return 0; /* Never reached */
419}
420
421int lex(str)
422char *str;
423{
424 if (str == (char *) NULL) return EOI;
425 if (*str == '-') {
426 register struct oper *op;
427
428 str++;
429 for (op = ops; op->op_str; op++)
430 if (strcmp(str, op->op_str) == 0) break;
431 return op->op_val;
432 }
433 if (str[1] == 0) {
434 switch (*str) {
435 case '(':
436 return LPAR;
437 case ')':
438 return RPAR;
439 case '!': return NOT;
440 }
441 }
442 return NONE;
443}
444
445struct node *
446 newnode(t)
447int t;
448{
449 struct node *n = (struct node *) Malloc(sizeof(struct node));
450
451 n->n_type = t;
452 return n;
453}
454
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...
461 */
462
463/* Isnumber checks correct number syntax. A sign is allowed, but the '+'
464 * only if the number is to be in decimal.
465 */
466int isnumber(str, base, sign)
467register char *str;
468int base;
469int sign;
470{
471 if (sign && ((*str == '-') || ((base == 8) && (*str == '+')))) str++;
472 while ((*str >= '0') && (*str < ('0' + base))) str++;
473 return(*str == '\0' ? 1 : 0);
474}
475
476/* Convert a string to an integer, storing sign info in *ps. */
477void number(str, base, pl, ps)
478char *str;
479int base;
480long *pl;
481int *ps;
482{
483 int up = '0' + base - 1;
484 long val = 0;
485
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;
490}
491
492
493void domode(op, mode, bits)
494int op;
495int *mode;
496int bits;
497{
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 */
507 }
508}
509
510void fmode(str, pl, ps)
511char *str;
512long *pl;
513int *ps;
514{
515 int m = 0, w, op;
516 char *p = str;
517
518 if (*p == '-') {
519 *ps = -1;
520 p++;
521 } else
522 *ps = 0;
523
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;
544 }
545 p++;
546 }
547 if (!ISOPER(*p)) fatal("-, + or = expected: ", p);
548 }
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);
573 }
574 p++;
575 }
576 if (*p) {
577 if (*p == ',')
578 p++;
579 else
580 fatal("garbage at end of mode string: ", p);
581 }
582 }
583 *pl = m;
584}
585
586struct node *
587 expr(t)
588int t;
589{
590 struct node *nd, *p, *nd2;
591
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;
599 }
600 ipp--;
601 return nd;
602}
603
604struct node *
605 primary(t)
606int t;
607{
608 struct node *nd, *p, *nd2;
609
610 nd = secondary(t);
611 if ((t = lex(*++ipp)) != OP_AND) {
612 ipp--;
613 if (t == EOI || t == RPAR || t == OP_OR) return nd;
614 }
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;
620}
621
622struct node *
623 secondary(t)
624int t;
625{
626 struct node *n, *p;
627
628 if (t == LPAR) {
629 n = expr(lex(*++ipp));
630 if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
631 return n;
632 }
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;
638 }
639 return simple(t);
640}
641
642void checkarg(arg)
643char *arg;
644{
645 if (arg == 0) fatal("syntax error, argument expected", "");
646}
647
648struct node *
649 simple(t)
650int t;
651{
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;
659
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", "");
691 }
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;
704 }
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;
717 }
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';
725 }
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;
763 }
764 e->e_vec[(e->e_cnt)++] =
765 (**ipp == '{' && (*ipp)[1] == '}'
766 && (*ipp)[2] == '\0') ? (char *) (-1) : *ipp;
767 ipp++;
768 }
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", "");
795 }
796 if ((t == OP_PRINT) || (t == OP_PRINT0) || (t == OP_EXEC) || (t == OP_OK))
797 needprint = 0;
798
799 return p;
800}
801
802/*######################## DIAGNOSTICS ##############################*/
803
804void nonfatal(s1, s2)
805char *s1, *s2;
806{
807 fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
808}
809
810void fatal(s1, s2)
811char *s1, *s2;
812{
813 nonfatal(s1, s2);
814 exit(1);
815}
816
817/*################### SMATCH #########################*/
818/* Don't try to understand the following one... */
819int smatch(s, t) /* shell-like matching */
820char *s, *t;
821{
822 register n;
823
824 if (*t == '\0') return *s == '\0';
825 if (*t == '*') {
826 ++t;
827 do
828 if (smatch(s, t)) return 1;
829 while (*s++ != '\0');
830 return 0;
831 }
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);
851 }
852 t += n;
853 }
854 return 0;
855 }
856 return(*s == *t) ? smatch(++s, ++t) : 0;
857}
858
859/*####################### EXECUTE ###########################*/
860/* Do -exec or -ok */
861
862char *
863 find_bin(s)
864char *s;
865{
866 char *f, *l, buf[PATH_MAX];
867
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;
878
879 while (f != l) *p++ = *f++;
880 f++;
881 *p++ = '/';
882 while (*p++ = *q++) {
883 }
884 if (access(buf, 1) == 0) return Salloc(buf);
885 }
886 if (*l == 0) break;
887 }
888 l++;
889 }
890 return 0;
891}
892
893int execute(op, e, path)
894int op;
895struct exec *e;
896char *path;
897{
898 int s, pid;
899 char *argv[MAXARG];
900 register char **p, **q;
901
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];
907
908 for (p = &argv[2]; *p; p++) {
909 write(tty, *p, strlen(*p));
910 write(tty, " ", 1);
911 }
912 write(tty, "? ", 2);
913 if (read(tty, answer, 10) < 2 || *answer != 'y') return 0;
914 }
915 if ((pid = fork()) == -1) fatal("can't fork", "");
916 if (pid == 0) {
917 register i = 3;
918
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);
925 }
926 return wait(&s) == pid && s == 0;
927}
Note: See TracBrowser for help on using the repository browser.