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 | |
b51b784d | 12 | static char sccsid[] = "@(#)function.c 5.8 (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; | |
b51b784d | 616 | mode_t *set, *setmode(); |
45fc66f9 KB |
617 | |
618 | ftsoptions &= ~FTS_NOSTAT; | |
619 | ||
620 | NEW(T_PERM, f_perm); | |
621 | ||
622 | if (*perm == '-') { | |
623 | new->flags = 1; | |
624 | ++perm; | |
625 | } | |
626 | ||
948b36af | 627 | if ((set = setmode(perm)) == NULL) |
45fc66f9 KB |
628 | bad_arg("-perm", "illegal mode string"); |
629 | ||
948b36af | 630 | new->m_data = getmode(set, 0); |
45fc66f9 KB |
631 | return(new); |
632 | } | |
633 | ||
634 | /* | |
635 | * -print functions -- | |
636 | * | |
637 | * Always true, causes the current pathame to be written to | |
638 | * standard output. | |
639 | */ | |
640 | /* ARGSUSED */ | |
641 | f_print(plan, entry) | |
642 | PLAN *plan; | |
643 | FTSENT *entry; | |
644 | { | |
f2037504 KB |
645 | (void)printf("%s\n", entry->fts_path); |
646 | return(1); | |
45fc66f9 KB |
647 | } |
648 | ||
649 | PLAN * | |
650 | c_print() | |
651 | { | |
652 | PLAN *new; | |
653 | ||
654 | output_specified = 1; | |
655 | ||
656 | NEW(T_PRINT, f_print); | |
657 | return(new); | |
658 | } | |
659 | ||
660 | /* | |
661 | * -prune functions -- | |
662 | * | |
663 | * Prune a portion of the hierarchy. | |
664 | */ | |
665 | /* ARGSUSED */ | |
666 | f_prune(plan, entry) | |
667 | PLAN *plan; | |
668 | FTSENT *entry; | |
669 | { | |
670 | extern FTS *tree; | |
671 | ||
672 | if (ftsset(tree, entry, FTS_SKIP)) { | |
673 | (void)fprintf(stderr, | |
f2037504 | 674 | "find: %s: %s.\n", entry->fts_path, strerror(errno)); |
45fc66f9 KB |
675 | exit(1); |
676 | } | |
f2037504 | 677 | return(1); |
45fc66f9 KB |
678 | } |
679 | ||
680 | PLAN * | |
681 | c_prune() | |
682 | { | |
683 | PLAN *new; | |
684 | ||
685 | NEW(T_PRUNE, f_prune); | |
686 | return(new); | |
687 | } | |
688 | ||
689 | /* | |
690 | * -size n[c] functions -- | |
691 | * | |
692 | * True if the file size in bytes, divided by an implementation defined | |
693 | * value and rounded up to the next integer, is n. If n is followed by | |
694 | * a c, the size is in bytes. | |
695 | */ | |
696 | #define FIND_SIZE 512 | |
697 | static int divsize = 1; | |
698 | ||
699 | f_size(plan, entry) | |
700 | PLAN *plan; | |
701 | FTSENT *entry; | |
702 | { | |
703 | off_t size; | |
704 | ||
f2037504 KB |
705 | size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) / |
706 | FIND_SIZE : entry->fts_statb.st_size; | |
45fc66f9 KB |
707 | COMPARE(size, plan->o_data); |
708 | } | |
709 | ||
710 | PLAN * | |
711 | c_size(arg) | |
712 | char *arg; | |
713 | { | |
714 | PLAN *new; | |
715 | char endch; | |
716 | ||
717 | ftsoptions &= ~FTS_NOSTAT; | |
718 | ||
719 | NEW(T_SIZE, f_size); | |
720 | new->o_data = find_parsenum(new, "-size", arg, &endch); | |
721 | if (endch == 'c') | |
722 | divsize = 0; | |
723 | return(new); | |
724 | } | |
725 | ||
726 | /* | |
727 | * -type c functions -- | |
728 | * | |
729 | * True if the type of the file is c, where c is b, c, d, p, or f for | |
730 | * block special file, character special file, directory, FIFO, or | |
731 | * regular file, respectively. | |
732 | */ | |
733 | f_type(plan, entry) | |
734 | PLAN *plan; | |
735 | FTSENT *entry; | |
736 | { | |
948b36af | 737 | return((entry->fts_statb.st_mode & S_IFMT) == plan->m_data); |
45fc66f9 KB |
738 | } |
739 | ||
740 | PLAN * | |
741 | c_type(typestring) | |
742 | char *typestring; | |
743 | { | |
744 | PLAN *new; | |
745 | mode_t mask; | |
746 | ||
747 | ftsoptions &= ~FTS_NOSTAT; | |
748 | ||
749 | switch (typestring[0]) { | |
750 | case 'b': | |
751 | mask = S_IFBLK; | |
752 | break; | |
753 | case 'c': | |
754 | mask = S_IFCHR; | |
755 | break; | |
756 | case 'd': | |
757 | mask = S_IFDIR; | |
758 | break; | |
759 | case 'f': | |
760 | mask = S_IFREG; | |
761 | break; | |
762 | case 'l': | |
763 | mask = S_IFLNK; | |
764 | break; | |
765 | case 'p': | |
766 | mask = S_IFIFO; | |
767 | break; | |
768 | case 's': | |
769 | mask = S_IFSOCK; | |
770 | break; | |
771 | default: | |
772 | bad_arg("-type", "unknown type"); | |
773 | } | |
774 | ||
775 | NEW(T_TYPE, f_type); | |
776 | new->m_data = mask; | |
777 | return(new); | |
778 | } | |
779 | ||
780 | /* | |
781 | * -user uname functions -- | |
782 | * | |
783 | * True if the file belongs to the user uname. If uname is numeric and | |
784 | * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not | |
785 | * return a valid user name, uname is taken as a user ID. | |
786 | */ | |
787 | f_user(plan, entry) | |
788 | PLAN *plan; | |
789 | FTSENT *entry; | |
790 | { | |
f2037504 | 791 | return(entry->fts_statb.st_uid == plan->u_data); |
45fc66f9 KB |
792 | } |
793 | ||
794 | PLAN * | |
795 | c_user(username) | |
796 | char *username; | |
797 | { | |
798 | PLAN *new; | |
799 | struct passwd *p; | |
800 | uid_t uid; | |
801 | ||
802 | ftsoptions &= ~FTS_NOSTAT; | |
803 | ||
804 | p = getpwnam(username); | |
805 | if (p == NULL) { | |
806 | uid = atoi(username); | |
807 | if (uid == 0 && username[0] != '0') | |
808 | bad_arg("-user", "no such user"); | |
809 | } else | |
810 | uid = p->pw_uid; | |
811 | ||
812 | NEW(T_USER, f_user); | |
813 | new->u_data = uid; | |
814 | return(new); | |
815 | } | |
816 | ||
817 | /* | |
818 | * -xdev functions -- | |
819 | * | |
820 | * Always true, causes find not to decend past directories that have a | |
821 | * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) | |
45fc66f9 KB |
822 | */ |
823 | PLAN * | |
824 | c_xdev() | |
825 | { | |
45fc66f9 KB |
826 | PLAN *new; |
827 | ||
45fc66f9 | 828 | ftsoptions &= ~FTS_NOSTAT; |
1292488d | 829 | ftsoptions |= FTS_XDEV; |
45fc66f9 KB |
830 | |
831 | NEW(T_XDEV, f_always_true); | |
832 | return(new); | |
833 | } | |
834 | ||
835 | /* | |
836 | * ( expression ) functions -- | |
837 | * | |
838 | * True if expression is true. | |
839 | */ | |
840 | f_expr(plan, entry) | |
841 | PLAN *plan; | |
842 | FTSENT *entry; | |
843 | { | |
844 | register PLAN *p; | |
845 | register int state; | |
846 | ||
847 | for (p = plan->p_data[0]; | |
848 | p && (state = (p->eval)(p, entry)); p = p->next); | |
849 | return(state); | |
850 | } | |
851 | ||
852 | /* | |
853 | * T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are | |
854 | * eliminated during phase 2 of find_formplan() --- the '(' node is converted | |
855 | * to a T_EXPR node containing the expression and the ')' node is discarded. | |
856 | */ | |
857 | PLAN * | |
858 | c_openparen() | |
859 | { | |
860 | PLAN *new; | |
861 | ||
862 | NEW(T_OPENPAREN, (int (*)())-1); | |
863 | return(new); | |
864 | } | |
865 | ||
866 | PLAN * | |
867 | c_closeparen() | |
868 | { | |
869 | PLAN *new; | |
870 | ||
871 | NEW(T_CLOSEPAREN, (int (*)())-1); | |
872 | return(new); | |
873 | } | |
874 | ||
875 | /* | |
876 | * -mtime n functions -- | |
877 | * | |
878 | * True if the difference between the file modification time and the | |
879 | * current time is n 24 hour periods. | |
880 | */ | |
881 | f_mtime(plan, entry) | |
882 | PLAN *plan; | |
883 | FTSENT *entry; | |
884 | { | |
885 | extern time_t now; | |
886 | ||
f2037504 KB |
887 | COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) / |
888 | SECSPERDAY, plan->t_data); | |
45fc66f9 KB |
889 | } |
890 | ||
891 | PLAN * | |
892 | c_mtime(arg) | |
893 | char *arg; | |
894 | { | |
895 | PLAN *new; | |
896 | ||
897 | ftsoptions &= ~FTS_NOSTAT; | |
898 | ||
899 | NEW(T_MTIME, f_mtime); | |
900 | new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL); | |
901 | return(new); | |
902 | } | |
903 | ||
904 | /* | |
905 | * ! expression functions -- | |
906 | * | |
907 | * Negation of a primary; the unary NOT operator. | |
908 | */ | |
909 | f_not(plan, entry) | |
910 | PLAN *plan; | |
911 | FTSENT *entry; | |
912 | { | |
913 | register PLAN *p; | |
914 | register int state; | |
915 | ||
916 | for (p = plan->p_data[0]; | |
917 | p && (state = (p->eval)(p, entry)); p = p->next); | |
918 | return(!state); | |
919 | } | |
920 | ||
921 | PLAN * | |
922 | c_not() | |
923 | { | |
924 | PLAN *new; | |
925 | ||
926 | NEW(T_NOT, f_not); | |
927 | return(new); | |
928 | } | |
929 | ||
930 | /* | |
931 | * expression -o expression functions -- | |
932 | * | |
933 | * Alternation of primaries; the OR operator. The second expression is | |
934 | * not evaluated if the first expression is true. | |
935 | */ | |
936 | f_or(plan, entry) | |
937 | PLAN *plan; | |
938 | FTSENT *entry; | |
939 | { | |
940 | register PLAN *p; | |
941 | register int state; | |
942 | ||
943 | for (p = plan->p_data[0]; | |
944 | p && (state = (p->eval)(p, entry)); p = p->next); | |
945 | ||
946 | if (state) | |
f2037504 | 947 | return(1); |
45fc66f9 KB |
948 | |
949 | for (p = plan->p_data[1]; | |
950 | p && (state = (p->eval)(p, entry)); p = p->next); | |
951 | return(state); | |
952 | } | |
953 | ||
954 | PLAN * | |
955 | c_or() | |
956 | { | |
957 | PLAN *new; | |
958 | ||
959 | NEW(T_OR, f_or); | |
960 | return(new); | |
961 | } |