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 | |
1292488d | 12 | static char sccsid[] = "@(#)function.c 5.5 (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) { |
f2037504 | 310 | if (statfs(entry->fts_accpath, &sb)) { |
45fc66f9 | 311 | (void)fprintf(stderr, "find: %s: %s.\n", |
f2037504 | 312 | entry->fts_accpath, strerror(errno)); |
45fc66f9 KB |
313 | exit(1); |
314 | } | |
1292488d | 315 | first = 0; |
f2037504 | 316 | val = plan->flags == MOUNT_NONE ? sb.f_flags : sb.f_type; |
45fc66f9 | 317 | } |
f2037504 KB |
318 | return(plan->flags == MOUNT_NONE ? |
319 | val & MNT_LOCAL : val == plan->flags); | |
45fc66f9 KB |
320 | } |
321 | ||
322 | PLAN * | |
323 | c_fstype(arg) | |
324 | char *arg; | |
325 | { | |
326 | register PLAN *new; | |
327 | ||
328 | ftsoptions &= ~FTS_NOSTAT; | |
329 | ||
330 | NEW(T_FSTYPE, f_fstype); | |
331 | switch(*arg) { | |
f2037504 KB |
332 | case 'l': |
333 | if (!strcmp(arg, "local")) { | |
334 | new->flags = MOUNT_NONE; | |
335 | return(new); | |
336 | } | |
337 | break; | |
45fc66f9 KB |
338 | case 'm': |
339 | if (!strcmp(arg, "mfs")) { | |
340 | new->flags = MOUNT_MFS; | |
341 | return(new); | |
342 | } | |
343 | break; | |
344 | case 'n': | |
345 | if (!strcmp(arg, "nfs")) { | |
346 | new->flags = MOUNT_NFS; | |
347 | return(new); | |
348 | } | |
349 | break; | |
350 | case 'p': | |
351 | if (!strcmp(arg, "pc")) { | |
352 | new->flags = MOUNT_PC; | |
353 | return(new); | |
354 | } | |
355 | break; | |
356 | case 'u': | |
357 | if (!strcmp(arg, "ufs")) { | |
358 | new->flags = MOUNT_UFS; | |
359 | return(new); | |
360 | } | |
361 | break; | |
362 | } | |
363 | (void)fprintf(stderr, "find: unknown file type %s.\n", arg); | |
364 | exit(1); | |
365 | /* NOTREACHED */ | |
366 | } | |
367 | ||
368 | /* | |
369 | * -group gname functions -- | |
370 | * | |
371 | * True if the file belongs to the group gname. If gname is numeric and | |
372 | * an equivalent of the getgrnam() function does not return a valid group | |
373 | * name, gname is taken as a group ID. | |
374 | */ | |
375 | f_group(plan, entry) | |
376 | PLAN *plan; | |
377 | FTSENT *entry; | |
378 | { | |
f2037504 | 379 | return(entry->fts_statb.st_gid == plan->g_data); |
45fc66f9 KB |
380 | } |
381 | ||
382 | PLAN * | |
383 | c_group(gname) | |
384 | char *gname; | |
385 | { | |
386 | PLAN *new; | |
387 | struct group *g; | |
388 | gid_t gid; | |
389 | ||
390 | ftsoptions &= ~FTS_NOSTAT; | |
391 | ||
392 | g = getgrnam(gname); | |
393 | if (g == NULL) { | |
394 | gid = atoi(gname); | |
395 | if (gid == 0 && gname[0] != '0') | |
396 | bad_arg("-group", "no such group"); | |
397 | } else | |
398 | gid = g->gr_gid; | |
399 | ||
400 | NEW(T_GROUP, f_group); | |
401 | new->g_data = gid; | |
402 | return(new); | |
403 | } | |
404 | ||
405 | /* | |
406 | * -inum n functions -- | |
407 | * | |
408 | * True if the file has inode # n. | |
409 | */ | |
410 | f_inum(plan, entry) | |
411 | PLAN *plan; | |
412 | FTSENT *entry; | |
413 | { | |
f2037504 | 414 | COMPARE(entry->fts_statb.st_ino, plan->i_data); |
45fc66f9 KB |
415 | } |
416 | ||
417 | PLAN * | |
418 | c_inum(arg) | |
419 | char *arg; | |
420 | { | |
421 | PLAN *new; | |
422 | ||
423 | ftsoptions &= ~FTS_NOSTAT; | |
424 | ||
425 | NEW(T_INUM, f_inum); | |
426 | new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL); | |
427 | return(new); | |
428 | } | |
429 | ||
430 | /* | |
431 | * -links n functions -- | |
432 | * | |
433 | * True if the file has n links. | |
434 | */ | |
435 | f_links(plan, entry) | |
436 | PLAN *plan; | |
437 | FTSENT *entry; | |
438 | { | |
f2037504 | 439 | COMPARE(entry->fts_statb.st_nlink, plan->l_data); |
45fc66f9 KB |
440 | } |
441 | ||
442 | PLAN * | |
443 | c_links(arg) | |
444 | char *arg; | |
445 | { | |
446 | PLAN *new; | |
447 | ||
448 | ftsoptions &= ~FTS_NOSTAT; | |
449 | ||
450 | NEW(T_LINKS, f_links); | |
451 | new->l_data = find_parsenum(new, "-links", arg, (char *)NULL); | |
452 | return(new); | |
453 | } | |
454 | ||
455 | /* | |
456 | * -ls functions -- | |
457 | * | |
458 | * Always true - prints the current entry to stdout in "ls" format. | |
459 | */ | |
460 | /* ARGSUSED */ | |
461 | f_ls(plan, entry) | |
462 | PLAN *plan; | |
463 | FTSENT *entry; | |
464 | { | |
f2037504 KB |
465 | printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb); |
466 | return(1); | |
45fc66f9 KB |
467 | } |
468 | ||
469 | PLAN * | |
470 | c_ls() | |
471 | { | |
472 | PLAN *new; | |
473 | ||
474 | ftsoptions &= ~FTS_NOSTAT; | |
475 | output_specified = 1; | |
476 | ||
477 | NEW(T_LS, f_ls); | |
478 | return(new); | |
479 | } | |
480 | ||
481 | /* | |
482 | * -name functions -- | |
483 | * | |
484 | * True if the basename of the filename being examined | |
485 | * matches pattern using Pattern Matching Notation S3.14 | |
486 | */ | |
487 | f_name(plan, entry) | |
488 | PLAN *plan; | |
489 | FTSENT *entry; | |
490 | { | |
f2037504 | 491 | return(fnmatch(plan->c_data, entry->fts_name, FNM_QUOTE)); |
45fc66f9 KB |
492 | } |
493 | ||
494 | PLAN * | |
495 | c_name(pattern) | |
496 | char *pattern; | |
497 | { | |
498 | PLAN *new; | |
499 | ||
500 | NEW(T_NAME, f_name); | |
501 | new->c_data = pattern; | |
502 | return(new); | |
503 | } | |
504 | ||
505 | /* | |
506 | * -newer file functions -- | |
507 | * | |
508 | * True if the current file has been modified more recently | |
509 | * then the modification time of the file named by the pathname | |
510 | * file. | |
511 | */ | |
512 | f_newer(plan, entry) | |
513 | PLAN *plan; | |
514 | FTSENT *entry; | |
515 | { | |
f2037504 | 516 | return(entry->fts_statb.st_mtime > plan->t_data); |
45fc66f9 KB |
517 | } |
518 | ||
519 | PLAN * | |
520 | c_newer(filename) | |
521 | char *filename; | |
522 | { | |
523 | PLAN *new; | |
524 | struct stat sb; | |
525 | ||
526 | ftsoptions &= ~FTS_NOSTAT; | |
527 | ||
528 | if (stat(filename, &sb)) { | |
529 | (void)fprintf(stderr, "find: %s: %s.\n", | |
530 | filename, strerror(errno)); | |
531 | exit(1); | |
532 | } | |
533 | NEW(T_NEWER, f_newer); | |
534 | new->t_data = sb.st_mtime; | |
535 | return(new); | |
536 | } | |
537 | ||
538 | /* | |
539 | * -nogroup functions -- | |
540 | * | |
541 | * True if file belongs to a user ID for which the equivalent | |
542 | * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. | |
543 | */ | |
544 | /* ARGSUSED */ | |
545 | f_nogroup(plan, entry) | |
546 | PLAN *plan; | |
547 | FTSENT *entry; | |
548 | { | |
f2037504 | 549 | return(group_from_gid(entry->fts_statb.st_gid, 1)); |
45fc66f9 KB |
550 | } |
551 | ||
552 | PLAN * | |
553 | c_nogroup() | |
554 | { | |
555 | PLAN *new; | |
556 | ||
557 | ftsoptions &= ~FTS_NOSTAT; | |
558 | ||
559 | NEW(T_NOGROUP, f_nogroup); | |
560 | return(new); | |
561 | } | |
562 | ||
563 | /* | |
564 | * -nouser functions -- | |
565 | * | |
566 | * True if file belongs to a user ID for which the equivalent | |
567 | * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. | |
568 | */ | |
569 | /* ARGSUSED */ | |
570 | f_nouser(plan, entry) | |
571 | PLAN *plan; | |
572 | FTSENT *entry; | |
573 | { | |
f2037504 | 574 | return(user_from_uid(entry->fts_statb.st_uid, 1)); |
45fc66f9 KB |
575 | } |
576 | ||
577 | PLAN * | |
578 | c_nouser() | |
579 | { | |
580 | PLAN *new; | |
581 | ||
582 | ftsoptions &= ~FTS_NOSTAT; | |
583 | ||
584 | NEW(T_NOUSER, f_nouser); | |
585 | return(new); | |
586 | } | |
587 | ||
588 | /* | |
589 | * -perm functions -- | |
590 | * | |
591 | * The mode argument is used to represent file mode bits. If it starts | |
592 | * with a leading digit, it's treated as an octal mode, otherwise as a | |
593 | * symbolic mode. | |
594 | */ | |
595 | f_perm(plan, entry) | |
596 | PLAN *plan; | |
597 | FTSENT *entry; | |
598 | { | |
599 | mode_t mode; | |
600 | ||
f2037504 | 601 | mode = entry->fts_statb.st_mode & |
45fc66f9 KB |
602 | (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO); |
603 | if (plan->flags) | |
604 | return((plan->m_data | mode) == mode); | |
605 | else | |
606 | return(mode == plan->m_data); | |
607 | /* NOTREACHED */ | |
608 | } | |
609 | ||
610 | PLAN * | |
611 | c_perm(perm) | |
612 | char *perm; | |
613 | { | |
614 | PLAN *new; | |
615 | ||
616 | ftsoptions &= ~FTS_NOSTAT; | |
617 | ||
618 | NEW(T_PERM, f_perm); | |
619 | ||
620 | if (*perm == '-') { | |
621 | new->flags = 1; | |
622 | ++perm; | |
623 | } | |
624 | ||
625 | if (setmode(perm)) | |
626 | bad_arg("-perm", "illegal mode string"); | |
627 | ||
628 | new->m_data = getmode(0); | |
629 | return(new); | |
630 | } | |
631 | ||
632 | /* | |
633 | * -print functions -- | |
634 | * | |
635 | * Always true, causes the current pathame to be written to | |
636 | * standard output. | |
637 | */ | |
638 | /* ARGSUSED */ | |
639 | f_print(plan, entry) | |
640 | PLAN *plan; | |
641 | FTSENT *entry; | |
642 | { | |
f2037504 KB |
643 | (void)printf("%s\n", entry->fts_path); |
644 | return(1); | |
45fc66f9 KB |
645 | } |
646 | ||
647 | PLAN * | |
648 | c_print() | |
649 | { | |
650 | PLAN *new; | |
651 | ||
652 | output_specified = 1; | |
653 | ||
654 | NEW(T_PRINT, f_print); | |
655 | return(new); | |
656 | } | |
657 | ||
658 | /* | |
659 | * -prune functions -- | |
660 | * | |
661 | * Prune a portion of the hierarchy. | |
662 | */ | |
663 | /* ARGSUSED */ | |
664 | f_prune(plan, entry) | |
665 | PLAN *plan; | |
666 | FTSENT *entry; | |
667 | { | |
668 | extern FTS *tree; | |
669 | ||
670 | if (ftsset(tree, entry, FTS_SKIP)) { | |
671 | (void)fprintf(stderr, | |
f2037504 | 672 | "find: %s: %s.\n", entry->fts_path, strerror(errno)); |
45fc66f9 KB |
673 | exit(1); |
674 | } | |
f2037504 | 675 | return(1); |
45fc66f9 KB |
676 | } |
677 | ||
678 | PLAN * | |
679 | c_prune() | |
680 | { | |
681 | PLAN *new; | |
682 | ||
683 | NEW(T_PRUNE, f_prune); | |
684 | return(new); | |
685 | } | |
686 | ||
687 | /* | |
688 | * -size n[c] functions -- | |
689 | * | |
690 | * True if the file size in bytes, divided by an implementation defined | |
691 | * value and rounded up to the next integer, is n. If n is followed by | |
692 | * a c, the size is in bytes. | |
693 | */ | |
694 | #define FIND_SIZE 512 | |
695 | static int divsize = 1; | |
696 | ||
697 | f_size(plan, entry) | |
698 | PLAN *plan; | |
699 | FTSENT *entry; | |
700 | { | |
701 | off_t size; | |
702 | ||
f2037504 KB |
703 | size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) / |
704 | FIND_SIZE : entry->fts_statb.st_size; | |
45fc66f9 KB |
705 | COMPARE(size, plan->o_data); |
706 | } | |
707 | ||
708 | PLAN * | |
709 | c_size(arg) | |
710 | char *arg; | |
711 | { | |
712 | PLAN *new; | |
713 | char endch; | |
714 | ||
715 | ftsoptions &= ~FTS_NOSTAT; | |
716 | ||
717 | NEW(T_SIZE, f_size); | |
718 | new->o_data = find_parsenum(new, "-size", arg, &endch); | |
719 | if (endch == 'c') | |
720 | divsize = 0; | |
721 | return(new); | |
722 | } | |
723 | ||
724 | /* | |
725 | * -type c functions -- | |
726 | * | |
727 | * True if the type of the file is c, where c is b, c, d, p, or f for | |
728 | * block special file, character special file, directory, FIFO, or | |
729 | * regular file, respectively. | |
730 | */ | |
731 | f_type(plan, entry) | |
732 | PLAN *plan; | |
733 | FTSENT *entry; | |
734 | { | |
f2037504 | 735 | return(entry->fts_statb.st_mode & plan->m_data); |
45fc66f9 KB |
736 | } |
737 | ||
738 | PLAN * | |
739 | c_type(typestring) | |
740 | char *typestring; | |
741 | { | |
742 | PLAN *new; | |
743 | mode_t mask; | |
744 | ||
745 | ftsoptions &= ~FTS_NOSTAT; | |
746 | ||
747 | switch (typestring[0]) { | |
748 | case 'b': | |
749 | mask = S_IFBLK; | |
750 | break; | |
751 | case 'c': | |
752 | mask = S_IFCHR; | |
753 | break; | |
754 | case 'd': | |
755 | mask = S_IFDIR; | |
756 | break; | |
757 | case 'f': | |
758 | mask = S_IFREG; | |
759 | break; | |
760 | case 'l': | |
761 | mask = S_IFLNK; | |
762 | break; | |
763 | case 'p': | |
764 | mask = S_IFIFO; | |
765 | break; | |
766 | case 's': | |
767 | mask = S_IFSOCK; | |
768 | break; | |
769 | default: | |
770 | bad_arg("-type", "unknown type"); | |
771 | } | |
772 | ||
773 | NEW(T_TYPE, f_type); | |
774 | new->m_data = mask; | |
775 | return(new); | |
776 | } | |
777 | ||
778 | /* | |
779 | * -user uname functions -- | |
780 | * | |
781 | * True if the file belongs to the user uname. If uname is numeric and | |
782 | * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not | |
783 | * return a valid user name, uname is taken as a user ID. | |
784 | */ | |
785 | f_user(plan, entry) | |
786 | PLAN *plan; | |
787 | FTSENT *entry; | |
788 | { | |
f2037504 | 789 | return(entry->fts_statb.st_uid == plan->u_data); |
45fc66f9 KB |
790 | } |
791 | ||
792 | PLAN * | |
793 | c_user(username) | |
794 | char *username; | |
795 | { | |
796 | PLAN *new; | |
797 | struct passwd *p; | |
798 | uid_t uid; | |
799 | ||
800 | ftsoptions &= ~FTS_NOSTAT; | |
801 | ||
802 | p = getpwnam(username); | |
803 | if (p == NULL) { | |
804 | uid = atoi(username); | |
805 | if (uid == 0 && username[0] != '0') | |
806 | bad_arg("-user", "no such user"); | |
807 | } else | |
808 | uid = p->pw_uid; | |
809 | ||
810 | NEW(T_USER, f_user); | |
811 | new->u_data = uid; | |
812 | return(new); | |
813 | } | |
814 | ||
815 | /* | |
816 | * -xdev functions -- | |
817 | * | |
818 | * Always true, causes find not to decend past directories that have a | |
819 | * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) | |
45fc66f9 KB |
820 | */ |
821 | PLAN * | |
822 | c_xdev() | |
823 | { | |
45fc66f9 KB |
824 | PLAN *new; |
825 | ||
45fc66f9 | 826 | ftsoptions &= ~FTS_NOSTAT; |
1292488d | 827 | ftsoptions |= FTS_XDEV; |
45fc66f9 KB |
828 | |
829 | NEW(T_XDEV, f_always_true); | |
830 | return(new); | |
831 | } | |
832 | ||
833 | /* | |
834 | * ( expression ) functions -- | |
835 | * | |
836 | * True if expression is true. | |
837 | */ | |
838 | f_expr(plan, entry) | |
839 | PLAN *plan; | |
840 | FTSENT *entry; | |
841 | { | |
842 | register PLAN *p; | |
843 | register int state; | |
844 | ||
845 | for (p = plan->p_data[0]; | |
846 | p && (state = (p->eval)(p, entry)); p = p->next); | |
847 | return(state); | |
848 | } | |
849 | ||
850 | /* | |
851 | * T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are | |
852 | * eliminated during phase 2 of find_formplan() --- the '(' node is converted | |
853 | * to a T_EXPR node containing the expression and the ')' node is discarded. | |
854 | */ | |
855 | PLAN * | |
856 | c_openparen() | |
857 | { | |
858 | PLAN *new; | |
859 | ||
860 | NEW(T_OPENPAREN, (int (*)())-1); | |
861 | return(new); | |
862 | } | |
863 | ||
864 | PLAN * | |
865 | c_closeparen() | |
866 | { | |
867 | PLAN *new; | |
868 | ||
869 | NEW(T_CLOSEPAREN, (int (*)())-1); | |
870 | return(new); | |
871 | } | |
872 | ||
873 | /* | |
874 | * -mtime n functions -- | |
875 | * | |
876 | * True if the difference between the file modification time and the | |
877 | * current time is n 24 hour periods. | |
878 | */ | |
879 | f_mtime(plan, entry) | |
880 | PLAN *plan; | |
881 | FTSENT *entry; | |
882 | { | |
883 | extern time_t now; | |
884 | ||
f2037504 KB |
885 | COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) / |
886 | SECSPERDAY, plan->t_data); | |
45fc66f9 KB |
887 | } |
888 | ||
889 | PLAN * | |
890 | c_mtime(arg) | |
891 | char *arg; | |
892 | { | |
893 | PLAN *new; | |
894 | ||
895 | ftsoptions &= ~FTS_NOSTAT; | |
896 | ||
897 | NEW(T_MTIME, f_mtime); | |
898 | new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL); | |
899 | return(new); | |
900 | } | |
901 | ||
902 | /* | |
903 | * ! expression functions -- | |
904 | * | |
905 | * Negation of a primary; the unary NOT operator. | |
906 | */ | |
907 | f_not(plan, entry) | |
908 | PLAN *plan; | |
909 | FTSENT *entry; | |
910 | { | |
911 | register PLAN *p; | |
912 | register int state; | |
913 | ||
914 | for (p = plan->p_data[0]; | |
915 | p && (state = (p->eval)(p, entry)); p = p->next); | |
916 | return(!state); | |
917 | } | |
918 | ||
919 | PLAN * | |
920 | c_not() | |
921 | { | |
922 | PLAN *new; | |
923 | ||
924 | NEW(T_NOT, f_not); | |
925 | return(new); | |
926 | } | |
927 | ||
928 | /* | |
929 | * expression -o expression functions -- | |
930 | * | |
931 | * Alternation of primaries; the OR operator. The second expression is | |
932 | * not evaluated if the first expression is true. | |
933 | */ | |
934 | f_or(plan, entry) | |
935 | PLAN *plan; | |
936 | FTSENT *entry; | |
937 | { | |
938 | register PLAN *p; | |
939 | register int state; | |
940 | ||
941 | for (p = plan->p_data[0]; | |
942 | p && (state = (p->eval)(p, entry)); p = p->next); | |
943 | ||
944 | if (state) | |
f2037504 | 945 | return(1); |
45fc66f9 KB |
946 | |
947 | for (p = plan->p_data[1]; | |
948 | p && (state = (p->eval)(p, entry)); p = p->next); | |
949 | return(state); | |
950 | } | |
951 | ||
952 | PLAN * | |
953 | c_or() | |
954 | { | |
955 | PLAN *new; | |
956 | ||
957 | NEW(T_OR, f_or); | |
958 | return(new); | |
959 | } |