1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990-2022 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /* config.h always comes first. */
19 #include <config.h>
20
21 /* system headers. */
22 #include <assert.h>
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <grp.h>
28 #include <math.h>
29 #include <pwd.h>
30 #include <selinux/selinux.h>
31 #include <stdarg.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <unistd.h> /* for unlinkat() */
36
37 /* gnulib headers. */
38 #include "areadlink.h"
39 #include "dirname.h"
40 #include "error.h"
41 #include "fcntl--.h"
42 #include "fnmatch.h"
43 #include "stat-size.h"
44 #include "stat-time.h"
45 #include "yesno.h"
46
47 /* find headers. */
48 #include "defs.h"
49 #include "die.h"
50 #include "dircallback.h"
51 #include "listfile.h"
52 #include "printquoted.h"
53 #include "system.h"
54
55
56
57 #ifdef CLOSEDIR_VOID
58 /* Fake a return value. */
59 # define CLOSEDIR(d) (closedir (d), 0)
60 #else
61 # define CLOSEDIR(d) closedir (d)
62 #endif
63
64 static bool match_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, bool ignore_case);
65
66 /* Returns ts1 - ts2 */
67 static double ts_difference (struct timespec ts1,
68 struct timespec ts2)
69 {
70 double d = difftime (ts1.tv_sec, ts2.tv_sec)
71 + (1.0e-9 * (ts1.tv_nsec - ts2.tv_nsec));
72 return d;
73 }
74
75
76 static int
77 compare_ts (struct timespec ts1,
78 struct timespec ts2)
79 {
80 if ((ts1.tv_sec == ts2.tv_sec) &&
81 (ts1.tv_nsec == ts2.tv_nsec))
82 {
83 return 0;
84 }
85 else
86 {
87 double diff = ts_difference (ts1, ts2);
88 return diff < 0.0 ? -1 : +1;
89 }
90 }
91
92 /* Predicate processing routines.
93
94 PATHNAME is the full pathname of the file being checked.
95 *STAT_BUF contains information about PATHNAME.
96 *PRED_PTR contains information for applying the predicate.
97
98 Return true if the file passes this predicate, false if not. */
99
100
101 /* pred_timewindow
102 *
103 * Returns true if THE_TIME is
104 * COMP_GT: after the specified time
105 * COMP_LT: before the specified time
106 * COMP_EQ: after the specified time but by not more than WINDOW seconds.
107 */
108 static bool
109 pred_timewindow (struct timespec ts, struct predicate const *pred_ptr, int window)
110 {
111 switch (pred_ptr->args.reftime.kind)
112 {
113 case COMP_GT:
114 return compare_ts (ts, pred_ptr->args.reftime.ts) > 0;
115
116 case COMP_LT:
117 return compare_ts (ts, pred_ptr->args.reftime.ts) < 0;
118
119 case COMP_EQ:
120 {
121 /* consider "find . -mtime 0".
122 *
123 * Here, the origin is exactly 86400 seconds before the start
124 * of the program (since -daystart was not specified). This
125 * function will be called with window=86400 and
126 * pred_ptr->args.reftime.ts as the origin. Hence a file
127 * created the instant the program starts will show a time
128 * difference (value of delta) of 86400. Similarly, a file
129 * created exactly 24h ago would be the newest file which was
130 * _not_ created today. So, if delta is 0.0, the file
131 * was not created today. If the delta is 86400, the file
132 * was created this instant.
133 */
134 double delta = ts_difference (ts, pred_ptr->args.reftime.ts);
135 return (delta > 0.0 && delta <= window);
136 }
137 }
138 assert (0);
139 abort ();
140 }
141
142
143 bool
144 pred_amin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
145 {
146 (void) &pathname;
147 return pred_timewindow (get_stat_atime(stat_buf), pred_ptr, 60);
148 }
149
150 bool
151 pred_and (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
152 {
153 if (pred_ptr->pred_left == NULL
154 || apply_predicate (pathname, stat_buf, pred_ptr->pred_left))
155 {
156 return apply_predicate (pathname, stat_buf, pred_ptr->pred_right);
157 }
158 else
159 return false;
160 }
161
162 bool
163 pred_anewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
164 {
165 (void) &pathname;
166 assert (COMP_GT == pred_ptr->args.reftime.kind);
167 return compare_ts (get_stat_atime(stat_buf), pred_ptr->args.reftime.ts) > 0;
168 }
169
170 bool
171 pred_atime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
172 {
173 (void) &pathname;
174 return pred_timewindow (get_stat_atime(stat_buf), pred_ptr, DAYSECS);
175 }
176
177 bool
178 pred_closeparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
179 {
180 (void) &pathname;
181 (void) &stat_buf;
182 (void) &pred_ptr;
183
184 return true;
185 }
186
187 bool
188 pred_cmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
189 {
190 (void) pathname;
191 return pred_timewindow (get_stat_ctime(stat_buf), pred_ptr, 60);
192 }
193
194 bool
195 pred_cnewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
196 {
197 (void) pathname;
198
199 assert (COMP_GT == pred_ptr->args.reftime.kind);
200 return compare_ts (get_stat_ctime(stat_buf), pred_ptr->args.reftime.ts) > 0;
201 }
202
203 bool
204 pred_comma (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
205 {
206 if (pred_ptr->pred_left != NULL)
207 {
208 apply_predicate (pathname, stat_buf,pred_ptr->pred_left);
209 }
210 return apply_predicate (pathname, stat_buf, pred_ptr->pred_right);
211 }
212
213 bool
214 pred_ctime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
215 {
216 (void) &pathname;
217 return pred_timewindow (get_stat_ctime(stat_buf), pred_ptr, DAYSECS);
218 }
219
220 static bool
221 perform_delete (int flags)
222 {
223 return 0 == unlinkat (state.cwd_dir_fd, state.rel_pathname, flags);
224 }
225
226
227 bool
228 pred_delete (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
229 {
230 (void) pred_ptr;
231 (void) stat_buf;
232 if (strcmp (state.rel_pathname, "."))
233 {
234 int flags=0;
235 if (state.have_stat && S_ISDIR(stat_buf->st_mode))
236 flags |= AT_REMOVEDIR;
237 if (perform_delete (flags))
238 {
239 return true;
240 }
241 else
242 {
243 if (ENOENT == errno && options.ignore_readdir_race)
244 {
245 /* Ignore unlink() error for vanished files. */
246 errno = 0;
247 return true;
248 }
249 if (EISDIR == errno)
250 {
251 if ((flags & AT_REMOVEDIR) == 0)
252 {
253 /* unlink() operation failed because we should have done rmdir(). */
254 flags |= AT_REMOVEDIR;
255 if (perform_delete (flags))
256 return true;
257 }
258 }
259 }
260 error (0, errno, _("cannot delete %s"),
261 safely_quote_err_filename (0, pathname));
262 /* Previously I had believed that having the -delete action
263 * return false provided the user with control over whether an
264 * error message is issued. While this is true, the policy of
265 * not affecting the exit status is contrary to the POSIX
266 * requirement that diagnostic messages are accompanied by a
267 * nonzero exit status. While -delete is not a POSIX option and
268 * we can therefore opt not to follow POSIX in this case, that
269 * seems somewhat arbitrary and confusing. So, as of
270 * findutils-4.3.11, we also set the exit status in this case.
271 */
272 state.exit_status = EXIT_FAILURE;
273 return false;
274 }
275 else
276 {
277 /* nothing to do. */
278 return true;
279 }
280 }
281
282 bool
283 pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
284 {
285 (void) pathname;
286 (void) pred_ptr;
287
288 if (S_ISDIR (stat_buf->st_mode))
289 {
290 int fd;
291 DIR *d;
292 struct dirent *dp;
293 bool empty = true;
294
295 errno = 0;
296 if ((fd = openat (state.cwd_dir_fd, state.rel_pathname, O_RDONLY
297 #if defined O_LARGEFILE
298 | O_LARGEFILE
299 #endif
300 | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK)) < 0)
301 {
302 error (0, errno, "%s", safely_quote_err_filename (0, pathname));
303 state.exit_status = EXIT_FAILURE;
304 return false;
305 }
306 d = fdopendir (fd);
307 if (d == NULL)
308 {
309 error (0, errno, "%s", safely_quote_err_filename (0, pathname));
310 state.exit_status = EXIT_FAILURE;
311 close (fd);
312 return false;
313 }
314 /* errno is not touched in the loop body, so initializing it here
315 * once before the loop is enough to detect readdir(3) errors. */
316 errno = 0;
317 for (dp = readdir (d); dp; dp = readdir (d))
318 {
319 if (dp->d_name[0] != '.'
320 || (dp->d_name[1] != '\0'
321 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
322 {
323 empty = false;
324 break;
325 }
326 }
327 if (errno)
328 {
329 /* Handle errors from readdir(3). */
330 error (0, errno, "%s", safely_quote_err_filename (0, pathname));
331 state.exit_status = EXIT_FAILURE;
332 CLOSEDIR (d);
333 return false;
334 }
335 if (CLOSEDIR (d))
336 {
337 error (0, errno, "%s", safely_quote_err_filename (0, pathname));
338 state.exit_status = EXIT_FAILURE;
339 return false;
340 }
341 return (empty);
342 }
343 else if (S_ISREG (stat_buf->st_mode))
344 return (stat_buf->st_size == 0);
345 else
346 return (false);
347 }
348
349
350 bool
351 pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
352 {
353 return impl_pred_exec (pathname, stat_buf, pred_ptr);
354 }
355
356 bool
357 pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
358 {
359 (void) &pathname;
360 return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
361 }
362
363 bool
364 pred_false (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
365 {
366 (void) &pathname;
367 (void) &stat_buf;
368 (void) &pred_ptr;
369
370
371 return (false);
372 }
373
374 bool
375 pred_fls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
376 {
377 FILE * stream = pred_ptr->args.printf_vec.stream;
378 list_file (pathname, state.cwd_dir_fd, state.rel_pathname, stat_buf,
379 options.start_time.tv_sec,
380 options.output_block_size,
381 pred_ptr->literal_control_chars, stream);
382 return true;
383 }
384
385 bool
386 pred_fprint (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
387 {
388 (void) &pathname;
389 (void) &stat_buf;
390
391 print_quoted (pred_ptr->args.printf_vec.stream,
392 pred_ptr->args.printf_vec.quote_opts,
393 pred_ptr->args.printf_vec.dest_is_tty,
394 "%s\n",
395 pathname);
396 return true;
397 }
398
399 bool
400 pred_fprint0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
401 {
402 FILE * fp = pred_ptr->args.printf_vec.stream;
403
404 (void) &stat_buf;
405
406 fputs (pathname, fp);
407 putc (0, fp);
408 return true;
409 }
410
411
412
413 bool
414 pred_fstype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
415 {
416 (void) pathname;
417
418 if (strcmp (filesystem_type (stat_buf, pathname), pred_ptr->args.str) == 0)
419 return true;
420 else
421 return false;
422 }
423
424 bool
425 pred_gid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
426 {
427 (void) pathname;
428
429 switch (pred_ptr->args.numinfo.kind)
430 {
431 case COMP_GT:
432 if (stat_buf->st_gid > pred_ptr->args.numinfo.l_val)
433 return (true);
434 break;
435 case COMP_LT:
436 if (stat_buf->st_gid < pred_ptr->args.numinfo.l_val)
437 return (true);
438 break;
439 case COMP_EQ:
440 if (stat_buf->st_gid == pred_ptr->args.numinfo.l_val)
441 return (true);
442 break;
443 }
444 return (false);
445 }
446
447 bool
448 pred_group (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
449 {
450 (void) pathname;
451
452 if (pred_ptr->args.gid == stat_buf->st_gid)
453 return (true);
454 else
455 return (false);
456 }
457
458 bool
459 pred_ilname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
460 {
461 return match_lname (pathname, stat_buf, pred_ptr, true);
462 }
463
464 /* Common code between -name, -iname. PATHNAME is being visited, STR
465 is name to compare basename against, and FLAGS are passed to
466 fnmatch. Recall that 'find / -name /' is one of the few times where a '/'
467 in the -name must actually find something. */
468 static bool
469 pred_name_common (const char *pathname, const char *str, int flags)
470 {
471 bool b;
472 /* We used to use last_component() here, but that would not allow us to modify the
473 * input string, which is const. We could optimise by duplicating the string only
474 * if we need to modify it, and I'll do that if there is a measurable
475 * performance difference on a machine built after 1990...
476 */
477 char *base = base_name (pathname);
478 /* remove trailing slashes, but leave "/" or "//foo" unchanged. */
479 strip_trailing_slashes (base);
480
481 /* FNM_PERIOD is not used here because POSIX requires that it not be.
482 * See https://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
483 */
484 b = fnmatch (str, base, flags) == 0;
485 free (base);
486 return b;
487 }
488
489 bool
490 pred_iname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
491 {
492 (void) stat_buf;
493 return pred_name_common (pathname, pred_ptr->args.str, FNM_CASEFOLD);
494 }
495
496 bool
497 pred_inum (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
498 {
499 (void) pathname;
500
501 switch (pred_ptr->args.numinfo.kind)
502 {
503 case COMP_GT:
504 if (stat_buf->st_ino > pred_ptr->args.numinfo.l_val)
505 return (true);
506 break;
507 case COMP_LT:
508 if (stat_buf->st_ino < pred_ptr->args.numinfo.l_val)
509 return (true);
510 break;
511 case COMP_EQ:
512 if (stat_buf->st_ino == pred_ptr->args.numinfo.l_val)
513 return (true);
514 break;
515 }
516 return (false);
517 }
518
519 bool
520 pred_ipath (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
521 {
522 (void) stat_buf;
523
524 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
525 return (true);
526 return (false);
527 }
528
529 bool
530 pred_links (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
531 {
532 (void) pathname;
533
534 switch (pred_ptr->args.numinfo.kind)
535 {
536 case COMP_GT:
537 if (stat_buf->st_nlink > pred_ptr->args.numinfo.l_val)
538 return (true);
539 break;
540 case COMP_LT:
541 if (stat_buf->st_nlink < pred_ptr->args.numinfo.l_val)
542 return (true);
543 break;
544 case COMP_EQ:
545 if (stat_buf->st_nlink == pred_ptr->args.numinfo.l_val)
546 return (true);
547 break;
548 }
549 return (false);
550 }
551
552 bool
553 pred_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
554 {
555 return match_lname (pathname, stat_buf, pred_ptr, false);
556 }
557
558 static bool
559 match_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, bool ignore_case)
560 {
561 bool ret = false;
562 #ifdef S_ISLNK
563 if (S_ISLNK (stat_buf->st_mode))
564 {
565 char *linkname = areadlinkat (state.cwd_dir_fd, state.rel_pathname);
566 if (linkname)
567 {
568 if (fnmatch (pred_ptr->args.str, linkname,
569 ignore_case ? FNM_CASEFOLD : 0) == 0)
570 ret = true;
571 }
572 else
573 {
574 nonfatal_target_file_error (errno, pathname);
575 state.exit_status = EXIT_FAILURE;
576 }
577 free (linkname);
578 }
579 #endif /* S_ISLNK */
580 return ret;
581 }
582
583 bool
584 pred_ls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
585 {
586 return pred_fls (pathname, stat_buf, pred_ptr);
587 }
588
589 bool
590 pred_mmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
591 {
592 (void) &pathname;
593 return pred_timewindow (get_stat_mtime(stat_buf), pred_ptr, 60);
594 }
595
596 bool
597 pred_mtime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
598 {
599 (void) pathname;
600 return pred_timewindow (get_stat_mtime(stat_buf), pred_ptr, DAYSECS);
601 }
602
603 bool
604 pred_name (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
605 {
606 (void) stat_buf;
607 return pred_name_common (pathname, pred_ptr->args.str, 0);
608 }
609
610 bool
611 pred_negate (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
612 {
613 return !apply_predicate (pathname, stat_buf, pred_ptr->pred_right);
614 }
615
616 bool
617 pred_newer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
618 {
619 (void) pathname;
620
621 assert (COMP_GT == pred_ptr->args.reftime.kind);
622 return compare_ts (get_stat_mtime(stat_buf), pred_ptr->args.reftime.ts) > 0;
623 }
624
625 bool
626 pred_newerXY (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
627 {
628 struct timespec ts;
629 bool collected = false;
630
631 assert (COMP_GT == pred_ptr->args.reftime.kind);
632
633 switch (pred_ptr->args.reftime.xval)
634 {
635 case XVAL_TIME:
636 assert (pred_ptr->args.reftime.xval != XVAL_TIME);
637 return false;
638
639 case XVAL_ATIME:
640 ts = get_stat_atime (stat_buf);
641 collected = true;
642 break;
643
644 case XVAL_BIRTHTIME:
645 ts = get_stat_birthtime (stat_buf);
646 collected = true;
647 if (ts.tv_nsec < 0)
648 {
649 /* XXX: Cannot determine birth time. Warn once. */
650 error (0, 0, _("WARNING: cannot determine birth time of file %s"),
651 safely_quote_err_filename (0, pathname));
652 return false;
653 }
654 break;
655
656 case XVAL_CTIME:
657 ts = get_stat_ctime (stat_buf);
658 collected = true;
659 break;
660
661 case XVAL_MTIME:
662 ts = get_stat_mtime (stat_buf);
663 collected = true;
664 break;
665 }
666
667 assert (collected);
668 return compare_ts (ts, pred_ptr->args.reftime.ts) > 0;
669 }
670
671 bool
672 pred_nogroup (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
673 {
674 (void) pathname;
675 (void) pred_ptr;
676 return getgrgid (stat_buf->st_gid) == NULL;
677 }
678
679 bool
680 pred_nouser (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
681 {
682 (void) pathname;
683 (void) pred_ptr;
684 return getpwuid (stat_buf->st_uid) == NULL;
685 }
686
687
688 static bool
689 is_ok (const char *program, const char *arg)
690 {
691 fflush (stdout);
692 /* The draft open standard requires that, in the POSIX locale,
693 the last non-blank character of this prompt be '?'.
694 The exact format is not specified.
695 This standard does not have requirements for locales other than POSIX
696 */
697 /* XXX: printing UNTRUSTED data here. */
698 if (fprintf (stderr, _("< %s ... %s > ? "), program, arg) < 0)
699 {
700 die (EXIT_FAILURE, errno, _("Failed to write prompt for -ok"));
701 }
702 fflush (stderr);
703 return yesno ();
704 }
705
706 bool
707 pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
708 {
709 if (is_ok (pred_ptr->args.exec_vec.replace_vec[0], pathname))
710 return impl_pred_exec (pathname, stat_buf, pred_ptr);
711 else
712 return false;
713 }
714
715 bool
716 pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
717 {
718 if (is_ok (pred_ptr->args.exec_vec.replace_vec[0], pathname))
719 return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
720 else
721 return false;
722 }
723
724 bool
725 pred_openparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
726 {
727 (void) pathname;
728 (void) stat_buf;
729 (void) pred_ptr;
730 return true;
731 }
732
733 bool
734 pred_or (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
735 {
736 if (pred_ptr->pred_left == NULL
737 || !apply_predicate (pathname, stat_buf, pred_ptr->pred_left))
738 {
739 return apply_predicate (pathname, stat_buf, pred_ptr->pred_right);
740 }
741 else
742 return true;
743 }
744
745 bool
746 pred_path (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
747 {
748 (void) stat_buf;
749 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
750 return (true);
751 return (false);
752 }
753
754 bool
755 pred_perm (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
756 {
757 mode_t mode = stat_buf->st_mode;
758 mode_t perm_val = pred_ptr->args.perm.val[S_ISDIR (mode) != 0];
759 (void) pathname;
760 switch (pred_ptr->args.perm.kind)
761 {
762 case PERM_AT_LEAST:
763 return (mode & perm_val) == perm_val;
764 break;
765
766 case PERM_ANY:
767 /* True if any of the bits set in the mask are also set in the file's mode.
768 *
769 *
770 * Otherwise, if onum is prefixed by a hyphen, the primary shall
771 * evaluate as true if at least all of the bits specified in
772 * onum that are also set in the octal mask 07777 are set.
773 *
774 * Eric Blake's interpretation is that the mode argument is zero,
775
776 */
777 if (0 == perm_val)
778 return true; /* Savannah bug 14748; we used to return false */
779 else
780 return (mode & perm_val) != 0;
781 break;
782
783 case PERM_EXACT:
784 return (mode & MODE_ALL) == perm_val;
785 break;
786
787 default:
788 abort ();
789 break;
790 }
791 }
792
793
794 bool
795 pred_executable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
796 {
797 (void) pathname;
798 (void) stat_buf;
799 (void) pred_ptr;
800
801 /* As for access, the check is performed with the real user id. */
802 return 0 == faccessat (state.cwd_dir_fd, state.rel_pathname, X_OK, 0);
803 }
804
805 bool
806 pred_readable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
807 {
808 (void) pathname;
809 (void) stat_buf;
810 (void) pred_ptr;
811
812 /* As for access, the check is performed with the real user id. */
813 return 0 == faccessat (state.cwd_dir_fd, state.rel_pathname, R_OK, 0);
814 }
815
816 bool
817 pred_writable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
818 {
819 (void) pathname;
820 (void) stat_buf;
821 (void) pred_ptr;
822
823 /* As for access, the check is performed with the real user id. */
824 return 0 == faccessat (state.cwd_dir_fd, state.rel_pathname, W_OK, 0);
825 }
826
827 bool
828 pred_print (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
829 {
830 (void) stat_buf;
831 (void) pred_ptr;
832
833 print_quoted (pred_ptr->args.printf_vec.stream,
834 pred_ptr->args.printf_vec.quote_opts,
835 pred_ptr->args.printf_vec.dest_is_tty,
836 "%s\n", pathname);
837 return true;
838 }
839
840 bool
841 pred_print0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
842 {
843 return pred_fprint0(pathname, stat_buf, pred_ptr);
844 }
845
846 bool
847 pred_prune (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
848 {
849 (void) pathname;
850 (void) pred_ptr;
851
852 if (options.do_dir_first == true) { /* no effect with -depth */
853 assert (state.have_stat);
854 if (stat_buf != NULL &&
855 S_ISDIR(stat_buf->st_mode))
856 state.stop_at_current_level = true;
857 }
858
859 /* findutils used to return options.do_dir_first here, so that -prune
860 * returns true only if -depth is not in effect. But POSIX requires
861 * that -prune always evaluate as true.
862 */
863 return true;
864 }
865
866 bool
867 pred_quit (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
868 {
869 (void) pathname;
870 (void) stat_buf;
871 (void) pred_ptr;
872
873 /* Run any cleanups. This includes executing any command lines
874 * we have partly built but not executed.
875 */
876 cleanup ();
877
878 /* Since -exec and friends don't leave child processes running in the
879 * background, there is no need to wait for them here.
880 */
881 exit (state.exit_status); /* 0 for success, etc. */
882 }
883
884 bool
885 pred_regex (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
886 {
887 int len = strlen (pathname);
888 (void) stat_buf;
889 if (re_match (pred_ptr->args.regex, pathname, len, 0,
890 (struct re_registers *) NULL) == len)
891 return (true);
892 return (false);
893 }
894
895 bool
896 pred_size (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
897 {
898 uintmax_t f_val;
899
900 (void) pathname;
901 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
902 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
903 switch (pred_ptr->args.size.kind)
904 {
905 case COMP_GT:
906 if (f_val > pred_ptr->args.size.size)
907 return (true);
908 break;
909 case COMP_LT:
910 if (f_val < pred_ptr->args.size.size)
911 return (true);
912 break;
913 case COMP_EQ:
914 if (f_val == pred_ptr->args.size.size)
915 return (true);
916 break;
917 }
918 return (false);
919 }
920
921 bool
922 pred_samefile (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
923 {
924 /* Potential optimisation: because of the loop protection, we always
925 * know the device of the current directory, hence the device number
926 * of the file we're currently considering. If -L is not in effect,
927 * and the device number of the file we're looking for is not the
928 * same as the device number of the current directory, this
929 * predicate cannot return true. Hence there would be no need to
930 * stat the file we're looking at.
931 *
932 * For the moment, we simply compare inode numbers, which should cut
933 * down greatly on the number of calls to stat. Some of the
934 * remainder will be unnecessary, but the additional complexity
935 * probably isn't worthwhile.
936 */
937 (void) pathname;
938
939 /* We will often still have an fd open on the file under consideration,
940 * but that's just to ensure inode number stability by maintaining
941 * a reference to it; we don't need the file for anything else.
942 */
943 if (stat_buf->st_ino)
944 {
945 if (stat_buf->st_ino != pred_ptr->args.samefileid.ino)
946 return false;
947 }
948 /* Now stat the file to check the device number. */
949 if (0 == get_statinfo (pathname, state.rel_pathname, stat_buf))
950 {
951 /* the repeated test here is necessary in case stat_buf.st_ino had been zero. */
952 return stat_buf->st_ino == pred_ptr->args.samefileid.ino
953 && stat_buf->st_dev == pred_ptr->args.samefileid.dev;
954 }
955 else
956 {
957 /* get_statinfo will already have emitted an error message. */
958 return false;
959 }
960 }
961
962 bool
963 pred_true (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
964 {
965 (void) pathname;
966 (void) stat_buf;
967 (void) pred_ptr;
968 return true;
969 }
970
971 bool
972 pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
973 {
974 mode_t mode;
975 enum file_type type = FTYPE_COUNT;
976
977 assert (state.have_type);
978
979 if (0 == state.type)
980 {
981 /* This can sometimes happen with broken NFS servers.
982 * See Savannah bug #16378.
983 */
984 return false;
985 }
986
987 (void) pathname;
988
989 if (state.have_stat)
990 mode = stat_buf->st_mode;
991 else
992 mode = state.type;
993
994 #ifndef S_IFMT
995 /* POSIX system; check `mode' the slow way.
996 * Search in the order of probability (f,d,l,b,c,s,p,D).
997 */
998 if (S_ISREG (mode))
999 type = FTYPE_REG;
1000 else if (S_ISDIR (mode))
1001 type = FTYPE_DIR;
1002 # ifdef S_IFLNK
1003 else if (S_ISLNK (mode))
1004 type = FTYPE_LNK;
1005 # endif
1006 else if (S_ISBLK (mode))
1007 type = FTYPE_BLK;
1008 else if (S_ISCHR (mode))
1009 type = FTYPE_CHR;
1010 # ifdef S_IFSOCK
1011 else if (S_ISSOCK (mode))
1012 type = FTYPE_SOCK;
1013 # endif
1014 # ifdef S_IFIFO
1015 else if (S_ISFIFO (mode))
1016 type = FTYPE_FIFO;
1017 # endif
1018 # ifdef S_IFDOOR
1019 else if (S_ISDOOR (mode))
1020 type = FTYPE_DOOR;
1021 # endif
1022 #else /* S_IFMT */
1023 /* Unix system; check `mode' the fast way. */
1024 switch (mode & S_IFMT)
1025 {
1026 case S_IFREG:
1027 type = FTYPE_REG;
1028 break;
1029 case S_IFDIR:
1030 type = FTYPE_DIR;
1031 break;
1032 # ifdef S_IFLNK
1033 case S_IFLNK:
1034 type = FTYPE_LNK;
1035 break;
1036 # endif
1037 case S_IFBLK:
1038 type = FTYPE_BLK;
1039 break;
1040 case S_IFCHR:
1041 type = FTYPE_CHR;
1042 break;
1043 # ifdef S_IFSOCK
1044 case S_IFSOCK:
1045 type = FTYPE_SOCK;
1046 break;
1047 # endif
1048 # ifdef S_IFIFO
1049 case S_IFIFO:
1050 type = FTYPE_FIFO;
1051 break;
1052 # endif
1053 # ifdef S_IFDOOR
1054 case S_IFDOOR:
1055 type = FTYPE_DOOR;
1056 break;
1057 # endif
1058 }
1059 #endif /* S_IFMT */
1060
1061 if ((type != FTYPE_COUNT) && pred_ptr->args.types[type])
1062 return true;
1063 else
1064 return false;
1065 }
1066
1067 bool
1068 pred_uid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1069 {
1070 (void) pathname;
1071 switch (pred_ptr->args.numinfo.kind)
1072 {
1073 case COMP_GT:
1074 if (stat_buf->st_uid > pred_ptr->args.numinfo.l_val)
1075 return (true);
1076 break;
1077 case COMP_LT:
1078 if (stat_buf->st_uid < pred_ptr->args.numinfo.l_val)
1079 return (true);
1080 break;
1081 case COMP_EQ:
1082 if (stat_buf->st_uid == pred_ptr->args.numinfo.l_val)
1083 return (true);
1084 break;
1085 }
1086 return (false);
1087 }
1088
1089 bool
1090 pred_used (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1091 {
1092 struct timespec delta, at, ct;
1093
1094 (void) pathname;
1095
1096 at = get_stat_atime (stat_buf);
1097 ct = get_stat_ctime (stat_buf);
1098
1099 /* Always evaluate to false if atime < ctime. */
1100 if (compare_ts (at, ct) < 0)
1101 return false;
1102
1103 delta.tv_sec = ct.tv_sec - at.tv_sec;
1104 delta.tv_nsec = ct.tv_nsec - at.tv_nsec;
1105 if (delta.tv_nsec < 0)
1106 {
1107 delta.tv_nsec += 1000000000;
1108 delta.tv_sec -= 1;
1109 }
1110 return pred_timewindow (delta, pred_ptr, DAYSECS);
1111 }
1112
1113 bool
1114 pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1115 {
1116 (void) pathname;
1117 if (pred_ptr->args.uid == stat_buf->st_uid)
1118 return (true);
1119 else
1120 return (false);
1121 }
1122
1123 bool
1124 pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1125 {
1126 struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */
1127 int (*ystat) (const char*, struct stat *p);
1128
1129 /* If we would normally stat the link itself, stat the target instead.
1130 * If we would normally follow the link, stat the link itself instead.
1131 */
1132 if (following_links ())
1133 ystat = optionp_stat;
1134 else
1135 ystat = optionl_stat;
1136
1137 set_stat_placeholders (&sbuf);
1138 if ((*ystat) (state.rel_pathname, &sbuf) != 0)
1139 {
1140 if (following_links () && errno == ENOENT)
1141 {
1142 /* If we failed to follow the symlink,
1143 * fall back on looking at the symlink itself.
1144 */
1145 /* Mimic behavior of ls -lL. */
1146 return (pred_type (pathname, stat_buf, pred_ptr));
1147 }
1148 else
1149 {
1150 error (0, errno, "%s", safely_quote_err_filename (0, pathname));
1151 state.exit_status = EXIT_FAILURE;
1152 }
1153 return false;
1154 }
1155 /* Now that we have our stat() information, query it in the same
1156 * way that -type does.
1157 */
1158 return (pred_type (pathname, &sbuf, pred_ptr));
1159 }
1160
1161
1162 bool
1163 pred_context (const char *pathname, struct stat *stat_buf,
1164 struct predicate *pred_ptr)
1165 {
1166 char *scontext;
1167 int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
1168 &scontext);
1169 (void) stat_buf;
1170
1171 if (rv < 0)
1172 {
1173 error (0, errno, _("getfilecon failed: %s"),
1174 safely_quote_err_filename (0, pathname));
1175 return false;
1176 }
1177
1178 rv = (fnmatch (pred_ptr->args.scontext, scontext, 0) == 0);
1179 freecon (scontext);
1180 return rv;
1181 }
1182
1183 /* Copy STR into BUF and trim blanks from the end of BUF.
1184 Return BUF. */
1185
1186 static char *
1187 blank_rtrim (const char *str, char *buf)
1188 {
1189 int i;
1190
1191 if (str == NULL)
1192 return (NULL);
1193 strcpy (buf, str);
1194 i = strlen (buf) - 1;
1195 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1196 i--;
1197 buf[++i] = '\0';
1198 return buf;
1199 }
1200
1201 /* Print out the predicate list starting at NODE. */
1202 void
1203 print_list (FILE *fp, struct predicate *node)
1204 {
1205 struct predicate *cur;
1206 char name[256];
1207
1208 cur = node;
1209 while (cur != NULL)
1210 {
1211 fprintf (fp, "[%s] ", blank_rtrim (cur->p_name, name));
1212 cur = cur->pred_next;
1213 }
1214 fprintf (fp, "\n");
1215 }
1216
1217 /* Print out the predicate list starting at NODE. */
1218 static void
1219 print_parenthesised (FILE *fp, struct predicate *node)
1220 {
1221 int parens = 0;
1222
1223 if (node)
1224 {
1225 if ((pred_is (node, pred_or) || pred_is (node, pred_and))
1226 && node->pred_left == NULL)
1227 {
1228 /* We print "<nothing> or X" as just "X"
1229 * We print "<nothing> and X" as just "X"
1230 */
1231 print_parenthesised(fp, node->pred_right);
1232 }
1233 else
1234 {
1235 if (node->pred_left || node->pred_right)
1236 parens = 1;
1237
1238 if (parens)
1239 fprintf (fp, "%s", " ( ");
1240 print_optlist (fp, node);
1241 if (parens)
1242 fprintf (fp, "%s", " ) ");
1243 }
1244 }
1245 }
1246
1247 void
1248 print_optlist (FILE *fp, const struct predicate *p)
1249 {
1250 if (p)
1251 {
1252 print_parenthesised (fp, p->pred_left);
1253 fprintf (fp,
1254 "%s%s%s",
1255 p->need_stat ? "[call stat] " : "",
1256 p->need_type ? "[need type] " : "",
1257 p->need_inum ? "[need inum] " : "");
1258 print_predicate (fp, p);
1259 fprintf (fp, " [est success rate %.4g] ", p->est_success_rate);
1260 if (options.debug_options & DebugSuccessRates)
1261 {
1262 fprintf (fp, "[real success rate %lu/%lu", p->perf.successes, p->perf.visits);
1263 if (p->perf.visits)
1264 {
1265 double real_rate = (double)p->perf.successes / (double)p->perf.visits;
1266 fprintf (fp, "=%.4g] ", real_rate);
1267 }
1268 else
1269 {
1270 fprintf (fp, "=_] ");
1271 }
1272 }
1273 print_parenthesised (fp, p->pred_right);
1274 }
1275 }
1276
1277 void show_success_rates (const struct predicate *p)
1278 {
1279 if (options.debug_options & DebugSuccessRates)
1280 {
1281 fprintf (stderr, "Predicate success rates after completion:\n");
1282 print_optlist (stderr, p);
1283 fprintf (stderr, "\n");
1284 }
1285 }
1286
1287
1288
1289
1290 #ifdef _NDEBUG
1291 /* If _NDEBUG is defined, the assertions will do nothing. Hence
1292 * there is no point in having a function body for pred_sanity_check()
1293 * if that preprocessor macro is defined.
1294 */
1295 void
1296 pred_sanity_check (const struct predicate *predicates)
1297 {
1298 /* Do nothing, since assert is a no-op with _NDEBUG set */
1299 return;
1300 }
1301 #else
1302 void
1303 pred_sanity_check (const struct predicate *predicates)
1304 {
1305 const struct predicate *p;
1306
1307 for (p=predicates; p != NULL; p=p->pred_next)
1308 {
1309 /* All predicates must do something. */
1310 assert (p->pred_func != NULL);
1311
1312 /* All predicates must have a parser table entry. */
1313 assert (p->parser_entry != NULL);
1314
1315 /* If the parser table tells us that just one predicate function is
1316 * possible, verify that that is still the one that is in effect.
1317 * If the parser has NULL for the predicate function, that means that
1318 * the parse_xxx function fills it in, so we can't check it.
1319 */
1320 if (p->parser_entry->pred_func)
1321 {
1322 assert (p->parser_entry->pred_func == p->pred_func);
1323 }
1324
1325 switch (p->parser_entry->type)
1326 {
1327 /* Options all take effect during parsing, so there should
1328 * be no predicate entries corresponding to them. Hence we
1329 * should not see any ARG_OPTION or ARG_POSITIONAL_OPTION
1330 * items.
1331 *
1332 * This is a silly way of coding this test, but it prevents
1333 * a compiler warning (i.e. otherwise it would think that
1334 * there would be case statements missing).
1335 */
1336 case ARG_OPTION:
1337 case ARG_POSITIONAL_OPTION:
1338 assert (p->parser_entry->type != ARG_OPTION);
1339 assert (p->parser_entry->type != ARG_POSITIONAL_OPTION);
1340 break;
1341
1342 case ARG_ACTION:
1343 assert (p->side_effects); /* actions have side effects. */
1344 if (!pred_is (p, pred_prune) && !pred_is(p, pred_quit))
1345 {
1346 /* actions other than -prune and -quit should
1347 * inhibit the default -print
1348 */
1349 assert (p->no_default_print);
1350 }
1351 break;
1352
1353 /* We happen to know that the only user of ARG_SPECIAL_PARSE
1354 * is a test, so handle it like ARG_TEST.
1355 */
1356 case ARG_SPECIAL_PARSE:
1357 case ARG_TEST:
1358 case ARG_PUNCTUATION:
1359 case ARG_NOOP:
1360 /* Punctuation and tests should have no side
1361 * effects and not inhibit default print.
1362 */
1363 assert (!p->no_default_print);
1364 assert (!p->side_effects);
1365 break;
1366 }
1367 }
1368 }
1369 #endif