Applied patch from Jim Meyering; rename dirfd to dir_fd to avoid shadowing problem
[findutils.git] / find / parser.c
blob246c4cee8b1e77407e7e614d5095ab30c2814885
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #include "defs.h"
22 #include <ctype.h>
23 #include <math.h>
24 #include <assert.h>
25 #include <pwd.h>
26 #include <errno.h>
27 #include <grp.h>
28 #include <fnmatch.h>
29 #include "modechange.h"
30 #include "modetype.h"
31 #include "xstrtol.h"
32 #include "xalloc.h"
33 #include "quote.h"
34 #include "quotearg.h"
35 #include "buildcmd.h"
36 #include "nextelem.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
40 #include "xstrtod.h"
41 #include "fts_.h"
42 #include "getdate.h"
43 #include "error.h"
44 #include "findutils-version.h"
46 #include <fcntl.h>
49 /* The presence of unistd.h is assumed by gnulib these days, so we
50 * might as well assume it too.
52 /* We need <unistd.h> for isatty(). */
53 #include <unistd.h>
54 #include <sys/stat.h>
56 #if ENABLE_NLS
57 # include <libintl.h>
58 # define _(Text) gettext (Text)
59 #else
60 # define _(Text) Text
61 #endif
62 #ifdef gettext_noop
63 # define N_(String) gettext_noop (String)
64 #else
65 /* See locate.c for explanation as to why not use (String) */
66 # define N_(String) String
67 #endif
69 #if !defined (isascii) || defined (STDC_HEADERS)
70 #ifdef isascii
71 #undef isascii
72 #endif
73 #define isascii(c) 1
74 #endif
76 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
77 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
79 #ifndef HAVE_ENDGRENT
80 #define endgrent()
81 #endif
82 #ifndef HAVE_ENDPWENT
83 #define endpwent()
84 #endif
86 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
87 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 #if 0
142 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 #endif
144 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
163 static boolean insert_type PARAMS((char **argv, int *arg_ptr,
164 const struct parser_table *entry,
165 PRED_FUNC which_pred));
166 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr,
167 const struct parser_table *entry,
168 int regex_options));
169 static boolean insert_fprintf (struct format_val *vec,
170 const struct parser_table *entry,
171 PRED_FUNC func,
172 const char *format);
174 static struct segment **make_segment PARAMS((struct segment **segment,
175 char *format, int len,
176 int kind, char format_char,
177 char aux_format_char,
178 struct predicate *pred));
179 static boolean insert_exec_ok PARAMS((const char *action,
180 const struct parser_table *entry,
181 int dir_fd,
182 char *argv[],
183 int *arg_ptr));
184 static boolean get_comp_type PARAMS((const char **str,
185 enum comparison_type *comp_type));
186 static boolean get_relative_timestamp PARAMS((const char *str,
187 struct time_val *tval,
188 struct timespec origin,
189 double sec_per_unit,
190 const char *overflowmessage));
191 static boolean get_num PARAMS((const char *str,
192 uintmax_t *num,
193 enum comparison_type *comp_type));
194 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr,
195 const struct parser_table *entry));
196 static void open_output_file (const char *path, struct format_val *p);
197 static void open_stdout (struct format_val *p);
198 static boolean stream_is_tty(FILE *fp);
199 static boolean parse_noop PARAMS((const struct parser_table* entry,
200 char **argv, int *arg_ptr));
202 #define PASTE(x,y) x##y
203 #define STRINGIFY(s) #s
205 #define PARSE_OPTION(what,suffix) \
206 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
208 #define PARSE_POSOPT(what,suffix) \
209 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
211 #define PARSE_TEST(what,suffix) \
212 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
214 #define PARSE_TEST_NP(what,suffix) \
215 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
217 #define PARSE_ACTION(what,suffix) \
218 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
220 #define PARSE_ACTION_NP(what,suffix) \
221 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
223 #define PARSE_PUNCTUATION(what,suffix) \
224 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
227 /* Predicates we cannot handle in the usual way. If you add an entry
228 * to this table, double-check the switch statement in
229 * pred_sanity_check() to make sure that the new case is being
230 * correctly handled.
232 static struct parser_table const parse_entry_newerXY =
234 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
237 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
238 If they are in some Unix versions of find, they are marked `Unix'. */
240 static struct parser_table const parse_table[] =
242 PARSE_PUNCTUATION("!", negate), /* POSIX */
243 PARSE_PUNCTUATION("not", negate), /* GNU */
244 PARSE_PUNCTUATION("(", openparen), /* POSIX */
245 PARSE_PUNCTUATION(")", closeparen), /* POSIX */
246 PARSE_PUNCTUATION(",", comma), /* GNU */
247 PARSE_PUNCTUATION("a", and), /* POSIX */
248 PARSE_TEST ("amin", amin), /* GNU */
249 PARSE_PUNCTUATION("and", and), /* GNU */
250 PARSE_TEST ("anewer", anewer), /* GNU */
251 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
252 PARSE_TEST ("cmin", cmin), /* GNU */
253 PARSE_TEST ("cnewer", cnewer), /* GNU */
254 {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
255 PARSE_POSOPT ("daystart", daystart), /* GNU */
256 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
257 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
258 PARSE_OPTION ("depth", depth), /* POSIX */
259 PARSE_TEST ("empty", empty), /* GNU */
260 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
261 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
262 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
263 PARSE_ACTION ("fls", fls), /* GNU */
264 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
265 PARSE_ACTION ("fprint", fprint), /* GNU */
266 PARSE_ACTION ("fprint0", fprint0), /* GNU */
267 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
268 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
269 PARSE_TEST ("gid", gid), /* GNU */
270 PARSE_TEST ("group", group), /* POSIX */
271 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
272 PARSE_TEST ("ilname", ilname), /* GNU */
273 PARSE_TEST ("iname", iname), /* GNU */
274 PARSE_TEST ("inum", inum), /* GNU, Unix */
275 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
276 PARSE_TEST_NP ("iregex", iregex), /* GNU */
277 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
278 PARSE_TEST ("links", links), /* POSIX */
279 PARSE_TEST ("lname", lname), /* GNU */
280 PARSE_ACTION ("ls", ls), /* GNU, Unix */
281 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
282 PARSE_OPTION ("mindepth", mindepth), /* GNU */
283 PARSE_TEST ("mmin", mmin), /* GNU */
284 PARSE_OPTION ("mount", xdev), /* Unix */
285 {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
286 PARSE_TEST ("name", name),
287 #ifdef UNIMPLEMENTED_UNIX
288 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
289 #endif
290 PARSE_TEST ("newer", newer), /* POSIX */
291 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
292 PARSE_OPTION ("noleaf", noleaf), /* GNU */
293 PARSE_TEST ("nogroup", nogroup), /* POSIX */
294 PARSE_TEST ("nouser", nouser), /* POSIX */
295 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
296 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
297 PARSE_PUNCTUATION("o", or), /* POSIX */
298 PARSE_PUNCTUATION("or", or), /* GNU */
299 PARSE_ACTION ("ok", ok), /* POSIX */
300 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
301 PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
302 PARSE_TEST ("perm", perm), /* POSIX */
303 PARSE_ACTION ("print", print), /* POSIX */
304 PARSE_ACTION ("print0", print0), /* GNU */
305 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
306 PARSE_ACTION ("prune", prune), /* POSIX */
307 PARSE_ACTION ("quit", quit), /* GNU */
308 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
309 PARSE_TEST ("regex", regex), /* GNU */
310 PARSE_OPTION ("regextype", regextype), /* GNU */
311 PARSE_TEST ("samefile", samefile), /* GNU */
312 #if 0
313 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
314 #endif
315 PARSE_TEST ("size", size), /* POSIX */
316 PARSE_TEST ("type", type), /* POSIX */
317 PARSE_TEST ("uid", uid), /* GNU */
318 PARSE_TEST ("used", used), /* GNU */
319 PARSE_TEST ("user", user), /* POSIX */
320 PARSE_OPTION ("warn", warn), /* GNU */
321 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
322 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
323 PARSE_OPTION ("xdev", xdev), /* POSIX */
324 PARSE_TEST ("xtype", xtype), /* GNU */
325 #ifdef UNIMPLEMENTED_UNIX
326 /* It's pretty ugly for find to know about archive formats.
327 Plus what it could do with cpio archives is very limited.
328 Better to leave it out. */
329 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
330 #endif
331 /* gnulib's stdbool.h might have made true and false into macros,
332 * so we can't leave named 'true' and 'false' tokens, so we have
333 * to expeant the relevant entries longhand.
335 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
336 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
337 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
339 /* Various other cases that don't fit neatly into our macro scheme. */
340 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
341 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
342 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
343 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
344 {0, 0, 0, 0}
348 static const char *first_nonoption_arg = NULL;
349 static const struct parser_table *noop = NULL;
352 void
353 check_option_combinations(const struct predicate *p)
355 enum { seen_delete=1u, seen_prune=2u };
356 unsigned int predicates = 0u;
358 while (p)
360 if (p->pred_func == pred_delete)
361 predicates |= seen_delete;
362 else if (p->pred_func == pred_prune)
363 predicates |= seen_prune;
364 p = p->pred_next;
367 if ((predicates & seen_prune) && (predicates & seen_delete))
369 /* The user specified both -delete and -prune. One might test
370 * this by first doing
371 * find dirs .... -prune ..... -print
372 * to fnd out what's going to get deleted, and then switch to
373 * find dirs .... -prune ..... -delete
374 * once we are happy. Unfortunately, the -delete action also
375 * implicitly turns on -depth, which will affect the behaviour
376 * of -prune (in fact, it makes it a no-op). In this case we
377 * would like to prevent unfortunate accidents, so we require
378 * the user to have explicitly used -depth.
380 * We only get away with this because the -delete predicate is not
381 * in POSIX. If it was, we couldn't issue a fatal error here.
383 if (!options.explicit_depth)
385 /* This fixes Savannah bug #20865. */
386 error (1, 0, _("The -delete action atomatically turns on -depth, "
387 "but -prune does nothing when -depth is in effect. "
388 "If you want to carry on anyway, just explicitly use "
389 "the -depth option."));
395 static const struct parser_table*
396 get_noop(void)
398 int i;
399 if (NULL == noop)
401 for (i = 0; parse_table[i].parser_name != 0; i++)
403 if (ARG_NOOP ==parse_table[i].type)
405 noop = &(parse_table[i]);
406 break;
410 return noop;
413 static int
414 get_stat_Ytime(const struct stat *p,
415 char what,
416 struct timespec *ret)
418 switch (what)
420 case 'a':
421 *ret = get_stat_atime(p);
422 return 1;
423 case 'B':
424 *ret = get_stat_birthtime(p);
425 return (ret->tv_nsec >= 0);
426 case 'c':
427 *ret = get_stat_ctime(p);
428 return 1;
429 case 'm':
430 *ret = get_stat_mtime(p);
431 return 1;
432 default:
433 assert (0);
434 abort();
438 void
439 set_follow_state(enum SymlinkOption opt)
441 if (options.debug_options & DebugStat)
443 /* For DebugStat, the choice is made at runtime within debug_stat()
444 * by checking the contents of the symlink_handling variable.
446 options.xstat = debug_stat;
448 else
450 switch (opt)
452 case SYMLINK_ALWAYS_DEREF: /* -L */
453 options.xstat = optionl_stat;
454 options.no_leaf_check = true;
455 break;
457 case SYMLINK_NEVER_DEREF: /* -P (default) */
458 options.xstat = optionp_stat;
459 /* Can't turn no_leaf_check off because the user might have specified
460 * -noleaf anyway
462 break;
464 case SYMLINK_DEREF_ARGSONLY: /* -H */
465 options.xstat = optionh_stat;
466 options.no_leaf_check = true;
469 options.symlink_handling = opt;
473 void
474 parse_begin_user_args (char **args, int argno,
475 const struct predicate *last,
476 const struct predicate *predicates)
478 (void) args;
479 (void) argno;
480 (void) last;
481 (void) predicates;
482 first_nonoption_arg = NULL;
485 void
486 parse_end_user_args (char **args, int argno,
487 const struct predicate *last,
488 const struct predicate *predicates)
490 /* does nothing */
491 (void) args;
492 (void) argno;
493 (void) last;
494 (void) predicates;
498 /* Check that it is legal to fid the given primary in its
499 * position and return it.
501 const struct parser_table*
502 found_parser(const char *original_arg, const struct parser_table *entry)
504 /* If this is an option, but we have already had a
505 * non-option argument, the user may be under the
506 * impression that the behaviour of the option
507 * argument is conditional on some preceding
508 * tests. This might typically be the case with,
509 * for example, -maxdepth.
511 * The options -daystart and -follow are exempt
512 * from this treatment, since their positioning
513 * in the command line does have an effect on
514 * subsequent tests but not previous ones. That
515 * might be intentional on the part of the user.
517 if (entry->type != ARG_POSITIONAL_OPTION)
519 /* Something other than -follow/-daystart.
520 * If this is an option, check if it followed
521 * a non-option and if so, issue a warning.
523 if (entry->type == ARG_OPTION)
525 if ((first_nonoption_arg != NULL)
526 && options.warnings )
528 /* option which follows a non-option */
529 error (0, 0,
530 _("warning: you have specified the %s "
531 "option after a non-option argument %s, "
532 "but options are not positional (%s affects "
533 "tests specified before it as well as those "
534 "specified after it). Please specify options "
535 "before other arguments.\n"),
536 original_arg,
537 first_nonoption_arg,
538 original_arg);
541 else
543 /* Not an option or a positional option,
544 * so remember we've seen it in order to
545 * use it in a possible future warning message.
547 if (first_nonoption_arg == NULL)
549 first_nonoption_arg = original_arg;
554 return entry;
558 /* Return a pointer to the parser function to invoke for predicate
559 SEARCH_NAME.
560 Return NULL if SEARCH_NAME is not a valid predicate name. */
562 const struct parser_table*
563 find_parser (char *search_name)
565 int i;
566 const char *original_arg = search_name;
568 /* Ugh. Special case -newerXY. */
569 if (0 == strncmp("-newer", search_name, 6)
570 && (8 == strlen(search_name)))
572 return found_parser(original_arg, &parse_entry_newerXY);
575 if (*search_name == '-')
576 search_name++;
578 for (i = 0; parse_table[i].parser_name != 0; i++)
580 if (strcmp (parse_table[i].parser_name, search_name) == 0)
582 return found_parser(original_arg, &parse_table[i]);
585 return NULL;
588 static float
589 estimate_file_age_success_rate(float num_days)
591 if (num_days < 0.1)
593 /* Assume 1% of files have timestamps in the future */
594 return 0.01f;
596 else if (num_days < 1)
598 /* Assume 30% of files have timestamps today */
599 return 0.3f;
601 else if (num_days > 100)
603 /* Assume 30% of files are very old */
604 return 0.3f;
606 else
608 /* Assume 39% of files are between 1 and 100 days old. */
609 return 0.39f;
613 static float
614 estimate_timestamp_success_rate(time_t when)
616 /* This calculation ignores the nanoseconds field of the
617 * origin, but I don't think that makes much difference
618 * to our estimate.
620 int num_days = (options.cur_day_start.tv_sec - when) / 86400;
621 return estimate_file_age_success_rate(num_days);
624 /* Collect an argument from the argument list, or
625 * return false.
627 static boolean
628 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
630 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
632 *collected_arg = NULL;
633 return false;
635 else
637 *collected_arg = argv[*arg_ptr];
638 (*arg_ptr)++;
639 return true;
643 static boolean
644 collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
646 const char *filename;
647 if (collect_arg(argv, arg_ptr, &filename))
649 if (0 == (options.xstat)(filename, p))
651 return true;
653 else
655 fatal_file_error(filename);
658 else
660 return false;
664 /* The parsers are responsible to continue scanning ARGV for
665 their arguments. Each parser knows what is and isn't
666 allowed for itself.
668 ARGV is the argument array.
669 *ARG_PTR is the index to start at in ARGV,
670 updated to point beyond the last element consumed.
672 The predicate structure is updated with the new information. */
675 static boolean
676 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
678 struct predicate *our_pred;
680 (void) argv;
681 (void) arg_ptr;
683 our_pred = get_new_pred (entry);
684 our_pred->pred_func = pred_and;
685 our_pred->p_type = BI_OP;
686 our_pred->p_prec = AND_PREC;
687 our_pred->need_stat = our_pred->need_type = false;
688 return true;
691 static boolean
692 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
694 struct stat stat_newer;
696 set_stat_placeholders(&stat_newer);
697 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
699 struct predicate *our_pred = insert_primary (entry);
700 our_pred->args.reftime.xval = XVAL_ATIME;
701 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
702 our_pred->args.reftime.kind = COMP_GT;
703 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
704 return true;
706 return false;
709 boolean
710 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
712 struct predicate *our_pred;
714 (void) argv;
715 (void) arg_ptr;
717 our_pred = get_new_pred (entry);
718 our_pred->pred_func = pred_closeparen;
719 our_pred->p_type = CLOSE_PAREN;
720 our_pred->p_prec = NO_PREC;
721 our_pred->need_stat = our_pred->need_type = false;
722 return true;
725 static boolean
726 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
728 struct stat stat_newer;
730 set_stat_placeholders(&stat_newer);
731 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
733 struct predicate *our_pred = insert_primary (entry);
734 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
735 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
736 our_pred->args.reftime.kind = COMP_GT;
737 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
738 return true;
740 return false;
743 static boolean
744 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
746 struct predicate *our_pred;
748 (void) argv;
749 (void) arg_ptr;
751 our_pred = get_new_pred (entry);
752 our_pred->pred_func = pred_comma;
753 our_pred->p_type = BI_OP;
754 our_pred->p_prec = COMMA_PREC;
755 our_pred->need_stat = our_pred->need_type = false;
756 our_pred->est_success_rate = 1.0f;
757 return true;
760 static boolean
761 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
763 struct tm *local;
765 (void) entry;
766 (void) argv;
767 (void) arg_ptr;
769 if (options.full_days == false)
771 options.cur_day_start.tv_sec += DAYSECS;
772 options.cur_day_start.tv_nsec = 0;
773 local = localtime (&options.cur_day_start.tv_sec);
774 options.cur_day_start.tv_sec -= (local
775 ? (local->tm_sec + local->tm_min * 60
776 + local->tm_hour * 3600)
777 : options.cur_day_start.tv_sec % DAYSECS);
778 options.full_days = true;
780 return true;
783 static boolean
784 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
786 struct predicate *our_pred;
787 (void) argv;
788 (void) arg_ptr;
790 our_pred = insert_primary (entry);
791 our_pred->side_effects = our_pred->no_default_print = true;
792 /* -delete implies -depth */
793 options.do_dir_first = false;
795 /* We do not need stat information because we check for the case
796 * (errno==EISDIR) in pred_delete.
798 our_pred->need_stat = our_pred->need_type = false;
800 our_pred->est_success_rate = 1.0f;
801 return true;
804 static boolean
805 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
807 (void) entry;
808 (void) argv;
810 options.do_dir_first = false;
811 options.explicit_depth = true;
812 return parse_noop(entry, argv, arg_ptr);
815 static boolean
816 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
818 if (options.warnings)
820 error (0, 0,
821 _("warning: the -d option is deprecated; please use "
822 "-depth instead, because the latter is a "
823 "POSIX-compliant feature."));
825 return parse_depth(entry, argv, arg_ptr);
828 static boolean
829 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
831 struct predicate *our_pred;
832 (void) argv;
833 (void) arg_ptr;
835 our_pred = insert_primary (entry);
836 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
837 return true;
840 static boolean
841 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
843 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
846 static boolean
847 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
849 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
852 static boolean
853 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
855 struct predicate *our_pred;
857 (void) argv;
858 (void) arg_ptr;
860 our_pred = insert_primary (entry);
861 our_pred->need_stat = our_pred->need_type = false;
862 our_pred->side_effects = our_pred->no_default_print = false;
863 our_pred->est_success_rate = 0.0f;
864 return true;
867 static boolean
868 insert_fls (const struct parser_table* entry, const char *filename)
870 struct predicate *our_pred = insert_primary (entry);
871 if (filename)
872 open_output_file (filename, &our_pred->args.printf_vec);
873 else
874 open_stdout (&our_pred->args.printf_vec);
875 our_pred->side_effects = our_pred->no_default_print = true;
876 our_pred->est_success_rate = 1.0f;
877 return true;
881 static boolean
882 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
884 const char *filename;
885 return collect_arg(argv, arg_ptr, &filename)
886 && insert_fls(entry, filename);
889 static boolean
890 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
892 set_follow_state(SYMLINK_ALWAYS_DEREF);
893 return parse_noop(entry, argv, arg_ptr);
896 static boolean
897 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
899 struct predicate *our_pred;
900 const char *filename;
901 if (collect_arg(argv, arg_ptr, &filename))
903 our_pred = insert_primary (entry);
904 open_output_file (filename, &our_pred->args.printf_vec);
905 our_pred->side_effects = our_pred->no_default_print = true;
906 our_pred->need_stat = our_pred->need_type = false;
907 our_pred->est_success_rate = 1.0f;
908 return true;
910 else
912 return false;
916 static boolean
917 insert_fprint(const struct parser_table* entry, const char *filename)
919 struct predicate *our_pred = insert_primary (entry);
920 if (filename)
921 open_output_file (filename, &our_pred->args.printf_vec);
922 else
923 open_stdout (&our_pred->args.printf_vec);
924 our_pred->side_effects = our_pred->no_default_print = true;
925 our_pred->need_stat = our_pred->need_type = false;
926 our_pred->est_success_rate = 1.0f;
927 return true;
931 static boolean
932 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
934 const char *filename;
935 if (collect_arg(argv, arg_ptr, &filename))
936 return insert_fprint(entry, filename);
937 else
938 return false;
941 static float estimate_fstype_success_rate(const char *fsname)
943 struct stat dir_stat;
944 const char *dir = "/";
945 if (0 == stat(dir, &dir_stat))
947 const char *fstype = filesystem_type(&dir_stat, dir);
948 /* Assume most files are on the same file system type as the root fs. */
949 if (0 == strcmp(fsname, fstype))
950 return 0.7f;
951 else
952 return 0.3f;
954 return 1.0f;
958 static boolean
959 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
961 const char *typename;
962 if (collect_arg(argv, arg_ptr, &typename))
964 struct predicate *our_pred = insert_primary (entry);
965 our_pred->args.str = typename;
967 /* This is an expensive operation, so although there are
968 * circumstances where it is selective, we ignore this fact
969 * because we probably don't want to promote this test to the
970 * front anyway.
972 our_pred->est_success_rate = estimate_fstype_success_rate(typename);
973 return true;
975 else
977 return false;
981 static boolean
982 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
984 struct predicate *p = insert_num (argv, arg_ptr, entry);
985 if (p)
987 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
988 return true;
990 else
992 return false;
997 static int
998 safe_atoi (const char *s)
1000 long lval;
1001 char *end;
1003 errno = 0;
1004 lval = strtol(s, &end, 10);
1005 if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
1007 /* max/min possible value, or an error. */
1008 if (errno == ERANGE)
1010 /* too big, or too small. */
1011 error(1, errno, "%s", s);
1013 else
1015 /* not a valid number */
1016 error(1, errno, "%s", s);
1018 /* Otherwise, we do a range chack against INT_MAX and INT_MIN
1019 * below.
1023 if (lval > INT_MAX || lval < INT_MIN)
1025 /* The number was in range for long, but not int. */
1026 errno = ERANGE;
1027 error(1, errno, "%s", s);
1029 else if (*end)
1031 error(1, errno, "Unexpected suffix %s on %s",
1032 quotearg_n_style(0, options.err_quoting_style, end),
1033 quotearg_n_style(1, options.err_quoting_style, s));
1035 else if (end == s)
1037 error(1, errno, "Expected an integer: %s",
1038 quotearg_n_style(0, options.err_quoting_style, s));
1040 return (int)lval;
1044 static boolean
1045 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
1047 const char *groupname;
1049 if (collect_arg(argv, arg_ptr, &groupname))
1051 gid_t gid;
1052 struct predicate *our_pred;
1053 struct group *cur_gr = getgrnam(groupname);
1054 endgrent();
1055 if (cur_gr)
1057 gid = cur_gr->gr_gid;
1059 else
1061 const int gid_len = strspn (groupname, "0123456789");
1062 if (gid_len)
1064 if (groupname[gid_len] == 0)
1066 gid = safe_atoi (groupname);
1068 else
1070 /* XXX: no test in test suite for this */
1071 error(1, 0, _("%s is not the name of an existing group and"
1072 " it does not look like a numeric group ID "
1073 "because it has the unexpected suffix %s"),
1074 quotearg_n_style(0, options.err_quoting_style, groupname),
1075 quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
1076 return false;
1079 else
1081 if (*groupname)
1083 /* XXX: no test in test suite for this */
1084 error(1, 0, _("%s is not the name of an existing group"),
1085 quotearg_n_style(0, options.err_quoting_style, groupname));
1087 else
1089 error(1, 0, _("argument to -group is empty, but should be a group name"));
1091 return false;
1094 our_pred = insert_primary (entry);
1095 our_pred->args.gid = gid;
1096 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1097 return true;
1099 return false;
1102 static boolean
1103 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
1105 (void) entry;
1106 (void) argv;
1107 (void) arg_ptr;
1109 usage(stdout, 0, NULL);
1110 puts (_("\n\
1111 default path is the current directory; default expression is -print\n\
1112 expression may consist of: operators, options, tests, and actions:\n"));
1113 puts (_("\
1114 operators (decreasing precedence; -and is implicit where no others are given):\n\
1115 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
1116 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1117 puts (_("\
1118 positional options (always true): -daystart -follow -regextype\n\n\
1119 normal options (always true, specified before other expressions):\n\
1120 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1121 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1122 puts (_("\
1123 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1124 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1125 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1126 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1127 puts (_("\
1128 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
1129 -readable -writable -executable\n\
1130 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1131 -used N -user NAME -xtype [bcdpfls]\n"));
1132 puts (_("\
1133 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1134 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1135 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1136 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1137 "));
1138 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1139 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1140 email to <bug-findutils@gnu.org>."));
1141 exit (0);
1144 static float
1145 estimate_pattern_match_rate(const char *pattern, int is_regex)
1147 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1149 /* A wildcard; assume the pattern matches most files. */
1150 return 0.8f;
1152 else
1154 return 0.1f;
1158 static boolean
1159 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1161 const char *name;
1162 if (collect_arg(argv, arg_ptr, &name))
1164 struct predicate *our_pred = insert_primary (entry);
1165 our_pred->args.str = name;
1166 /* Use the generic glob pattern estimator to figure out how many
1167 * links will match, but bear in mind that most files won't be links.
1169 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1170 return true;
1172 else
1174 return false;
1179 /* sanity check the fnmatch() function to make sure that case folding
1180 * is supported (as opposed to just having the flag ignored).
1182 static boolean
1183 fnmatch_sanitycheck(void)
1185 static boolean checked = false;
1186 if (!checked)
1188 if (0 != fnmatch("foo", "foo", 0)
1189 || 0 == fnmatch("Foo", "foo", 0)
1190 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1192 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1193 return false;
1195 checked = true;
1197 return checked;
1201 static boolean
1202 check_name_arg(const char *pred, const char *arg)
1204 if (options.warnings && strchr(arg, '/'))
1206 error(0, 0,_("warning: Unix filenames usually don't contain slashes "
1207 "(though pathnames do). That means that '%s %s' will "
1208 "probably evaluate to false all the time on this system. "
1209 "You might find the '-wholename' test more useful, or "
1210 "perhaps '-samefile'. Alternatively, if you are using "
1211 "GNU grep, you could "
1212 "use 'find ... -print0 | grep -FzZ %s'."),
1213 pred,
1214 safely_quote_err_filename(0, arg),
1215 safely_quote_err_filename(1, arg));
1217 return true; /* allow it anyway */
1222 static boolean
1223 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1225 const char *name;
1226 fnmatch_sanitycheck();
1227 if (collect_arg(argv, arg_ptr, &name))
1229 if (check_name_arg("-iname", name))
1231 struct predicate *our_pred = insert_primary (entry);
1232 our_pred->need_stat = our_pred->need_type = false;
1233 our_pred->args.str = name;
1234 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1235 return true;
1238 return false;
1241 static boolean
1242 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1244 struct predicate *p = insert_num (argv, arg_ptr, entry);
1245 if (p)
1247 /* inode number is exact match only, so very low proportions of
1248 * files match
1250 p->est_success_rate = 1e-6;
1251 return true;
1253 else
1255 return false;
1259 /* -ipath is deprecated (at RMS's request) in favour of
1260 * -iwholename. See the node "GNU Manuals" in standards.texi
1261 * for the rationale for this (basically, GNU prefers the use
1262 * of the phrase "file name" to "path name"
1264 static boolean
1265 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1267 const char *name;
1269 fnmatch_sanitycheck ();
1270 if (collect_arg (argv, arg_ptr, &name))
1272 struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
1273 our_pred->need_stat = our_pred->need_type = false;
1274 our_pred->args.str = name;
1275 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1276 return true;
1278 return false;
1281 static boolean
1282 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1284 return parse_ipath (entry, argv, arg_ptr);
1287 static boolean
1288 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1290 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1293 static boolean
1294 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1296 struct predicate *p = insert_num (argv, arg_ptr, entry);
1297 if (p)
1299 if (p->args.numinfo.l_val == 1)
1300 p->est_success_rate = 0.99;
1301 else if (p->args.numinfo.l_val == 2)
1302 p->est_success_rate = 0.01;
1303 else
1304 p->est_success_rate = 1e-3;
1305 return true;
1307 else
1309 return false;
1313 static boolean
1314 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1316 const char *name;
1317 fnmatch_sanitycheck();
1318 if (collect_arg(argv, arg_ptr, &name))
1320 struct predicate *our_pred = insert_primary (entry);
1321 our_pred->args.str = name;
1322 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1323 return true;
1325 return false;
1328 static boolean
1329 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1331 (void) &argv;
1332 (void) &arg_ptr;
1333 return insert_fls(entry, NULL);
1336 static boolean
1337 insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
1338 int *limitptr)
1340 const char *depthstr;
1341 int depth_len;
1342 const char *predicate = argv[(*arg_ptr)-1];
1343 if (collect_arg(argv, arg_ptr, &depthstr))
1345 depth_len = strspn (depthstr, "0123456789");
1346 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1348 (*limitptr) = safe_atoi (depthstr);
1349 if (*limitptr >= 0)
1351 return parse_noop(entry, argv, arg_ptr);
1354 error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
1355 predicate,
1356 quotearg_n_style(0, options.err_quoting_style, depthstr));
1357 return false;
1359 /* missing argument */
1360 return false;
1364 static boolean
1365 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1367 return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
1370 static boolean
1371 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1373 return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
1377 static boolean
1378 do_parse_xmin (const struct parser_table* entry,
1379 char **argv,
1380 int *arg_ptr,
1381 enum xval xv)
1383 const char *minutes;
1385 if (collect_arg(argv, arg_ptr, &minutes))
1387 struct time_val tval;
1388 tval.xval = xv;
1389 struct timespec origin = options.cur_day_start;
1390 origin.tv_sec += DAYSECS;
1391 if (get_relative_timestamp(minutes, &tval, origin, 60,
1392 "arithmetic overflow while converting %s "
1393 "minutes to a number of seconds"))
1395 struct predicate *our_pred = insert_primary (entry);
1396 our_pred->args.reftime = tval;
1397 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1398 return true;
1401 return false;
1403 static boolean
1404 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1406 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1409 static boolean
1410 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1412 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1416 static boolean
1417 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1419 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1422 static boolean
1423 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1425 const char *name;
1426 if (collect_arg(argv, arg_ptr, &name))
1428 fnmatch_sanitycheck();
1429 if (check_name_arg("-name", name))
1431 struct predicate *our_pred = insert_primary (entry);
1432 our_pred->need_stat = our_pred->need_type = false;
1433 our_pred->args.str = name;
1434 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1435 return true;
1438 return false;
1441 static boolean
1442 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1444 struct predicate *our_pred;
1446 (void) &argv;
1447 (void) &arg_ptr;
1449 our_pred = get_new_pred_chk_op (entry);
1450 our_pred->pred_func = pred_negate;
1451 our_pred->p_type = UNI_OP;
1452 our_pred->p_prec = NEGATE_PREC;
1453 our_pred->need_stat = our_pred->need_type = false;
1454 return true;
1457 static boolean
1458 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1460 struct predicate *our_pred;
1461 struct stat stat_newer;
1463 set_stat_placeholders(&stat_newer);
1464 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
1466 our_pred = insert_primary (entry);
1467 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1468 our_pred->args.reftime.xval = XVAL_MTIME;
1469 our_pred->args.reftime.kind = COMP_GT;
1470 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1471 return true;
1473 return false;
1477 static boolean
1478 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1480 (void) argv;
1481 (void) arg_ptr;
1483 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1485 return false;
1487 else if (8u != strlen(argv[*arg_ptr]))
1489 return false;
1491 else
1493 char x, y;
1494 const char validchars[] = "aBcmt";
1496 assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
1497 x = argv[*arg_ptr][6];
1498 y = argv[*arg_ptr][7];
1501 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1502 if ('B' == x || 'B' == y)
1504 error(0, 0,
1505 _("This system does not provide a way to find the birth time of a file."));
1506 return 0;
1508 #endif
1510 /* -newertY (for any Y) is invalid. */
1511 if (x == 't'
1512 || 0 == strchr(validchars, x)
1513 || 0 == strchr( validchars, y))
1515 return false;
1517 else
1519 struct predicate *our_pred;
1521 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1522 * past the test name (for most other tests, this is already done)
1524 (*arg_ptr)++;
1526 our_pred = insert_primary (entry);
1529 switch (x)
1531 case 'a':
1532 our_pred->args.reftime.xval = XVAL_ATIME;
1533 break;
1534 case 'B':
1535 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1536 break;
1537 case 'c':
1538 our_pred->args.reftime.xval = XVAL_CTIME;
1539 break;
1540 case 'm':
1541 our_pred->args.reftime.xval = XVAL_MTIME;
1542 break;
1543 default:
1544 assert (strchr(validchars, x));
1545 assert (0);
1548 if ('t' == y)
1550 if (!get_date(&our_pred->args.reftime.ts,
1551 argv[*arg_ptr],
1552 &options.start_time))
1554 error(1, 0,
1555 _("I cannot figure out how to interpret %s as a date or time"),
1556 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1559 else
1561 struct stat stat_newer;
1563 /* Stat the named file. */
1564 set_stat_placeholders(&stat_newer);
1565 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1566 fatal_file_error(argv[*arg_ptr]);
1568 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1570 /* We cannot extract a timestamp from the struct stat. */
1571 error(1, 0, _("Cannot obtain birth time of file %s"),
1572 safely_quote_err_filename(0, argv[*arg_ptr]));
1575 our_pred->args.reftime.kind = COMP_GT;
1576 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1577 (*arg_ptr)++;
1579 assert (our_pred->pred_func != NULL);
1580 assert (our_pred->pred_func == pred_newerXY);
1581 assert (our_pred->need_stat);
1582 return true;
1588 static boolean
1589 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1591 options.no_leaf_check = true;
1592 return parse_noop(entry, argv, arg_ptr);
1595 #ifdef CACHE_IDS
1596 /* Arbitrary amount by which to increase size
1597 of `uid_unused' and `gid_unused'. */
1598 #define ALLOC_STEP 2048
1600 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1601 char *uid_unused = NULL;
1603 /* Number of elements in `uid_unused'. */
1604 unsigned uid_allocated;
1606 /* Similar for GIDs and group entries. */
1607 char *gid_unused = NULL;
1608 unsigned gid_allocated;
1609 #endif
1611 static boolean
1612 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1614 struct predicate *our_pred;
1616 (void) &argv;
1617 (void) &arg_ptr;
1619 our_pred = insert_primary (entry);
1620 our_pred->est_success_rate = 1e-4;
1621 #ifdef CACHE_IDS
1622 if (gid_unused == NULL)
1624 struct group *gr;
1626 gid_allocated = ALLOC_STEP;
1627 gid_unused = xmalloc (gid_allocated);
1628 memset (gid_unused, 1, gid_allocated);
1629 setgrent ();
1630 while ((gr = getgrent ()) != NULL)
1632 if ((unsigned) gr->gr_gid >= gid_allocated)
1634 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1635 gid_unused = xrealloc (gid_unused, new_allocated);
1636 memset (gid_unused + gid_allocated, 1,
1637 new_allocated - gid_allocated);
1638 gid_allocated = new_allocated;
1640 gid_unused[(unsigned) gr->gr_gid] = 0;
1642 endgrent ();
1644 #endif
1645 return true;
1648 static boolean
1649 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1651 struct predicate *our_pred;
1652 (void) argv;
1653 (void) arg_ptr;
1656 our_pred = insert_primary (entry);
1657 our_pred->est_success_rate = 1e-3;
1658 #ifdef CACHE_IDS
1659 if (uid_unused == NULL)
1661 struct passwd *pw;
1663 uid_allocated = ALLOC_STEP;
1664 uid_unused = xmalloc (uid_allocated);
1665 memset (uid_unused, 1, uid_allocated);
1666 setpwent ();
1667 while ((pw = getpwent ()) != NULL)
1669 if ((unsigned) pw->pw_uid >= uid_allocated)
1671 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1672 uid_unused = xrealloc (uid_unused, new_allocated);
1673 memset (uid_unused + uid_allocated, 1,
1674 new_allocated - uid_allocated);
1675 uid_allocated = new_allocated;
1677 uid_unused[(unsigned) pw->pw_uid] = 0;
1679 endpwent ();
1681 #endif
1682 return true;
1685 static boolean
1686 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1688 options.warnings = false;
1689 return parse_noop(entry, argv, arg_ptr);
1692 static boolean
1693 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1695 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1698 static boolean
1699 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1701 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1704 boolean
1705 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1707 struct predicate *our_pred;
1709 (void) argv;
1710 (void) arg_ptr;
1712 our_pred = get_new_pred_chk_op (entry);
1713 our_pred->pred_func = pred_openparen;
1714 our_pred->p_type = OPEN_PAREN;
1715 our_pred->p_prec = NO_PREC;
1716 our_pred->need_stat = our_pred->need_type = false;
1717 return true;
1720 static boolean
1721 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1723 struct predicate *our_pred;
1725 (void) argv;
1726 (void) arg_ptr;
1728 our_pred = get_new_pred (entry);
1729 our_pred->pred_func = pred_or;
1730 our_pred->p_type = BI_OP;
1731 our_pred->p_prec = OR_PREC;
1732 our_pred->need_stat = our_pred->need_type = false;
1733 return true;
1736 /* For some time, -path was deprecated (at RMS's request) in favour of
1737 * -iwholename. See the node "GNU Manuals" in standards.texi for the
1738 * rationale for this (basically, GNU prefers the use of the phrase
1739 * "file name" to "path name".
1741 * We do not issue a warning that this usage is deprecated
1742 * since
1743 * (a) HPUX find supports this predicate also and
1744 * (b) it will soon be in POSIX anyway.
1746 static boolean
1747 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1749 const char *name;
1750 if (collect_arg(argv, arg_ptr, &name))
1752 struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
1753 our_pred->need_stat = our_pred->need_type = false;
1754 our_pred->args.str = name;
1755 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1756 return true;
1758 return false;
1761 static boolean
1762 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1764 return parse_path (entry, argv, arg_ptr);
1767 static void
1768 non_posix_mode(const char *mode)
1770 if (options.posixly_correct)
1772 error (1, 0, _("Mode %s is not valid when POSIXLY_CORRECT is on."),
1773 quotearg_n_style(0, options.err_quoting_style, mode));
1778 static boolean
1779 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1781 mode_t perm_val[2];
1782 float rate;
1783 int mode_start = 0;
1784 boolean havekind = false;
1785 enum permissions_type kind = PERM_EXACT;
1786 struct mode_change *change = NULL;
1787 struct predicate *our_pred;
1788 const char *perm_expr;
1790 if (!collect_arg(argv, arg_ptr, &perm_expr))
1791 return false;
1793 switch (perm_expr[0])
1795 case '-':
1796 mode_start = 1;
1797 kind = PERM_AT_LEAST;
1798 havekind = true;
1799 rate = 0.2;
1800 break;
1802 case '+':
1803 change = mode_compile (perm_expr);
1804 if (NULL == change)
1806 /* Most likely the caller is an old script that is still
1807 * using the obsolete GNU syntax '-perm +MODE'. This old
1808 * syntax was withdrawn in favor of '-perm /MODE' because
1809 * it is incompatible with POSIX in some cases, but we
1810 * still support uses of it that are not incompatible with
1811 * POSIX.
1813 * Example: POSIXLY_CORRECT=y find -perm +a+x
1815 non_posix_mode(perm_expr);
1817 /* support the previous behaviour. */
1818 mode_start = 1;
1819 kind = PERM_ANY;
1820 rate = 0.3;
1822 else
1824 /* This is a POSIX-compatible usage */
1825 mode_start = 0;
1826 kind = PERM_EXACT;
1827 rate = 0.1;
1829 havekind = true;
1830 break;
1832 case '/': /* GNU extension */
1833 non_posix_mode(perm_expr);
1834 mode_start = 1;
1835 kind = PERM_ANY;
1836 havekind = true;
1837 rate = 0.3;
1838 break;
1840 default:
1841 /* For example, '-perm 0644', which is valid and matches
1842 * only files whose mode is exactly 0644.
1844 mode_start = 0;
1845 kind = PERM_EXACT;
1846 havekind = true;
1847 rate = 0.01;
1848 break;
1851 if (NULL == change)
1853 change = mode_compile (perm_expr + mode_start);
1854 if (NULL == change)
1855 error (1, 0, _("invalid mode %s"),
1856 quotearg_n_style(0, options.err_quoting_style, perm_expr));
1858 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1859 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1860 free (change);
1862 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1864 /* The meaning of -perm /000 will change in the future. It
1865 * currently matches no files, but like -perm -000 it should
1866 * match all files.
1868 * Starting in 2005, we used to issue a warning message
1869 * informing the user that the behaviour would change in the
1870 * future. We have now changed the behaviour and issue a
1871 * warning message that the behaviour recently changed.
1873 error (0, 0,
1874 _("warning: you have specified a mode pattern %s (which is "
1875 "equivalent to /000). The meaning of -perm /000 has now been "
1876 "changed to be consistent with -perm -000; that is, while it "
1877 "used to match no files, it now matches all files."),
1878 perm_expr);
1880 kind = PERM_AT_LEAST;
1881 havekind = true;
1883 /* The "magic" number below is just the fraction of files on my
1884 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1885 * Actual totals are 1472 and 1073833.
1887 rate = 0.9986; /* probably matches anything but a broken symlink */
1890 our_pred = insert_primary (entry);
1891 our_pred->est_success_rate = rate;
1892 if (havekind)
1894 our_pred->args.perm.kind = kind;
1896 else
1899 switch (perm_expr[0])
1901 case '-':
1902 our_pred->args.perm.kind = PERM_AT_LEAST;
1903 break;
1904 case '+':
1905 our_pred->args.perm.kind = PERM_ANY;
1906 break;
1907 default:
1908 our_pred->args.perm.kind = PERM_EXACT;
1909 break;
1912 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1913 return true;
1916 boolean
1917 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1919 struct predicate *our_pred;
1921 (void) argv;
1922 (void) arg_ptr;
1924 our_pred = insert_primary (entry);
1925 /* -print has the side effect of printing. This prevents us
1926 from doing undesired multiple printing when the user has
1927 already specified -print. */
1928 our_pred->side_effects = our_pred->no_default_print = true;
1929 our_pred->need_stat = our_pred->need_type = false;
1930 open_stdout(&our_pred->args.printf_vec);
1931 return true;
1934 static boolean
1935 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1937 return insert_fprint(entry, NULL);
1940 static boolean
1941 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1943 const char *format;
1944 if (collect_arg(argv, arg_ptr, &format))
1946 struct format_val fmt;
1947 open_stdout(&fmt);
1948 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1950 return false;
1953 static boolean
1954 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1956 const char *format, *filename;
1957 if (collect_arg(argv, arg_ptr, &filename))
1959 if (collect_arg(argv, arg_ptr, &format))
1961 struct format_val fmt;
1962 open_output_file (filename, &fmt);
1963 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1966 return false;
1969 static boolean
1970 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1972 struct predicate *our_pred;
1974 (void) argv;
1975 (void) arg_ptr;
1977 our_pred = insert_primary (entry);
1978 our_pred->need_stat = our_pred->need_type = false;
1979 /* -prune has a side effect that it does not descend into
1980 the current directory. */
1981 our_pred->side_effects = true;
1982 our_pred->no_default_print = false;
1983 return true;
1986 static boolean
1987 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1989 struct predicate *our_pred = insert_primary (entry);
1990 (void) argv;
1991 (void) arg_ptr;
1992 our_pred->need_stat = our_pred->need_type = false;
1993 our_pred->side_effects = true; /* Exiting is a side effect... */
1994 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1995 our_pred->est_success_rate = 1.0f;
1996 return true;
2000 static boolean
2001 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
2003 const char *type_name;
2004 if (collect_arg(argv, arg_ptr, &type_name))
2006 /* collect the regex type name */
2007 options.regex_options = get_regex_type(type_name);
2008 return parse_noop(entry, argv, arg_ptr);
2010 return false;
2014 static boolean
2015 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
2017 return insert_regex (argv, arg_ptr, entry, options.regex_options);
2020 static boolean
2021 insert_regex (char **argv,
2022 int *arg_ptr,
2023 const struct parser_table *entry,
2024 int regex_options)
2026 const char *rx;
2027 if (collect_arg(argv, arg_ptr, &rx))
2029 struct re_pattern_buffer *re;
2030 const char *error_message;
2031 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
2032 our_pred->need_stat = our_pred->need_type = false;
2033 re = xmalloc (sizeof (struct re_pattern_buffer));
2034 our_pred->args.regex = re;
2035 re->allocated = 100;
2036 re->buffer = xmalloc (re->allocated);
2037 re->fastmap = NULL;
2039 re_set_syntax(regex_options);
2040 re->syntax = regex_options;
2041 re->translate = NULL;
2043 error_message = re_compile_pattern (rx, strlen(rx), re);
2044 if (error_message)
2045 error (1, 0, "%s", error_message);
2046 our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
2047 return true;
2049 return false;
2052 static boolean
2053 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
2055 struct predicate *our_pred;
2056 uintmax_t num;
2057 char suffix;
2058 enum comparison_type c_type;
2060 int blksize = 512;
2061 int len;
2063 /* XXX: cannot (yet) convert to ue collect_arg() as this
2064 * function modifies the args in-place.
2066 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2067 return false;
2069 len = strlen (argv[*arg_ptr]);
2070 if (len == 0)
2071 error (1, 0, _("invalid null argument to -size"));
2073 suffix = argv[*arg_ptr][len - 1];
2074 switch (suffix)
2076 case 'b':
2077 blksize = 512;
2078 argv[*arg_ptr][len - 1] = '\0';
2079 break;
2081 case 'c':
2082 blksize = 1;
2083 argv[*arg_ptr][len - 1] = '\0';
2084 break;
2086 case 'k':
2087 blksize = 1024;
2088 argv[*arg_ptr][len - 1] = '\0';
2089 break;
2091 case 'M': /* Megabytes */
2092 blksize = 1024*1024;
2093 argv[*arg_ptr][len - 1] = '\0';
2094 break;
2096 case 'G': /* Gigabytes */
2097 blksize = 1024*1024*1024;
2098 argv[*arg_ptr][len - 1] = '\0';
2099 break;
2101 case 'w':
2102 blksize = 2;
2103 argv[*arg_ptr][len - 1] = '\0';
2104 break;
2106 case '0':
2107 case '1':
2108 case '2':
2109 case '3':
2110 case '4':
2111 case '5':
2112 case '6':
2113 case '7':
2114 case '8':
2115 case '9':
2116 break;
2118 default:
2119 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
2121 /* TODO: accept fractional megabytes etc. ? */
2122 if (!get_num (argv[*arg_ptr], &num, &c_type))
2124 error(1, 0,
2125 _("Invalid argument `%s%c' to -size"),
2126 argv[*arg_ptr], (int)suffix);
2127 return false;
2129 our_pred = insert_primary (entry);
2130 our_pred->args.size.kind = c_type;
2131 our_pred->args.size.blocksize = blksize;
2132 our_pred->args.size.size = num;
2133 our_pred->need_stat = true;
2134 our_pred->need_type = false;
2136 if (COMP_GT == c_type)
2137 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
2138 else if (COMP_LT == c_type)
2139 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
2140 else
2141 our_pred->est_success_rate = 0.01;
2143 (*arg_ptr)++;
2144 return true;
2148 static boolean
2149 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2151 /* General idea: stat the file, remember device and inode numbers.
2152 * If a candidate file matches those, it's the same file.
2154 struct predicate *our_pred;
2155 struct stat st, fst;
2156 int fd, openflags;
2158 set_stat_placeholders(&st);
2159 if (!collect_arg_stat_info(argv, arg_ptr, &st))
2160 return false;
2162 set_stat_placeholders(&fst);
2163 /* POSIX systems are free to re-use the inode number of a deleted
2164 * file. To ensure that we are not fooled by inode reuse, we hold
2165 * the file open if we can. This would prevent the system reusing
2166 * the file.
2168 fd = -3; /* means, uninitialised */
2169 openflags = O_RDONLY;
2171 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2173 if (options.open_nofollow_available)
2175 assert (O_NOFOLLOW != 0);
2176 openflags |= O_NOFOLLOW;
2177 fd = -1; /* safe to open it. */
2179 else
2181 if (S_ISLNK(st.st_mode))
2183 /* no way to ensure that a symlink will not be followed
2184 * by open(2), so fall back on using lstat(). Accept
2185 * the risk that the named file will be deleted and
2186 * replaced with another having the same inode.
2188 * Avoid opening the file.
2190 fd = -2; /* Do not open it */
2192 else
2194 fd = -1;
2195 /* Race condition here: the file might become a symlink here. */
2199 else
2201 /* We want to dereference the symlink anyway */
2202 fd = -1; /* safe to open it without O_NOFOLLOW */
2205 assert (fd != -3); /* check we made a decision */
2206 if (fd == -1)
2208 /* Race condition here. The file might become a
2209 * symbolic link in between out call to stat and
2210 * the call to open.
2212 fd = open(argv[*arg_ptr], openflags);
2214 if (fd >= 0)
2216 /* We stat the file again here to prevent a race condition
2217 * between the first stat and the call to open(2).
2219 if (0 != fstat(fd, &fst))
2221 fatal_file_error(argv[*arg_ptr]);
2223 else
2225 /* Worry about the race condition. If the file became a
2226 * symlink after our first stat and before our call to
2227 * open, fst may contain the stat information for the
2228 * destination of the link, not the link itself.
2230 if ((*options.xstat) (argv[*arg_ptr], &st))
2231 fatal_file_error(argv[*arg_ptr]);
2233 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2234 && (!options.open_nofollow_available))
2236 if (S_ISLNK(st.st_mode))
2238 /* We lost the race. Leave the data in st. The
2239 * file descriptor points to the wrong thing.
2241 close(fd);
2242 fd = -1;
2244 else
2246 /* Several possibilities here:
2247 * 1. There was no race
2248 * 2. The file changed into a symlink after the stat and
2249 * before the open, and then back into a non-symlink
2250 * before the second stat.
2252 * In case (1) there is no problem. In case (2),
2253 * the stat() and fstat() calls will have returned
2254 * different data. O_NOFOLLOW was not available,
2255 * so the open() call may have followed a symlink
2256 * even if the -P option is in effect.
2258 if ((st.st_dev == fst.st_dev)
2259 && (st.st_ino == fst.st_ino))
2261 /* No race. No need to copy fst to st,
2262 * since they should be identical (modulo
2263 * differences in padding bytes).
2266 else
2268 /* We lost the race. Leave the data in st. The
2269 * file descriptor points to the wrong thing.
2271 close(fd);
2272 fd = -1;
2276 else
2278 st = fst;
2284 our_pred = insert_primary (entry);
2285 our_pred->args.samefileid.ino = st.st_ino;
2286 our_pred->args.samefileid.dev = st.st_dev;
2287 our_pred->args.samefileid.fd = fd;
2288 our_pred->need_type = false;
2289 our_pred->need_stat = true;
2290 our_pred->est_success_rate = 0.01f;
2291 return true;
2294 #if 0
2295 /* This function is commented out partly because support for it is
2296 * uneven.
2298 static boolean
2299 parse_show_control_chars (const struct parser_table* entry,
2300 char **argv,
2301 int *arg_ptr)
2303 const char *arg;
2304 const char *errmsg = _("The -show-control-chars option takes "
2305 "a single argument which "
2306 "must be 'literal' or 'safe'");
2308 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2310 error (1, errno, "%s", errmsg);
2311 return false;
2313 else
2315 arg = argv[*arg_ptr];
2317 if (0 == strcmp("literal", arg))
2319 options.literal_control_chars = true;
2321 else if (0 == strcmp("safe", arg))
2323 options.literal_control_chars = false;
2325 else
2327 error (1, errno, "%s", errmsg);
2328 return false;
2330 (*arg_ptr)++; /* consume the argument. */
2331 return true;
2334 #endif
2337 static boolean
2338 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2340 struct predicate *our_pred;
2342 (void) argv;
2343 (void) arg_ptr;
2345 our_pred = insert_primary (entry);
2346 our_pred->need_stat = our_pred->need_type = false;
2347 our_pred->est_success_rate = 1.0f;
2348 return true;
2351 static boolean
2352 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2354 (void) entry;
2355 return parse_true(get_noop(), argv, arg_ptr);
2358 static boolean
2359 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2361 struct predicate *our_pred;
2362 (void) argv;
2363 (void) arg_ptr;
2364 our_pred = insert_primary (entry);
2365 our_pred->need_stat = our_pred->need_type = false;
2366 our_pred->side_effects = our_pred->no_default_print = false;
2367 if (pred_is(our_pred, pred_executable))
2368 our_pred->est_success_rate = 0.2;
2369 else
2370 our_pred->est_success_rate = 0.9;
2371 return true;
2374 static boolean
2375 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2377 return insert_type (argv, arg_ptr, entry, pred_type);
2380 static boolean
2381 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2383 struct predicate *p = insert_num (argv, arg_ptr, entry);
2384 if (p)
2386 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2387 return true;
2389 else
2391 return false;
2395 static boolean
2396 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2398 struct predicate *our_pred;
2399 struct time_val tval;
2400 const char *offset_str;
2401 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2403 if (collect_arg(argv, arg_ptr, &offset_str))
2405 /* The timespec is actually a delta value, so we use an origin of 0. */
2406 struct timespec zero = {0,0};
2407 if (get_relative_timestamp(offset_str, &tval, zero, DAYSECS, errmsg))
2409 our_pred = insert_primary (entry);
2410 our_pred->args.reftime = tval;
2411 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2412 return true;
2414 else
2416 error(1, 0, _("Invalid argument %s to -used"), offset_str);
2417 return false;
2420 else
2422 return false; /* missing argument */
2426 static boolean
2427 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2429 const char *username;
2431 if (collect_arg(argv, arg_ptr, &username))
2433 struct predicate *our_pred;
2434 uid_t uid;
2435 struct passwd *cur_pwd = getpwnam(username);
2436 endpwent();
2437 if (cur_pwd != NULL)
2439 uid = cur_pwd->pw_uid;
2441 else
2443 int uid_len = strspn (username, "0123456789");
2444 if (uid_len && (username[uid_len]==0))
2445 uid = safe_atoi (username);
2446 else
2447 return false;
2449 our_pred = insert_primary (entry);
2450 our_pred->args.uid = uid;
2451 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2452 return true;
2454 return false;
2457 static boolean
2458 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2460 int features = 0;
2461 int flags;
2463 (void) argv;
2464 (void) arg_ptr;
2465 (void) entry;
2467 display_findutils_version("find");
2468 printf (_("Features enabled: "));
2470 #if CACHE_IDS
2471 printf("CACHE_IDS ");
2472 ++features;
2473 #endif
2474 #if DEBUG
2475 printf("DEBUG ");
2476 ++features;
2477 #endif
2478 #if DEBUG_STAT
2479 printf("DEBUG_STAT ");
2480 ++features;
2481 #endif
2482 #if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
2483 printf("D_TYPE ");
2484 ++features;
2485 #endif
2486 #if defined O_NOFOLLOW
2487 printf("O_NOFOLLOW(%s) ",
2488 (options.open_nofollow_available ? "enabled" : "disabled"));
2489 ++features;
2490 #endif
2491 #if defined LEAF_OPTIMISATION
2492 printf("LEAF_OPTIMISATION ");
2493 ++features;
2494 #endif
2496 flags = 0;
2497 if (is_fts_enabled(&flags))
2499 int nflags = 0;
2500 printf("FTS(");
2501 ++features;
2503 if (flags & FTS_CWDFD)
2505 if (nflags)
2507 printf(",");
2509 printf("FTS_CWDFD");
2510 ++nflags;
2512 printf(") ");
2515 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2516 ++features;
2518 if (0 == features)
2520 /* For the moment, leave this as English in case someone wants
2521 to parse these strings. */
2522 printf("none");
2524 printf("\n");
2526 exit (0);
2529 static boolean
2530 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2532 options.stay_on_filesystem = true;
2533 return parse_noop(entry, argv, arg_ptr);
2536 static boolean
2537 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2539 options.ignore_readdir_race = true;
2540 return parse_noop(entry, argv, arg_ptr);
2543 static boolean
2544 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2546 options.ignore_readdir_race = false;
2547 return parse_noop(entry, argv, arg_ptr);
2550 static boolean
2551 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2553 options.warnings = true;
2554 return parse_noop(entry, argv, arg_ptr);
2557 static boolean
2558 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2560 return insert_type (argv, arg_ptr, entry, pred_xtype);
2563 static boolean
2564 insert_type (char **argv, int *arg_ptr,
2565 const struct parser_table *entry,
2566 PRED_FUNC which_pred)
2568 mode_t type_cell;
2569 struct predicate *our_pred;
2570 float rate = 0.5;
2571 const char *typeletter;
2573 if (collect_arg(argv, arg_ptr, &typeletter))
2575 if (strlen(typeletter) != 1u)
2577 error(1, 0, _("Arguments to -type should contain only one letter"));
2578 return false;
2581 switch (typeletter[0])
2583 case 'b': /* block special */
2584 type_cell = S_IFBLK;
2585 rate = 0.01f;
2586 break;
2587 case 'c': /* character special */
2588 type_cell = S_IFCHR;
2589 rate = 0.01f;
2590 break;
2591 case 'd': /* directory */
2592 type_cell = S_IFDIR;
2593 rate = 0.4f;
2594 break;
2595 case 'f': /* regular file */
2596 type_cell = S_IFREG;
2597 rate = 0.95f;
2598 break;
2599 #ifdef S_IFLNK
2600 case 'l': /* symbolic link */
2601 type_cell = S_IFLNK;
2602 rate = 0.1f;
2603 break;
2604 #endif
2605 #ifdef S_IFIFO
2606 case 'p': /* pipe */
2607 type_cell = S_IFIFO;
2608 rate = 0.01f;
2609 break;
2610 #endif
2611 #ifdef S_IFSOCK
2612 case 's': /* socket */
2613 type_cell = S_IFSOCK;
2614 rate = 0.01f;
2615 break;
2616 #endif
2617 #ifdef S_IFDOOR
2618 case 'D': /* Solaris door */
2619 type_cell = S_IFDOOR;
2620 rate = 0.01f;
2621 break;
2622 #endif
2623 default: /* None of the above ... nuke 'em. */
2624 error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
2625 return false;
2627 our_pred = insert_primary_withpred (entry, which_pred);
2628 our_pred->est_success_rate = rate;
2630 /* Figure out if we will need to stat the file, because if we don't
2631 * need to follow symlinks, we can avoid a stat call by using
2632 * struct dirent.d_type.
2634 if (which_pred == pred_xtype)
2636 our_pred->need_stat = true;
2637 our_pred->need_type = false;
2639 else
2641 our_pred->need_stat = false; /* struct dirent is enough */
2642 our_pred->need_type = true;
2644 our_pred->args.type = type_cell;
2645 return true;
2647 return false;
2651 /* Return true if the file accessed via FP is a terminal.
2653 static boolean
2654 stream_is_tty(FILE *fp)
2656 int fd = fileno(fp);
2657 if (-1 == fd)
2659 return false; /* not a valid stream */
2661 else
2663 return isatty(fd) ? true : false;
2671 /* XXX: do we need to pass FUNC to this function? */
2672 static boolean
2673 insert_fprintf (struct format_val *vec,
2674 const struct parser_table *entry, PRED_FUNC func,
2675 const char *format_const)
2677 char *format = (char*)format_const; /* XXX: casting away constness */
2678 register char *scan; /* Current address in scanning `format'. */
2679 register char *scan2; /* Address inside of element being scanned. */
2680 struct segment **segmentp; /* Address of current segment. */
2681 struct predicate *our_pred;
2683 our_pred = insert_primary_withpred (entry, func);
2684 our_pred->side_effects = our_pred->no_default_print = true;
2685 our_pred->args.printf_vec = *vec;
2686 our_pred->need_type = false;
2687 our_pred->need_stat = false;
2688 our_pred->p_cost = NeedsNothing;
2690 segmentp = &our_pred->args.printf_vec.segment;
2691 *segmentp = NULL;
2693 for (scan = format; *scan; scan++)
2695 if (*scan == '\\')
2697 scan2 = scan + 1;
2698 if (*scan2 >= '0' && *scan2 <= '7')
2700 register int n, i;
2702 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2703 i++, scan2++)
2704 n = 8 * n + *scan2 - '0';
2705 scan2--;
2706 *scan = n;
2708 else
2710 switch (*scan2)
2712 case 'a':
2713 *scan = 7;
2714 break;
2715 case 'b':
2716 *scan = '\b';
2717 break;
2718 case 'c':
2719 make_segment (segmentp, format, scan - format,
2720 KIND_STOP, 0, 0,
2721 our_pred);
2722 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2723 our_pred->p_cost = NeedsStatInfo;
2724 return true;
2725 case 'f':
2726 *scan = '\f';
2727 break;
2728 case 'n':
2729 *scan = '\n';
2730 break;
2731 case 'r':
2732 *scan = '\r';
2733 break;
2734 case 't':
2735 *scan = '\t';
2736 break;
2737 case 'v':
2738 *scan = '\v';
2739 break;
2740 case '\\':
2741 /* *scan = '\\'; * it already is */
2742 break;
2743 default:
2744 error (0, 0,
2745 _("warning: unrecognized escape `\\%c'"), *scan2);
2746 scan++;
2747 continue;
2750 segmentp = make_segment (segmentp, format, scan - format + 1,
2751 KIND_PLAIN, 0, 0,
2752 our_pred);
2753 format = scan2 + 1; /* Move past the escape. */
2754 scan = scan2; /* Incremented immediately by `for'. */
2756 else if (*scan == '%')
2758 if (scan[1] == 0)
2760 /* Trailing %. We don't like those. */
2761 error (1, 0, _("error: %s at end of format string"), scan);
2763 else if (scan[1] == '%')
2765 segmentp = make_segment (segmentp, format, scan - format + 1,
2766 KIND_PLAIN, 0, 0,
2767 our_pred);
2768 scan++;
2769 format = scan + 1;
2770 continue;
2772 /* Scan past flags, width and precision, to verify kind. */
2773 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2774 /* Do nothing. */ ;
2775 while (ISDIGIT (*scan2))
2776 scan2++;
2777 if (*scan2 == '.')
2778 for (scan2++; ISDIGIT (*scan2); scan2++)
2779 /* Do nothing. */ ;
2780 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2782 segmentp = make_segment (segmentp, format, scan2 - format,
2783 KIND_FORMAT, *scan2, 0,
2784 our_pred);
2785 scan = scan2;
2786 format = scan + 1;
2788 else if (strchr ("ABCT", *scan2) && scan2[1])
2790 segmentp = make_segment (segmentp, format, scan2 - format,
2791 KIND_FORMAT, scan2[0], scan2[1],
2792 our_pred);
2793 scan = scan2 + 1;
2794 format = scan + 1;
2795 continue;
2797 else
2799 /* An unrecognized % escape. Print the char after the %. */
2800 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2801 *scan2);
2802 segmentp = make_segment (segmentp, format, scan - format,
2803 KIND_PLAIN, 0, 0,
2804 our_pred);
2805 format = scan + 1;
2806 continue;
2811 if (scan > format)
2812 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2813 our_pred);
2814 return true;
2817 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2818 from the text in FORMAT, which has length LEN.
2819 Return the address of the `next' pointer of the new segment. */
2821 static struct segment **
2822 make_segment (struct segment **segment,
2823 char *format,
2824 int len,
2825 int kind,
2826 char format_char,
2827 char aux_format_char,
2828 struct predicate *pred)
2830 enum EvaluationCost mycost = NeedsNothing;
2831 char *fmt;
2833 *segment = xmalloc (sizeof (struct segment));
2835 (*segment)->segkind = kind;
2836 (*segment)->format_char[0] = format_char;
2837 (*segment)->format_char[1] = aux_format_char;
2838 (*segment)->next = NULL;
2839 (*segment)->text_len = len;
2841 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2842 strncpy (fmt, format, len);
2843 fmt += len;
2845 switch (kind)
2847 case KIND_PLAIN: /* Plain text string, no % conversion. */
2848 case KIND_STOP: /* Terminate argument, no newline. */
2849 assert (0 == format_char);
2850 assert (0 == aux_format_char);
2851 *fmt = '\0';
2852 if (mycost > pred->p_cost)
2853 pred->p_cost = NeedsNothing;
2854 return &(*segment)->next;
2855 break;
2858 assert (kind == KIND_FORMAT);
2859 switch (format_char)
2861 case 'l': /* object of symlink */
2862 pred->need_stat = true;
2863 mycost = NeedsLinkName;
2864 *fmt++ = 's';
2865 break;
2867 case 'y': /* file type */
2868 pred->need_type = true;
2869 mycost = NeedsType;
2870 *fmt++ = 's';
2871 break;
2873 case 'a': /* atime in `ctime' format */
2874 case 'A': /* atime in user-specified strftime format */
2875 case 'B': /* birth time in user-specified strftime format */
2876 case 'c': /* ctime in `ctime' format */
2877 case 'C': /* ctime in user-specified strftime format */
2878 case 'F': /* file system type */
2879 case 'g': /* group name */
2880 case 'i': /* inode number */
2881 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2882 case 's': /* size in bytes */
2883 case 't': /* mtime in `ctime' format */
2884 case 'T': /* mtime in user-specified strftime format */
2885 case 'u': /* user name */
2886 pred->need_stat = true;
2887 mycost = NeedsStatInfo;
2888 *fmt++ = 's';
2889 break;
2891 case 'S': /* sparseness */
2892 pred->need_stat = true;
2893 mycost = NeedsStatInfo;
2894 *fmt++ = 'g';
2895 break;
2897 case 'Y': /* symlink pointed file type */
2898 pred->need_stat = true;
2899 mycost = NeedsType; /* true for amortised effect */
2900 *fmt++ = 's';
2901 break;
2903 case 'f': /* basename of path */
2904 case 'h': /* leading directories part of path */
2905 case 'p': /* pathname */
2906 case 'P': /* pathname with ARGV element stripped */
2907 *fmt++ = 's';
2908 break;
2910 case 'H': /* ARGV element file was found under */
2911 *fmt++ = 's';
2912 break;
2914 /* Numeric items that one might expect to honour
2915 * #, 0, + flags but which do not.
2917 case 'G': /* GID number */
2918 case 'U': /* UID number */
2919 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2920 case 'D': /* Filesystem device on which the file exits */
2921 case 'k': /* size in 1K blocks */
2922 case 'n': /* number of links */
2923 pred->need_stat = true;
2924 mycost = NeedsStatInfo;
2925 *fmt++ = 's';
2926 break;
2928 /* Numeric items that DO honour #, 0, + flags.
2930 case 'd': /* depth in search tree (0 = ARGV element) */
2931 *fmt++ = 'd';
2932 break;
2934 case 'm': /* mode as octal number (perms only) */
2935 *fmt++ = 'o';
2936 pred->need_stat = true;
2937 mycost = NeedsStatInfo;
2938 break;
2940 case '{':
2941 case '[':
2942 case '(':
2943 error (1, 0,
2944 _("error: the format directive `%%%c' is reserved for future use"),
2945 (int)kind);
2946 /*NOTREACHED*/
2947 break;
2949 *fmt = '\0';
2951 if (mycost > pred->p_cost)
2952 pred->p_cost = mycost;
2953 return &(*segment)->next;
2956 static void
2957 check_path_safety(const char *action, char **argv)
2959 char *s;
2960 const char *path = getenv("PATH");
2961 if (NULL == path)
2963 /* $PATH is not set. Assume the OS default is safe.
2964 * That may not be true on Windows, but I'm not aware
2965 * of a way to get Windows to avoid searching the
2966 * current directory anyway.
2968 return;
2971 (void)argv;
2973 s = next_element(path, 1);
2974 while ((s = next_element ((char *) NULL, 1)) != NULL)
2976 if (0 == strcmp(s, "."))
2978 error(1, 0, _("The current directory is included in the PATH "
2979 "environment variable, which is insecure in "
2980 "combination with the %s action of find. "
2981 "Please remove the current directory from your "
2982 "$PATH (that is, remove \".\" or leading or trailing "
2983 "colons)"),
2984 action);
2986 else if ('/' != s[0])
2988 /* Relative paths are also dangerous in $PATH. */
2989 error(1, 0, _("The relative path %s is included in the PATH "
2990 "environment variable, which is insecure in "
2991 "combination with the %s action of find. "
2992 "Please remove that entry from $PATH"),
2993 safely_quote_err_filename(0, s),
2994 action);
3000 /* handles both exec and ok predicate */
3001 static boolean
3002 new_insert_exec_ok (const char *action,
3003 const struct parser_table *entry,
3004 int dir_fd,
3005 char **argv,
3006 int *arg_ptr)
3008 int start, end; /* Indexes in ARGV of start & end of cmd. */
3009 int i; /* Index into cmd args */
3010 int saw_braces; /* True if previous arg was '{}'. */
3011 boolean allow_plus; /* True if + is a valid terminator */
3012 int brace_count; /* Number of instances of {}. */
3013 PRED_FUNC func = entry->pred_func;
3014 enum BC_INIT_STATUS bcstatus;
3016 struct predicate *our_pred;
3017 struct exec_val *execp; /* Pointer for efficiency. */
3019 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
3020 return false;
3022 our_pred = insert_primary_withpred (entry, func);
3023 our_pred->side_effects = our_pred->no_default_print = true;
3024 our_pred->need_type = our_pred->need_stat = false;
3026 execp = &our_pred->args.exec_vec;
3028 if ((func != pred_okdir) && (func != pred_ok))
3030 allow_plus = true;
3031 execp->close_stdin = false;
3033 else
3035 allow_plus = false;
3036 /* If find reads stdin (i.e. for -ok and similar), close stdin
3037 * in the child to prevent some script from consiming the output
3038 * intended for find.
3040 execp->close_stdin = true;
3044 if ((func == pred_execdir) || (func == pred_okdir))
3046 options.ignore_readdir_race = false;
3047 check_path_safety(action, argv);
3048 execp->use_current_dir = true;
3050 else
3052 execp->use_current_dir = false;
3055 our_pred->args.exec_vec.multiple = 0;
3057 /* Count the number of args with path replacements, up until the ';'.
3058 * Also figure out if the command is terminated by ";" or by "+".
3060 start = *arg_ptr;
3061 for (end = start, saw_braces=0, brace_count=0;
3062 (argv[end] != NULL)
3063 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
3064 end++)
3066 /* For -exec and -execdir, "{} +" can terminate the command. */
3067 if ( allow_plus
3068 && argv[end][0] == '+' && argv[end][1] == 0
3069 && saw_braces)
3071 our_pred->args.exec_vec.multiple = 1;
3072 break;
3075 saw_braces = 0;
3076 if (mbsstr (argv[end], "{}"))
3078 saw_braces = 1;
3079 ++brace_count;
3081 if (0 == end && (func == pred_execdir || func == pred_okdir))
3083 /* The POSIX standard says that {} replacement should
3084 * occur even in the utility name. This is insecure
3085 * since it means we will be executing a command whose
3086 * name is chosen according to whatever find finds in
3087 * the file system. That can be influenced by an
3088 * attacker. Hence for -execdir and -okdir this is not
3089 * allowed. We can specify this as those options are
3090 * not defined by POSIX.
3092 error(1, 0, _("You may not use {} within the utility name for "
3093 "-execdir and -okdir, because this is a potential "
3094 "security problem."));
3099 /* Fail if no command given or no semicolon found. */
3100 if ((end == start) || (argv[end] == NULL))
3102 *arg_ptr = end;
3103 free(our_pred);
3104 return false;
3107 if (our_pred->args.exec_vec.multiple && brace_count > 1)
3110 const char *suffix;
3111 if (func == pred_execdir)
3112 suffix = "dir";
3113 else
3114 suffix = "";
3116 error(1, 0,
3117 _("Only one instance of {} is supported with -exec%s ... +"),
3118 suffix);
3121 /* We use a switch statement here so that the compiler warns us when
3122 * we forget to handle a newly invented enum value.
3124 * Like xargs, we allow 2KiB of headroom for the launched utility to
3125 * export its own environment variables before calling something
3126 * else.
3128 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
3129 switch (bcstatus)
3131 case BC_INIT_ENV_TOO_BIG:
3132 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
3133 error(1, 0,
3134 _("The environment is too large for exec()."));
3135 break;
3136 case BC_INIT_OK:
3137 /* Good news. Carry on. */
3138 break;
3140 bc_use_sensible_arg_max(&execp->ctl);
3143 execp->ctl.exec_callback = launch;
3145 if (our_pred->args.exec_vec.multiple)
3147 /* "+" terminator, so we can just append our arguments after the
3148 * command and initial arguments.
3150 execp->replace_vec = NULL;
3151 execp->ctl.replace_pat = NULL;
3152 execp->ctl.rplen = 0;
3153 execp->ctl.lines_per_exec = 0; /* no limit */
3154 execp->ctl.args_per_exec = 0; /* no limit */
3156 /* remember how many arguments there are */
3157 execp->ctl.initial_argc = (end-start) - 1;
3159 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
3160 bc_init_state(&execp->ctl, &execp->state, execp);
3162 /* Gather the initial arguments. Skip the {}. */
3163 for (i=start; i<end-1; ++i)
3165 bc_push_arg(&execp->ctl, &execp->state,
3166 argv[i], strlen(argv[i])+1,
3167 NULL, 0,
3171 else
3173 /* Semicolon terminator - more than one {} is supported, so we
3174 * have to do brace-replacement.
3176 execp->num_args = end - start;
3178 execp->ctl.replace_pat = "{}";
3179 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
3180 execp->ctl.lines_per_exec = 0; /* no limit */
3181 execp->ctl.args_per_exec = 0; /* no limit */
3182 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
3185 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3186 bc_init_state(&execp->ctl, &execp->state, execp);
3188 /* Remember the (pre-replacement) arguments for later. */
3189 for (i=0; i<execp->num_args; ++i)
3191 execp->replace_vec[i] = argv[i+start];
3195 if (argv[end] == NULL)
3196 *arg_ptr = end;
3197 else
3198 *arg_ptr = end + 1;
3200 return true;
3205 static boolean
3206 insert_exec_ok (const char *action,
3207 const struct parser_table *entry,
3208 int dir_fd,
3209 char **argv,
3210 int *arg_ptr)
3212 return new_insert_exec_ok(action, entry, dir_fd, argv, arg_ptr);
3217 /* Get a timestamp and comparison type.
3219 STR is the ASCII representation.
3220 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3221 relative to ORIGIN (usually the current moment or midnight).
3222 Thus the sense of the comparison type appears to be reversed.
3223 Set *COMP_TYPE to the kind of comparison that is requested.
3224 Issue OVERFLOWMESSAGE if overflow occurs.
3225 Return true if all okay, false if input error.
3227 Used by -atime, -ctime and -mtime (parsers) to
3228 get the appropriate information for a time predicate processor. */
3230 static boolean
3231 get_relative_timestamp (const char *str,
3232 struct time_val *result,
3233 struct timespec origin,
3234 double sec_per_unit,
3235 const char *overflowmessage)
3237 uintmax_t checkval;
3238 double offset, seconds, nanosec;
3240 if (get_comp_type(&str, &result->kind))
3242 /* Invert the sense of the comparison */
3243 switch (result->kind)
3245 case COMP_LT: result->kind = COMP_GT; break;
3246 case COMP_GT: result->kind = COMP_LT; break;
3247 default: break;
3250 /* Convert the ASCII number into floating-point. */
3251 if (xstrtod(str, NULL, &offset, strtod))
3253 /* Separate the floating point number the user specified
3254 * (which is a number of days, or minutes, etc) into an
3255 * integral number of seconds (SECONDS) and a fraction (NANOSEC).
3257 nanosec = modf(offset * sec_per_unit, &seconds);
3258 nanosec *= 1.0e9; /* convert from fractional seconds to ns. */
3260 result->ts.tv_sec = origin.tv_sec - seconds;
3261 result->ts.tv_nsec = origin.tv_nsec - nanosec;
3262 checkval = (uintmax_t)origin.tv_sec - seconds;
3264 if (origin.tv_nsec < nanosec)
3266 /* Perform a carry operation */
3267 result->ts.tv_nsec += 1000000000;
3268 result->ts.tv_sec -= 1;
3269 checkval -= 1;
3271 /* Check for overflow. */
3272 if (checkval != result->ts.tv_sec)
3274 /* an overflow has occurred. */
3275 error (1, 0, overflowmessage, str);
3277 return true;
3279 else
3281 /* Conversion from ASCII to double failed. */
3282 return false;
3285 else
3287 return false;
3291 /* Insert a time predicate based on the information in ENTRY.
3292 ARGV is a pointer to the argument array.
3293 ARG_PTR is a pointer to an index into the array, incremented if
3294 all went well.
3296 Return true if input is valid, false if not.
3298 A new predicate node is assigned, along with an argument node
3299 obtained with malloc.
3301 Used by -atime, -ctime, and -mtime parsers. */
3303 static boolean
3304 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3306 struct predicate *our_pred;
3307 struct time_val tval;
3308 enum comparison_type comp;
3309 const char *timearg, *orig_timearg;
3310 const char *errmsg = "arithmetic overflow while converting %s "
3311 "days to a number of seconds";
3312 struct timespec origin;
3314 if (!collect_arg(argv, arg_ptr, &timearg))
3315 return false;
3316 orig_timearg = timearg;
3318 /* Decide the origin by previewing the comparison type. */
3319 origin = options.cur_day_start;
3321 if (get_comp_type(&timearg, &comp))
3323 /* Remember, we invert the sense of the comparison, so this tests
3324 * against COMP_LT instead of COMP_GT...
3326 if (COMP_LT == comp)
3328 uintmax_t expected = origin.tv_sec + (DAYSECS-1);
3329 origin.tv_sec += (DAYSECS-1);
3330 if (origin.tv_sec != expected)
3332 error(1, 0,
3333 _("arithmetic overflow when trying to calculate the end of today"));
3337 /* We discard the value of comp here, as get_relative_timestamp
3338 * will set tval.kind. For that to work, we have to restore
3339 * timearg so that it points to the +/- prefix, if any. get_comp_type()
3340 * will have advanced timearg, so we restore it.
3342 timearg = orig_timearg;
3344 if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
3345 return false;
3347 our_pred = insert_primary (entry);
3348 our_pred->args.reftime = tval;
3349 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3351 if (options.debug_options & DebugExpressionTree)
3353 time_t t;
3355 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3356 fprintf (stderr, " type: %s %s ",
3357 (tval.kind == COMP_GT) ? "gt" :
3358 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3359 (tval.kind == COMP_GT) ? " >" :
3360 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3361 t = our_pred->args.reftime.ts.tv_sec;
3362 fprintf (stderr, "%ju %s",
3363 (uintmax_t) our_pred->args.reftime.ts.tv_sec,
3364 ctime (&t));
3365 if (tval.kind == COMP_EQ)
3367 t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
3368 fprintf (stderr, " < %ju %s",
3369 (uintmax_t) t, ctime (&t));
3373 return true;
3376 /* Get the comparison type prefix (if any) from a number argument.
3377 The prefix is at *STR.
3378 Set *COMP_TYPE to the kind of comparison that is requested.
3379 Advance *STR beyond any initial comparison prefix.
3381 Return true if all okay, false if input error. */
3382 static boolean
3383 get_comp_type(const char **str, enum comparison_type *comp_type)
3385 switch (**str)
3387 case '+':
3388 *comp_type = COMP_GT;
3389 (*str)++;
3390 break;
3391 case '-':
3392 *comp_type = COMP_LT;
3393 (*str)++;
3394 break;
3395 default:
3396 *comp_type = COMP_EQ;
3397 break;
3399 return true;
3406 /* Get a number with comparison information.
3407 The sense of the comparison information is 'normal'; that is,
3408 '+' looks for a count > than the number and '-' less than.
3410 STR is the ASCII representation of the number.
3411 Set *NUM to the number.
3412 Set *COMP_TYPE to the kind of comparison that is requested.
3414 Return true if all okay, false if input error. */
3416 static boolean
3417 get_num (const char *str,
3418 uintmax_t *num,
3419 enum comparison_type *comp_type)
3421 char *pend;
3423 if (str == NULL)
3424 return false;
3426 /* Figure out the comparison type if the caller accepts one. */
3427 if (comp_type)
3429 if (!get_comp_type(&str, comp_type))
3430 return false;
3433 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3436 /* Insert a number predicate.
3437 ARGV is a pointer to the argument array.
3438 *ARG_PTR is an index into ARGV, incremented if all went well.
3439 *PRED is the predicate processor to insert.
3441 Return true if input is valid, false if error.
3443 A new predicate node is assigned, along with an argument node
3444 obtained with malloc.
3446 Used by -inum and -links parsers. */
3448 static struct predicate *
3449 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3451 const char *numstr;
3453 if (collect_arg(argv, arg_ptr, &numstr))
3455 uintmax_t num;
3456 enum comparison_type c_type;
3458 if (get_num (numstr, &num, &c_type))
3460 struct predicate *our_pred = insert_primary (entry);
3461 our_pred->args.numinfo.kind = c_type;
3462 our_pred->args.numinfo.l_val = num;
3464 if (options.debug_options & DebugExpressionTree)
3466 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3467 fprintf (stderr, " type: %s %s ",
3468 (c_type == COMP_GT) ? "gt" :
3469 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3470 (c_type == COMP_GT) ? " >" :
3471 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3472 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3474 return our_pred;
3477 return NULL;
3480 static void
3481 open_output_file (const char *path, struct format_val *p)
3483 p->segment = NULL;
3484 p->quote_opts = clone_quoting_options (NULL);
3486 if (!strcmp (path, "/dev/stderr"))
3488 p->stream = stderr;
3489 p->filename = _("standard error");
3491 else if (!strcmp (path, "/dev/stdout"))
3493 p->stream = stdout;
3494 p->filename = _("standard output");
3496 else
3498 p->stream = fopen_safer (path, "w");
3499 p->filename = path;
3501 if (p->stream == NULL)
3503 fatal_file_error(path);
3507 p->dest_is_tty = stream_is_tty(p->stream);
3510 static void
3511 open_stdout (struct format_val *p)
3513 open_output_file("/dev/stdout", p);