1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003, 2004,
3 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* config.h must always come first. */
41 #include "modechange.h"
42 #include "mountlist.h"
43 #include "parse-datetime.h"
46 #include "regextype.h"
47 #include "safe-atoi.h"
48 #include "selinux-at.h"
49 #include "splitstring.h"
50 #include "stat-time.h"
59 #include "findutils-version.h"
66 # define _(Text) gettext (Text)
71 # define N_(String) gettext_noop (String)
73 /* See locate.c for explanation as to why not use (String) */
74 # define N_(String) String
84 static bool parse_accesscheck (const struct parser_table*, char *argv[], int *arg_ptr);
85 static bool parse_amin (const struct parser_table*, char *argv[], int *arg_ptr);
86 static bool parse_and (const struct parser_table*, char *argv[], int *arg_ptr);
87 static bool parse_anewer (const struct parser_table*, char *argv[], int *arg_ptr);
88 static bool parse_cmin (const struct parser_table*, char *argv[], int *arg_ptr);
89 static bool parse_cnewer (const struct parser_table*, char *argv[], int *arg_ptr);
90 static bool parse_comma (const struct parser_table*, char *argv[], int *arg_ptr);
91 static bool parse_daystart (const struct parser_table*, char *argv[], int *arg_ptr);
92 static bool parse_delete (const struct parser_table*, char *argv[], int *arg_ptr);
93 static bool parse_d (const struct parser_table*, char *argv[], int *arg_ptr);
94 static bool parse_depth (const struct parser_table*, char *argv[], int *arg_ptr);
95 static bool parse_empty (const struct parser_table*, char *argv[], int *arg_ptr);
96 static bool parse_exec (const struct parser_table*, char *argv[], int *arg_ptr);
97 static bool parse_execdir (const struct parser_table*, char *argv[], int *arg_ptr);
98 static bool parse_false (const struct parser_table*, char *argv[], int *arg_ptr);
99 static bool parse_fls (const struct parser_table*, char *argv[], int *arg_ptr);
100 static bool parse_fprintf (const struct parser_table*, char *argv[], int *arg_ptr);
101 static bool parse_follow (const struct parser_table*, char *argv[], int *arg_ptr);
102 static bool parse_fprint (const struct parser_table*, char *argv[], int *arg_ptr);
103 static bool parse_fprint0 (const struct parser_table*, char *argv[], int *arg_ptr);
104 static bool parse_fstype (const struct parser_table*, char *argv[], int *arg_ptr);
105 static bool parse_gid (const struct parser_table*, char *argv[], int *arg_ptr);
106 static bool parse_group (const struct parser_table*, char *argv[], int *arg_ptr);
107 static bool parse_help (const struct parser_table*, char *argv[], int *arg_ptr);
108 static bool parse_ilname (const struct parser_table*, char *argv[], int *arg_ptr);
109 static bool parse_iname (const struct parser_table*, char *argv[], int *arg_ptr);
110 static bool parse_inum (const struct parser_table*, char *argv[], int *arg_ptr);
111 static bool parse_ipath (const struct parser_table*, char *argv[], int *arg_ptr);
112 static bool parse_iregex (const struct parser_table*, char *argv[], int *arg_ptr);
113 static bool parse_iwholename (const struct parser_table*, char *argv[], int *arg_ptr);
114 static bool parse_links (const struct parser_table*, char *argv[], int *arg_ptr);
115 static bool parse_lname (const struct parser_table*, char *argv[], int *arg_ptr);
116 static bool parse_ls (const struct parser_table*, char *argv[], int *arg_ptr);
117 static bool parse_maxdepth (const struct parser_table*, char *argv[], int *arg_ptr);
118 static bool parse_mindepth (const struct parser_table*, char *argv[], int *arg_ptr);
119 static bool parse_mmin (const struct parser_table*, char *argv[], int *arg_ptr);
120 static bool parse_name (const struct parser_table*, char *argv[], int *arg_ptr);
121 static bool parse_negate (const struct parser_table*, char *argv[], int *arg_ptr);
122 static bool parse_newer (const struct parser_table*, char *argv[], int *arg_ptr);
123 static bool parse_newerXY (const struct parser_table*, char *argv[], int *arg_ptr);
124 static bool parse_noleaf (const struct parser_table*, char *argv[], int *arg_ptr);
125 static bool parse_nogroup (const struct parser_table*, char *argv[], int *arg_ptr);
126 static bool parse_nouser (const struct parser_table*, char *argv[], int *arg_ptr);
127 static bool parse_nowarn (const struct parser_table*, char *argv[], int *arg_ptr);
128 static bool parse_ok (const struct parser_table*, char *argv[], int *arg_ptr);
129 static bool parse_okdir (const struct parser_table*, char *argv[], int *arg_ptr);
130 static bool parse_or (const struct parser_table*, char *argv[], int *arg_ptr);
131 static bool parse_path (const struct parser_table*, char *argv[], int *arg_ptr);
132 static bool parse_perm (const struct parser_table*, char *argv[], int *arg_ptr);
133 static bool parse_print0 (const struct parser_table*, char *argv[], int *arg_ptr);
134 static bool parse_printf (const struct parser_table*, char *argv[], int *arg_ptr);
135 static bool parse_prune (const struct parser_table*, char *argv[], int *arg_ptr);
136 static bool parse_regex (const struct parser_table*, char *argv[], int *arg_ptr);
137 static bool parse_regextype (const struct parser_table*, char *argv[], int *arg_ptr);
138 static bool parse_samefile (const struct parser_table*, char *argv[], int *arg_ptr);
139 static bool parse_size (const struct parser_table*, char *argv[], int *arg_ptr);
140 static bool parse_time (const struct parser_table*, char *argv[], int *arg_ptr);
141 static bool parse_true (const struct parser_table*, char *argv[], int *arg_ptr);
142 static bool parse_type (const struct parser_table*, char *argv[], int *arg_ptr);
143 static bool parse_uid (const struct parser_table*, char *argv[], int *arg_ptr);
144 static bool parse_used (const struct parser_table*, char *argv[], int *arg_ptr);
145 static bool parse_user (const struct parser_table*, char *argv[], int *arg_ptr);
146 static bool parse_version (const struct parser_table*, char *argv[], int *arg_ptr);
147 static bool parse_wholename (const struct parser_table*, char *argv[], int *arg_ptr);
148 static bool parse_xdev (const struct parser_table*, char *argv[], int *arg_ptr);
149 static bool parse_ignore_race (const struct parser_table*, char *argv[], int *arg_ptr);
150 static bool parse_noignore_race (const struct parser_table*, char *argv[], int *arg_ptr);
151 static bool parse_warn (const struct parser_table*, char *argv[], int *arg_ptr);
152 static bool parse_xtype (const struct parser_table*, char *argv[], int *arg_ptr);
153 static bool parse_quit (const struct parser_table*, char *argv[], int *arg_ptr);
154 static bool parse_context (const struct parser_table*, char *argv[], int *arg_ptr);
156 static bool parse_show_control_chars (const struct parser_table*, char *argv[], int *arg_ptr);
161 static bool insert_type (char **argv, int *arg_ptr,
162 const struct parser_table *entry,
163 PRED_FUNC which_pred);
164 static bool insert_regex (char *argv[], int *arg_ptr,
165 const struct parser_table *entry,
167 static bool insert_exec_ok (const char *action,
168 const struct parser_table *entry,
171 static bool get_comp_type (const char **str,
172 enum comparison_type *comp_type);
173 static bool get_relative_timestamp (const char *str,
174 struct time_val *tval,
175 struct timespec origin,
177 const char *overflowmessage);
178 static bool get_num (const char *str,
180 enum comparison_type *comp_type);
181 static struct predicate* insert_num (char *argv[], int *arg_ptr,
182 const struct parser_table *entry);
183 static void open_output_file (const char *path, struct format_val *p);
184 static void open_stdout (struct format_val *p);
185 static bool stream_is_tty(FILE *fp);
186 static bool parse_noop (const struct parser_table* entry,
187 char **argv, int *arg_ptr);
189 #define PASTE(x,y) x##y
192 #define PARSE_OPTION(what,suffix) \
193 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
195 #define PARSE_POSOPT(what,suffix) \
196 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
198 #define PARSE_TEST(what,suffix) \
199 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
201 #define PARSE_TEST_NP(what,suffix) \
202 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
204 #define PARSE_ACTION(what,suffix) \
205 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
207 #define PARSE_PUNCTUATION(what,suffix) \
208 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
211 /* Predicates we cannot handle in the usual way. If you add an entry
212 * to this table, double-check the switch statement in
213 * pred_sanity_check() to make sure that the new case is being
216 static struct parser_table const parse_entry_newerXY =
218 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
221 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
222 If they are in some Unix versions of find, they are marked `Unix'. */
224 static struct parser_table const parse_table[] =
226 PARSE_PUNCTUATION("!", negate), /* POSIX */
227 PARSE_PUNCTUATION("not", negate), /* GNU */
228 PARSE_PUNCTUATION("(", openparen), /* POSIX */
229 PARSE_PUNCTUATION(")", closeparen), /* POSIX */
230 PARSE_PUNCTUATION(",", comma), /* GNU */
231 PARSE_PUNCTUATION("a", and), /* POSIX */
232 PARSE_TEST ("amin", amin), /* GNU */
233 PARSE_PUNCTUATION("and", and), /* GNU */
234 PARSE_TEST ("anewer", anewer), /* GNU */
235 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
236 PARSE_TEST ("cmin", cmin), /* GNU */
237 PARSE_TEST ("cnewer", cnewer), /* GNU */
238 {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
239 PARSE_TEST ("context", context), /* GNU */
240 PARSE_POSOPT ("daystart", daystart), /* GNU */
241 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
242 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
243 PARSE_OPTION ("depth", depth), /* POSIX */
244 PARSE_TEST ("empty", empty), /* GNU */
245 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
246 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
247 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
248 PARSE_ACTION ("fls", fls), /* GNU */
249 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
250 PARSE_ACTION ("fprint", fprint), /* GNU */
251 PARSE_ACTION ("fprint0", fprint0), /* GNU */
252 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
253 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
254 PARSE_TEST ("gid", gid), /* GNU */
255 PARSE_TEST ("group", group), /* POSIX */
256 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
257 PARSE_TEST ("ilname", ilname), /* GNU */
258 PARSE_TEST ("iname", iname), /* GNU */
259 PARSE_TEST ("inum", inum), /* GNU, Unix */
260 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
261 PARSE_TEST_NP ("iregex", iregex), /* GNU */
262 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
263 PARSE_TEST ("links", links), /* POSIX */
264 PARSE_TEST ("lname", lname), /* GNU */
265 PARSE_ACTION ("ls", ls), /* GNU, Unix */
266 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
267 PARSE_OPTION ("mindepth", mindepth), /* GNU */
268 PARSE_TEST ("mmin", mmin), /* GNU */
269 PARSE_OPTION ("mount", xdev), /* Unix */
270 {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
271 PARSE_TEST ("name", name),
272 #ifdef UNIMPLEMENTED_UNIX
273 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
275 PARSE_TEST ("newer", newer), /* POSIX */
276 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
277 PARSE_OPTION ("noleaf", noleaf), /* GNU */
278 PARSE_TEST ("nogroup", nogroup), /* POSIX */
279 PARSE_TEST ("nouser", nouser), /* POSIX */
280 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
281 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
282 PARSE_PUNCTUATION("o", or), /* POSIX */
283 PARSE_PUNCTUATION("or", or), /* GNU */
284 PARSE_ACTION ("ok", ok), /* POSIX */
285 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
286 PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
287 PARSE_TEST ("perm", perm), /* POSIX */
288 PARSE_ACTION ("print", print), /* POSIX */
289 PARSE_ACTION ("print0", print0), /* GNU */
290 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
291 PARSE_ACTION ("prune", prune), /* POSIX */
292 PARSE_ACTION ("quit", quit), /* GNU */
293 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
294 PARSE_TEST ("regex", regex), /* GNU */
295 PARSE_POSOPT ("regextype", regextype), /* GNU */
296 PARSE_TEST ("samefile", samefile), /* GNU */
298 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
300 PARSE_TEST ("size", size), /* POSIX */
301 PARSE_TEST ("type", type), /* POSIX */
302 PARSE_TEST ("uid", uid), /* GNU */
303 PARSE_TEST ("used", used), /* GNU */
304 PARSE_TEST ("user", user), /* POSIX */
305 PARSE_OPTION ("warn", warn), /* GNU */
306 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
307 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
308 PARSE_OPTION ("xdev", xdev), /* POSIX */
309 PARSE_TEST ("xtype", xtype), /* GNU */
310 #ifdef UNIMPLEMENTED_UNIX
311 /* It's pretty ugly for find to know about archive formats.
312 Plus what it could do with cpio archives is very limited.
313 Better to leave it out. */
314 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
316 /* gnulib's stdbool.h might have made true and false into macros,
317 * so we can't leave named 'true' and 'false' tokens, so we have
318 * to expeant the relevant entries longhand.
320 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
321 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
322 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
324 /* Various other cases that don't fit neatly into our macro scheme. */
325 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
326 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
327 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
328 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
333 static const char *first_nonoption_arg = NULL;
334 static const struct parser_table *noop = NULL;
337 fallback_getfilecon (int fd, const char *name, security_context_t *p,
340 /* Our original getfilecon () call failed. Perhaps we can't follow a
341 * symbolic link. If that might be the problem, lgetfilecon () the link.
342 * Otherwise, admit defeat. */
348 fprintf (stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling "
349 "back on lgetfilecon()\n", name);
351 return lgetfileconat (fd, name, p);
358 case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
365 /* optionh_getfilecon () implements the getfilecon operation when the
366 * -H option is in effect.
368 * If the item to be examined is a command-line argument, we follow
369 * symbolic links. If the getfilecon () call fails on the command-line
370 * item, we fall back on the properties of the symbolic link.
372 * If the item to be examined is not a command-line argument, we
373 * examine the link itself. */
375 optionh_getfilecon (int fd, const char *name, security_context_t *p)
378 if (0 == state.curdepth)
380 /* This file is from the command line; dereference the link (if it is
382 rv = getfileconat (fd, name, p);
384 return 0; /* success */
386 return fallback_getfilecon (fd, name, p, rv);
390 /* Not a file on the command line; do not dereference the link. */
391 return lgetfileconat (fd, name, p);
395 /* optionl_getfilecon () implements the getfilecon operation when the
396 * -L option is in effect. That option makes us examine the thing the
397 * symbolic link points to, not the symbolic link itself. */
399 optionl_getfilecon (int fd, const char *name, security_context_t *p)
401 int rv = getfileconat (fd, name, p);
403 return 0; /* normal case. */
405 return fallback_getfilecon (fd, name, p, rv);
408 /* optionp_getfilecon () implements the stat operation when the -P
409 * option is in effect (this is also the default). That option makes
410 * us examine the symbolic link itself, not the thing it points to. */
412 optionp_getfilecon (int fd, const char *name, security_context_t *p)
414 return lgetfileconat (fd, name, p);
418 check_option_combinations (const struct predicate *p)
420 enum { seen_delete=1u, seen_prune=2u };
421 unsigned int predicates = 0u;
425 if (p->pred_func == pred_delete)
426 predicates |= seen_delete;
427 else if (p->pred_func == pred_prune)
428 predicates |= seen_prune;
432 if ((predicates & seen_prune) && (predicates & seen_delete))
434 /* The user specified both -delete and -prune. One might test
435 * this by first doing
436 * find dirs .... -prune ..... -print
437 * to fnd out what's going to get deleted, and then switch to
438 * find dirs .... -prune ..... -delete
439 * once we are happy. Unfortunately, the -delete action also
440 * implicitly turns on -depth, which will affect the behaviour
441 * of -prune (in fact, it makes it a no-op). In this case we
442 * would like to prevent unfortunate accidents, so we require
443 * the user to have explicitly used -depth.
445 * We only get away with this because the -delete predicate is not
446 * in POSIX. If it was, we couldn't issue a fatal error here.
448 if (!options.explicit_depth)
450 /* This fixes Savannah bug #20865. */
451 error (EXIT_FAILURE, 0,
452 _("The -delete action automatically turns on -depth, "
453 "but -prune does nothing when -depth is in effect. "
454 "If you want to carry on anyway, just explicitly use "
455 "the -depth option."));
461 static const struct parser_table*
467 for (i = 0; parse_table[i].parser_name != 0; i++)
469 if (ARG_NOOP ==parse_table[i].type)
471 noop = &(parse_table[i]);
480 get_stat_Ytime (const struct stat *p,
482 struct timespec *ret)
487 *ret = get_stat_atime (p);
490 *ret = get_stat_birthtime (p);
491 return (ret->tv_nsec >= 0);
493 *ret = get_stat_ctime (p);
496 *ret = get_stat_mtime (p);
505 set_follow_state (enum SymlinkOption opt)
507 if (options.debug_options & DebugStat)
509 /* For DebugStat, the choice is made at runtime within debug_stat()
510 * by checking the contents of the symlink_handling variable.
512 options.xstat = debug_stat;
518 case SYMLINK_ALWAYS_DEREF: /* -L */
519 options.xstat = optionl_stat;
520 options.x_getfilecon = optionl_getfilecon;
521 options.no_leaf_check = true;
524 case SYMLINK_NEVER_DEREF: /* -P (default) */
525 options.xstat = optionp_stat;
526 options.x_getfilecon = optionp_getfilecon;
527 /* Can't turn no_leaf_check off because the user might have specified
532 case SYMLINK_DEREF_ARGSONLY: /* -H */
533 options.xstat = optionh_stat;
534 options.x_getfilecon = optionh_getfilecon;
535 options.no_leaf_check = true;
538 options.symlink_handling = opt;
543 parse_begin_user_args (char **args, int argno,
544 const struct predicate *last,
545 const struct predicate *predicates)
551 first_nonoption_arg = NULL;
555 parse_end_user_args (char **args, int argno,
556 const struct predicate *last,
557 const struct predicate *predicates)
567 /* Check that it is legal to fid the given primary in its
568 * position and return it.
570 static const struct parser_table*
571 found_parser (const char *original_arg, const struct parser_table *entry)
573 /* If this is an option, but we have already had a
574 * non-option argument, the user may be under the
575 * impression that the behaviour of the option
576 * argument is conditional on some preceding
577 * tests. This might typically be the case with,
578 * for example, -maxdepth.
580 * The options -daystart and -follow are exempt
581 * from this treatment, since their positioning
582 * in the command line does have an effect on
583 * subsequent tests but not previous ones. That
584 * might be intentional on the part of the user.
586 if (entry->type != ARG_POSITIONAL_OPTION)
588 /* Something other than -follow/-daystart.
589 * If this is an option, check if it followed
590 * a non-option and if so, issue a warning.
592 if (entry->type == ARG_OPTION)
594 if ((first_nonoption_arg != NULL)
595 && options.warnings )
597 /* option which follows a non-option */
599 _("warning: you have specified the %s "
600 "option after a non-option argument %s, "
601 "but options are not positional (%s affects "
602 "tests specified before it as well as those "
603 "specified after it). Please specify options "
604 "before other arguments.\n"),
612 /* Not an option or a positional option,
613 * so remember we've seen it in order to
614 * use it in a possible future warning message.
616 if (first_nonoption_arg == NULL)
618 first_nonoption_arg = original_arg;
627 /* Return a pointer to the parser function to invoke for predicate
629 Return NULL if SEARCH_NAME is not a valid predicate name. */
631 const struct parser_table*
632 find_parser (const char *search_name)
635 const char *original_arg = search_name;
637 /* Ugh. Special case -newerXY. */
638 if (0 == strncmp ("-newer", search_name, 6)
639 && (8 == strlen (search_name)))
641 return found_parser (original_arg, &parse_entry_newerXY);
644 if (*search_name == '-')
647 for (i = 0; parse_table[i].parser_name != 0; i++)
649 if (strcmp (parse_table[i].parser_name, search_name) == 0)
651 return found_parser (original_arg, &parse_table[i]);
658 estimate_file_age_success_rate (float num_days)
662 /* Assume 1% of files have timestamps in the future */
665 else if (num_days < 1)
667 /* Assume 30% of files have timestamps today */
670 else if (num_days > 100)
672 /* Assume 30% of files are very old */
677 /* Assume 39% of files are between 1 and 100 days old. */
683 estimate_timestamp_success_rate (time_t when)
685 /* This calculation ignores the nanoseconds field of the
686 * origin, but I don't think that makes much difference
689 int num_days = (options.cur_day_start.tv_sec - when) / 86400;
690 return estimate_file_age_success_rate (num_days);
693 /* Collect an argument from the argument list, or
697 collect_arg_nonconst (char **argv, int *arg_ptr, char **collected_arg)
699 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
701 *collected_arg = NULL;
706 *collected_arg = argv[*arg_ptr];
713 collect_arg (char **argv, int *arg_ptr, const char **collected_arg)
716 const bool result = collect_arg_nonconst (argv, arg_ptr, &arg);
717 *collected_arg = arg;
724 collect_arg_stat_info (char **argv, int *arg_ptr, struct stat *p,
725 const char **argument)
727 const char *filename;
728 if (collect_arg (argv, arg_ptr, &filename))
730 *argument = filename;
731 if (0 == (options.xstat)(filename, p))
737 fatal_target_file_error (errno, filename);
747 /* The parsers are responsible to continue scanning ARGV for
748 their arguments. Each parser knows what is and isn't
751 ARGV is the argument array.
752 *ARG_PTR is the index to start at in ARGV,
753 updated to point beyond the last element consumed.
755 The predicate structure is updated with the new information. */
759 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
761 struct predicate *our_pred;
766 our_pred = get_new_pred_noarg (entry);
767 our_pred->pred_func = pred_and;
768 our_pred->p_type = BI_OP;
769 our_pred->p_prec = AND_PREC;
770 our_pred->need_stat = our_pred->need_type = false;
775 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
777 struct stat stat_newer;
780 set_stat_placeholders (&stat_newer);
781 if (collect_arg_stat_info (argv, arg_ptr, &stat_newer, &arg))
783 struct predicate *our_pred = insert_primary (entry, arg);
784 our_pred->args.reftime.xval = XVAL_ATIME;
785 our_pred->args.reftime.ts = get_stat_mtime (&stat_newer);
786 our_pred->args.reftime.kind = COMP_GT;
787 our_pred->est_success_rate = estimate_timestamp_success_rate (stat_newer.st_mtime);
794 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
796 struct predicate *our_pred;
801 our_pred = get_new_pred_noarg (entry);
802 our_pred->pred_func = pred_closeparen;
803 our_pred->p_type = CLOSE_PAREN;
804 our_pred->p_prec = NO_PREC;
805 our_pred->need_stat = our_pred->need_type = false;
810 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
812 struct stat stat_newer;
815 set_stat_placeholders (&stat_newer);
816 if (collect_arg_stat_info (argv, arg_ptr, &stat_newer, &arg))
818 struct predicate *our_pred = insert_primary (entry, arg);
819 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
820 our_pred->args.reftime.ts = get_stat_mtime (&stat_newer);
821 our_pred->args.reftime.kind = COMP_GT;
822 our_pred->est_success_rate = estimate_timestamp_success_rate (stat_newer.st_mtime);
829 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
831 struct predicate *our_pred;
836 our_pred = get_new_pred_noarg (entry);
837 our_pred->pred_func = pred_comma;
838 our_pred->p_type = BI_OP;
839 our_pred->p_prec = COMMA_PREC;
840 our_pred->need_stat = our_pred->need_type = false;
841 our_pred->est_success_rate = 1.0f;
846 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
854 if (options.full_days == false)
856 options.cur_day_start.tv_sec += DAYSECS;
857 options.cur_day_start.tv_nsec = 0;
858 local = localtime (&options.cur_day_start.tv_sec);
859 options.cur_day_start.tv_sec -= (local
860 ? (local->tm_sec + local->tm_min * 60
861 + local->tm_hour * 3600)
862 : options.cur_day_start.tv_sec % DAYSECS);
863 options.full_days = true;
869 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
871 struct predicate *our_pred;
875 our_pred = insert_primary_noarg (entry);
876 our_pred->side_effects = our_pred->no_default_print = true;
877 /* -delete implies -depth */
878 options.do_dir_first = false;
880 /* We do not need stat information because we check for the case
881 * (errno==EISDIR) in pred_delete.
883 our_pred->need_stat = our_pred->need_type = false;
885 our_pred->est_success_rate = 1.0f;
890 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
895 options.do_dir_first = false;
896 options.explicit_depth = true;
897 return parse_noop (entry, argv, arg_ptr);
901 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
903 if (options.warnings)
906 _("warning: the -d option is deprecated; please use "
907 "-depth instead, because the latter is a "
908 "POSIX-compliant feature."));
910 return parse_depth (entry, argv, arg_ptr);
914 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
916 struct predicate *our_pred;
920 our_pred = insert_primary_noarg (entry);
921 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
926 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
928 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
932 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
934 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
940 struct predicate *our_pred;
941 const struct parser_table *entry_false;
943 entry_false = find_parser("false");
944 our_pred = insert_primary_noarg (entry_false);
945 our_pred->need_stat = our_pred->need_type = false;
946 our_pred->side_effects = our_pred->no_default_print = false;
947 our_pred->est_success_rate = 0.0f;
953 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
958 return insert_false ();
962 insert_fls (const struct parser_table* entry, const char *filename)
964 struct predicate *our_pred = insert_primary_noarg (entry);
966 open_output_file (filename, &our_pred->args.printf_vec);
968 open_stdout (&our_pred->args.printf_vec);
969 our_pred->side_effects = our_pred->no_default_print = true;
970 our_pred->est_success_rate = 1.0f;
976 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
978 const char *filename;
979 if (collect_arg (argv, arg_ptr, &filename))
981 if (insert_fls (entry, filename))
984 --*arg_ptr; /* don't consume the invalid arg. */
990 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
992 set_follow_state (SYMLINK_ALWAYS_DEREF);
993 return parse_noop (entry, argv, arg_ptr);
997 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
999 struct predicate *our_pred;
1000 const char *filename;
1001 if (collect_arg (argv, arg_ptr, &filename))
1003 our_pred = insert_primary (entry, filename);
1004 open_output_file (filename, &our_pred->args.printf_vec);
1005 our_pred->side_effects = our_pred->no_default_print = true;
1006 our_pred->need_stat = our_pred->need_type = false;
1007 our_pred->est_success_rate = 1.0f;
1017 insert_fprint (const struct parser_table* entry, const char *filename)
1019 struct predicate *our_pred = insert_primary (entry, filename);
1021 open_output_file (filename, &our_pred->args.printf_vec);
1023 open_stdout (&our_pred->args.printf_vec);
1024 our_pred->side_effects = our_pred->no_default_print = true;
1025 our_pred->need_stat = our_pred->need_type = false;
1026 our_pred->est_success_rate = 1.0f;
1032 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1034 const char *filename;
1035 if (collect_arg (argv, arg_ptr, &filename))
1037 if (insert_fprint (entry, filename))
1040 --*arg_ptr; /* don't consume the bad arg. */
1045 static float estimate_fstype_success_rate (const char *fsname)
1047 struct stat dir_stat;
1048 const char *the_root_dir = "/";
1049 if (0 == stat (the_root_dir, &dir_stat)) /* it's an absolute path anyway */
1051 const char *fstype = filesystem_type (&dir_stat, the_root_dir);
1052 /* Assume most files are on the same file system type as the root fs. */
1053 if (0 == strcmp (fsname, fstype))
1064 is_used_fs_type(const char *name)
1066 if (0 == strcmp("afs", name))
1068 /* I guess AFS may not appear in /etc/mtab (or equivalent) but still be in use,
1069 so assume we always need to check for AFS. */
1074 const struct mount_entry *entries = read_file_system_list(false);
1077 const struct mount_entry *entry;
1078 for (entry = entries; entry; entry = entry->me_next)
1080 if (0 == strcmp(name, entry->me_type))
1094 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
1096 const char *typename;
1097 if (collect_arg (argv, arg_ptr, &typename))
1099 if (options.optimisation_level < 2 || is_used_fs_type (typename))
1101 struct predicate *our_pred = insert_primary (entry, typename);
1102 our_pred->args.str = typename;
1104 /* This is an expensive operation, so although there are
1105 * circumstances where it is selective, we ignore this fact
1106 * because we probably don't want to promote this test to the
1109 our_pred->est_success_rate = estimate_fstype_success_rate (typename);
1114 /* This filesystem type is not listed in the mount table.
1115 * Hence this predicate will always return false (with this argument).
1116 * Substitute a predicate with the same effect as -false.
1118 if (options.debug_options & DebugTreeOpt)
1121 "-fstype %s can never succeed, substituting -false\n",
1124 return insert_false ();
1134 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
1136 struct predicate *p = insert_num (argv, arg_ptr, entry);
1139 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1144 --*arg_ptr; /* don't consume the invalid argument. */
1151 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
1153 const char *groupname;
1154 const int saved_argc = *arg_ptr;
1156 if (collect_arg (argv, arg_ptr, &groupname))
1159 struct predicate *our_pred;
1160 struct group *cur_gr = getgrnam (groupname);
1164 gid = cur_gr->gr_gid;
1168 const int gid_len = strspn (groupname, "0123456789");
1171 if (groupname[gid_len] == 0)
1173 gid = safe_atoi (groupname, options.err_quoting_style);
1177 /* XXX: no test in test suite for this */
1178 error (EXIT_FAILURE, 0,
1179 _("%s is not the name of an existing group and"
1180 " it does not look like a numeric group ID "
1181 "because it has the unexpected suffix %s"),
1182 quotearg_n_style (0, options.err_quoting_style, groupname),
1183 quotearg_n_style (1, options.err_quoting_style, groupname+gid_len));
1184 *arg_ptr = saved_argc; /* don't consume the invalid argument. */
1192 /* XXX: no test in test suite for this */
1193 error (EXIT_FAILURE, 0,
1194 _("%s is not the name of an existing group"),
1195 quotearg_n_style (0, options.err_quoting_style, groupname));
1199 error (EXIT_FAILURE, 0,
1200 _("argument to -group is empty, but should be a group name"));
1202 *arg_ptr = saved_argc; /* don't consume the invalid argument. */
1206 our_pred = insert_primary (entry, groupname);
1207 our_pred->args.gid = gid;
1208 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1215 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
1221 usage (stdout, 0, NULL);
1223 default path is the current directory; default expression is -print\n\
1224 expression may consist of: operators, options, tests, and actions:\n"));
1226 operators (decreasing precedence; -and is implicit where no others are given):\n\
1227 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
1228 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1230 positional options (always true): -daystart -follow -regextype\n\n\
1231 normal options (always true, specified before other expressions):\n\
1232 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1233 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1235 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1236 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1237 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1238 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1240 -nouser -nogroup -path PATTERN -perm [-/]MODE -regex PATTERN\n\
1241 -readable -writable -executable\n\
1242 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1243 -used N -user NAME -xtype [bcdpfls]"));
1245 -context CONTEXT\n"));
1247 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1248 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1249 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1250 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1252 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1253 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1254 email to <bug-findutils@gnu.org>."));
1255 exit (EXIT_SUCCESS);
1259 estimate_pattern_match_rate (const char *pattern, int is_regex)
1261 if (strpbrk (pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1263 /* A wildcard; assume the pattern matches most files. */
1273 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1276 if (collect_arg (argv, arg_ptr, &name))
1278 struct predicate *our_pred = insert_primary (entry, name);
1279 our_pred->args.str = name;
1280 /* Use the generic glob pattern estimator to figure out how many
1281 * links will match, but bear in mind that most files won't be links.
1283 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate (name, 0);
1293 /* sanity check the fnmatch() function to make sure that case folding
1294 * is supported (as opposed to just having the flag ignored).
1297 fnmatch_sanitycheck (void)
1299 static bool checked = false;
1302 if (0 != fnmatch ("foo", "foo", 0)
1303 || 0 == fnmatch ("Foo", "foo", 0)
1304 || 0 != fnmatch ("Foo", "foo", FNM_CASEFOLD))
1306 error (EXIT_FAILURE, 0,
1307 _("sanity check of the fnmatch() library function failed."));
1317 check_name_arg (const char *pred, const char *arg)
1319 if (options.warnings && strchr (arg, '/'))
1321 error (0, 0,_("warning: Unix filenames usually don't contain slashes "
1322 "(though pathnames do). That means that '%s %s' will "
1323 "probably evaluate to false all the time on this system. "
1324 "You might find the '-wholename' test more useful, or "
1325 "perhaps '-samefile'. Alternatively, if you are using "
1326 "GNU grep, you could "
1327 "use 'find ... -print0 | grep -FzZ %s'."),
1329 safely_quote_err_filename (0, arg),
1330 safely_quote_err_filename (1, arg));
1332 return true; /* allow it anyway */
1338 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1341 fnmatch_sanitycheck ();
1342 if (collect_arg (argv, arg_ptr, &name))
1344 if (check_name_arg ("-iname", name))
1346 struct predicate *our_pred = insert_primary (entry, name);
1347 our_pred->need_stat = our_pred->need_type = false;
1348 our_pred->args.str = name;
1349 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1357 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1359 struct predicate *p = insert_num (argv, arg_ptr, entry);
1362 /* inode number is exact match only, so very low proportions of
1365 p->est_success_rate = 1e-6;
1366 p->need_inum = true;
1367 p->need_stat = false;
1368 p->need_type = false;
1373 --*arg_ptr; /* don't consume the invalid argument. */
1379 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1381 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1385 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1387 struct predicate *p = insert_num (argv, arg_ptr, entry);
1390 if (p->args.numinfo.l_val == 1)
1391 p->est_success_rate = 0.99;
1392 else if (p->args.numinfo.l_val == 2)
1393 p->est_success_rate = 0.01;
1395 p->est_success_rate = 1e-3;
1400 --*arg_ptr; /* don't consume the invalid argument. */
1406 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1409 fnmatch_sanitycheck ();
1410 if (collect_arg (argv, arg_ptr, &name))
1412 struct predicate *our_pred = insert_primary (entry, name);
1413 our_pred->args.str = name;
1414 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate (name, 0);
1421 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1425 return insert_fls (entry, NULL);
1429 insert_depthspec (const struct parser_table* entry, char **argv, int *arg_ptr,
1432 const char *depthstr;
1434 const char *predicate = argv[(*arg_ptr)-1];
1435 if (collect_arg (argv, arg_ptr, &depthstr))
1437 depth_len = strspn (depthstr, "0123456789");
1438 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1440 (*limitptr) = safe_atoi (depthstr, options.err_quoting_style);
1443 return parse_noop (entry, argv, arg_ptr);
1446 error (EXIT_FAILURE, 0,
1447 _("Expected a positive decimal integer argument to %s, but got %s"),
1449 quotearg_n_style (0, options.err_quoting_style, depthstr));
1453 /* missing argument */
1459 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1461 return insert_depthspec (entry, argv, arg_ptr, &options.maxdepth);
1465 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1467 return insert_depthspec (entry, argv, arg_ptr, &options.mindepth);
1472 do_parse_xmin (const struct parser_table* entry,
1477 const char *minutes;
1478 const int saved_argc = *arg_ptr;
1480 if (collect_arg (argv, arg_ptr, &minutes))
1482 struct time_val tval;
1483 struct timespec origin = options.cur_day_start;
1485 origin.tv_sec += DAYSECS;
1486 if (get_relative_timestamp (minutes, &tval, origin, 60,
1487 "arithmetic overflow while converting %s "
1488 "minutes to a number of seconds"))
1490 struct predicate *our_pred = insert_primary (entry, minutes);
1491 our_pred->args.reftime = tval;
1492 our_pred->est_success_rate = estimate_timestamp_success_rate (tval.ts.tv_sec);
1497 /* Don't consume the invalid argument. */
1498 *arg_ptr = saved_argc;
1504 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1506 return do_parse_xmin (entry, argv, arg_ptr, XVAL_ATIME);
1510 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1512 return do_parse_xmin (entry, argv, arg_ptr, XVAL_CTIME);
1517 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1519 return do_parse_xmin (entry, argv, arg_ptr, XVAL_MTIME);
1523 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1526 const int saved_argc = *arg_ptr;
1528 if (collect_arg (argv, arg_ptr, &name))
1530 fnmatch_sanitycheck ();
1531 if (check_name_arg ("-name", name))
1533 struct predicate *our_pred = insert_primary (entry, name);
1534 our_pred->need_stat = our_pred->need_type = false;
1535 our_pred->args.str = name;
1536 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1541 *arg_ptr = saved_argc; /* don't consume the invalid argument. */
1548 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1550 struct predicate *our_pred;
1555 our_pred = get_new_pred_chk_op (entry, NULL);
1556 our_pred->pred_func = pred_negate;
1557 our_pred->p_type = UNI_OP;
1558 our_pred->p_prec = NEGATE_PREC;
1559 our_pred->need_stat = our_pred->need_type = false;
1564 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1566 struct predicate *our_pred;
1567 struct stat stat_newer;
1570 set_stat_placeholders (&stat_newer);
1571 if (collect_arg_stat_info (argv, arg_ptr, &stat_newer, &arg))
1573 our_pred = insert_primary (entry, arg);
1574 our_pred->args.reftime.ts = get_stat_mtime (&stat_newer);
1575 our_pred->args.reftime.xval = XVAL_MTIME;
1576 our_pred->args.reftime.kind = COMP_GT;
1577 our_pred->est_success_rate = estimate_timestamp_success_rate (stat_newer.st_mtime);
1585 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1590 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1594 else if (8u != strlen (argv[*arg_ptr]))
1601 const char validchars[] = "aBcmt";
1603 assert (0 == strncmp ("-newer", argv[*arg_ptr], 6));
1604 x = argv[*arg_ptr][6];
1605 y = argv[*arg_ptr][7];
1608 #if !defined HAVE_STRUCT_STAT_ST_BIRTHTIME && !defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC && !defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC && !defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC
1609 if ('B' == x || 'B' == y)
1612 _("This system does not provide a way to find the birth time of a file."));
1617 /* -newertY (for any Y) is invalid. */
1619 || (NULL == strchr (validchars, x))
1620 || (NULL == strchr ( validchars, y)))
1626 struct predicate *our_pred;
1628 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1629 * past the test name (for most other tests, this is already done)
1631 if (argv[1+*arg_ptr] == NULL)
1633 error (EXIT_FAILURE, 0, _("The %s test needs an argument"),
1634 quotearg_n_style (0, options.err_quoting_style, argv[*arg_ptr]));
1641 our_pred = insert_primary (entry, argv[*arg_ptr]);
1647 our_pred->args.reftime.xval = XVAL_ATIME;
1650 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1653 our_pred->args.reftime.xval = XVAL_CTIME;
1656 our_pred->args.reftime.xval = XVAL_MTIME;
1659 assert (strchr (validchars, x));
1665 if (!parse_datetime (&our_pred->args.reftime.ts,
1667 &options.start_time))
1669 error (EXIT_FAILURE, 0,
1670 _("I cannot figure out how to interpret %s as a date or time"),
1671 quotearg_n_style (0, options.err_quoting_style, argv[*arg_ptr]));
1676 struct stat stat_newer;
1678 /* Stat the named file. */
1679 set_stat_placeholders (&stat_newer);
1680 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1681 fatal_target_file_error (errno, argv[*arg_ptr]);
1683 if (!get_stat_Ytime (&stat_newer, y, &our_pred->args.reftime.ts))
1685 /* We cannot extract a timestamp from the struct stat. */
1686 error (EXIT_FAILURE, 0,
1687 _("Cannot obtain birth time of file %s"),
1688 safely_quote_err_filename (0, argv[*arg_ptr]));
1691 our_pred->args.reftime.kind = COMP_GT;
1692 our_pred->est_success_rate = estimate_timestamp_success_rate (our_pred->args.reftime.ts.tv_sec);
1695 assert (our_pred->pred_func != NULL);
1696 assert (our_pred->pred_func == pred_newerXY);
1697 assert (our_pred->need_stat);
1705 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1707 options.no_leaf_check = true;
1708 return parse_noop (entry, argv, arg_ptr);
1712 /* Arbitrary amount by which to increase size
1713 of `uid_unused' and `gid_unused'. */
1714 #define ALLOC_STEP 2048
1716 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1717 char *uid_unused = NULL;
1719 /* Number of elements in `uid_unused'. */
1720 unsigned uid_allocated;
1722 /* Similar for GIDs and group entries. */
1723 char *gid_unused = NULL;
1724 unsigned gid_allocated;
1728 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1730 struct predicate *our_pred;
1735 our_pred = insert_primary (entry, NULL);
1736 our_pred->est_success_rate = 1e-4;
1738 if (gid_unused == NULL)
1742 gid_allocated = ALLOC_STEP;
1743 gid_unused = xmalloc (gid_allocated);
1744 memset (gid_unused, 1, gid_allocated);
1746 while ((gr = getgrent ()) != NULL)
1748 if ((unsigned) gr->gr_gid >= gid_allocated)
1750 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1751 gid_unused = xrealloc (gid_unused, new_allocated);
1752 memset (gid_unused + gid_allocated, 1,
1753 new_allocated - gid_allocated);
1754 gid_allocated = new_allocated;
1756 gid_unused[(unsigned) gr->gr_gid] = 0;
1765 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1767 struct predicate *our_pred;
1772 our_pred = insert_primary_noarg (entry);
1773 our_pred->est_success_rate = 1e-3;
1775 if (uid_unused == NULL)
1779 uid_allocated = ALLOC_STEP;
1780 uid_unused = xmalloc (uid_allocated);
1781 memset (uid_unused, 1, uid_allocated);
1783 while ((pw = getpwent ()) != NULL)
1785 if ((unsigned) pw->pw_uid >= uid_allocated)
1787 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1788 uid_unused = xrealloc (uid_unused, new_allocated);
1789 memset (uid_unused + uid_allocated, 1,
1790 new_allocated - uid_allocated);
1791 uid_allocated = new_allocated;
1793 uid_unused[(unsigned) pw->pw_uid] = 0;
1802 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1804 options.warnings = false;
1805 return parse_noop (entry, argv, arg_ptr);
1809 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1811 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1815 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1817 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1821 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1823 struct predicate *our_pred;
1828 our_pred = get_new_pred_chk_op (entry, NULL);
1829 our_pred->pred_func = pred_openparen;
1830 our_pred->p_type = OPEN_PAREN;
1831 our_pred->p_prec = NO_PREC;
1832 our_pred->need_stat = our_pred->need_type = false;
1837 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1839 struct predicate *our_pred;
1844 our_pred = get_new_pred_noarg (entry);
1845 our_pred->pred_func = pred_or;
1846 our_pred->p_type = BI_OP;
1847 our_pred->p_prec = OR_PREC;
1848 our_pred->need_stat = our_pred->need_type = false;
1853 is_feasible_path_argument (const char *arg, bool foldcase)
1855 const char *last = strrchr (arg, '/');
1856 if (last && !last[1])
1858 /* The name ends with "/". */
1859 if (matches_start_point (arg, foldcase))
1861 /* "-path foo/" can succeed if one of the start points is "foo/". */
1874 insert_path_check (const struct parser_table* entry, char **argv, int *arg_ptr,
1875 const char *predicate_name, PREDICATEFUNCTION pred)
1878 bool foldcase = false;
1880 if (pred == pred_ipath)
1883 fnmatch_sanitycheck ();
1885 if (collect_arg (argv, arg_ptr, &name))
1887 struct predicate *our_pred = insert_primary_withpred (entry, pred, name);
1888 our_pred->need_stat = our_pred->need_type = false;
1889 our_pred->args.str = name;
1890 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1892 if (!options.posixly_correct
1893 && !is_feasible_path_argument (name, foldcase))
1895 error (0, 0, _("warning: -%s %s will not match anything "
1896 "because it ends with /."),
1897 predicate_name, name);
1898 our_pred->est_success_rate = 1.0e-8;
1905 /* For some time, -path was deprecated (at RMS's request) in favour of
1906 * -iwholename. See the node "GNU Manuals" in standards.texi for the
1907 * rationale for this (basically, GNU prefers the use of the phrase
1908 * "file name" to "path name".
1910 * We do not issue a warning that this usage is deprecated
1912 * (a) HPUX find supports this predicate also and
1913 * (b) it will soon be in POSIX anyway.
1916 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1918 return insert_path_check (entry, argv, arg_ptr, "path", pred_path);
1922 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1924 return insert_path_check (entry, argv, arg_ptr, "wholename", pred_path);
1927 /* -ipath was deprecated (at RMS's request) in favour of
1928 * -iwholename. See the node "GNU Manuals" in standards.texi
1929 * for the rationale for this (basically, GNU prefers the use
1930 * of the phrase "file name" to "path name".
1931 * However, -path is now standardised so I un-deprecated -ipath.
1934 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1936 return insert_path_check (entry, argv, arg_ptr, "ipath", pred_ipath);
1940 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1942 return insert_path_check (entry, argv, arg_ptr, "iwholename", pred_ipath);
1947 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1952 enum permissions_type kind = PERM_EXACT;
1953 struct mode_change *change;
1954 struct predicate *our_pred;
1955 const char *perm_expr;
1957 if (!collect_arg (argv, arg_ptr, &perm_expr))
1960 switch (perm_expr[0])
1964 kind = PERM_AT_LEAST;
1968 case '/': /* GNU extension */
1975 /* For example, '-perm 0644', which is valid and matches
1976 * only files whose mode is exactly 0644.
1984 change = mode_compile (perm_expr + mode_start);
1986 /* Reject invalid modes, or modes of the form +NUMERICMODE.
1987 The latter were formerly accepted as a GNU extension, but that
1988 extension was incompatible with how GNU 'chmod' treats these modes now,
1989 and it would be confusing if 'find' continued to support it. */
1991 || (perm_expr[0] == '+' && '0' <= perm_expr[1] && perm_expr[1] < '8'))
1992 error (EXIT_FAILURE, 0, _("invalid mode %s"),
1993 quotearg_n_style (0, options.err_quoting_style, perm_expr));
1994 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1995 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1998 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
2000 /* The meaning of -perm /000 will change in the future. It
2001 * currently matches no files, but like -perm -000 it should
2004 * Starting in 2005, we used to issue a warning message
2005 * informing the user that the behaviour would change in the
2006 * future. We have now changed the behaviour and issue a
2007 * warning message that the behaviour recently changed.
2010 _("warning: you have specified a mode pattern %s (which is "
2011 "equivalent to /000). The meaning of -perm /000 has now been "
2012 "changed to be consistent with -perm -000; that is, while it "
2013 "used to match no files, it now matches all files."),
2016 kind = PERM_AT_LEAST;
2018 /* The "magic" number below is just the fraction of files on my
2019 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
2020 * Actual totals are 1472 and 1073833.
2022 rate = 0.9986; /* probably matches anything but a broken symlink */
2025 our_pred = insert_primary (entry, perm_expr);
2026 our_pred->est_success_rate = rate;
2027 our_pred->args.perm.kind = kind;
2028 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
2033 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
2035 struct predicate *our_pred;
2040 our_pred = insert_primary_noarg (entry);
2041 /* -print has the side effect of printing. This prevents us
2042 from doing undesired multiple printing when the user has
2043 already specified -print. */
2044 our_pred->side_effects = our_pred->no_default_print = true;
2045 our_pred->need_stat = our_pred->need_type = false;
2046 open_stdout (&our_pred->args.printf_vec);
2051 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
2056 return insert_fprint (entry, NULL);
2060 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
2063 const int saved_argc = *arg_ptr;
2065 if (collect_arg_nonconst (argv, arg_ptr, &format))
2067 struct format_val fmt;
2069 if (insert_fprintf (&fmt, entry, format))
2075 *arg_ptr = saved_argc; /* don't consume the invalid argument. */
2083 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
2085 const char *filename;
2087 int saved_argc = *arg_ptr;
2089 if (collect_arg (argv, arg_ptr, &filename))
2091 if (collect_arg_nonconst (argv, arg_ptr, &format))
2093 struct format_val fmt;
2094 open_output_file (filename, &fmt);
2095 saved_argc = *arg_ptr;
2097 if (insert_fprintf (&fmt, entry, format))
2101 *arg_ptr = saved_argc; /* don't consume the invalid argument. */
2106 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
2108 struct predicate *our_pred;
2113 our_pred = insert_primary_noarg (entry);
2114 if (options.do_dir_first == false)
2115 our_pred->need_stat = our_pred->need_type = false;
2116 /* -prune has a side effect that it does not descend into
2117 the current directory. */
2118 our_pred->side_effects = true;
2119 our_pred->no_default_print = false;
2124 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
2126 struct predicate *our_pred = insert_primary_noarg (entry);
2129 our_pred->need_stat = our_pred->need_type = false;
2130 our_pred->side_effects = true; /* Exiting is a side effect... */
2131 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
2132 our_pred->est_success_rate = 1.0f;
2138 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
2140 const char *type_name;
2141 if (collect_arg (argv, arg_ptr, &type_name))
2143 /* collect the regex type name */
2144 options.regex_options = get_regex_type (type_name);
2145 return parse_noop (entry, argv, arg_ptr);
2152 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
2154 return insert_regex (argv, arg_ptr, entry, options.regex_options);
2158 insert_regex (char **argv,
2160 const struct parser_table *entry,
2164 if (collect_arg (argv, arg_ptr, &rx))
2166 struct re_pattern_buffer *re;
2167 const char *error_message;
2168 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex, rx);
2169 our_pred->need_stat = our_pred->need_type = false;
2170 re = xmalloc (sizeof (struct re_pattern_buffer));
2171 our_pred->args.regex = re;
2172 re->allocated = 100;
2173 re->buffer = xmalloc (re->allocated);
2176 re_set_syntax (regex_options);
2177 re->syntax = regex_options;
2178 re->translate = NULL;
2180 error_message = re_compile_pattern (rx, strlen (rx), re);
2182 error (EXIT_FAILURE, 0, "%s", error_message);
2183 our_pred->est_success_rate = estimate_pattern_match_rate (rx, 1);
2190 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
2192 struct predicate *our_pred;
2196 enum comparison_type c_type;
2201 /* XXX: cannot (yet) convert to ue collect_arg() as this
2202 * function modifies the args in-place.
2204 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2206 arg = argv[*arg_ptr];
2210 error (EXIT_FAILURE, 0, _("invalid null argument to -size"));
2212 suffix = arg[len - 1];
2217 arg[len - 1] = '\0';
2222 arg[len - 1] = '\0';
2227 arg[len - 1] = '\0';
2230 case 'M': /* Megabytes */
2231 blksize = 1024*1024;
2232 arg[len - 1] = '\0';
2235 case 'G': /* Gigabytes */
2236 blksize = 1024*1024*1024;
2237 arg[len - 1] = '\0';
2242 arg[len - 1] = '\0';
2259 error (EXIT_FAILURE, 0,
2260 _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
2262 /* TODO: accept fractional megabytes etc. ? */
2263 if (!get_num (arg, &num, &c_type))
2269 error (EXIT_FAILURE, 0,
2270 _("Invalid argument `%s%s' to -size"),
2274 our_pred = insert_primary (entry, arg);
2275 our_pred->args.size.kind = c_type;
2276 our_pred->args.size.blocksize = blksize;
2277 our_pred->args.size.size = num;
2278 our_pred->need_stat = true;
2279 our_pred->need_type = false;
2281 if (COMP_GT == c_type)
2282 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
2283 else if (COMP_LT == c_type)
2284 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
2286 our_pred->est_success_rate = 0.01;
2294 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2296 /* General idea: stat the file, remember device and inode numbers.
2297 * If a candidate file matches those, it's the same file.
2299 struct predicate *our_pred;
2300 struct stat st, fst;
2302 const char *filename;
2304 set_stat_placeholders (&st);
2305 if (!collect_arg_stat_info (argv, arg_ptr, &st, &filename))
2308 set_stat_placeholders (&fst);
2309 /* POSIX systems are free to re-use the inode number of a deleted
2310 * file. To ensure that we are not fooled by inode reuse, we hold
2311 * the file open if we can. This would prevent the system reusing
2314 fd = -3; /* -3 means uninitialized */
2315 openflags = O_RDONLY;
2317 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2319 if (options.open_nofollow_available)
2321 assert (O_NOFOLLOW != 0);
2322 openflags |= O_NOFOLLOW;
2323 fd = -1; /* safe to open it. */
2327 if (S_ISLNK(st.st_mode))
2329 /* no way to ensure that a symlink will not be followed
2330 * by open(2), so fall back on using lstat(). Accept
2331 * the risk that the named file will be deleted and
2332 * replaced with another having the same inode.
2334 * Avoid opening the file.
2336 fd = -2; /* Do not open it */
2341 /* Race condition here: the file might become a symlink here. */
2347 /* We want to dereference the symlink anyway */
2348 fd = -1; /* safe to open it without O_NOFOLLOW */
2351 assert (fd != -3); /* check we made a decision */
2354 /* Race condition here. The file might become a
2355 * symbolic link in between our call to stat and
2356 * the call to open_cloexec.
2358 fd = open_cloexec (filename, openflags);
2362 /* We stat the file again here to prevent a race condition
2363 * between the first stat and the call to open(2).
2365 if (0 != fstat (fd, &fst))
2367 fatal_target_file_error (errno, filename);
2371 /* Worry about the race condition. If the file became a
2372 * symlink after our first stat and before our call to
2373 * open, fst may contain the stat information for the
2374 * destination of the link, not the link itself.
2376 if ((*options.xstat) (filename, &st))
2377 fatal_target_file_error (errno, filename);
2379 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2380 && (!options.open_nofollow_available))
2382 if (S_ISLNK(st.st_mode))
2384 /* We lost the race. Leave the data in st. The
2385 * file descriptor points to the wrong thing.
2392 /* Several possibilities here:
2393 * 1. There was no race
2394 * 2. The file changed into a symlink after the stat and
2395 * before the open, and then back into a non-symlink
2396 * before the second stat.
2398 * In case (1) there is no problem. In case (2),
2399 * the stat() and fstat() calls will have returned
2400 * different data. O_NOFOLLOW was not available,
2401 * so the open() call may have followed a symlink
2402 * even if the -P option is in effect.
2404 if ((st.st_dev == fst.st_dev)
2405 && (st.st_ino == fst.st_ino))
2407 /* No race. No need to copy fst to st,
2408 * since they should be identical (modulo
2409 * differences in padding bytes).
2414 /* We lost the race. Leave the data in st. The
2415 * file descriptor points to the wrong thing.
2430 our_pred = insert_primary (entry, filename);
2431 our_pred->args.samefileid.ino = st.st_ino;
2432 our_pred->args.samefileid.dev = st.st_dev;
2433 our_pred->args.samefileid.fd = fd;
2434 our_pred->need_type = false;
2435 /* smarter way: compare type and inode number first. */
2436 /* TODO: maybe optimise this away by being optimistic */
2437 our_pred->need_stat = true;
2438 our_pred->est_success_rate = 0.01f;
2443 /* This function is commented out partly because support for it is
2447 parse_show_control_chars (const struct parser_table* entry,
2452 const char *errmsg = _("The -show-control-chars option takes "
2453 "a single argument which "
2454 "must be 'literal' or 'safe'");
2456 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2458 error (EXIT_FAILURE, errno, "%s", errmsg);
2463 arg = argv[*arg_ptr];
2465 if (0 == strcmp ("literal", arg))
2467 options.literal_control_chars = true;
2469 else if (0 == strcmp ("safe", arg))
2471 options.literal_control_chars = false;
2475 error (EXIT_FAILURE, errno, "%s", errmsg);
2478 (*arg_ptr)++; /* consume the argument. */
2486 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2488 struct predicate *our_pred;
2493 our_pred = insert_primary_noarg (entry);
2494 our_pred->need_stat = our_pred->need_type = false;
2495 our_pred->est_success_rate = 1.0f;
2500 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2503 return parse_true (get_noop (), argv, arg_ptr);
2507 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2509 struct predicate *our_pred;
2512 our_pred = insert_primary_noarg (entry);
2513 our_pred->need_stat = our_pred->need_type = false;
2514 our_pred->side_effects = our_pred->no_default_print = false;
2515 if (pred_is(our_pred, pred_executable))
2516 our_pred->est_success_rate = 0.2;
2518 our_pred->est_success_rate = 0.9;
2523 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2525 return insert_type (argv, arg_ptr, entry, pred_type);
2529 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2531 struct predicate *p = insert_num (argv, arg_ptr, entry);
2534 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2539 --*arg_ptr; /* don't consume the invalid argument. */
2545 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2547 struct predicate *our_pred;
2548 struct time_val tval;
2549 const char *offset_str;
2550 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2552 if (collect_arg (argv, arg_ptr, &offset_str))
2554 /* The timespec is actually a delta value, so we use an origin of 0. */
2555 struct timespec zero = {0,0};
2556 if (get_relative_timestamp (offset_str, &tval, zero, DAYSECS, errmsg))
2558 our_pred = insert_primary (entry, offset_str);
2559 our_pred->args.reftime = tval;
2560 our_pred->est_success_rate = estimate_file_age_success_rate (tval.ts.tv_sec / DAYSECS);
2565 error (EXIT_FAILURE, 0,
2566 _("Invalid argument %s to -used"), offset_str);
2573 return false; /* missing argument */
2578 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2580 const char *username;
2582 if (collect_arg (argv, arg_ptr, &username))
2584 struct predicate *our_pred;
2586 struct passwd *cur_pwd = getpwnam (username);
2588 if (cur_pwd != NULL)
2590 uid = cur_pwd->pw_uid;
2594 const size_t uid_len = strspn (username, "0123456789");
2595 if (uid_len && (username[uid_len]==0))
2597 uid = safe_atoi (username, options.err_quoting_style);
2601 /* This is a fatal error (if we just return false, the caller
2602 * will say "invalid argument `username' to -user", which is
2603 * not as helpful). */
2606 error (EXIT_FAILURE, 0,
2607 _("%s is not the name of a known user"),
2608 quotearg_n_style (0, options.err_quoting_style,
2613 error (EXIT_FAILURE, 0,
2614 _("The argument to -user should not be empty"));
2620 our_pred = insert_primary (entry, username);
2621 our_pred->args.uid = uid;
2622 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2629 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2631 bool has_features = false;
2638 display_findutils_version ("find");
2639 printf (_("Features enabled: "));
2642 printf ("CACHE_IDS ");
2643 has_features = true;
2647 has_features = true;
2650 printf ("DEBUG_STAT ");
2651 has_features = true;
2653 #if defined HAVE_STRUCT_DIRENT_D_TYPE
2655 has_features = true;
2657 #if defined O_NOFOLLOW
2658 printf ("O_NOFOLLOW(%s) ",
2659 (options.open_nofollow_available ? "enabled" : "disabled"));
2660 has_features = true;
2662 #if defined LEAF_OPTIMISATION
2663 printf ("LEAF_OPTIMISATION ");
2664 has_features = true;
2666 if (0 < is_selinux_enabled ())
2668 printf ("SELINUX ");
2669 has_features = true;
2673 if (is_fts_enabled (&flags))
2677 has_features = true;
2679 if (flags & FTS_CWDFD)
2685 printf ("FTS_CWDFD");
2686 has_features = true;
2691 printf ("CBO(level=%d) ", (int)(options.optimisation_level));
2692 has_features = true;
2696 /* For the moment, leave this as English in case someone wants
2697 to parse these strings. */
2702 exit (EXIT_SUCCESS);
2706 parse_context (const struct parser_table* entry, char **argv, int *arg_ptr)
2708 struct predicate *our_pred;
2710 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2713 if (is_selinux_enabled () <= 0)
2715 error (EXIT_FAILURE, 0,
2716 _("invalid predicate -context: SELinux is not enabled."));
2719 our_pred = insert_primary (entry, NULL);
2720 our_pred->est_success_rate = 0.01f;
2721 our_pred->need_stat = false;
2723 our_pred->p_name = find_pred_name (pred_context);
2725 our_pred->args.scontext = argv[*arg_ptr];
2732 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2734 options.stay_on_filesystem = true;
2735 return parse_noop (entry, argv, arg_ptr);
2739 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2741 options.ignore_readdir_race = true;
2742 return parse_noop (entry, argv, arg_ptr);
2746 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2748 options.ignore_readdir_race = false;
2749 return parse_noop (entry, argv, arg_ptr);
2753 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2755 options.warnings = true;
2756 return parse_noop (entry, argv, arg_ptr);
2760 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2762 return insert_type (argv, arg_ptr, entry, pred_xtype);
2766 insert_type (char **argv, int *arg_ptr,
2767 const struct parser_table *entry,
2768 PRED_FUNC which_pred)
2771 struct predicate *our_pred;
2773 const char *typeletter;
2775 if (collect_arg (argv, arg_ptr, &typeletter))
2777 if (strlen (typeletter) != 1u)
2779 error (EXIT_FAILURE, 0,
2780 _("Arguments to -type should contain only one letter"));
2785 switch (typeletter[0])
2787 case 'b': /* block special */
2788 type_cell = S_IFBLK;
2791 case 'c': /* character special */
2792 type_cell = S_IFCHR;
2795 case 'd': /* directory */
2796 type_cell = S_IFDIR;
2799 case 'f': /* regular file */
2800 type_cell = S_IFREG;
2803 case 'l': /* symbolic link */
2805 type_cell = S_IFLNK;
2808 error (EXIT_FAILURE, 0,
2809 _("-type %c is not supported because symbolic links "
2810 "are not supported on the platform find was compiled on."),
2814 case 'p': /* pipe */
2816 type_cell = S_IFIFO;
2819 error (EXIT_FAILURE, 0,
2820 _("-type %c is not supported because FIFOs "
2821 "are not supported on the platform find was compiled on."),
2825 case 's': /* socket */
2827 type_cell = S_IFSOCK;
2830 error (EXIT_FAILURE, 0,
2831 _("-type %c is not supported because named sockets "
2832 "are not supported on the platform find was compiled on."),
2836 case 'D': /* Solaris door */
2838 type_cell = S_IFDOOR;
2841 error (EXIT_FAILURE, 0,
2842 _("-type %c is not supported because Solaris doors "
2843 "are not supported on the platform find was compiled on."),
2847 default: /* None of the above ... nuke 'em. */
2848 error (EXIT_FAILURE, 0,
2849 _("Unknown argument to -type: %c"), (*typeletter));
2853 our_pred = insert_primary_withpred (entry, which_pred, typeletter);
2854 our_pred->est_success_rate = rate;
2856 /* Figure out if we will need to stat the file, because if we don't
2857 * need to follow symlinks, we can avoid a stat call by using
2858 * struct dirent.d_type.
2860 if (which_pred == pred_xtype)
2862 our_pred->need_stat = true;
2863 our_pred->need_type = false;
2867 our_pred->need_stat = false; /* struct dirent is enough */
2868 our_pred->need_type = true;
2870 our_pred->args.type = type_cell;
2877 /* Return true if the file accessed via FP is a terminal.
2880 stream_is_tty (FILE *fp)
2882 int fd = fileno (fp);
2885 return false; /* not a valid stream */
2889 return isatty (fd) ? true : false;
2900 check_path_safety (const char *action)
2902 const char *path = getenv ("PATH");
2903 const char *path_separators = ":";
2908 /* $PATH is not set. Assume the OS default is safe.
2909 * That may not be true on Windows, but I'm not aware
2910 * of a way to get Windows to avoid searching the
2911 * current directory anyway.
2916 splitstring (path, path_separators, true, &pos, &len);
2919 if (0 == len || (1 == len && path[pos] == '.'))
2921 /* empty field signifies . */
2922 error (EXIT_FAILURE, 0,
2923 _("The current directory is included in the PATH "
2924 "environment variable, which is insecure in "
2925 "combination with the %s action of find. "
2926 "Please remove the current directory from your "
2927 "$PATH (that is, remove \".\", doubled colons, "
2928 "or leading or trailing colons)"),
2931 else if (path[pos] != '/')
2933 char *relpath = strndup (&path[pos], len);
2934 error (EXIT_FAILURE, 0,
2935 _("The relative path %s is included in the PATH "
2936 "environment variable, which is insecure in "
2937 "combination with the %s action of find. "
2938 "Please remove that entry from $PATH"),
2939 safely_quote_err_filename (0, relpath ? relpath : &path[pos]),
2944 } while (splitstring (path, path_separators, false, &pos, &len));
2948 /* handles both exec and ok predicate */
2950 insert_exec_ok (const char *action,
2951 const struct parser_table *entry,
2955 int start, end; /* Indexes in ARGV of start & end of cmd. */
2956 int i; /* Index into cmd args */
2957 int saw_braces; /* True if previous arg was '{}'. */
2958 bool allow_plus; /* True if + is a valid terminator */
2959 int brace_count; /* Number of instances of {}. */
2960 const char *brace_arg; /* Which arg did {} appear in? */
2961 PRED_FUNC func = entry->pred_func;
2962 enum BC_INIT_STATUS bcstatus;
2964 struct predicate *our_pred;
2965 struct exec_val *execp; /* Pointer for efficiency. */
2967 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2970 our_pred = insert_primary_withpred (entry, func, "(some -exec* arguments)");
2971 our_pred->side_effects = our_pred->no_default_print = true;
2972 our_pred->need_type = our_pred->need_stat = false;
2974 execp = &our_pred->args.exec_vec;
2975 execp->wd_for_exec = NULL;
2977 if ((func != pred_okdir) && (func != pred_ok))
2980 execp->close_stdin = false;
2985 /* If find reads stdin (i.e. for -ok and similar), close stdin
2986 * in the child to prevent some script from consiming the output
2987 * intended for find.
2989 execp->close_stdin = true;
2993 if ((func == pred_execdir) || (func == pred_okdir))
2995 execp->wd_for_exec = NULL;
2996 options.ignore_readdir_race = false;
2997 check_path_safety (action);
3001 assert (NULL != initial_wd);
3002 execp->wd_for_exec = initial_wd;
3005 our_pred->args.exec_vec.multiple = 0;
3007 /* Count the number of args with path replacements, up until the ';'.
3008 * Also figure out if the command is terminated by ";" or by "+".
3011 for (end = start, saw_braces=0, brace_count=0, brace_arg=NULL;
3013 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
3016 /* For -exec and -execdir, "{} +" can terminate the command. */
3018 && argv[end][0] == '+' && argv[end][1] == 0
3021 our_pred->args.exec_vec.multiple = 1;
3026 if (mbsstr (argv[end], "{}"))
3029 brace_arg = argv[end];
3032 if (0 == end && (func == pred_execdir || func == pred_okdir))
3034 /* The POSIX standard says that {} replacement should
3035 * occur even in the utility name. This is insecure
3036 * since it means we will be executing a command whose
3037 * name is chosen according to whatever find finds in
3038 * the file system. That can be influenced by an
3039 * attacker. Hence for -execdir and -okdir this is not
3040 * allowed. We can specify this as those options are
3041 * not defined by POSIX.
3043 error (EXIT_FAILURE, 0,
3044 _("You may not use {} within the utility name for "
3045 "-execdir and -okdir, because this is a potential "
3046 "security problem."));
3051 /* Fail if no command given or no semicolon found. */
3052 if ((end == start) || (argv[end] == NULL))
3059 if (our_pred->args.exec_vec.multiple)
3062 if (func == pred_execdir)
3067 if (brace_count > 1)
3069 error (EXIT_FAILURE, 0,
3070 _("Only one instance of {} is supported with -exec%s ... +"),
3073 else if (strlen (brace_arg) != 2u)
3075 enum { MsgBufSize = 19 };
3076 char buf[MsgBufSize];
3077 const size_t needed = snprintf (buf, MsgBufSize, "-exec%s ... {} +", suffix);
3078 assert (needed <= MsgBufSize); /* If this assertion fails, correct the value of MsgBufSize. */
3079 error (EXIT_FAILURE, 0,
3080 _("In %s the %s must appear by itself, but you specified %s"),
3081 quotearg_n_style (0, options.err_quoting_style, buf),
3082 quotearg_n_style (1, options.err_quoting_style, "{}"),
3083 quotearg_n_style (2, options.err_quoting_style, brace_arg));
3087 /* We use a switch statement here so that the compiler warns us when
3088 * we forget to handle a newly invented enum value.
3090 * Like xargs, we allow 2KiB of headroom for the launched utility to
3091 * export its own environment variables before calling something
3094 bcstatus = bc_init_controlinfo (&execp->ctl, 2048u);
3097 case BC_INIT_ENV_TOO_BIG:
3098 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
3099 error (EXIT_FAILURE, 0,
3100 _("The environment is too large for exec()."));
3103 /* Good news. Carry on. */
3106 bc_use_sensible_arg_max (&execp->ctl);
3109 execp->ctl.exec_callback = launch;
3111 if (our_pred->args.exec_vec.multiple)
3113 /* "+" terminator, so we can just append our arguments after the
3114 * command and initial arguments.
3116 execp->replace_vec = NULL;
3117 execp->ctl.replace_pat = NULL;
3118 execp->ctl.rplen = 0;
3119 execp->ctl.lines_per_exec = 0; /* no limit */
3120 execp->ctl.args_per_exec = 0; /* no limit */
3122 /* remember how many arguments there are */
3123 execp->ctl.initial_argc = (end-start) - 1;
3125 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
3126 bc_init_state (&execp->ctl, &execp->state, execp);
3128 /* Gather the initial arguments. Skip the {}. */
3129 for (i=start; i<end-1; ++i)
3131 bc_push_arg (&execp->ctl, &execp->state,
3132 argv[i], strlen (argv[i])+1,
3139 /* Semicolon terminator - more than one {} is supported, so we
3140 * have to do brace-replacement.
3142 execp->num_args = end - start;
3144 execp->ctl.replace_pat = "{}";
3145 execp->ctl.rplen = strlen (execp->ctl.replace_pat);
3146 execp->ctl.lines_per_exec = 0; /* no limit */
3147 execp->ctl.args_per_exec = 0; /* no limit */
3148 execp->replace_vec = xmalloc (sizeof(char*)*execp->num_args);
3151 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3152 bc_init_state (&execp->ctl, &execp->state, execp);
3154 /* Remember the (pre-replacement) arguments for later. */
3155 for (i=0; i<execp->num_args; ++i)
3157 execp->replace_vec[i] = argv[i+start];
3161 if (argv[end] == NULL)
3171 /* Get a timestamp and comparison type.
3173 STR is the ASCII representation.
3174 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3175 relative to ORIGIN (usually the current moment or midnight).
3176 Thus the sense of the comparison type appears to be reversed.
3177 Set *COMP_TYPE to the kind of comparison that is requested.
3178 Issue OVERFLOWMESSAGE if overflow occurs.
3179 Return true if all okay, false if input error.
3181 Used by -atime, -ctime and -mtime (parsers) to
3182 get the appropriate information for a time predicate processor. */
3185 get_relative_timestamp (const char *str,
3186 struct time_val *result,
3187 struct timespec origin,
3188 double sec_per_unit,
3189 const char *overflowmessage)
3191 double offset, seconds, nanosec;
3192 static const long nanosec_per_sec = 1000000000;
3194 if (get_comp_type (&str, &result->kind))
3196 /* Invert the sense of the comparison */
3197 switch (result->kind)
3199 case COMP_LT: result->kind = COMP_GT; break;
3200 case COMP_GT: result->kind = COMP_LT; break;
3202 break; /* inversion leaves it unchanged */
3205 /* Convert the ASCII number into floating-point. */
3206 if (xstrtod (str, NULL, &offset, strtod))
3208 /* Separate the floating point number the user specified
3209 * (which is a number of days, or minutes, etc) into an
3210 * integral number of seconds (SECONDS) and a fraction (NANOSEC).
3212 nanosec = modf (offset * sec_per_unit, &seconds);
3213 nanosec *= 1.0e9; /* convert from fractional seconds to ns. */
3214 assert (nanosec < nanosec_per_sec);
3216 /* Perform the subtraction, and then check for overflow.
3217 * On systems where signed aritmetic overflow does not
3218 * wrap, this check may be unreliable. The C standard
3219 * does not require this approach to work, but I am aware
3220 * of no platforms where it fails.
3222 result->ts.tv_sec = origin.tv_sec - seconds;
3223 if ((origin.tv_sec < result->ts.tv_sec) != (seconds < 0))
3225 /* an overflow has occurred. */
3226 error (EXIT_FAILURE, 0, overflowmessage, str);
3229 result->ts.tv_nsec = origin.tv_nsec - nanosec;
3230 if (origin.tv_nsec < nanosec)
3232 /* Perform a carry operation */
3233 result->ts.tv_nsec += nanosec_per_sec;
3234 result->ts.tv_sec -= 1;
3240 /* Conversion from ASCII to double failed. */
3250 /* Insert a time predicate based on the information in ENTRY.
3251 ARGV is a pointer to the argument array.
3252 ARG_PTR is a pointer to an index into the array, incremented if
3255 Return true if input is valid, false if not.
3257 A new predicate node is assigned, along with an argument node
3258 obtained with malloc.
3260 Used by -atime, -ctime, and -mtime parsers. */
3263 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3265 struct predicate *our_pred;
3266 struct time_val tval;
3267 enum comparison_type comp;
3268 const char *timearg, *orig_timearg;
3269 const char *errmsg = _("arithmetic overflow while converting %s "
3270 "days to a number of seconds");
3271 struct timespec origin;
3272 const int saved_argc = *arg_ptr;
3274 if (!collect_arg (argv, arg_ptr, &timearg))
3276 orig_timearg = timearg;
3278 /* Decide the origin by previewing the comparison type. */
3279 origin = options.cur_day_start;
3281 if (get_comp_type (&timearg, &comp))
3283 /* Remember, we invert the sense of the comparison, so this tests
3284 * against COMP_LT instead of COMP_GT...
3286 if (COMP_LT == comp)
3288 uintmax_t expected = origin.tv_sec + (DAYSECS-1);
3289 origin.tv_sec += (DAYSECS-1);
3290 if (origin.tv_sec != expected)
3292 error (EXIT_FAILURE, 0,
3293 _("arithmetic overflow when trying to calculate the end of today"));
3297 /* We discard the value of comp here, as get_relative_timestamp
3298 * will set tval.kind. For that to work, we have to restore
3299 * timearg so that it points to the +/- prefix, if any. get_comp_type()
3300 * will have advanced timearg, so we restore it.
3302 timearg = orig_timearg;
3304 if (!get_relative_timestamp (timearg, &tval, origin, DAYSECS, errmsg))
3306 *arg_ptr = saved_argc; /* don't consume the invalid argument */
3310 our_pred = insert_primary (entry, orig_timearg);
3311 our_pred->args.reftime = tval;
3312 our_pred->est_success_rate = estimate_timestamp_success_rate (tval.ts.tv_sec);
3314 if (options.debug_options & DebugExpressionTree)
3318 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3319 fprintf (stderr, " type: %s %s ",
3320 (tval.kind == COMP_GT) ? "gt" :
3321 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3322 (tval.kind == COMP_GT) ? " >" :
3323 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3324 t = our_pred->args.reftime.ts.tv_sec;
3325 fprintf (stderr, "%ju %s",
3326 (uintmax_t) our_pred->args.reftime.ts.tv_sec,
3328 if (tval.kind == COMP_EQ)
3330 t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
3331 fprintf (stderr, " < %ju %s",
3332 (uintmax_t) t, ctime (&t));
3339 /* Get the comparison type prefix (if any) from a number argument.
3340 The prefix is at *STR.
3341 Set *COMP_TYPE to the kind of comparison that is requested.
3342 Advance *STR beyond any initial comparison prefix.
3344 Return true if all okay, false if input error. */
3346 get_comp_type (const char **str, enum comparison_type *comp_type)
3351 *comp_type = COMP_GT;
3355 *comp_type = COMP_LT;
3359 *comp_type = COMP_EQ;
3369 /* Get a number with comparison information.
3370 The sense of the comparison information is 'normal'; that is,
3371 '+' looks for a count > than the number and '-' less than.
3373 STR is the ASCII representation of the number.
3374 Set *NUM to the number.
3375 Set *COMP_TYPE to the kind of comparison that is requested.
3377 Return true if all okay, false if input error. */
3380 get_num (const char *str,
3382 enum comparison_type *comp_type)
3389 /* Figure out the comparison type if the caller accepts one. */
3392 if (!get_comp_type (&str, comp_type))
3396 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3399 /* Insert a number predicate.
3400 ARGV is a pointer to the argument array.
3401 *ARG_PTR is an index into ARGV, incremented if all went well.
3402 *PRED is the predicate processor to insert.
3404 Return true if input is valid, false if error.
3406 A new predicate node is assigned, along with an argument node
3407 obtained with malloc.
3409 Used by -inum and -links parsers. */
3411 static struct predicate *
3412 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3416 if (collect_arg (argv, arg_ptr, &numstr))
3419 enum comparison_type c_type;
3421 if (get_num (numstr, &num, &c_type))
3423 struct predicate *our_pred = insert_primary (entry, numstr);
3424 our_pred->args.numinfo.kind = c_type;
3425 our_pred->args.numinfo.l_val = num;
3427 if (options.debug_options & DebugExpressionTree)
3429 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3430 fprintf (stderr, " type: %s %s ",
3431 (c_type == COMP_GT) ? "gt" :
3432 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3433 (c_type == COMP_GT) ? " >" :
3434 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3435 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3444 open_output_file (const char *path, struct format_val *p)
3447 p->quote_opts = clone_quoting_options (NULL);
3449 if (!strcmp (path, "/dev/stderr"))
3452 p->filename = _("standard error");
3454 else if (!strcmp (path, "/dev/stdout"))
3457 p->filename = _("standard output");
3461 p->stream = sharefile_fopen (state.shared_files, path);
3464 if (p->stream == NULL)
3466 fatal_nontarget_file_error (errno, path);
3470 p->dest_is_tty = stream_is_tty (p->stream);
3474 open_stdout (struct format_val *p)
3476 open_output_file ("/dev/stdout", p);