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 |
|
---|
75 | struct exec {
|
---|
76 | int e_cnt;
|
---|
77 | char *e_vec[MAXARG];
|
---|
78 | };
|
---|
79 |
|
---|
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;
|
---|
93 | };
|
---|
94 |
|
---|
95 | struct 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 |
|
---|
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? */
|
---|
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 */
|
---|
217 | char *Malloc(n)
|
---|
218 | int 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 */
|
---|
227 | char *Salloc(s)
|
---|
228 | char *s;
|
---|
229 | {
|
---|
230 | return strcpy(Malloc(strlen(s) + 1), s);
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 | /* Main: the main body */
|
---|
235 | int main(argc, argv)
|
---|
236 | int argc;
|
---|
237 | char *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(¤t_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 |
|
---|
274 | void find(path, pred, last)
|
---|
275 | char *path, *last;
|
---|
276 | struct 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 |
|
---|
335 | int check(path, st, n, last)
|
---|
336 | char *path, *last;
|
---|
337 | register struct stat *st;
|
---|
338 | register 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 |
|
---|
406 | int ichk(val, n)
|
---|
407 | long val;
|
---|
408 | struct 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 |
|
---|
421 | int lex(str)
|
---|
422 | char *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 |
|
---|
445 | struct node *
|
---|
446 | newnode(t)
|
---|
447 | int 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 | */
|
---|
466 | int isnumber(str, base, sign)
|
---|
467 | register char *str;
|
---|
468 | int base;
|
---|
469 | int 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. */
|
---|
477 | void number(str, base, pl, ps)
|
---|
478 | char *str;
|
---|
479 | int base;
|
---|
480 | long *pl;
|
---|
481 | int *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 |
|
---|
493 | void domode(op, mode, bits)
|
---|
494 | int op;
|
---|
495 | int *mode;
|
---|
496 | int 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 |
|
---|
510 | void fmode(str, pl, ps)
|
---|
511 | char *str;
|
---|
512 | long *pl;
|
---|
513 | int *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 |
|
---|
586 | struct node *
|
---|
587 | expr(t)
|
---|
588 | int 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 |
|
---|
604 | struct node *
|
---|
605 | primary(t)
|
---|
606 | int 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 |
|
---|
622 | struct node *
|
---|
623 | secondary(t)
|
---|
624 | int 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 |
|
---|
642 | void checkarg(arg)
|
---|
643 | char *arg;
|
---|
644 | {
|
---|
645 | if (arg == 0) fatal("syntax error, argument expected", "");
|
---|
646 | }
|
---|
647 |
|
---|
648 | struct node *
|
---|
649 | simple(t)
|
---|
650 | int 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 |
|
---|
804 | void nonfatal(s1, s2)
|
---|
805 | char *s1, *s2;
|
---|
806 | {
|
---|
807 | fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
|
---|
808 | }
|
---|
809 |
|
---|
810 | void fatal(s1, s2)
|
---|
811 | char *s1, *s2;
|
---|
812 | {
|
---|
813 | nonfatal(s1, s2);
|
---|
814 | exit(1);
|
---|
815 | }
|
---|
816 |
|
---|
817 | /*################### SMATCH #########################*/
|
---|
818 | /* Don't try to understand the following one... */
|
---|
819 | int smatch(s, t) /* shell-like matching */
|
---|
820 | char *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 |
|
---|
862 | char *
|
---|
863 | find_bin(s)
|
---|
864 | char *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 |
|
---|
893 | int execute(op, e, path)
|
---|
894 | int op;
|
---|
895 | struct exec *e;
|
---|
896 | char *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 | }
|
---|