Correctly detect and diagnose I/O errors in print-related predicates. This fixed...
[findutils.git] / find / parser.c
blobdbc75f586d32b72ce0e73ac6583d998992f1fb00
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 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 2, or (at your option)
8 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, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA.
22 #include "defs.h"
23 #include <ctype.h>
24 #include <math.h>
25 #include <assert.h>
26 #include <pwd.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 "gnulib-version.h"
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #else
49 #include <sys/file.h>
50 #endif
52 /* The presence of unistd.h is assumed by gnulib these days, so we
53 * might as well assume it too.
55 /* We need <unistd.h> for isatty(). */
56 #include <unistd.h>
58 #if ENABLE_NLS
59 # include <libintl.h>
60 # define _(Text) gettext (Text)
61 #else
62 # define _(Text) Text
63 #endif
64 #ifdef gettext_noop
65 # define N_(String) gettext_noop (String)
66 #else
67 /* See locate.c for explanation as to why not use (String) */
68 # define N_(String) String
69 #endif
71 #if !defined (isascii) || defined (STDC_HEADERS)
72 #ifdef isascii
73 #undef isascii
74 #endif
75 #define isascii(c) 1
76 #endif
78 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
79 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
81 #ifndef HAVE_ENDGRENT
82 #define endgrent()
83 #endif
84 #ifndef HAVE_ENDPWENT
85 #define endpwent()
86 #endif
88 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
89 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 #if 0
144 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 #endif
146 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
159 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
162 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
165 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
166 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
167 static boolean insert_fprintf (struct format_val *vec,
168 const struct parser_table *entry,
169 PRED_FUNC func,
170 const char *format);
172 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
173 int kind, char format_char, char aux_format_char,
174 struct predicate *pred));
175 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, int dirfd, char *argv[], int *arg_ptr));
176 static boolean get_comp_type PARAMS((char **str, enum comparison_type *comp_type));
177 static boolean get_relative_timestamp PARAMS((char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
178 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
179 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
180 static void open_output_file (const char *path, struct format_val *p);
181 static void open_stdout (struct format_val *p);
182 static boolean stream_is_tty(FILE *fp);
183 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
185 #define PASTE(x,y) x##y
186 #define STRINGIFY(s) #s
188 #define PARSE_OPTION(what,suffix) \
189 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
191 #define PARSE_POSOPT(what,suffix) \
192 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
194 #define PARSE_TEST(what,suffix) \
195 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
197 #define PARSE_TEST_NP(what,suffix) \
198 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
200 #define PARSE_ACTION(what,suffix) \
201 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
203 #define PARSE_ACTION_NP(what,suffix) \
204 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
206 #define PARSE_PUNCTUATION(what,suffix) \
207 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
210 /* Predicates we cannot handle in the usual way. If you add an entry
211 * to this table, double-check the switch statement in
212 * pred_sanity_check() to make sure that the new case is being
213 * correctly handled.
215 static struct parser_table const parse_entry_newerXY =
217 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
220 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
221 If they are in some Unix versions of find, they are marked `Unix'. */
223 static struct parser_table const parse_table[] =
225 PARSE_PUNCTUATION("!", negate),
226 PARSE_PUNCTUATION("not", negate), /* GNU */
227 PARSE_PUNCTUATION("(", openparen),
228 PARSE_PUNCTUATION(")", closeparen),
229 PARSE_PUNCTUATION(",", comma), /* GNU */
230 PARSE_PUNCTUATION("a", and),
231 PARSE_TEST ("amin", amin), /* GNU */
232 PARSE_PUNCTUATION("and", and), /* GNU */
233 PARSE_TEST ("anewer", anewer), /* GNU */
234 {ARG_TEST, "atime", parse_time, pred_atime},
235 PARSE_TEST ("cmin", cmin), /* GNU */
236 PARSE_TEST ("cnewer", cnewer), /* GNU */
237 {ARG_TEST, "ctime", parse_time, pred_ctime},
238 PARSE_POSOPT ("daystart", daystart), /* GNU */
239 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
240 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
241 PARSE_OPTION ("depth", depth),
242 PARSE_TEST ("empty", empty), /* GNU */
243 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
244 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
245 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
246 PARSE_ACTION ("fls", fls), /* GNU */
247 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
248 PARSE_ACTION ("fprint", fprint), /* GNU */
249 PARSE_ACTION ("fprint0", fprint0), /* GNU */
250 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
251 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
252 PARSE_TEST ("gid", gid), /* GNU */
253 PARSE_TEST ("group", group),
254 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
255 PARSE_TEST ("ilname", ilname), /* GNU */
256 PARSE_TEST ("iname", iname), /* GNU */
257 PARSE_TEST ("inum", inum), /* GNU, Unix */
258 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
259 PARSE_TEST_NP ("iregex", iregex), /* GNU */
260 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
261 PARSE_TEST ("links", links),
262 PARSE_TEST ("lname", lname), /* GNU */
263 PARSE_ACTION ("ls", ls), /* GNU, Unix */
264 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
265 PARSE_OPTION ("mindepth", mindepth), /* GNU */
266 PARSE_TEST ("mmin", mmin), /* GNU */
267 PARSE_OPTION ("mount", xdev), /* Unix */
268 {ARG_TEST, "mtime", parse_time, pred_mtime},
269 PARSE_TEST ("name", name),
270 #ifdef UNIMPLEMENTED_UNIX
271 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
272 #endif
273 PARSE_TEST ("newer", newer),
274 {ARG_TEST, "atime", parse_time, pred_atime},
275 PARSE_OPTION ("noleaf", noleaf), /* GNU */
276 PARSE_TEST ("nogroup", nogroup),
277 PARSE_TEST ("nouser", nouser),
278 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
279 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
280 PARSE_PUNCTUATION("o", or),
281 PARSE_PUNCTUATION("or", or), /* GNU */
282 PARSE_ACTION ("ok", ok),
283 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
284 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
285 PARSE_TEST ("perm", perm),
286 PARSE_ACTION ("print", print),
287 PARSE_ACTION ("print0", print0), /* GNU */
288 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
289 PARSE_ACTION ("prune", prune),
290 PARSE_ACTION ("quit", quit), /* GNU */
291 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
292 PARSE_TEST ("regex", regex), /* GNU */
293 PARSE_OPTION ("regextype", regextype), /* GNU */
294 PARSE_TEST ("samefile", samefile), /* GNU */
295 #if 0
296 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
297 #endif
298 PARSE_TEST ("size", size),
299 PARSE_TEST ("type", type),
300 PARSE_TEST ("uid", uid), /* GNU */
301 PARSE_TEST ("used", used), /* GNU */
302 PARSE_TEST ("user", user),
303 PARSE_OPTION ("warn", warn), /* GNU */
304 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
305 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
306 PARSE_OPTION ("xdev", xdev),
307 PARSE_TEST ("xtype", xtype), /* GNU */
308 #ifdef UNIMPLEMENTED_UNIX
309 /* It's pretty ugly for find to know about archive formats.
310 Plus what it could do with cpio archives is very limited.
311 Better to leave it out. */
312 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
313 #endif
314 /* gnulib's stdbool.h might have made true and false into macros,
315 * so we can't leave named 'true' and 'false' tokens, so we have
316 * to expeant the relevant entries longhand.
318 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
319 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
320 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
322 /* Various other cases that don't fit neatly into our macro scheme. */
323 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
324 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
325 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
326 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
327 {0, 0, 0, 0}
331 static const char *first_nonoption_arg = NULL;
332 static const struct parser_table *noop = NULL;
335 static const struct parser_table*
336 get_noop(void)
338 int i;
339 if (NULL == noop)
341 for (i = 0; parse_table[i].parser_name != 0; i++)
343 if (ARG_NOOP ==parse_table[i].type)
345 noop = &(parse_table[i]);
346 break;
350 return noop;
353 static int
354 get_stat_Ytime(const struct stat *p,
355 char what,
356 struct timespec *ret)
358 switch (what)
360 case 'a':
361 *ret = get_stat_atime(p);
362 return 1;
363 case 'B':
364 *ret = get_stat_birthtime(p);
365 return (ret->tv_nsec >= 0);
366 case 'c':
367 *ret = get_stat_ctime(p);
368 return 1;
369 case 'm':
370 *ret = get_stat_mtime(p);
371 return 1;
372 default:
373 assert(0);
374 abort();
375 abort();
379 void
380 set_follow_state(enum SymlinkOption opt)
382 if (options.debug_options & DebugStat)
384 /* For DebugStat, the choice is made at runtime within debug_stat()
385 * by checking the contents of the symlink_handling variable.
387 options.xstat = debug_stat;
389 else
391 switch (opt)
393 case SYMLINK_ALWAYS_DEREF: /* -L */
394 options.xstat = optionl_stat;
395 options.no_leaf_check = true;
396 break;
398 case SYMLINK_NEVER_DEREF: /* -P (default) */
399 options.xstat = optionp_stat;
400 /* Can't turn no_leaf_check off because the user might have specified
401 * -noleaf anyway
403 break;
405 case SYMLINK_DEREF_ARGSONLY: /* -H */
406 options.xstat = optionh_stat;
407 options.no_leaf_check = true;
410 options.symlink_handling = opt;
414 void
415 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
417 (void) args;
418 (void) argno;
419 (void) last;
420 (void) predicates;
421 first_nonoption_arg = NULL;
424 void
425 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
427 /* does nothing */
428 (void) args;
429 (void) argno;
430 (void) last;
431 (void) predicates;
435 /* Check that it is legal to fid the given primary in its
436 * position and return it.
438 const struct parser_table*
439 found_parser(const char *original_arg, const struct parser_table *entry)
441 /* If this is an option, but we have already had a
442 * non-option argument, the user may be under the
443 * impression that the behaviour of the option
444 * argument is conditional on some preceding
445 * tests. This might typically be the case with,
446 * for example, -maxdepth.
448 * The options -daystart and -follow are exempt
449 * from this treatment, since their positioning
450 * in the command line does have an effect on
451 * subsequent tests but not previous ones. That
452 * might be intentional on the part of the user.
454 if (entry->type != ARG_POSITIONAL_OPTION)
456 /* Something other than -follow/-daystart.
457 * If this is an option, check if it followed
458 * a non-option and if so, issue a warning.
460 if (entry->type == ARG_OPTION)
462 if ((first_nonoption_arg != NULL)
463 && options.warnings )
465 /* option which follows a non-option */
466 error (0, 0,
467 _("warning: you have specified the %s "
468 "option after a non-option argument %s, "
469 "but options are not positional (%s affects "
470 "tests specified before it as well as those "
471 "specified after it). Please specify options "
472 "before other arguments.\n"),
473 original_arg,
474 first_nonoption_arg,
475 original_arg);
478 else
480 /* Not an option or a positional option,
481 * so remember we've seen it in order to
482 * use it in a possible future warning message.
484 if (first_nonoption_arg == NULL)
486 first_nonoption_arg = original_arg;
491 return entry;
495 /* Return a pointer to the parser function to invoke for predicate
496 SEARCH_NAME.
497 Return NULL if SEARCH_NAME is not a valid predicate name. */
499 const struct parser_table*
500 find_parser (char *search_name)
502 int i;
503 const char *original_arg = search_name;
505 /* Ugh. Special case -newerXY. */
506 if (0 == strncmp("-newer", search_name, 6)
507 && (8 == strlen(search_name)))
509 return found_parser(original_arg, &parse_entry_newerXY);
512 if (*search_name == '-')
513 search_name++;
515 for (i = 0; parse_table[i].parser_name != 0; i++)
517 if (strcmp (parse_table[i].parser_name, search_name) == 0)
519 return found_parser(original_arg, &parse_table[i]);
522 return NULL;
525 static float
526 estimate_file_age_success_rate(float num_days)
528 if (num_days < 0.1)
530 /* Assume 1% of files have timestamps in the future */
531 return 0.01f;
533 else if (num_days < 1)
535 /* Assume 30% of files have timestamps today */
536 return 0.3f;
538 else if (num_days > 100)
540 /* Assume 30% of files are very old */
541 return 0.3f;
543 else
545 /* Assume 39% of files are between 1 and 100 days old. */
546 return 0.39f;
550 static float
551 estimate_timestamp_success_rate(time_t when)
553 int num_days = (options.cur_day_start - when) / 86400;
554 return estimate_file_age_success_rate(num_days);
557 /* Collect an argument from the argument list, or
558 * return false.
560 static boolean
561 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
563 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
565 *collected_arg = NULL;
566 return false;
568 else
570 *collected_arg = argv[*arg_ptr];
571 (*arg_ptr)++;
572 return true;
576 /* The parsers are responsible to continue scanning ARGV for
577 their arguments. Each parser knows what is and isn't
578 allowed for itself.
580 ARGV is the argument array.
581 *ARG_PTR is the index to start at in ARGV,
582 updated to point beyond the last element consumed.
584 The predicate structure is updated with the new information. */
587 static boolean
588 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
590 struct predicate *our_pred;
592 (void) argv;
593 (void) arg_ptr;
595 our_pred = get_new_pred (entry);
596 our_pred->pred_func = pred_and;
597 our_pred->p_type = BI_OP;
598 our_pred->p_prec = AND_PREC;
599 our_pred->need_stat = our_pred->need_type = false;
600 return true;
603 static boolean
604 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
606 struct predicate *our_pred;
607 struct stat stat_newer;
609 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
610 return false;
611 set_stat_placeholders(&stat_newer);
612 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
613 fatal_file_error(argv[*arg_ptr]);
614 our_pred = insert_primary (entry);
615 our_pred->args.reftime.xval = XVAL_ATIME;
616 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
617 our_pred->args.reftime.kind = COMP_GT;
618 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
619 (*arg_ptr)++;
620 return true;
623 boolean
624 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
626 struct predicate *our_pred;
628 (void) argv;
629 (void) arg_ptr;
631 our_pred = get_new_pred (entry);
632 our_pred->pred_func = pred_closeparen;
633 our_pred->p_type = CLOSE_PAREN;
634 our_pred->p_prec = NO_PREC;
635 our_pred->need_stat = our_pred->need_type = false;
636 return true;
639 static boolean
640 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
642 struct predicate *our_pred;
643 struct stat stat_newer;
645 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
646 return false;
647 set_stat_placeholders(&stat_newer);
648 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
649 fatal_file_error(argv[*arg_ptr]);
650 our_pred = insert_primary (entry);
651 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
652 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
653 our_pred->args.reftime.kind = COMP_GT;
654 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
655 (*arg_ptr)++;
656 return true;
659 static boolean
660 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
662 struct predicate *our_pred;
664 (void) argv;
665 (void) arg_ptr;
667 our_pred = get_new_pred (entry);
668 our_pred->pred_func = pred_comma;
669 our_pred->p_type = BI_OP;
670 our_pred->p_prec = COMMA_PREC;
671 our_pred->need_stat = our_pred->need_type = false;
672 our_pred->est_success_rate = 1.0f;
673 return true;
676 static boolean
677 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
679 struct tm *local;
681 (void) entry;
682 (void) argv;
683 (void) arg_ptr;
685 if (options.full_days == false)
687 options.cur_day_start += DAYSECS;
688 local = localtime (&options.cur_day_start);
689 options.cur_day_start -= (local
690 ? (local->tm_sec + local->tm_min * 60
691 + local->tm_hour * 3600)
692 : options.cur_day_start % DAYSECS);
693 options.full_days = true;
695 return true;
698 static boolean
699 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
701 struct predicate *our_pred;
702 (void) argv;
703 (void) arg_ptr;
705 our_pred = insert_primary (entry);
706 our_pred->side_effects = our_pred->no_default_print = true;
707 /* -delete implies -depth */
708 options.do_dir_first = false;
710 /* We do not need stat information because we check for the case
711 * (errno==EISDIR) in pred_delete.
713 our_pred->need_stat = our_pred->need_type = false;
715 our_pred->est_success_rate = 1.0f;
716 return true;
719 static boolean
720 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
722 (void) entry;
723 (void) argv;
724 (void) arg_ptr;
726 options.do_dir_first = false;
727 return parse_noop(entry, argv, arg_ptr);
730 static boolean
731 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
733 (void) argv;
734 (void) arg_ptr;
736 if (options.warnings)
738 error (0, 0,
739 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
741 return parse_depth(entry, argv, arg_ptr);
744 static boolean
745 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
747 struct predicate *our_pred;
748 (void) argv;
749 (void) arg_ptr;
751 our_pred = insert_primary (entry);
752 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
753 return true;
756 static boolean
757 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
759 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
762 static boolean
763 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
765 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
768 static boolean
769 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
771 struct predicate *our_pred;
773 (void) argv;
774 (void) arg_ptr;
776 our_pred = insert_primary (entry);
777 our_pred->need_stat = our_pred->need_type = false;
778 our_pred->side_effects = our_pred->no_default_print = false;
779 our_pred->est_success_rate = 0.0f;
780 return true;
783 static boolean
784 insert_fls (const struct parser_table* entry, const char *filename)
786 struct predicate *our_pred = insert_primary (entry);
787 if (filename)
788 open_output_file (filename, &our_pred->args.printf_vec);
789 else
790 open_stdout (&our_pred->args.printf_vec);
791 our_pred->side_effects = our_pred->no_default_print = true;
792 our_pred->est_success_rate = 1.0f;
793 return true;
797 static boolean
798 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
800 const char *filename;
801 return collect_arg(argv, arg_ptr, &filename)
802 && insert_fls(entry, filename);
805 static boolean
806 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
808 (void) entry;
809 (void) argv;
810 (void) arg_ptr;
812 set_follow_state(SYMLINK_ALWAYS_DEREF);
813 return parse_noop(entry, argv, arg_ptr);
816 static boolean
817 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
819 struct predicate *our_pred;
821 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
822 return false;
823 our_pred = insert_primary (entry);
824 open_output_file (argv[*arg_ptr], &our_pred->args.printf_vec);
825 our_pred->side_effects = our_pred->no_default_print = true;
826 our_pred->need_stat = our_pred->need_type = false;
827 our_pred->est_success_rate = 1.0f;
828 (*arg_ptr)++;
829 return true;
832 static boolean
833 insert_fprint(const struct parser_table* entry, const char *filename)
835 struct predicate *our_pred = insert_primary (entry);
836 if (filename)
837 open_output_file (filename, &our_pred->args.printf_vec);
838 else
839 open_stdout (&our_pred->args.printf_vec);
840 our_pred->side_effects = our_pred->no_default_print = true;
841 our_pred->need_stat = our_pred->need_type = false;
842 our_pred->est_success_rate = 1.0f;
843 return true;
847 static boolean
848 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
850 const char *filename;
851 if (collect_arg(argv, arg_ptr, &filename))
852 return insert_fprint(entry, filename);
853 else
854 return false;
857 static float estimate_fstype_success_rate(const char *fsname)
859 struct stat dir_stat;
860 const char *dir = "/";
861 if (0 == stat(dir, &dir_stat))
863 const char *fstype = filesystem_type(&dir_stat, dir);
864 /* Assume most files are on the same filesystem type as the root fs. */
865 if (0 == strcmp(fsname, fstype))
866 return 0.7f;
867 else
868 return 0.3f;
870 return 1.0f;
874 static boolean
875 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
877 struct predicate *our_pred;
879 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
880 return false;
881 our_pred = insert_primary (entry);
882 our_pred->args.str = argv[*arg_ptr];
884 /* This is an expensive operation, so although there are
885 * circumstances where it is selective, we ignore this fact because
886 * we probably don't want to promote this test to the front anyway.
888 our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
889 (*arg_ptr)++;
890 return true;
893 static boolean
894 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
896 struct predicate *p = insert_num (argv, arg_ptr, entry);
897 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
898 return p;
901 static boolean
902 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
904 struct group *cur_gr;
905 struct predicate *our_pred;
906 gid_t gid;
907 int gid_len;
909 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
910 return false;
911 cur_gr = getgrnam (argv[*arg_ptr]);
912 endgrent ();
913 if (cur_gr != NULL)
914 gid = cur_gr->gr_gid;
915 else
917 gid_len = strspn (argv[*arg_ptr], "0123456789");
918 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
919 return false;
920 gid = atoi (argv[*arg_ptr]);
922 our_pred = insert_primary (entry);
923 our_pred->args.gid = gid;
924 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
925 (*arg_ptr)++;
926 return true;
929 static boolean
930 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
932 (void) entry;
933 (void) argv;
934 (void) arg_ptr;
936 usage(stdout, 0, NULL);
937 puts (_("\n\
938 default path is the current directory; default expression is -print\n\
939 expression may consist of: operators, options, tests, and actions:\n"));
940 puts (_("\
941 operators (decreasing precedence; -and is implicit where no others are given):\n\
942 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
943 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
944 puts (_("\
945 positional options (always true): -daystart -follow -regextype\n\n\
946 normal options (always true, specified before other expressions):\n\
947 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
948 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
949 puts (_("\
950 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
951 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
952 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
953 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
954 puts (_("\
955 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
956 -readable -writable -executable\n\
957 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
958 -used N -user NAME -xtype [bcdpfls]\n"));
959 puts (_("\
960 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
961 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
962 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
963 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
964 "));
965 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
966 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
967 email to <bug-findutils@gnu.org>."));
968 exit (0);
971 static float
972 estimate_pattern_match_rate(const char *pattern, int is_regex)
974 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
976 /* A wildcard; assume the pattern matches most files. */
977 return 0.8f;
979 else
981 return 0.1f;
985 static boolean
986 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
988 struct predicate *our_pred;
990 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
991 return false;
992 our_pred = insert_primary (entry);
993 our_pred->args.str = argv[*arg_ptr];
994 /* Use the generic glob pattern estimator to figure out how many
995 * links will match, but bear in mind that most files won't be links.
997 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
998 (*arg_ptr)++;
999 return true;
1003 /* sanity check the fnmatch() function to make sure
1004 * it really is the GNU version.
1006 static boolean
1007 fnmatch_sanitycheck(void)
1009 /* fprintf(stderr, "Performing find sanity check..."); */
1010 if (0 != fnmatch("foo", "foo", 0)
1011 || 0 == fnmatch("Foo", "foo", 0)
1012 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1014 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1015 /* fprintf(stderr, "FAILED\n"); */
1016 return false;
1019 /* fprintf(stderr, "OK\n"); */
1020 return true;
1024 static boolean
1025 check_name_arg(const char *pred, const char *arg)
1027 if (strchr(arg, '/'))
1029 error(0, 0,_("warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '%s %s' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ %s'."),
1030 pred,
1031 safely_quote_err_filename(0, arg),
1032 safely_quote_err_filename(1, arg));
1034 return true; /* allow it anyway */
1039 static boolean
1040 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1042 struct predicate *our_pred;
1044 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1045 return false;
1046 if (!check_name_arg("-iname", argv[*arg_ptr]))
1047 return false;
1049 fnmatch_sanitycheck();
1051 our_pred = insert_primary (entry);
1052 our_pred->need_stat = our_pred->need_type = false;
1053 our_pred->args.str = argv[*arg_ptr];
1054 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1055 (*arg_ptr)++;
1056 return true;
1059 static boolean
1060 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1062 struct predicate *p = insert_num (argv, arg_ptr, entry);
1063 /* inode number is exact match only, so very low proportions of files match */
1064 p->est_success_rate = 1e-6;
1065 return p;
1068 /* -ipath is deprecated (at RMS's request) in favour of
1069 * -iwholename. See the node "GNU Manuals" in standards.texi
1070 * for the rationale for this (basically, GNU prefers the use
1071 * of the phrase "file name" to "path name"
1073 static boolean
1074 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1076 error (0, 0,
1077 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1079 return parse_iwholename(entry, argv, arg_ptr);
1082 static boolean
1083 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1085 struct predicate *our_pred;
1087 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1088 return false;
1090 fnmatch_sanitycheck();
1092 our_pred = insert_primary_withpred (entry, pred_ipath);
1093 our_pred->need_stat = our_pred->need_type = false;
1094 our_pred->args.str = argv[*arg_ptr];
1095 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1096 (*arg_ptr)++;
1097 return true;
1100 static boolean
1101 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1103 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1106 static boolean
1107 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1109 struct predicate *p = insert_num (argv, arg_ptr, entry);
1110 if (p->args.numinfo.l_val == 1)
1111 p->est_success_rate = 0.99;
1112 else if (p->args.numinfo.l_val == 2)
1113 p->est_success_rate = 0.01;
1114 else
1115 p->est_success_rate = 1e-3;
1116 return p;
1119 static boolean
1120 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1122 struct predicate *our_pred;
1124 (void) argv;
1125 (void) arg_ptr;
1127 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1128 return false;
1130 fnmatch_sanitycheck();
1132 our_pred = insert_primary (entry);
1133 our_pred->args.str = argv[*arg_ptr];
1134 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
1135 (*arg_ptr)++;
1136 return true;
1139 static boolean
1140 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1142 (void) &argv;
1143 (void) &arg_ptr;
1144 return insert_fls(entry, NULL);
1147 static boolean
1148 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1150 int depth_len;
1151 (void) entry;
1153 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1154 return false;
1155 depth_len = strspn (argv[*arg_ptr], "0123456789");
1156 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1157 return false;
1158 options.maxdepth = atoi (argv[*arg_ptr]);
1159 if (options.maxdepth < 0)
1160 return false;
1161 (*arg_ptr)++;
1162 return parse_noop(entry, argv, arg_ptr);
1165 static boolean
1166 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1168 int depth_len;
1169 (void) entry;
1171 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1172 return false;
1173 depth_len = strspn (argv[*arg_ptr], "0123456789");
1174 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1175 return false;
1176 options.mindepth = atoi (argv[*arg_ptr]);
1177 if (options.mindepth < 0)
1178 return false;
1179 (*arg_ptr)++;
1180 return parse_noop(entry, argv, arg_ptr);
1184 static boolean
1185 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr, enum xval xv)
1187 struct predicate *our_pred;
1188 struct time_val tval;
1190 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1191 return false;
1193 tval.xval = xv;
1194 if (!get_relative_timestamp(argv[*arg_ptr], &tval,
1195 options.cur_day_start + DAYSECS, 60,
1196 "arithmetic overflow while converting %s minutes to a number of seconds"))
1197 return false;
1199 our_pred = insert_primary (entry);
1200 our_pred->args.reftime = tval;
1201 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1202 (*arg_ptr)++;
1203 return true;
1205 static boolean
1206 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1208 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1211 static boolean
1212 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1214 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1218 static boolean
1219 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1221 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1224 static boolean
1225 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1227 struct predicate *our_pred;
1229 (void) argv;
1230 (void) arg_ptr;
1232 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1233 return false;
1234 if (!check_name_arg("-name", argv[*arg_ptr]))
1235 return false;
1236 fnmatch_sanitycheck();
1238 our_pred = insert_primary (entry);
1239 our_pred->need_stat = our_pred->need_type = false;
1240 our_pred->args.str = argv[*arg_ptr];
1241 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1242 (*arg_ptr)++;
1243 return true;
1246 static boolean
1247 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1249 struct predicate *our_pred;
1251 (void) &argv;
1252 (void) &arg_ptr;
1254 our_pred = get_new_pred_chk_op (entry);
1255 our_pred->pred_func = pred_negate;
1256 our_pred->p_type = UNI_OP;
1257 our_pred->p_prec = NEGATE_PREC;
1258 our_pred->need_stat = our_pred->need_type = false;
1259 return true;
1262 static boolean
1263 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1265 struct predicate *our_pred;
1266 struct stat stat_newer;
1268 (void) argv;
1269 (void) arg_ptr;
1271 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1272 return false;
1273 set_stat_placeholders(&stat_newer);
1274 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1275 fatal_file_error(argv[*arg_ptr]);
1276 our_pred = insert_primary (entry);
1277 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1278 our_pred->args.reftime.xval = XVAL_MTIME;
1279 our_pred->args.reftime.kind = COMP_GT;
1280 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1281 (*arg_ptr)++;
1282 return true;
1286 static boolean
1287 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1289 (void) argv;
1290 (void) arg_ptr;
1292 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1294 return false;
1296 else if (8u != strlen(argv[*arg_ptr]))
1298 return false;
1300 else
1302 char x, y;
1303 const char validchars[] = "aBcmt";
1305 assert(0 == strncmp("-newer", argv[*arg_ptr], 6));
1306 x = argv[*arg_ptr][6];
1307 y = argv[*arg_ptr][7];
1310 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1311 if ('B' == x || 'B' == y)
1313 error(0, 0,
1314 _("This system does not provide a way to find the birth time of a file."));
1315 return 0;
1317 #endif
1319 /* -newertY (for any Y) is invalid. */
1320 if (x == 't'
1321 || 0 == strchr(validchars, x)
1322 || 0 == strchr( validchars, y))
1324 return false;
1326 else
1328 struct predicate *our_pred;
1330 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1331 * past the test name (for most other tests, this is already done)
1333 (*arg_ptr)++;
1335 our_pred = insert_primary (entry);
1338 switch (x)
1340 case 'a':
1341 our_pred->args.reftime.xval = XVAL_ATIME;
1342 break;
1343 case 'B':
1344 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1345 break;
1346 case 'c':
1347 our_pred->args.reftime.xval = XVAL_CTIME;
1348 break;
1349 case 'm':
1350 our_pred->args.reftime.xval = XVAL_MTIME;
1351 break;
1352 default:
1353 assert(strchr(validchars, x));
1354 assert(0);
1357 if ('t' == y)
1359 if (!get_date(&our_pred->args.reftime.ts,
1360 argv[*arg_ptr],
1361 &options.start_time))
1363 error(1, 0,
1364 _("I cannot figure out how to interpret %s as a date or time"),
1365 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1368 else
1370 struct stat stat_newer;
1372 /* Stat the named file. */
1373 set_stat_placeholders(&stat_newer);
1374 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1375 fatal_file_error(argv[*arg_ptr]);
1377 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1379 /* We cannot extract a timestamp from the struct stat. */
1380 error(1, 0, _("Cannot obtain birth time of file %s"),
1381 safely_quote_err_filename(0, argv[*arg_ptr]));
1384 our_pred->args.reftime.kind = COMP_GT;
1385 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1386 (*arg_ptr)++;
1388 assert(our_pred->pred_func != NULL);
1389 assert(our_pred->pred_func == pred_newerXY);
1390 assert(our_pred->need_stat);
1391 return true;
1397 static boolean
1398 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1400 (void) &argv;
1401 (void) &arg_ptr;
1402 (void) entry;
1404 options.no_leaf_check = true;
1405 return parse_noop(entry, argv, arg_ptr);
1408 #ifdef CACHE_IDS
1409 /* Arbitrary amount by which to increase size
1410 of `uid_unused' and `gid_unused'. */
1411 #define ALLOC_STEP 2048
1413 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1414 char *uid_unused = NULL;
1416 /* Number of elements in `uid_unused'. */
1417 unsigned uid_allocated;
1419 /* Similar for GIDs and group entries. */
1420 char *gid_unused = NULL;
1421 unsigned gid_allocated;
1422 #endif
1424 static boolean
1425 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1427 struct predicate *our_pred;
1429 (void) &argv;
1430 (void) &arg_ptr;
1432 our_pred = insert_primary (entry);
1433 our_pred->est_success_rate = 1e-4;
1434 #ifdef CACHE_IDS
1435 if (gid_unused == NULL)
1437 struct group *gr;
1439 gid_allocated = ALLOC_STEP;
1440 gid_unused = xmalloc (gid_allocated);
1441 memset (gid_unused, 1, gid_allocated);
1442 setgrent ();
1443 while ((gr = getgrent ()) != NULL)
1445 if ((unsigned) gr->gr_gid >= gid_allocated)
1447 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1448 gid_unused = xrealloc (gid_unused, new_allocated);
1449 memset (gid_unused + gid_allocated, 1,
1450 new_allocated - gid_allocated);
1451 gid_allocated = new_allocated;
1453 gid_unused[(unsigned) gr->gr_gid] = 0;
1455 endgrent ();
1457 #endif
1458 return true;
1461 static boolean
1462 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1464 struct predicate *our_pred;
1465 (void) argv;
1466 (void) arg_ptr;
1469 our_pred = insert_primary (entry);
1470 our_pred->est_success_rate = 1e-3;
1471 #ifdef CACHE_IDS
1472 if (uid_unused == NULL)
1474 struct passwd *pw;
1476 uid_allocated = ALLOC_STEP;
1477 uid_unused = xmalloc (uid_allocated);
1478 memset (uid_unused, 1, uid_allocated);
1479 setpwent ();
1480 while ((pw = getpwent ()) != NULL)
1482 if ((unsigned) pw->pw_uid >= uid_allocated)
1484 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1485 uid_unused = xrealloc (uid_unused, new_allocated);
1486 memset (uid_unused + uid_allocated, 1,
1487 new_allocated - uid_allocated);
1488 uid_allocated = new_allocated;
1490 uid_unused[(unsigned) pw->pw_uid] = 0;
1492 endpwent ();
1494 #endif
1495 return true;
1498 static boolean
1499 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1501 (void) argv;
1502 (void) arg_ptr;
1503 (void) entry;
1505 options.warnings = false;
1506 return parse_noop(entry, argv, arg_ptr);
1509 static boolean
1510 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1512 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1515 static boolean
1516 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1518 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1521 boolean
1522 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1524 struct predicate *our_pred;
1526 (void) argv;
1527 (void) arg_ptr;
1529 our_pred = get_new_pred_chk_op (entry);
1530 our_pred->pred_func = pred_openparen;
1531 our_pred->p_type = OPEN_PAREN;
1532 our_pred->p_prec = NO_PREC;
1533 our_pred->need_stat = our_pred->need_type = false;
1534 return true;
1537 static boolean
1538 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1540 struct predicate *our_pred;
1542 (void) argv;
1543 (void) arg_ptr;
1545 our_pred = get_new_pred (entry);
1546 our_pred->pred_func = pred_or;
1547 our_pred->p_type = BI_OP;
1548 our_pred->p_prec = OR_PREC;
1549 our_pred->need_stat = our_pred->need_type = false;
1550 return true;
1553 /* -path is deprecated (at RMS's request) in favour of
1554 * -iwholename. See the node "GNU Manuals" in standards.texi
1555 * for the rationale for this (basically, GNU prefers the use
1556 * of the phrase "file name" to "path name".
1558 * We do not issue a warning that this usage is deprecated
1559 * since HPUX find supports this predicate also.
1561 static boolean
1562 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1564 return parse_wholename(entry, argv, arg_ptr);
1567 static boolean
1568 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1570 struct predicate *our_pred;
1572 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1573 return false;
1574 our_pred = insert_primary_withpred (entry, pred_path);
1575 our_pred->need_stat = our_pred->need_type = false;
1576 our_pred->args.str = argv[*arg_ptr];
1577 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1578 (*arg_ptr)++;
1579 return true;
1582 static boolean
1583 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1585 mode_t perm_val[2];
1586 float rate;
1587 int mode_start = 0;
1588 boolean havekind = false;
1589 enum permissions_type kind = PERM_EXACT;
1590 struct mode_change *change = NULL;
1591 struct predicate *our_pred;
1593 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1594 return false;
1596 switch (argv[*arg_ptr][0])
1598 case '-':
1599 mode_start = 1;
1600 kind = PERM_AT_LEAST;
1601 havekind = true;
1602 rate = 0.2;
1603 break;
1605 case '+':
1606 change = mode_compile (argv[*arg_ptr]);
1607 if (NULL == change)
1609 /* Most likely the caller is an old script that is still
1610 * using the obsolete GNU syntax '-perm +MODE'. This old
1611 * syntax was withdrawn in favor of '-perm /MODE' because
1612 * it is incompatible with POSIX in some cases, but we
1613 * still support uses of it that are not incompatible with
1614 * POSIX.
1616 mode_start = 1;
1617 kind = PERM_ANY;
1618 rate = 0.3;
1620 else
1622 /* This is a POSIX-compatible usage */
1623 mode_start = 0;
1624 kind = PERM_EXACT;
1625 rate = 0.1;
1627 havekind = true;
1628 break;
1630 case '/': /* GNU extension */
1631 mode_start = 1;
1632 kind = PERM_ANY;
1633 havekind = true;
1634 rate = 0.3;
1635 break;
1637 default:
1638 /* For example, '-perm 0644', which is valid and matches
1639 * only files whose mode is exactly 0644.
1641 mode_start = 0;
1642 kind = PERM_EXACT;
1643 havekind = true;
1644 rate = 0.01;
1645 break;
1648 if (NULL == change)
1650 change = mode_compile (argv[*arg_ptr] + mode_start);
1651 if (NULL == change)
1652 error (1, 0, _("invalid mode %s"),
1653 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1655 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1656 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1657 free (change);
1659 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1661 /* The meaning of -perm /000 will change in the future. It
1662 * currently matches no files, but like -perm -000 it should
1663 * match all files.
1665 * Starting in 2005, we used to issue a warning message
1666 * informing the user that the behaviour would change in the
1667 * future. We have now changed the behaviour and issue a
1668 * warning message that the behaviour recently changed.
1670 error (0, 0,
1671 _("warning: you have specified a mode pattern %s (which is "
1672 "equivalent to /000). The meaning of -perm /000 has now been "
1673 "changed to be consistent with -perm -000; that is, while it "
1674 "used to match no files, it now matches all files."),
1675 argv[*arg_ptr]);
1677 kind = PERM_AT_LEAST;
1678 havekind = true;
1680 /* The "magic" number below is just the fraction of files on my
1681 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1682 * Actual totals are 1472 and 1073833.
1684 rate = 0.9986; /* probably matches anything but a broken symlink */
1687 our_pred = insert_primary (entry);
1688 our_pred->est_success_rate = rate;
1689 if (havekind)
1691 our_pred->args.perm.kind = kind;
1693 else
1696 switch (argv[*arg_ptr][0])
1698 case '-':
1699 our_pred->args.perm.kind = PERM_AT_LEAST;
1700 break;
1701 case '+':
1702 our_pred->args.perm.kind = PERM_ANY;
1703 break;
1704 default:
1705 our_pred->args.perm.kind = PERM_EXACT;
1706 break;
1709 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1710 (*arg_ptr)++;
1711 return true;
1714 boolean
1715 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1717 struct predicate *our_pred;
1719 (void) argv;
1720 (void) arg_ptr;
1722 our_pred = insert_primary (entry);
1723 /* -print has the side effect of printing. This prevents us
1724 from doing undesired multiple printing when the user has
1725 already specified -print. */
1726 our_pred->side_effects = our_pred->no_default_print = true;
1727 our_pred->need_stat = our_pred->need_type = false;
1728 open_stdout(&our_pred->args.printf_vec);
1729 return true;
1732 static boolean
1733 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1735 return insert_fprint(entry, NULL);
1738 static boolean
1739 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1741 const char *format;
1742 if (collect_arg(argv, arg_ptr, &format))
1744 struct format_val fmt;
1745 open_stdout(&fmt);
1746 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1748 return false;
1751 static boolean
1752 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1754 const char *format, *filename;
1755 if (collect_arg(argv, arg_ptr, &filename))
1757 if (collect_arg(argv, arg_ptr, &format))
1759 struct format_val fmt;
1760 open_output_file (filename, &fmt);
1761 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1764 return false;
1767 static boolean
1768 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1770 struct predicate *our_pred;
1772 (void) argv;
1773 (void) arg_ptr;
1775 our_pred = insert_primary (entry);
1776 our_pred->need_stat = our_pred->need_type = false;
1777 /* -prune has a side effect that it does not descend into
1778 the current directory. */
1779 our_pred->side_effects = true;
1780 our_pred->no_default_print = false;
1781 return true;
1784 static boolean
1785 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1787 struct predicate *our_pred = insert_primary (entry);
1788 (void) argv;
1789 (void) arg_ptr;
1790 our_pred->need_stat = our_pred->need_type = false;
1791 our_pred->side_effects = true; /* Exiting is a side effect... */
1792 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1793 our_pred->est_success_rate = 1.0f;
1794 return true;
1798 static boolean
1799 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1801 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1802 return false;
1804 /* collect the regex type name */
1805 options.regex_options = get_regex_type(argv[*arg_ptr]);
1806 (*arg_ptr)++;
1808 return parse_noop(entry, argv, arg_ptr);
1812 static boolean
1813 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1815 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1818 static boolean
1819 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1821 struct predicate *our_pred;
1822 struct re_pattern_buffer *re;
1823 const char *error_message;
1825 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1826 return false;
1827 our_pred = insert_primary_withpred (entry, pred_regex);
1828 our_pred->need_stat = our_pred->need_type = false;
1829 re = (struct re_pattern_buffer *)
1830 xmalloc (sizeof (struct re_pattern_buffer));
1831 our_pred->args.regex = re;
1832 re->allocated = 100;
1833 re->buffer = (unsigned char *) xmalloc (re->allocated);
1834 re->fastmap = NULL;
1836 re_set_syntax(regex_options);
1837 re->syntax = regex_options;
1838 re->translate = NULL;
1840 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1841 re);
1842 if (error_message)
1843 error (1, 0, "%s", error_message);
1844 our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
1845 (*arg_ptr)++;
1846 return true;
1849 static boolean
1850 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1852 struct predicate *our_pred;
1853 uintmax_t num;
1854 enum comparison_type c_type;
1855 int blksize = 512;
1856 int len;
1858 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1859 return false;
1860 len = strlen (argv[*arg_ptr]);
1861 if (len == 0)
1862 error (1, 0, _("invalid null argument to -size"));
1863 switch (argv[*arg_ptr][len - 1])
1865 case 'b':
1866 blksize = 512;
1867 argv[*arg_ptr][len - 1] = '\0';
1868 break;
1870 case 'c':
1871 blksize = 1;
1872 argv[*arg_ptr][len - 1] = '\0';
1873 break;
1875 case 'k':
1876 blksize = 1024;
1877 argv[*arg_ptr][len - 1] = '\0';
1878 break;
1880 case 'M': /* Megabytes */
1881 blksize = 1024*1024;
1882 argv[*arg_ptr][len - 1] = '\0';
1883 break;
1885 case 'G': /* Gigabytes */
1886 blksize = 1024*1024*1024;
1887 argv[*arg_ptr][len - 1] = '\0';
1888 break;
1890 case 'w':
1891 blksize = 2;
1892 argv[*arg_ptr][len - 1] = '\0';
1893 break;
1895 case '0':
1896 case '1':
1897 case '2':
1898 case '3':
1899 case '4':
1900 case '5':
1901 case '6':
1902 case '7':
1903 case '8':
1904 case '9':
1905 break;
1907 default:
1908 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1910 /* TODO: accept fractional megabytes etc. ? */
1911 if (!get_num (argv[*arg_ptr], &num, &c_type))
1912 return false;
1913 our_pred = insert_primary (entry);
1914 our_pred->args.size.kind = c_type;
1915 our_pred->args.size.blocksize = blksize;
1916 our_pred->args.size.size = num;
1917 our_pred->need_stat = true;
1918 our_pred->need_type = false;
1920 if (COMP_GT == c_type)
1921 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1922 else if (COMP_LT == c_type)
1923 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1924 else
1925 our_pred->est_success_rate = 0.01;
1927 (*arg_ptr)++;
1928 return true;
1932 static boolean
1933 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1935 /* General idea: stat the file, remember device and inode numbers.
1936 * If a candidate file matches those, it's the same file.
1938 struct predicate *our_pred;
1939 struct stat st, fst;
1940 int fd, openflags;
1942 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1943 return false;
1945 set_stat_placeholders(&st);
1946 set_stat_placeholders(&fst);
1948 if ((*options.xstat) (argv[*arg_ptr], &st))
1949 fatal_file_error(argv[*arg_ptr]);
1951 /* POSIX systems are free to re-use the inode number of a deleted
1952 * file. To ensure that we are not fooled by inode reuse, we hold
1953 * the file open if we can. This would prevent the system reusing
1954 * the file.
1956 fd = -3; /* means, uninitialised */
1957 openflags = O_RDONLY;
1959 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
1961 if (options.open_nofollow_available)
1963 assert(O_NOFOLLOW != 0);
1964 openflags |= O_NOFOLLOW;
1965 fd = -1; /* safe to open it. */
1967 else
1969 if (S_ISLNK(st.st_mode))
1971 /* no way to ensure that a symlink will not be followed
1972 * by open(2), so fall back on using lstat(). Accept
1973 * the risk that the named file will be deleted and
1974 * replaced with another having the same inode.
1976 * Avoid opening the file.
1978 fd = -2; /* Do not open it */
1980 else
1982 fd = -1;
1983 /* Race condition here: the file might become a symlink here. */
1987 else
1989 /* We want to dereference the symlink anyway */
1990 fd = -1; /* safe to open it without O_NOFOLLOW */
1993 assert(fd != -3); /* check we made a decision */
1994 if (fd == -1)
1996 /* Race condition here. The file might become a
1997 * symbolic link in between out call to stat and
1998 * the call to open.
2000 fd = open(argv[*arg_ptr], openflags);
2002 if (fd >= 0)
2004 /* We stat the file again here to prevent a race condition
2005 * between the first stat and the call to open(2).
2007 if (0 != fstat(fd, &fst))
2009 fatal_file_error(argv[*arg_ptr]);
2011 else
2013 /* Worry about the race condition. If the file became a
2014 * symlink after our first stat and before our call to
2015 * open, fst may contain the stat information for the
2016 * destination of the link, not the link itself.
2018 if ((*options.xstat) (argv[*arg_ptr], &st))
2019 fatal_file_error(argv[*arg_ptr]);
2021 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2022 && (!options.open_nofollow_available))
2024 if (S_ISLNK(st.st_mode))
2026 /* We lost the race. Leave the data in st. The
2027 * file descriptor points to the wrong thing.
2029 close(fd);
2030 fd = -1;
2032 else
2034 /* Several possibilities here:
2035 * 1. There was no race
2036 * 2. The file changed into a symlink after the stat and
2037 * before the open, and then back into a non-symlink
2038 * before the second stat.
2040 * In case (1) there is no problem. In case (2),
2041 * the stat() and fstat() calls will have returned
2042 * different data. O_NOFOLLOW was not available,
2043 * so the open() call may have followed a symlink
2044 * even if the -P option is in effect.
2046 if ((st.st_dev == fst.st_dev)
2047 && (st.st_ino == fst.st_ino))
2049 /* No race. No need to copy fst to st,
2050 * since they should be identical (modulo
2051 * differences in padding bytes).
2054 else
2056 /* We lost the race. Leave the data in st. The
2057 * file descriptor points to the wrong thing.
2059 close(fd);
2060 fd = -1;
2064 else
2066 st = fst;
2072 our_pred = insert_primary (entry);
2073 our_pred->args.samefileid.ino = st.st_ino;
2074 our_pred->args.samefileid.dev = st.st_dev;
2075 our_pred->args.samefileid.fd = fd;
2076 our_pred->need_type = false;
2077 our_pred->need_stat = true;
2078 our_pred->est_success_rate = 0.01f;
2079 (*arg_ptr)++;
2080 return true;
2083 #if 0
2084 /* This function is commented out partly because support for it is
2085 * uneven.
2087 static boolean
2088 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
2090 const char *arg;
2091 const char *errmsg = _("The -show-control-chars option takes a single argument which "
2092 "must be 'literal' or 'safe'");
2094 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2096 error (1, errno, "%s", errmsg);
2097 return false;
2099 else
2101 arg = argv[*arg_ptr];
2103 if (0 == strcmp("literal", arg))
2105 options.literal_control_chars = true;
2107 else if (0 == strcmp("safe", arg))
2109 options.literal_control_chars = false;
2111 else
2113 error (1, errno, "%s", errmsg);
2114 return false;
2116 (*arg_ptr)++; /* consume the argument. */
2117 return true;
2120 #endif
2123 static boolean
2124 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2126 struct predicate *our_pred;
2128 (void) argv;
2129 (void) arg_ptr;
2131 our_pred = insert_primary (entry);
2132 our_pred->need_stat = our_pred->need_type = false;
2133 our_pred->est_success_rate = 1.0f;
2134 return true;
2137 static boolean
2138 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2140 (void) entry;
2141 return parse_true(get_noop(), argv, arg_ptr);
2144 static boolean
2145 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2147 struct predicate *our_pred;
2148 (void) argv;
2149 (void) arg_ptr;
2150 our_pred = insert_primary (entry);
2151 our_pred->need_stat = our_pred->need_type = false;
2152 our_pred->side_effects = our_pred->no_default_print = false;
2153 if (pred_is(our_pred, pred_executable))
2154 our_pred->est_success_rate = 0.2;
2155 else
2156 our_pred->est_success_rate = 0.9;
2157 return true;
2160 static boolean
2161 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2163 return insert_type (argv, arg_ptr, entry, pred_type);
2166 static boolean
2167 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2169 struct predicate *p = insert_num (argv, arg_ptr, entry);
2170 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2171 return p;
2174 static boolean
2175 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2177 struct predicate *our_pred;
2178 struct time_val tval;
2179 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2181 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2182 return false;
2184 /* The timespec is actually a delta value, so we use an origin of 0. */
2185 if (!get_relative_timestamp(argv[*arg_ptr], &tval, 0, DAYSECS, errmsg))
2186 return false;
2188 our_pred = insert_primary (entry);
2189 our_pred->args.reftime = tval;
2190 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2191 (*arg_ptr)++;
2192 return true;
2195 static boolean
2196 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2198 struct passwd *cur_pwd;
2199 struct predicate *our_pred;
2200 uid_t uid;
2201 int uid_len;
2203 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2204 return false;
2205 cur_pwd = getpwnam (argv[*arg_ptr]);
2206 endpwent ();
2207 if (cur_pwd != NULL)
2208 uid = cur_pwd->pw_uid;
2209 else
2211 uid_len = strspn (argv[*arg_ptr], "0123456789");
2212 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
2213 return false;
2214 uid = atoi (argv[*arg_ptr]);
2216 our_pred = insert_primary (entry);
2217 our_pred->args.uid = uid;
2218 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2219 (*arg_ptr)++;
2220 return true;
2223 static boolean
2224 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2226 extern char *version_string;
2227 int features = 0;
2228 int flags;
2230 (void) argv;
2231 (void) arg_ptr;
2232 (void) entry;
2234 fflush (stderr);
2235 printf (_("GNU find version %s\n"), version_string);
2236 printf (_("Built using GNU gnulib version %s\n"), gnulib_version);
2237 printf (_("Features enabled: "));
2239 #if CACHE_IDS
2240 printf("CACHE_IDS ");
2241 ++features;
2242 #endif
2243 #if DEBUG
2244 printf("DEBUG ");
2245 ++features;
2246 #endif
2247 #if DEBUG_STAT
2248 printf("DEBUG_STAT ");
2249 ++features;
2250 #endif
2251 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
2252 printf("D_TYPE ");
2253 ++features;
2254 #endif
2255 #if defined(O_NOFOLLOW)
2256 printf("O_NOFOLLOW(%s) ",
2257 (options.open_nofollow_available ? "enabled" : "disabled"));
2258 ++features;
2259 #endif
2260 #if defined(LEAF_OPTIMISATION)
2261 printf("LEAF_OPTIMISATION ");
2262 ++features;
2263 #endif
2265 flags = 0;
2266 if (is_fts_enabled(&flags))
2268 int nflags = 0;
2269 printf("FTS(");
2270 ++features;
2272 if (flags & FTS_CWDFD)
2274 if (nflags)
2276 printf(",");
2278 printf("FTS_CWDFD");
2279 ++nflags;
2281 printf(") ");
2284 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2285 ++features;
2287 if (0 == features)
2289 /* For the moment, leave this as English in case someone wants
2290 to parse these strings. */
2291 printf("none");
2293 printf("\n");
2295 exit (0);
2298 static boolean
2299 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2301 (void) argv;
2302 (void) arg_ptr;
2303 (void) entry;
2304 options.stay_on_filesystem = true;
2305 return parse_noop(entry, argv, arg_ptr);
2308 static boolean
2309 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2311 (void) argv;
2312 (void) arg_ptr;
2313 (void) entry;
2314 options.ignore_readdir_race = true;
2315 return parse_noop(entry, argv, arg_ptr);
2318 static boolean
2319 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2321 (void) argv;
2322 (void) arg_ptr;
2323 (void) entry;
2324 options.ignore_readdir_race = false;
2325 return parse_noop(entry, argv, arg_ptr);
2328 static boolean
2329 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2331 (void) argv;
2332 (void) arg_ptr;
2333 (void) entry;
2334 options.warnings = true;
2335 return parse_noop(entry, argv, arg_ptr);
2338 static boolean
2339 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2341 (void) argv;
2342 (void) arg_ptr;
2343 return insert_type (argv, arg_ptr, entry, pred_xtype);
2346 static boolean
2347 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2349 mode_t type_cell;
2350 struct predicate *our_pred;
2351 float rate = 0.5;
2353 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
2354 || (strlen (argv[*arg_ptr]) != 1))
2355 return false;
2356 switch (argv[*arg_ptr][0])
2358 case 'b': /* block special */
2359 type_cell = S_IFBLK;
2360 rate = 0.01f;
2361 break;
2362 case 'c': /* character special */
2363 type_cell = S_IFCHR;
2364 rate = 0.01f;
2365 break;
2366 case 'd': /* directory */
2367 type_cell = S_IFDIR;
2368 rate = 0.4f;
2369 break;
2370 case 'f': /* regular file */
2371 type_cell = S_IFREG;
2372 rate = 0.95f;
2373 break;
2374 #ifdef S_IFLNK
2375 case 'l': /* symbolic link */
2376 type_cell = S_IFLNK;
2377 rate = 0.1f;
2378 break;
2379 #endif
2380 #ifdef S_IFIFO
2381 case 'p': /* pipe */
2382 type_cell = S_IFIFO;
2383 rate = 0.01f;
2384 break;
2385 #endif
2386 #ifdef S_IFSOCK
2387 case 's': /* socket */
2388 type_cell = S_IFSOCK;
2389 rate = 0.01f;
2390 break;
2391 #endif
2392 #ifdef S_IFDOOR
2393 case 'D': /* Solaris door */
2394 type_cell = S_IFDOOR;
2395 rate = 0.01f;
2396 break;
2397 #endif
2398 default: /* None of the above ... nuke 'em. */
2399 return false;
2401 our_pred = insert_primary_withpred (entry, which_pred);
2402 our_pred->est_success_rate = rate;
2404 /* Figure out if we will need to stat the file, because if we don't
2405 * need to follow symlinks, we can avoid a stat call by using
2406 * struct dirent.d_type.
2408 if (which_pred == pred_xtype)
2410 our_pred->need_stat = true;
2411 our_pred->need_type = false;
2413 else
2415 our_pred->need_stat = false; /* struct dirent is enough */
2416 our_pred->need_type = true;
2418 our_pred->args.type = type_cell;
2419 (*arg_ptr)++; /* Move on to next argument. */
2420 return true;
2424 /* Return true if the file accessed via FP is a terminal.
2426 static boolean
2427 stream_is_tty(FILE *fp)
2429 int fd = fileno(fp);
2430 if (-1 == fd)
2432 return false; /* not a valid stream */
2434 else
2436 return isatty(fd) ? true : false;
2444 /* XXX: do we need to pass FUNC to this function? */
2445 static boolean
2446 insert_fprintf (struct format_val *vec,
2447 const struct parser_table *entry, PRED_FUNC func,
2448 const char *format_const)
2450 char *format = (char*)format_const; /* XXX: casting away constness */
2451 register char *scan; /* Current address in scanning `format'. */
2452 register char *scan2; /* Address inside of element being scanned. */
2453 struct segment **segmentp; /* Address of current segment. */
2454 struct predicate *our_pred;
2456 our_pred = insert_primary_withpred (entry, func);
2457 our_pred->side_effects = our_pred->no_default_print = true;
2458 our_pred->args.printf_vec = *vec;
2459 our_pred->need_type = false;
2460 our_pred->need_stat = false;
2461 our_pred->p_cost = NeedsNothing;
2463 segmentp = &our_pred->args.printf_vec.segment;
2464 *segmentp = NULL;
2466 for (scan = format; *scan; scan++)
2468 if (*scan == '\\')
2470 scan2 = scan + 1;
2471 if (*scan2 >= '0' && *scan2 <= '7')
2473 register int n, i;
2475 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2476 i++, scan2++)
2477 n = 8 * n + *scan2 - '0';
2478 scan2--;
2479 *scan = n;
2481 else
2483 switch (*scan2)
2485 case 'a':
2486 *scan = 7;
2487 break;
2488 case 'b':
2489 *scan = '\b';
2490 break;
2491 case 'c':
2492 make_segment (segmentp, format, scan - format,
2493 KIND_STOP, 0, 0,
2494 our_pred);
2495 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2496 our_pred->p_cost = NeedsStatInfo;
2497 return true;
2498 case 'f':
2499 *scan = '\f';
2500 break;
2501 case 'n':
2502 *scan = '\n';
2503 break;
2504 case 'r':
2505 *scan = '\r';
2506 break;
2507 case 't':
2508 *scan = '\t';
2509 break;
2510 case 'v':
2511 *scan = '\v';
2512 break;
2513 case '\\':
2514 /* *scan = '\\'; * it already is */
2515 break;
2516 default:
2517 error (0, 0,
2518 _("warning: unrecognized escape `\\%c'"), *scan2);
2519 scan++;
2520 continue;
2523 segmentp = make_segment (segmentp, format, scan - format + 1,
2524 KIND_PLAIN, 0, 0,
2525 our_pred);
2526 format = scan2 + 1; /* Move past the escape. */
2527 scan = scan2; /* Incremented immediately by `for'. */
2529 else if (*scan == '%')
2531 if (scan[1] == 0)
2533 /* Trailing %. We don't like those. */
2534 error (1, 0, _("error: %s at end of format string"), scan);
2536 else if (scan[1] == '%')
2538 segmentp = make_segment (segmentp, format, scan - format + 1,
2539 KIND_PLAIN, 0, 0,
2540 our_pred);
2541 scan++;
2542 format = scan + 1;
2543 continue;
2545 /* Scan past flags, width and precision, to verify kind. */
2546 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2547 /* Do nothing. */ ;
2548 while (ISDIGIT (*scan2))
2549 scan2++;
2550 if (*scan2 == '.')
2551 for (scan2++; ISDIGIT (*scan2); scan2++)
2552 /* Do nothing. */ ;
2553 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2555 segmentp = make_segment (segmentp, format, scan2 - format,
2556 KIND_FORMAT, *scan2, 0,
2557 our_pred);
2558 scan = scan2;
2559 format = scan + 1;
2561 else if (strchr ("ABCT", *scan2) && scan2[1])
2563 segmentp = make_segment (segmentp, format, scan2 - format,
2564 KIND_FORMAT, scan2[0], scan2[1],
2565 our_pred);
2566 scan = scan2 + 1;
2567 format = scan + 1;
2568 continue;
2570 else
2572 /* An unrecognized % escape. Print the char after the %. */
2573 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2574 *scan2);
2575 segmentp = make_segment (segmentp, format, scan - format,
2576 KIND_PLAIN, 0, 0,
2577 our_pred);
2578 format = scan + 1;
2579 continue;
2584 if (scan > format)
2585 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2586 our_pred);
2587 return true;
2590 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2591 from the text in FORMAT, which has length LEN.
2592 Return the address of the `next' pointer of the new segment. */
2594 static struct segment **
2595 make_segment (struct segment **segment,
2596 char *format,
2597 int len,
2598 int kind,
2599 char format_char,
2600 char aux_format_char,
2601 struct predicate *pred)
2603 enum EvaluationCost mycost = NeedsNothing;
2604 char *fmt;
2606 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2608 (*segment)->segkind = kind;
2609 (*segment)->format_char[0] = format_char;
2610 (*segment)->format_char[1] = aux_format_char;
2611 (*segment)->next = NULL;
2612 (*segment)->text_len = len;
2614 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2615 strncpy (fmt, format, len);
2616 fmt += len;
2618 switch (kind)
2620 case KIND_PLAIN: /* Plain text string, no % conversion. */
2621 case KIND_STOP: /* Terminate argument, no newline. */
2622 assert(0 == format_char);
2623 assert(0 == aux_format_char);
2624 *fmt = '\0';
2625 if (mycost > pred->p_cost)
2626 pred->p_cost = NeedsNothing;
2627 return &(*segment)->next;
2628 break;
2631 assert(kind == KIND_FORMAT);
2632 switch (format_char)
2634 case 'l': /* object of symlink */
2635 pred->need_stat = true;
2636 mycost = NeedsLinkName;
2637 *fmt++ = 's';
2638 break;
2640 case 'y': /* file type */
2641 pred->need_type = true;
2642 mycost = NeedsType;
2643 *fmt++ = 's';
2644 break;
2646 case 'a': /* atime in `ctime' format */
2647 case 'A': /* atime in user-specified strftime format */
2648 case 'B': /* birth time in user-specified strftime format */
2649 case 'c': /* ctime in `ctime' format */
2650 case 'C': /* ctime in user-specified strftime format */
2651 case 'F': /* filesystem type */
2652 case 'g': /* group name */
2653 case 'i': /* inode number */
2654 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2655 case 's': /* size in bytes */
2656 case 't': /* mtime in `ctime' format */
2657 case 'T': /* mtime in user-specified strftime format */
2658 case 'u': /* user name */
2659 pred->need_stat = true;
2660 mycost = NeedsStatInfo;
2661 *fmt++ = 's';
2662 break;
2664 case 'S': /* sparseness */
2665 pred->need_stat = true;
2666 mycost = NeedsStatInfo;
2667 *fmt++ = 'g';
2668 break;
2670 case 'Y': /* symlink pointed file type */
2671 pred->need_stat = true;
2672 mycost = NeedsType; /* true for amortised effect */
2673 *fmt++ = 's';
2674 break;
2676 case 'f': /* basename of path */
2677 case 'h': /* leading directories part of path */
2678 case 'p': /* pathname */
2679 case 'P': /* pathname with ARGV element stripped */
2680 *fmt++ = 's';
2681 break;
2683 case 'H': /* ARGV element file was found under */
2684 *fmt++ = 's';
2685 break;
2687 /* Numeric items that one might expect to honour
2688 * #, 0, + flags but which do not.
2690 case 'G': /* GID number */
2691 case 'U': /* UID number */
2692 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2693 case 'D': /* Filesystem device on which the file exits */
2694 case 'k': /* size in 1K blocks */
2695 case 'n': /* number of links */
2696 pred->need_stat = true;
2697 mycost = NeedsStatInfo;
2698 *fmt++ = 's';
2699 break;
2701 /* Numeric items that DO honour #, 0, + flags.
2703 case 'd': /* depth in search tree (0 = ARGV element) */
2704 *fmt++ = 'd';
2705 break;
2707 case 'm': /* mode as octal number (perms only) */
2708 *fmt++ = 'o';
2709 pred->need_stat = true;
2710 mycost = NeedsStatInfo;
2711 break;
2713 case '{':
2714 case '[':
2715 case '(':
2716 error (1, 0,
2717 _("error: the format directive `%%%c' is reserved for future use"),
2718 (int)kind);
2719 /*NOTREACHED*/
2720 break;
2722 *fmt = '\0';
2724 if (mycost > pred->p_cost)
2725 pred->p_cost = mycost;
2726 return &(*segment)->next;
2729 static void
2730 check_path_safety(const char *action, char **argv)
2732 const char *path = getenv("PATH");
2734 (void)argv;
2736 char *s;
2737 s = next_element(path, 1);
2738 while ((s = next_element ((char *) NULL, 1)) != NULL)
2740 if (0 == strcmp(s, "."))
2742 error(1, 0, _("The current directory is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove the current directory from your $PATH (that is, remove \".\" or leading or trailing colons)"),
2743 action);
2745 else if ('/' != s[0])
2747 /* Relative paths are also dangerous in $PATH. */
2748 error(1, 0, _("The ralative path %s is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove that entry from $PATH"),
2749 safely_quote_err_filename(0, s),
2750 action);
2756 /* handles both exec and ok predicate */
2757 static boolean
2758 new_insert_exec_ok (const char *action,
2759 const struct parser_table *entry,
2760 int dirfd,
2761 char **argv,
2762 int *arg_ptr)
2764 int start, end; /* Indexes in ARGV of start & end of cmd. */
2765 int i; /* Index into cmd args */
2766 int saw_braces; /* True if previous arg was '{}'. */
2767 boolean allow_plus; /* True if + is a valid terminator */
2768 int brace_count; /* Number of instances of {}. */
2769 PRED_FUNC func = entry->pred_func;
2770 enum BC_INIT_STATUS bcstatus;
2772 struct predicate *our_pred;
2773 struct exec_val *execp; /* Pointer for efficiency. */
2775 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2776 return false;
2778 our_pred = insert_primary_withpred (entry, func);
2779 our_pred->side_effects = our_pred->no_default_print = true;
2780 our_pred->need_type = our_pred->need_stat = false;
2782 execp = &our_pred->args.exec_vec;
2784 if ((func != pred_okdir) && (func != pred_ok))
2786 allow_plus = true;
2787 execp->close_stdin = false;
2789 else
2791 allow_plus = false;
2792 /* If find reads stdin (i.e. for -ok and similar), close stdin
2793 * in the child to prevent some script from consiming the output
2794 * intended for find.
2796 execp->close_stdin = true;
2800 if ((func == pred_execdir) || (func == pred_okdir))
2802 options.ignore_readdir_race = false;
2803 check_path_safety(action, argv);
2804 execp->use_current_dir = true;
2806 else
2808 execp->use_current_dir = false;
2811 our_pred->args.exec_vec.multiple = 0;
2813 /* Count the number of args with path replacements, up until the ';'.
2814 * Also figure out if the command is terminated by ";" or by "+".
2816 start = *arg_ptr;
2817 for (end = start, saw_braces=0, brace_count=0;
2818 (argv[end] != NULL)
2819 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2820 end++)
2822 /* For -exec and -execdir, "{} +" can terminate the command. */
2823 if ( allow_plus
2824 && argv[end][0] == '+' && argv[end][1] == 0
2825 && saw_braces)
2827 our_pred->args.exec_vec.multiple = 1;
2828 break;
2831 saw_braces = 0;
2832 if (mbsstr (argv[end], "{}"))
2834 saw_braces = 1;
2835 ++brace_count;
2837 if (0 == end && (func == pred_execdir || func == pred_okdir))
2839 /* The POSIX standard says that {} replacement should
2840 * occur even in the utility name. This is insecure
2841 * since it means we will be executing a command whose
2842 * name is chosen according to whatever find finds in
2843 * the filesystem. That can be influenced by an
2844 * attacker. Hence for -execdir and -okdir this is not
2845 * allowed. We can specify this as those options are
2846 * not defined by POSIX.
2848 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2853 /* Fail if no command given or no semicolon found. */
2854 if ((end == start) || (argv[end] == NULL))
2856 *arg_ptr = end;
2857 free(our_pred);
2858 return false;
2861 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2864 const char *suffix;
2865 if (func == pred_execdir)
2866 suffix = "dir";
2867 else
2868 suffix = "";
2870 error(1, 0,
2871 _("Only one instance of {} is supported with -exec%s ... +"),
2872 suffix);
2875 /* We use a switch statement here so that the compiler warns us when
2876 * we forget to handle a newly invented enum value.
2878 * Like xargs, we allow 2KiB of headroom for the launched utility to
2879 * export its own environment variables before calling something
2880 * else.
2882 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
2883 switch (bcstatus)
2885 case BC_INIT_ENV_TOO_BIG:
2886 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
2887 error(1, 0,
2888 _("The environment is too large for exec()."));
2889 break;
2890 case BC_INIT_OK:
2891 /* Good news. Carry on. */
2892 break;
2894 bc_use_sensible_arg_max(&execp->ctl);
2897 execp->ctl.exec_callback = launch;
2899 if (our_pred->args.exec_vec.multiple)
2901 /* "+" terminator, so we can just append our arguments after the
2902 * command and initial arguments.
2904 execp->replace_vec = NULL;
2905 execp->ctl.replace_pat = NULL;
2906 execp->ctl.rplen = 0;
2907 execp->ctl.lines_per_exec = 0; /* no limit */
2908 execp->ctl.args_per_exec = 0; /* no limit */
2910 /* remember how many arguments there are */
2911 execp->ctl.initial_argc = (end-start) - 1;
2913 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2914 bc_init_state(&execp->ctl, &execp->state, execp);
2916 /* Gather the initial arguments. Skip the {}. */
2917 for (i=start; i<end-1; ++i)
2919 bc_push_arg(&execp->ctl, &execp->state,
2920 argv[i], strlen(argv[i])+1,
2921 NULL, 0,
2925 else
2927 /* Semicolon terminator - more than one {} is supported, so we
2928 * have to do brace-replacement.
2930 execp->num_args = end - start;
2932 execp->ctl.replace_pat = "{}";
2933 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2934 execp->ctl.lines_per_exec = 0; /* no limit */
2935 execp->ctl.args_per_exec = 0; /* no limit */
2936 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2939 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2940 bc_init_state(&execp->ctl, &execp->state, execp);
2942 /* Remember the (pre-replacement) arguments for later. */
2943 for (i=0; i<execp->num_args; ++i)
2945 execp->replace_vec[i] = argv[i+start];
2949 if (argv[end] == NULL)
2950 *arg_ptr = end;
2951 else
2952 *arg_ptr = end + 1;
2954 return true;
2959 static boolean
2960 insert_exec_ok (const char *action, const struct parser_table *entry, int dirfd, char **argv, int *arg_ptr)
2962 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
2967 /* Get a timestamp and comparison type.
2969 STR is the ASCII representation.
2970 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
2971 relative to ORIGIN (usually the current moment or midnight).
2972 Thus the sense of the comparison type appears to be reversed.
2973 Set *COMP_TYPE to the kind of comparison that is requested.
2974 Issue OVERFLOWMESSAGE if overflow occurs.
2975 Return true if all okay, false if input error.
2977 Used by -atime, -ctime and -mtime (parsers) to
2978 get the appropriate information for a time predicate processor. */
2980 static boolean
2981 get_relative_timestamp (char *str,
2982 struct time_val *result,
2983 time_t origin,
2984 double sec_per_unit,
2985 const char *overflowmessage)
2987 uintmax_t checkval;
2988 double offset, seconds, f;
2990 if (get_comp_type(&str, &result->kind))
2992 /* Invert the sense of the comparison */
2993 switch (result->kind)
2995 case COMP_LT: result->kind = COMP_GT; break;
2996 case COMP_GT: result->kind = COMP_LT; break;
2997 default: break;
3000 /* Convert the ASCII number into floating-point. */
3001 if (xstrtod(str, NULL, &offset, strtod))
3003 /* Separate the floating point number the user specified
3004 * (which is a number of days, or minutes, etc) into an
3005 * integral number of seconds (SECONDS) and a fraction (F).
3007 f = modf(offset * sec_per_unit, &seconds);
3009 result->ts.tv_sec = origin - seconds;
3010 result->ts.tv_nsec = fabs(f * 1e9);
3012 /* Check for overflow. */
3013 checkval = (uintmax_t)origin - seconds;
3014 if (checkval != result->ts.tv_sec)
3016 /* an overflow has occurred. */
3017 error (1, 0, overflowmessage, str);
3019 return true;
3021 else
3023 /* Conversion from ASCII to double failed. */
3024 return false;
3027 else
3029 return false;
3033 /* Insert a time predicate based on the information in ENTRY.
3034 ARGV is a pointer to the argument array.
3035 ARG_PTR is a pointer to an index into the array, incremented if
3036 all went well.
3038 Return true if input is valid, false if not.
3040 A new predicate node is assigned, along with an argument node
3041 obtained with malloc.
3043 Used by -atime, -ctime, and -mtime parsers. */
3045 static boolean
3046 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3048 struct predicate *our_pred;
3049 struct time_val tval;
3050 enum comparison_type comp;
3051 char *s;
3052 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
3053 time_t origin;
3055 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
3056 return false;
3058 /* Decide the origin by previewing the comparison type. */
3059 origin = options.cur_day_start;
3060 s = argv[*arg_ptr];
3061 if (get_comp_type(&s, &comp))
3063 /* Remember, we invert the sense of the comparison, so this tests against COMP_LT instead of COMP_GT... */
3064 if (COMP_LT == tval.kind)
3066 uintmax_t expected = origin + (DAYSECS-1);
3067 origin += (DAYSECS-1);
3068 if (origin != expected)
3070 error(1, 0,
3071 _("arithmetic overflow when trying to calculate the end of today"));
3074 /* We discard the value of comp here, as get_relative_timestamp
3075 * will set tval.kind.
3079 if (!get_relative_timestamp(argv[*arg_ptr], &tval, origin, DAYSECS, errmsg))
3080 return false;
3082 our_pred = insert_primary (entry);
3083 our_pred->args.reftime = tval;
3084 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3085 (*arg_ptr)++;
3087 if (options.debug_options & DebugExpressionTree)
3089 time_t t;
3091 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3092 fprintf (stderr, " type: %s %s ",
3093 (tval.kind == COMP_GT) ? "gt" :
3094 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3095 (tval.kind == COMP_GT) ? " >" :
3096 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3097 t = our_pred->args.reftime.ts.tv_sec;
3098 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3099 if (tval.kind == COMP_EQ)
3101 t = our_pred->args.reftime.ts.tv_sec += DAYSECS;
3102 fprintf (stderr, " < %ju %s",
3103 (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3104 our_pred->args.reftime.ts.tv_sec -= DAYSECS;
3108 return true;
3111 /* Get the comparison type prefix (if any) from a number argument.
3112 The prefix is at *STR.
3113 Set *COMP_TYPE to the kind of comparison that is requested.
3114 Advance *STR beyond any initial comparison prefix.
3116 Return true if all okay, false if input error. */
3117 static boolean
3118 get_comp_type(char **str, enum comparison_type *comp_type)
3120 switch (**str)
3122 case '+':
3123 *comp_type = COMP_GT;
3124 (*str)++;
3125 break;
3126 case '-':
3127 *comp_type = COMP_LT;
3128 (*str)++;
3129 break;
3130 default:
3131 *comp_type = COMP_EQ;
3132 break;
3134 return true;
3141 /* Get a number with comparison information.
3142 The sense of the comparison information is 'normal'; that is,
3143 '+' looks for a count > than the number and '-' less than.
3145 STR is the ASCII representation of the number.
3146 Set *NUM to the number.
3147 Set *COMP_TYPE to the kind of comparison that is requested.
3149 Return true if all okay, false if input error. */
3151 static boolean
3152 get_num (char *str,
3153 uintmax_t *num,
3154 enum comparison_type *comp_type)
3156 char *pend;
3158 if (str == NULL)
3159 return false;
3161 /* Figure out the comparison type if the caller accepts one. */
3162 if (comp_type)
3164 if (!get_comp_type(&str, comp_type))
3165 return false;
3168 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3171 /* Insert a number predicate.
3172 ARGV is a pointer to the argument array.
3173 *ARG_PTR is an index into ARGV, incremented if all went well.
3174 *PRED is the predicate processor to insert.
3176 Return true if input is valid, false if error.
3178 A new predicate node is assigned, along with an argument node
3179 obtained with malloc.
3181 Used by -inum and -links parsers. */
3183 static struct predicate *
3184 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3186 struct predicate *our_pred;
3187 uintmax_t num;
3188 enum comparison_type c_type;
3190 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
3191 return NULL;
3192 if (!get_num (argv[*arg_ptr], &num, &c_type))
3193 return NULL;
3194 our_pred = insert_primary (entry);
3195 our_pred->args.numinfo.kind = c_type;
3196 our_pred->args.numinfo.l_val = num;
3197 (*arg_ptr)++;
3199 if (options.debug_options & DebugExpressionTree)
3201 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3202 fprintf (stderr, " type: %s %s ",
3203 (c_type == COMP_GT) ? "gt" :
3204 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3205 (c_type == COMP_GT) ? " >" :
3206 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3207 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3209 return our_pred;
3212 static void
3213 open_output_file (const char *path, struct format_val *p)
3215 p->segment = NULL;
3216 p->quote_opts = clone_quoting_options (NULL);
3218 if (!strcmp (path, "/dev/stderr"))
3220 p->stream = stderr;
3221 p->filename = _("standard error stream");
3223 else if (!strcmp (path, "/dev/stdout"))
3225 p->stream = stdout;
3226 p->filename = _("standard output stream");
3228 else
3230 p->stream = fopen_safer (path, "w");
3231 p->filename = path;
3233 if (p->stream == NULL)
3235 fatal_file_error(path);
3239 p->dest_is_tty = stream_is_tty(p->stream);
3242 static void
3243 open_stdout (struct format_val *p)
3245 open_output_file("/dev/stdout", p);