Commit | Line | Data |
---|---|---|
45fc66f9 KB |
1 | /*- |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Cimarron D. Taylor of the University of California, Berkeley. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | */ | |
10 | ||
11 | #ifndef lint | |
86408357 | 12 | static char sccsid[] = "@(#)function.c 5.6 (Berkeley) %G%"; |
45fc66f9 KB |
13 | #endif /* not lint */ |
14 | ||
15 | #include <sys/types.h> | |
16 | #include <sys/stat.h> | |
17 | #include <sys/wait.h> | |
18 | #include <sys/mount.h> | |
19 | #include <grp.h> | |
20 | #include <pwd.h> | |
21 | #include <fts.h> | |
22 | #include <unistd.h> | |
23 | #include <tzfile.h> | |
24 | #include <stdio.h> | |
38dde0cd | 25 | #include <string.h> |
45fc66f9 KB |
26 | #include "find.h" |
27 | ||
28 | #define FIND_EQUAL 0 | |
29 | #define FIND_LESSTHAN 1 | |
30 | #define FIND_GREATER 2 | |
31 | ||
45fc66f9 KB |
32 | #define COMPARE(a, b) { \ |
33 | switch(plan->flags) { \ | |
34 | case FIND_EQUAL: \ | |
35 | return(a == b); \ | |
36 | case FIND_LESSTHAN: \ | |
37 | return(a < b); \ | |
38 | case FIND_GREATER: \ | |
39 | return(a > b); \ | |
40 | } \ | |
f2037504 | 41 | return(0); \ |
45fc66f9 KB |
42 | } |
43 | ||
44 | #define NEW(t, f) { \ | |
45 | new = (PLAN *)emalloc(sizeof(PLAN)); \ | |
46 | new->type = t; \ | |
47 | new->eval = f; \ | |
48 | new->flags = 0; \ | |
49 | new->next = NULL; \ | |
50 | } | |
51 | ||
52 | /* | |
53 | * find_parsenum -- | |
54 | * Parse a string of the form [+-]# and return the value. | |
55 | */ | |
56 | long | |
57 | find_parsenum(plan, option, str, endch) | |
58 | PLAN *plan; | |
59 | char *option, *str, *endch; | |
60 | { | |
61 | long value; | |
62 | char *endchar; /* pointer to character ending conversion */ | |
63 | ||
64 | /* determine comparison from leading + or - */ | |
65 | switch(*str) { | |
66 | case '+': | |
67 | ++str; | |
68 | plan->flags = FIND_GREATER; | |
69 | break; | |
70 | case '-': | |
71 | ++str; | |
72 | plan->flags = FIND_LESSTHAN; | |
73 | break; | |
74 | default: | |
75 | plan->flags = FIND_EQUAL; | |
76 | break; | |
77 | } | |
78 | ||
79 | /* | |
80 | * convert the string with strtol(). Note, if strtol() returns zero | |
81 | * and endchar points to the beginning of the string we know we have | |
82 | * a syntax error. | |
83 | */ | |
84 | value = strtol(str, &endchar, 10); | |
85 | if (!value && endchar == str || | |
86 | endchar[0] && (!endch || endchar[0] != *endch)) | |
87 | bad_arg(option, "illegal numeric value"); | |
88 | if (endch) | |
89 | *endch = endchar[0]; | |
90 | return(value); | |
91 | } | |
92 | ||
93 | /* | |
94 | * -atime n functions -- | |
95 | * | |
96 | * True if the difference between the file access time and the | |
97 | * current time is n 24 hour periods. | |
98 | * | |
99 | */ | |
100 | f_atime(plan, entry) | |
101 | PLAN *plan; | |
102 | FTSENT *entry; | |
103 | { | |
104 | extern time_t now; | |
105 | ||
f2037504 KB |
106 | COMPARE((now - entry->fts_statb.st_atime + |
107 | SECSPERDAY - 1) / SECSPERDAY, plan->t_data); | |
45fc66f9 KB |
108 | } |
109 | ||
110 | PLAN * | |
111 | c_atime(arg) | |
112 | char *arg; | |
113 | { | |
114 | PLAN *new; | |
115 | ||
116 | ftsoptions &= ~FTS_NOSTAT; | |
117 | ||
118 | NEW(T_ATIME, f_atime); | |
119 | new->t_data = find_parsenum(new, "-atime", arg, (char *)NULL); | |
120 | return(new); | |
121 | } | |
122 | /* | |
123 | * -ctime n functions -- | |
124 | * | |
125 | * True if the difference between the last change of file | |
126 | * status information and the current time is n 24 hour periods. | |
127 | */ | |
128 | f_ctime(plan, entry) | |
129 | PLAN *plan; | |
130 | FTSENT *entry; | |
131 | { | |
132 | extern time_t now; | |
133 | ||
f2037504 KB |
134 | COMPARE((now - entry->fts_statb.st_ctime + |
135 | SECSPERDAY - 1) / SECSPERDAY, plan->t_data); | |
45fc66f9 KB |
136 | } |
137 | ||
138 | PLAN * | |
139 | c_ctime(arg) | |
140 | char *arg; | |
141 | { | |
142 | PLAN *new; | |
143 | ||
144 | ftsoptions &= ~FTS_NOSTAT; | |
145 | ||
146 | NEW(T_CTIME, f_ctime); | |
147 | new->t_data = find_parsenum(new, "-ctime", arg, (char *)NULL); | |
148 | return(new); | |
149 | } | |
150 | ||
151 | /* | |
152 | * -depth functions -- | |
153 | * | |
154 | * Always true, causes descent of the directory hierarchy to be done | |
155 | * so that all entries in a directory are acted on before the directory | |
156 | * itself. | |
157 | */ | |
158 | /* ARGSUSED */ | |
159 | f_always_true(plan, entry) | |
160 | PLAN *plan; | |
161 | FTSENT *entry; | |
162 | { | |
f2037504 | 163 | return(1); |
45fc66f9 KB |
164 | } |
165 | ||
166 | PLAN * | |
167 | c_depth() | |
168 | { | |
169 | extern int depth; | |
170 | PLAN *new; | |
171 | ||
172 | depth = 1; | |
173 | ||
174 | NEW(T_DEPTH, f_always_true); | |
175 | return(new); | |
176 | } | |
177 | ||
178 | /* | |
179 | * [-exec | -ok] utility [arg ... ] ; functions -- | |
180 | * | |
181 | * True if the executed utility returns a zero value as exit status. | |
182 | * The end of the primary expression is delimited by a semicolon. If | |
183 | * "{}" occurs anywhere, it gets replaced by the current pathname. | |
184 | * The current directory for the execution of utility is the same as | |
185 | * the current directory when the find utility was started. | |
186 | * | |
187 | * The primary -ok is different in that it requests affirmation of the | |
188 | * user before executing the utility. | |
189 | */ | |
190 | f_exec(plan, entry) | |
191 | register PLAN *plan; | |
192 | FTSENT *entry; | |
193 | { | |
194 | register int cnt; | |
195 | char *find_subst(); | |
196 | union wait pstat; | |
197 | pid_t pid, waitpid(); | |
198 | ||
199 | for (cnt = 0; plan->e_argv[cnt]; ++cnt) | |
200 | if (plan->e_len[cnt]) | |
201 | find_subst(plan->e_orig[cnt], &plan->e_argv[cnt], | |
f2037504 | 202 | entry->fts_path, plan->e_len[cnt]); |
45fc66f9 KB |
203 | |
204 | if (plan->flags && !find_queryuser(plan->e_argv)) | |
f2037504 | 205 | return(0); |
45fc66f9 KB |
206 | |
207 | switch(pid = vfork()) { | |
208 | case -1: | |
209 | (void)fprintf(stderr, "find: fork: %s.\n", strerror(errno)); | |
210 | exit(1); | |
211 | /* NOTREACHED */ | |
212 | case 0: | |
213 | execvp(plan->e_argv[0], plan->e_argv); | |
214 | (void)fprintf(stderr, | |
215 | "find: %s: %s.\n", plan->e_argv[0], strerror(errno)); | |
216 | exit(1); | |
217 | /* NOTREACHED */ | |
218 | } | |
219 | pid = waitpid(pid, &pstat, 0); | |
f2037504 | 220 | return(pid != -1 && !pstat.w_status); |
45fc66f9 KB |
221 | } |
222 | ||
223 | /* | |
224 | * c_exec -- | |
225 | * build three parallel arrays, one with pointers to the strings passed | |
226 | * on the command line, one with (possibly duplicated) pointers to the | |
227 | * argv array, and one with integer values that are lengths of the | |
228 | * strings, but also flags meaning that the string has to be massaged. | |
229 | */ | |
230 | PLAN * | |
231 | c_exec(argvp, isok) | |
232 | char ***argvp; | |
233 | int isok; | |
234 | { | |
235 | PLAN *new; /* node returned */ | |
236 | register int cnt; | |
237 | register char **argv, **ap, *p; | |
238 | ||
239 | ftsoptions |= FTS_NOCHDIR; | |
240 | output_specified = 1; | |
241 | ||
242 | NEW(T_EXEC, f_exec); | |
243 | new->flags = isok; | |
244 | ||
245 | for (ap = argv = *argvp;; ++ap) { | |
246 | if (!*ap) | |
247 | bad_arg(isok ? "-ok" : "-exec", "no terminating \";\""); | |
248 | if (**ap == ';') | |
249 | break; | |
250 | } | |
251 | ||
252 | cnt = ap - *argvp + 1; | |
253 | new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *)); | |
254 | new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *)); | |
255 | new->e_len = (int *)emalloc((u_int)cnt * sizeof(u_char)); | |
256 | ||
257 | for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { | |
258 | new->e_orig[cnt] = *argv; | |
259 | for (p = *argv; *p; ++p) | |
260 | if (p[0] == '{' && p[1] == '}') { | |
261 | new->e_argv[cnt] = emalloc((u_int)1024); | |
262 | new->e_len[cnt] = 1024; | |
263 | break; | |
264 | } | |
265 | if (!*p) { | |
266 | new->e_argv[cnt] = *argv; | |
267 | new->e_len[cnt] = 0; | |
268 | } | |
269 | } | |
270 | new->e_argv[cnt] = new->e_orig[cnt] = NULL; | |
271 | ||
272 | *argvp = argv + 1; | |
273 | return(new); | |
274 | } | |
275 | ||
276 | /* | |
277 | * -follow functions -- | |
278 | * | |
279 | * Always true, causes symbolic links to be followed on a global | |
280 | * basis. | |
281 | */ | |
282 | PLAN * | |
283 | c_follow() | |
284 | { | |
285 | PLAN *new; | |
286 | ||
287 | ftsoptions &= ~FTS_PHYSICAL; | |
288 | ftsoptions |= FTS_LOGICAL; | |
289 | ||
290 | NEW(T_FOLLOW, f_always_true); | |
291 | return(new); | |
292 | } | |
293 | ||
294 | /* | |
295 | * -fstype functions -- | |
296 | * | |
297 | * True if the file is of a certain type. | |
298 | */ | |
299 | f_fstype(plan, entry) | |
300 | PLAN *plan; | |
301 | FTSENT *entry; | |
302 | { | |
1292488d KB |
303 | static dev_t curdev; /* need a guaranteed illegal dev value */ |
304 | static int first = 1; | |
45fc66f9 | 305 | struct statfs sb; |
f2037504 | 306 | static short val; |
45fc66f9 KB |
307 | |
308 | /* only check when we cross mount point */ | |
1292488d | 309 | if (first || curdev != entry->fts_statb.st_dev) { |
86408357 | 310 | curdev = entry->fts_statb.st_dev; |
f2037504 | 311 | if (statfs(entry->fts_accpath, &sb)) { |
45fc66f9 | 312 | (void)fprintf(stderr, "find: %s: %s.\n", |
f2037504 | 313 | entry->fts_accpath, strerror(errno)); |
45fc66f9 KB |
314 | exit(1); |
315 | } | |
1292488d | 316 | first = 0; |
f2037504 | 317 | val = plan->flags == MOUNT_NONE ? sb.f_flags : sb.f_type; |
45fc66f9 | 318 | } |
f2037504 KB |
319 | return(plan->flags == MOUNT_NONE ? |
320 | val & MNT_LOCAL : val == plan->flags); | |
45fc66f9 KB |
321 | } |
322 | ||
323 | PLAN * | |
324 | c_fstype(arg) | |
325 | char *arg; | |
326 | { | |
327 | register PLAN *new; | |
328 | ||
329 | ftsoptions &= ~FTS_NOSTAT; | |
330 | ||
331 | NEW(T_FSTYPE, f_fstype); | |
332 | switch(*arg) { | |
f2037504 KB |
333 | case 'l': |
334 | if (!strcmp(arg, "local")) { | |
335 | new->flags = MOUNT_NONE; | |
336 | return(new); | |
337 | } | |
338 | break; | |
45fc66f9 KB |
339 | case 'm': |
340 | if (!strcmp(arg, "mfs")) { | |
341 | new->flags = MOUNT_MFS; | |
342 | return(new); | |
343 | } | |
344 | break; | |
345 | case 'n': | |
346 | if (!strcmp(arg, "nfs")) { | |
347 | new->flags = MOUNT_NFS; | |
348 | return(new); | |
349 | } | |
350 | break; | |
351 | case 'p': | |
352 | if (!strcmp(arg, "pc")) { | |
353 | new->flags = MOUNT_PC; | |
354 | return(new); | |
355 | } | |
356 | break; | |
357 | case 'u': | |
358 | if (!strcmp(arg, "ufs")) { | |
359 | new->flags = MOUNT_UFS; | |
360 | return(new); | |
361 | } | |
362 | break; | |
363 | } | |
364 | (void)fprintf(stderr, "find: unknown file type %s.\n", arg); | |
365 | exit(1); | |
366 | /* NOTREACHED */ | |
367 | } | |
368 | ||
369 | /* | |
370 | * -group gname functions -- | |
371 | * | |
372 | * True if the file belongs to the group gname. If gname is numeric and | |
373 | * an equivalent of the getgrnam() function does not return a valid group | |
374 | * name, gname is taken as a group ID. | |
375 | */ | |
376 | f_group(plan, entry) | |
377 | PLAN *plan; | |
378 | FTSENT *entry; | |
379 | { | |
f2037504 | 380 | return(entry->fts_statb.st_gid == plan->g_data); |
45fc66f9 KB |
381 | } |
382 | ||
383 | PLAN * | |
384 | c_group(gname) | |
385 | char *gname; | |
386 | { | |
387 | PLAN *new; | |
388 | struct group *g; | |
389 | gid_t gid; | |
390 | ||
391 | ftsoptions &= ~FTS_NOSTAT; | |
392 | ||
393 | g = getgrnam(gname); | |
394 | if (g == NULL) { | |
395 | gid = atoi(gname); | |
396 | if (gid == 0 && gname[0] != '0') | |
397 | bad_arg("-group", "no such group"); | |
398 | } else | |
399 | gid = g->gr_gid; | |
400 | ||
401 | NEW(T_GROUP, f_group); | |
402 | new->g_data = gid; | |
403 | return(new); | |
404 | } | |
405 | ||
406 | /* | |
407 | * -inum n functions -- | |
408 | * | |
409 | * True if the file has inode # n. | |
410 | */ | |
411 | f_inum(plan, entry) | |
412 | PLAN *plan; | |
413 | FTSENT *entry; | |
414 | { | |
f2037504 | 415 | COMPARE(entry->fts_statb.st_ino, plan->i_data); |
45fc66f9 KB |
416 | } |
417 | ||
418 | PLAN * | |
419 | c_inum(arg) | |
420 | char *arg; | |
421 | { | |
422 | PLAN *new; | |
423 | ||
424 | ftsoptions &= ~FTS_NOSTAT; | |
425 | ||
426 | NEW(T_INUM, f_inum); | |
427 | new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL); | |
428 | return(new); | |
429 | } | |
430 | ||
431 | /* | |
432 | * -links n functions -- | |
433 | * | |
434 | * True if the file has n links. | |
435 | */ | |
436 | f_links(plan, entry) | |
437 | PLAN *plan; | |
438 | FTSENT *entry; | |
439 | { | |
f2037504 | 440 | COMPARE(entry->fts_statb.st_nlink, plan->l_data); |
45fc66f9 KB |
441 | } |
442 | ||
443 | PLAN * | |
444 | c_links(arg) | |
445 | char *arg; | |
446 | { | |
447 | PLAN *new; | |
448 | ||
449 | ftsoptions &= ~FTS_NOSTAT; | |
450 | ||
451 | NEW(T_LINKS, f_links); | |
452 | new->l_data = find_parsenum(new, "-links", arg, (char *)NULL); | |
453 | return(new); | |
454 | } | |
455 | ||
456 | /* | |
457 | * -ls functions -- | |
458 | * | |
459 | * Always true - prints the current entry to stdout in "ls" format. | |
460 | */ | |
461 | /* ARGSUSED */ | |
462 | f_ls(plan, entry) | |
463 | PLAN *plan; | |
464 | FTSENT *entry; | |
465 | { | |
f2037504 KB |
466 | printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb); |
467 | return(1); | |
45fc66f9 KB |
468 | } |
469 | ||
470 | PLAN * | |
471 | c_ls() | |
472 | { | |
473 | PLAN *new; | |
474 | ||
475 | ftsoptions &= ~FTS_NOSTAT; | |
476 | output_specified = 1; | |
477 | ||
478 | NEW(T_LS, f_ls); | |
479 | return(new); | |
480 | } | |
481 | ||
482 | /* | |
483 | * -name functions -- | |
484 | * | |
485 | * True if the basename of the filename being examined | |
486 | * matches pattern using Pattern Matching Notation S3.14 | |
487 | */ | |
488 | f_name(plan, entry) | |
489 | PLAN *plan; | |
490 | FTSENT *entry; | |
491 | { | |
f2037504 | 492 | return(fnmatch(plan->c_data, entry->fts_name, FNM_QUOTE)); |
45fc66f9 KB |
493 | } |
494 | ||
495 | PLAN * | |
496 | c_name(pattern) | |
497 | char *pattern; | |
498 | { | |
499 | PLAN *new; | |
500 | ||
501 | NEW(T_NAME, f_name); | |
502 | new->c_data = pattern; | |
503 | return(new); | |
504 | } | |
505 | ||
506 | /* | |
507 | * -newer file functions -- | |
508 | * | |
509 | * True if the current file has been modified more recently | |
510 | * then the modification time of the file named by the pathname | |
511 | * file. | |
512 | */ | |
513 | f_newer(plan, entry) | |
514 | PLAN *plan; | |
515 | FTSENT *entry; | |
516 | { | |
f2037504 | 517 | return(entry->fts_statb.st_mtime > plan->t_data); |
45fc66f9 KB |
518 | } |
519 | ||
520 | PLAN * | |
521 | c_newer(filename) | |
522 | char *filename; | |
523 | { | |
524 | PLAN *new; | |
525 | struct stat sb; | |
526 | ||
527 | ftsoptions &= ~FTS_NOSTAT; | |
528 | ||
529 | if (stat(filename, &sb)) { | |
530 | (void)fprintf(stderr, "find: %s: %s.\n", | |
531 | filename, strerror(errno)); | |
532 | exit(1); | |
533 | } | |
534 | NEW(T_NEWER, f_newer); | |
535 | new->t_data = sb.st_mtime; | |
536 | return(new); | |
537 | } | |
538 | ||
539 | /* | |
540 | * -nogroup functions -- | |
541 | * | |
542 | * True if file belongs to a user ID for which the equivalent | |
543 | * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. | |
544 | */ | |
545 | /* ARGSUSED */ | |
546 | f_nogroup(plan, entry) | |
547 | PLAN *plan; | |
548 | FTSENT *entry; | |
549 | { | |
f2037504 | 550 | return(group_from_gid(entry->fts_statb.st_gid, 1)); |
45fc66f9 KB |
551 | } |
552 | ||
553 | PLAN * | |
554 | c_nogroup() | |
555 | { | |
556 | PLAN *new; | |
557 | ||
558 | ftsoptions &= ~FTS_NOSTAT; | |
559 | ||
560 | NEW(T_NOGROUP, f_nogroup); | |
561 | return(new); | |
562 | } | |
563 | ||
564 | /* | |
565 | * -nouser functions -- | |
566 | * | |
567 | * True if file belongs to a user ID for which the equivalent | |
568 | * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. | |
569 | */ | |
570 | /* ARGSUSED */ | |
571 | f_nouser(plan, entry) | |
572 | PLAN *plan; | |
573 | FTSENT *entry; | |
574 | { | |
f2037504 | 575 | return(user_from_uid(entry->fts_statb.st_uid, 1)); |
45fc66f9 KB |
576 | } |
577 | ||
578 | PLAN * | |
579 | c_nouser() | |
580 | { | |
581 | PLAN *new; | |
582 | ||
583 | ftsoptions &= ~FTS_NOSTAT; | |
584 | ||
585 | NEW(T_NOUSER, f_nouser); | |
586 | return(new); | |
587 | } | |
588 | ||
589 | /* | |
590 | * -perm functions -- | |
591 | * | |
592 | * The mode argument is used to represent file mode bits. If it starts | |
593 | * with a leading digit, it's treated as an octal mode, otherwise as a | |
594 | * symbolic mode. | |
595 | */ | |
596 | f_perm(plan, entry) | |
597 | PLAN *plan; | |
598 | FTSENT *entry; | |
599 | { | |
600 | mode_t mode; | |
601 | ||
f2037504 | 602 | mode = entry->fts_statb.st_mode & |
45fc66f9 KB |
603 | (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO); |
604 | if (plan->flags) | |
605 | return((plan->m_data | mode) == mode); | |
606 | else | |
607 | return(mode == plan->m_data); | |
608 | /* NOTREACHED */ | |
609 | } | |
610 | ||
611 | PLAN * | |
612 | c_perm(perm) | |
613 | char *perm; | |
614 | { | |
615 | PLAN *new; | |
616 | ||
617 | ftsoptions &= ~FTS_NOSTAT; | |
618 | ||
619 | NEW(T_PERM, f_perm); | |
620 | ||
621 | if (*perm == '-') { | |
622 | new->flags = 1; | |
623 | ++perm; | |
624 | } | |
625 | ||
626 | if (setmode(perm)) | |
627 | bad_arg("-perm", "illegal mode string"); | |
628 | ||
629 | new->m_data = getmode(0); | |
630 | return(new); | |
631 | } | |
632 | ||
633 | /* | |
634 | * -print functions -- | |
635 | * | |
636 | * Always true, causes the current pathame to be written to | |
637 | * standard output. | |
638 | */ | |
639 | /* ARGSUSED */ | |
640 | f_print(plan, entry) | |
641 | PLAN *plan; | |
642 | FTSENT *entry; | |
643 | { | |
f2037504 KB |
644 | (void)printf("%s\n", entry->fts_path); |
645 | return(1); | |
45fc66f9 KB |
646 | } |
647 | ||
648 | PLAN * | |
649 | c_print() | |
650 | { | |
651 | PLAN *new; | |
652 | ||
653 | output_specified = 1; | |
654 | ||
655 | NEW(T_PRINT, f_print); | |
656 | return(new); | |
657 | } | |
658 | ||
659 | /* | |
660 | * -prune functions -- | |
661 | * | |
662 | * Prune a portion of the hierarchy. | |
663 | */ | |
664 | /* ARGSUSED */ | |
665 | f_prune(plan, entry) | |
666 | PLAN *plan; | |
667 | FTSENT *entry; | |
668 | { | |
669 | extern FTS *tree; | |
670 | ||
671 | if (ftsset(tree, entry, FTS_SKIP)) { | |
672 | (void)fprintf(stderr, | |
f2037504 | 673 | "find: %s: %s.\n", entry->fts_path, strerror(errno)); |
45fc66f9 KB |
674 | exit(1); |
675 | } | |
f2037504 | 676 | return(1); |
45fc66f9 KB |
677 | } |
678 | ||
679 | PLAN * | |
680 | c_prune() | |
681 | { | |
682 | PLAN *new; | |
683 | ||
684 | NEW(T_PRUNE, f_prune); | |
685 | return(new); | |
686 | } | |
687 | ||
688 | /* | |
689 | * -size n[c] functions -- | |
690 | * | |
691 | * True if the file size in bytes, divided by an implementation defined | |
692 | * value and rounded up to the next integer, is n. If n is followed by | |
693 | * a c, the size is in bytes. | |
694 | */ | |
695 | #define FIND_SIZE 512 | |
696 | static int divsize = 1; | |
697 | ||
698 | f_size(plan, entry) | |
699 | PLAN *plan; | |
700 | FTSENT *entry; | |
701 | { | |
702 | off_t size; | |
703 | ||
f2037504 KB |
704 | size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) / |
705 | FIND_SIZE : entry->fts_statb.st_size; | |
45fc66f9 KB |
706 | COMPARE(size, plan->o_data); |
707 | } | |
708 | ||
709 | PLAN * | |
710 | c_size(arg) | |
711 | char *arg; | |
712 | { | |
713 | PLAN *new; | |
714 | char endch; | |
715 | ||
716 | ftsoptions &= ~FTS_NOSTAT; | |
717 | ||
718 | NEW(T_SIZE, f_size); | |
719 | new->o_data = find_parsenum(new, "-size", arg, &endch); | |
720 | if (endch == 'c') | |
721 | divsize = 0; | |
722 | return(new); | |
723 | } | |
724 | ||
725 | /* | |
726 | * -type c functions -- | |
727 | * | |
728 | * True if the type of the file is c, where c is b, c, d, p, or f for | |
729 | * block special file, character special file, directory, FIFO, or | |
730 | * regular file, respectively. | |
731 | */ | |
732 | f_type(plan, entry) | |
733 | PLAN *plan; | |
734 | FTSENT *entry; | |
735 | { | |
f2037504 | 736 | return(entry->fts_statb.st_mode & plan->m_data); |
45fc66f9 KB |
737 | } |
738 | ||
739 | PLAN * | |
740 | c_type(typestring) | |
741 | char *typestring; | |
742 | { | |
743 | PLAN *new; | |
744 | mode_t mask; | |
745 | ||
746 | ftsoptions &= ~FTS_NOSTAT; | |
747 | ||
748 | switch (typestring[0]) { | |
749 | case 'b': | |
750 | mask = S_IFBLK; | |
751 | break; | |
752 | case 'c': | |
753 | mask = S_IFCHR; | |
754 | break; | |
755 | case 'd': | |
756 | mask = S_IFDIR; | |
757 | break; | |
758 | case 'f': | |
759 | mask = S_IFREG; | |
760 | break; | |
761 | case 'l': | |
762 | mask = S_IFLNK; | |
763 | break; | |
764 | case 'p': | |
765 | mask = S_IFIFO; | |
766 | break; | |
767 | case 's': | |
768 | mask = S_IFSOCK; | |
769 | break; | |
770 | default: | |
771 | bad_arg("-type", "unknown type"); | |
772 | } | |
773 | ||
774 | NEW(T_TYPE, f_type); | |
775 | new->m_data = mask; | |
776 | return(new); | |
777 | } | |
778 | ||
779 | /* | |
780 | * -user uname functions -- | |
781 | * | |
782 | * True if the file belongs to the user uname. If uname is numeric and | |
783 | * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not | |
784 | * return a valid user name, uname is taken as a user ID. | |
785 | */ | |
786 | f_user(plan, entry) | |
787 | PLAN *plan; | |
788 | FTSENT *entry; | |
789 | { | |
f2037504 | 790 | return(entry->fts_statb.st_uid == plan->u_data); |
45fc66f9 KB |
791 | } |
792 | ||
793 | PLAN * | |
794 | c_user(username) | |
795 | char *username; | |
796 | { | |
797 | PLAN *new; | |
798 | struct passwd *p; | |
799 | uid_t uid; | |
800 | ||
801 | ftsoptions &= ~FTS_NOSTAT; | |
802 | ||
803 | p = getpwnam(username); | |
804 | if (p == NULL) { | |
805 | uid = atoi(username); | |
806 | if (uid == 0 && username[0] != '0') | |
807 | bad_arg("-user", "no such user"); | |
808 | } else | |
809 | uid = p->pw_uid; | |
810 | ||
811 | NEW(T_USER, f_user); | |
812 | new->u_data = uid; | |
813 | return(new); | |
814 | } | |
815 | ||
816 | /* | |
817 | * -xdev functions -- | |
818 | * | |
819 | * Always true, causes find not to decend past directories that have a | |
820 | * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) | |
45fc66f9 KB |
821 | */ |
822 | PLAN * | |
823 | c_xdev() | |
824 | { | |
45fc66f9 KB |
825 | PLAN *new; |
826 | ||
45fc66f9 | 827 | ftsoptions &= ~FTS_NOSTAT; |
1292488d | 828 | ftsoptions |= FTS_XDEV; |
45fc66f9 KB |
829 | |
830 | NEW(T_XDEV, f_always_true); | |
831 | return(new); | |
832 | } | |
833 | ||
834 | /* | |
835 | * ( expression ) functions -- | |
836 | * | |
837 | * True if expression is true. | |
838 | */ | |
839 | f_expr(plan, entry) | |
840 | PLAN *plan; | |
841 | FTSENT *entry; | |
842 | { | |
843 | register PLAN *p; | |
844 | register int state; | |
845 | ||
846 | for (p = plan->p_data[0]; | |
847 | p && (state = (p->eval)(p, entry)); p = p->next); | |
848 | return(state); | |
849 | } | |
850 | ||
851 | /* | |
852 | * T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are | |
853 | * eliminated during phase 2 of find_formplan() --- the '(' node is converted | |
854 | * to a T_EXPR node containing the expression and the ')' node is discarded. | |
855 | */ | |
856 | PLAN * | |
857 | c_openparen() | |
858 | { | |
859 | PLAN *new; | |
860 | ||
861 | NEW(T_OPENPAREN, (int (*)())-1); | |
862 | return(new); | |
863 | } | |
864 | ||
865 | PLAN * | |
866 | c_closeparen() | |
867 | { | |
868 | PLAN *new; | |
869 | ||
870 | NEW(T_CLOSEPAREN, (int (*)())-1); | |
871 | return(new); | |
872 | } | |
873 | ||
874 | /* | |
875 | * -mtime n functions -- | |
876 | * | |
877 | * True if the difference between the file modification time and the | |
878 | * current time is n 24 hour periods. | |
879 | */ | |
880 | f_mtime(plan, entry) | |
881 | PLAN *plan; | |
882 | FTSENT *entry; | |
883 | { | |
884 | extern time_t now; | |
885 | ||
f2037504 KB |
886 | COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) / |
887 | SECSPERDAY, plan->t_data); | |
45fc66f9 KB |
888 | } |
889 | ||
890 | PLAN * | |
891 | c_mtime(arg) | |
892 | char *arg; | |
893 | { | |
894 | PLAN *new; | |
895 | ||
896 | ftsoptions &= ~FTS_NOSTAT; | |
897 | ||
898 | NEW(T_MTIME, f_mtime); | |
899 | new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL); | |
900 | return(new); | |
901 | } | |
902 | ||
903 | /* | |
904 | * ! expression functions -- | |
905 | * | |
906 | * Negation of a primary; the unary NOT operator. | |
907 | */ | |
908 | f_not(plan, entry) | |
909 | PLAN *plan; | |
910 | FTSENT *entry; | |
911 | { | |
912 | register PLAN *p; | |
913 | register int state; | |
914 | ||
915 | for (p = plan->p_data[0]; | |
916 | p && (state = (p->eval)(p, entry)); p = p->next); | |
917 | return(!state); | |
918 | } | |
919 | ||
920 | PLAN * | |
921 | c_not() | |
922 | { | |
923 | PLAN *new; | |
924 | ||
925 | NEW(T_NOT, f_not); | |
926 | return(new); | |
927 | } | |
928 | ||
929 | /* | |
930 | * expression -o expression functions -- | |
931 | * | |
932 | * Alternation of primaries; the OR operator. The second expression is | |
933 | * not evaluated if the first expression is true. | |
934 | */ | |
935 | f_or(plan, entry) | |
936 | PLAN *plan; | |
937 | FTSENT *entry; | |
938 | { | |
939 | register PLAN *p; | |
940 | register int state; | |
941 | ||
942 | for (p = plan->p_data[0]; | |
943 | p && (state = (p->eval)(p, entry)); p = p->next); | |
944 | ||
945 | if (state) | |
f2037504 | 946 | return(1); |
45fc66f9 KB |
947 | |
948 | for (p = plan->p_data[1]; | |
949 | p && (state = (p->eval)(p, entry)); p = p->next); | |
950 | return(state); | |
951 | } | |
952 | ||
953 | PLAN * | |
954 | c_or() | |
955 | { | |
956 | PLAN *new; | |
957 | ||
958 | NEW(T_OR, f_or); | |
959 | return(new); | |
960 | } |