Fix for Savannah bug #20273, find -ok with seekable stdin.
[findutils.git] / find / parser.c
blob2a5b19e2f347a3a83fb14f72da91925a44c8d01b
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #include "defs.h"
22 #include <ctype.h>
23 #include <math.h>
24 #include <assert.h>
25 #include <pwd.h>
26 #include <errno.h>
27 #include <grp.h>
28 #include <fnmatch.h>
29 #include "modechange.h"
30 #include "modetype.h"
31 #include "xstrtol.h"
32 #include "xalloc.h"
33 #include "quote.h"
34 #include "quotearg.h"
35 #include "buildcmd.h"
36 #include "nextelem.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
40 #include "xstrtod.h"
41 #include "fts_.h"
42 #include "getdate.h"
43 #include "error.h"
44 #include "findutils-version.h"
46 #include <fcntl.h>
49 /* The presence of unistd.h is assumed by gnulib these days, so we
50 * might as well assume it too.
52 /* We need <unistd.h> for isatty(). */
53 #include <unistd.h>
54 #include <sys/stat.h>
56 #if ENABLE_NLS
57 # include <libintl.h>
58 # define _(Text) gettext (Text)
59 #else
60 # define _(Text) Text
61 #endif
62 #ifdef gettext_noop
63 # define N_(String) gettext_noop (String)
64 #else
65 /* See locate.c for explanation as to why not use (String) */
66 # define N_(String) String
67 #endif
69 #if !defined (isascii) || defined (STDC_HEADERS)
70 #ifdef isascii
71 #undef isascii
72 #endif
73 #define isascii(c) 1
74 #endif
76 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
77 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
79 #ifndef HAVE_ENDGRENT
80 #define endgrent()
81 #endif
82 #ifndef HAVE_ENDPWENT
83 #define endpwent()
84 #endif
86 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
87 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 #if 0
142 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 #endif
144 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
163 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
164 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
165 static boolean insert_fprintf (struct format_val *vec,
166 const struct parser_table *entry,
167 PRED_FUNC func,
168 const char *format);
170 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
171 int kind, char format_char, char aux_format_char,
172 struct predicate *pred));
173 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, int dirfd, char *argv[], int *arg_ptr));
174 static boolean get_comp_type PARAMS((const char **str, enum comparison_type *comp_type));
175 static boolean get_relative_timestamp PARAMS((const char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
176 static boolean get_num PARAMS((const char *str, uintmax_t *num, enum comparison_type *comp_type));
177 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
178 static void open_output_file (const char *path, struct format_val *p);
179 static void open_stdout (struct format_val *p);
180 static boolean stream_is_tty(FILE *fp);
181 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
183 #define PASTE(x,y) x##y
184 #define STRINGIFY(s) #s
186 #define PARSE_OPTION(what,suffix) \
187 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
189 #define PARSE_POSOPT(what,suffix) \
190 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
192 #define PARSE_TEST(what,suffix) \
193 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
195 #define PARSE_TEST_NP(what,suffix) \
196 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
198 #define PARSE_ACTION(what,suffix) \
199 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
201 #define PARSE_ACTION_NP(what,suffix) \
202 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
204 #define PARSE_PUNCTUATION(what,suffix) \
205 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
208 /* Predicates we cannot handle in the usual way. If you add an entry
209 * to this table, double-check the switch statement in
210 * pred_sanity_check() to make sure that the new case is being
211 * correctly handled.
213 static struct parser_table const parse_entry_newerXY =
215 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
218 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
219 If they are in some Unix versions of find, they are marked `Unix'. */
221 static struct parser_table const parse_table[] =
223 PARSE_PUNCTUATION("!", negate),
224 PARSE_PUNCTUATION("not", negate), /* GNU */
225 PARSE_PUNCTUATION("(", openparen),
226 PARSE_PUNCTUATION(")", closeparen),
227 PARSE_PUNCTUATION(",", comma), /* GNU */
228 PARSE_PUNCTUATION("a", and),
229 PARSE_TEST ("amin", amin), /* GNU */
230 PARSE_PUNCTUATION("and", and), /* GNU */
231 PARSE_TEST ("anewer", anewer), /* GNU */
232 {ARG_TEST, "atime", parse_time, pred_atime},
233 PARSE_TEST ("cmin", cmin), /* GNU */
234 PARSE_TEST ("cnewer", cnewer), /* GNU */
235 {ARG_TEST, "ctime", parse_time, pred_ctime},
236 PARSE_POSOPT ("daystart", daystart), /* GNU */
237 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
238 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
239 PARSE_OPTION ("depth", depth),
240 PARSE_TEST ("empty", empty), /* GNU */
241 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
242 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
243 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
244 PARSE_ACTION ("fls", fls), /* GNU */
245 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
246 PARSE_ACTION ("fprint", fprint), /* GNU */
247 PARSE_ACTION ("fprint0", fprint0), /* GNU */
248 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
249 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
250 PARSE_TEST ("gid", gid), /* GNU */
251 PARSE_TEST ("group", group),
252 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
253 PARSE_TEST ("ilname", ilname), /* GNU */
254 PARSE_TEST ("iname", iname), /* GNU */
255 PARSE_TEST ("inum", inum), /* GNU, Unix */
256 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
257 PARSE_TEST_NP ("iregex", iregex), /* GNU */
258 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
259 PARSE_TEST ("links", links),
260 PARSE_TEST ("lname", lname), /* GNU */
261 PARSE_ACTION ("ls", ls), /* GNU, Unix */
262 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
263 PARSE_OPTION ("mindepth", mindepth), /* GNU */
264 PARSE_TEST ("mmin", mmin), /* GNU */
265 PARSE_OPTION ("mount", xdev), /* Unix */
266 {ARG_TEST, "mtime", parse_time, pred_mtime},
267 PARSE_TEST ("name", name),
268 #ifdef UNIMPLEMENTED_UNIX
269 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
270 #endif
271 PARSE_TEST ("newer", newer),
272 {ARG_TEST, "atime", parse_time, pred_atime},
273 PARSE_OPTION ("noleaf", noleaf), /* GNU */
274 PARSE_TEST ("nogroup", nogroup),
275 PARSE_TEST ("nouser", nouser),
276 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
277 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
278 PARSE_PUNCTUATION("o", or),
279 PARSE_PUNCTUATION("or", or), /* GNU */
280 PARSE_ACTION ("ok", ok),
281 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
282 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
283 PARSE_TEST ("perm", perm),
284 PARSE_ACTION ("print", print),
285 PARSE_ACTION ("print0", print0), /* GNU */
286 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
287 PARSE_ACTION ("prune", prune),
288 PARSE_ACTION ("quit", quit), /* GNU */
289 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
290 PARSE_TEST ("regex", regex), /* GNU */
291 PARSE_OPTION ("regextype", regextype), /* GNU */
292 PARSE_TEST ("samefile", samefile), /* GNU */
293 #if 0
294 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
295 #endif
296 PARSE_TEST ("size", size),
297 PARSE_TEST ("type", type),
298 PARSE_TEST ("uid", uid), /* GNU */
299 PARSE_TEST ("used", used), /* GNU */
300 PARSE_TEST ("user", user),
301 PARSE_OPTION ("warn", warn), /* GNU */
302 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
303 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
304 PARSE_OPTION ("xdev", xdev),
305 PARSE_TEST ("xtype", xtype), /* GNU */
306 #ifdef UNIMPLEMENTED_UNIX
307 /* It's pretty ugly for find to know about archive formats.
308 Plus what it could do with cpio archives is very limited.
309 Better to leave it out. */
310 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
311 #endif
312 /* gnulib's stdbool.h might have made true and false into macros,
313 * so we can't leave named 'true' and 'false' tokens, so we have
314 * to expeant the relevant entries longhand.
316 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
317 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
318 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
320 /* Various other cases that don't fit neatly into our macro scheme. */
321 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
322 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
323 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
324 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
325 {0, 0, 0, 0}
329 static const char *first_nonoption_arg = NULL;
330 static const struct parser_table *noop = NULL;
333 static const struct parser_table*
334 get_noop(void)
336 int i;
337 if (NULL == noop)
339 for (i = 0; parse_table[i].parser_name != 0; i++)
341 if (ARG_NOOP ==parse_table[i].type)
343 noop = &(parse_table[i]);
344 break;
348 return noop;
351 static int
352 get_stat_Ytime(const struct stat *p,
353 char what,
354 struct timespec *ret)
356 switch (what)
358 case 'a':
359 *ret = get_stat_atime(p);
360 return 1;
361 case 'B':
362 *ret = get_stat_birthtime(p);
363 return (ret->tv_nsec >= 0);
364 case 'c':
365 *ret = get_stat_ctime(p);
366 return 1;
367 case 'm':
368 *ret = get_stat_mtime(p);
369 return 1;
370 default:
371 assert (0);
372 abort();
376 void
377 set_follow_state(enum SymlinkOption opt)
379 if (options.debug_options & DebugStat)
381 /* For DebugStat, the choice is made at runtime within debug_stat()
382 * by checking the contents of the symlink_handling variable.
384 options.xstat = debug_stat;
386 else
388 switch (opt)
390 case SYMLINK_ALWAYS_DEREF: /* -L */
391 options.xstat = optionl_stat;
392 options.no_leaf_check = true;
393 break;
395 case SYMLINK_NEVER_DEREF: /* -P (default) */
396 options.xstat = optionp_stat;
397 /* Can't turn no_leaf_check off because the user might have specified
398 * -noleaf anyway
400 break;
402 case SYMLINK_DEREF_ARGSONLY: /* -H */
403 options.xstat = optionh_stat;
404 options.no_leaf_check = true;
407 options.symlink_handling = opt;
411 void
412 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
414 (void) args;
415 (void) argno;
416 (void) last;
417 (void) predicates;
418 first_nonoption_arg = NULL;
421 void
422 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
424 /* does nothing */
425 (void) args;
426 (void) argno;
427 (void) last;
428 (void) predicates;
432 /* Check that it is legal to fid the given primary in its
433 * position and return it.
435 const struct parser_table*
436 found_parser(const char *original_arg, const struct parser_table *entry)
438 /* If this is an option, but we have already had a
439 * non-option argument, the user may be under the
440 * impression that the behaviour of the option
441 * argument is conditional on some preceding
442 * tests. This might typically be the case with,
443 * for example, -maxdepth.
445 * The options -daystart and -follow are exempt
446 * from this treatment, since their positioning
447 * in the command line does have an effect on
448 * subsequent tests but not previous ones. That
449 * might be intentional on the part of the user.
451 if (entry->type != ARG_POSITIONAL_OPTION)
453 /* Something other than -follow/-daystart.
454 * If this is an option, check if it followed
455 * a non-option and if so, issue a warning.
457 if (entry->type == ARG_OPTION)
459 if ((first_nonoption_arg != NULL)
460 && options.warnings )
462 /* option which follows a non-option */
463 error (0, 0,
464 _("warning: you have specified the %s "
465 "option after a non-option argument %s, "
466 "but options are not positional (%s affects "
467 "tests specified before it as well as those "
468 "specified after it). Please specify options "
469 "before other arguments.\n"),
470 original_arg,
471 first_nonoption_arg,
472 original_arg);
475 else
477 /* Not an option or a positional option,
478 * so remember we've seen it in order to
479 * use it in a possible future warning message.
481 if (first_nonoption_arg == NULL)
483 first_nonoption_arg = original_arg;
488 return entry;
492 /* Return a pointer to the parser function to invoke for predicate
493 SEARCH_NAME.
494 Return NULL if SEARCH_NAME is not a valid predicate name. */
496 const struct parser_table*
497 find_parser (char *search_name)
499 int i;
500 const char *original_arg = search_name;
502 /* Ugh. Special case -newerXY. */
503 if (0 == strncmp("-newer", search_name, 6)
504 && (8 == strlen(search_name)))
506 return found_parser(original_arg, &parse_entry_newerXY);
509 if (*search_name == '-')
510 search_name++;
512 for (i = 0; parse_table[i].parser_name != 0; i++)
514 if (strcmp (parse_table[i].parser_name, search_name) == 0)
516 return found_parser(original_arg, &parse_table[i]);
519 return NULL;
522 static float
523 estimate_file_age_success_rate(float num_days)
525 if (num_days < 0.1)
527 /* Assume 1% of files have timestamps in the future */
528 return 0.01f;
530 else if (num_days < 1)
532 /* Assume 30% of files have timestamps today */
533 return 0.3f;
535 else if (num_days > 100)
537 /* Assume 30% of files are very old */
538 return 0.3f;
540 else
542 /* Assume 39% of files are between 1 and 100 days old. */
543 return 0.39f;
547 static float
548 estimate_timestamp_success_rate(time_t when)
550 int num_days = (options.cur_day_start - when) / 86400;
551 return estimate_file_age_success_rate(num_days);
554 /* Collect an argument from the argument list, or
555 * return false.
557 static boolean
558 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
560 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
562 *collected_arg = NULL;
563 return false;
565 else
567 *collected_arg = argv[*arg_ptr];
568 (*arg_ptr)++;
569 return true;
573 static boolean
574 collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
576 const char *filename;
577 if (collect_arg(argv, arg_ptr, &filename))
579 if (0 == (options.xstat)(filename, p))
581 return true;
583 else
585 fatal_file_error(filename);
588 else
590 return false;
594 /* The parsers are responsible to continue scanning ARGV for
595 their arguments. Each parser knows what is and isn't
596 allowed for itself.
598 ARGV is the argument array.
599 *ARG_PTR is the index to start at in ARGV,
600 updated to point beyond the last element consumed.
602 The predicate structure is updated with the new information. */
605 static boolean
606 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
608 struct predicate *our_pred;
610 (void) argv;
611 (void) arg_ptr;
613 our_pred = get_new_pred (entry);
614 our_pred->pred_func = pred_and;
615 our_pred->p_type = BI_OP;
616 our_pred->p_prec = AND_PREC;
617 our_pred->need_stat = our_pred->need_type = false;
618 return true;
621 static boolean
622 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
624 struct stat stat_newer;
626 set_stat_placeholders(&stat_newer);
627 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
629 struct predicate *our_pred = insert_primary (entry);
630 our_pred->args.reftime.xval = XVAL_ATIME;
631 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
632 our_pred->args.reftime.kind = COMP_GT;
633 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
634 return true;
636 return false;
639 boolean
640 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
642 struct predicate *our_pred;
644 (void) argv;
645 (void) arg_ptr;
647 our_pred = get_new_pred (entry);
648 our_pred->pred_func = pred_closeparen;
649 our_pred->p_type = CLOSE_PAREN;
650 our_pred->p_prec = NO_PREC;
651 our_pred->need_stat = our_pred->need_type = false;
652 return true;
655 static boolean
656 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
658 struct stat stat_newer;
660 set_stat_placeholders(&stat_newer);
661 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
663 struct predicate *our_pred = insert_primary (entry);
664 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
665 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
666 our_pred->args.reftime.kind = COMP_GT;
667 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
668 return true;
670 return false;
673 static boolean
674 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
676 struct predicate *our_pred;
678 (void) argv;
679 (void) arg_ptr;
681 our_pred = get_new_pred (entry);
682 our_pred->pred_func = pred_comma;
683 our_pred->p_type = BI_OP;
684 our_pred->p_prec = COMMA_PREC;
685 our_pred->need_stat = our_pred->need_type = false;
686 our_pred->est_success_rate = 1.0f;
687 return true;
690 static boolean
691 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
693 struct tm *local;
695 (void) entry;
696 (void) argv;
697 (void) arg_ptr;
699 if (options.full_days == false)
701 options.cur_day_start += DAYSECS;
702 local = localtime (&options.cur_day_start);
703 options.cur_day_start -= (local
704 ? (local->tm_sec + local->tm_min * 60
705 + local->tm_hour * 3600)
706 : options.cur_day_start % DAYSECS);
707 options.full_days = true;
709 return true;
712 static boolean
713 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
715 struct predicate *our_pred;
716 (void) argv;
717 (void) arg_ptr;
719 our_pred = insert_primary (entry);
720 our_pred->side_effects = our_pred->no_default_print = true;
721 /* -delete implies -depth */
722 options.do_dir_first = false;
724 /* We do not need stat information because we check for the case
725 * (errno==EISDIR) in pred_delete.
727 our_pred->need_stat = our_pred->need_type = false;
729 our_pred->est_success_rate = 1.0f;
730 return true;
733 static boolean
734 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
736 (void) entry;
737 (void) argv;
739 options.do_dir_first = false;
740 return parse_noop(entry, argv, arg_ptr);
743 static boolean
744 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
746 if (options.warnings)
748 error (0, 0,
749 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
751 return parse_depth(entry, argv, arg_ptr);
754 static boolean
755 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
757 struct predicate *our_pred;
758 (void) argv;
759 (void) arg_ptr;
761 our_pred = insert_primary (entry);
762 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
763 return true;
766 static boolean
767 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
769 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
772 static boolean
773 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
775 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
778 static boolean
779 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
781 struct predicate *our_pred;
783 (void) argv;
784 (void) arg_ptr;
786 our_pred = insert_primary (entry);
787 our_pred->need_stat = our_pred->need_type = false;
788 our_pred->side_effects = our_pred->no_default_print = false;
789 our_pred->est_success_rate = 0.0f;
790 return true;
793 static boolean
794 insert_fls (const struct parser_table* entry, const char *filename)
796 struct predicate *our_pred = insert_primary (entry);
797 if (filename)
798 open_output_file (filename, &our_pred->args.printf_vec);
799 else
800 open_stdout (&our_pred->args.printf_vec);
801 our_pred->side_effects = our_pred->no_default_print = true;
802 our_pred->est_success_rate = 1.0f;
803 return true;
807 static boolean
808 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
810 const char *filename;
811 return collect_arg(argv, arg_ptr, &filename)
812 && insert_fls(entry, filename);
815 static boolean
816 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
818 set_follow_state(SYMLINK_ALWAYS_DEREF);
819 return parse_noop(entry, argv, arg_ptr);
822 static boolean
823 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
825 struct predicate *our_pred;
826 const char *filename;
827 if (collect_arg(argv, arg_ptr, &filename))
829 our_pred = insert_primary (entry);
830 open_output_file (filename, &our_pred->args.printf_vec);
831 our_pred->side_effects = our_pred->no_default_print = true;
832 our_pred->need_stat = our_pred->need_type = false;
833 our_pred->est_success_rate = 1.0f;
834 return true;
836 else
838 return false;
842 static boolean
843 insert_fprint(const struct parser_table* entry, const char *filename)
845 struct predicate *our_pred = insert_primary (entry);
846 if (filename)
847 open_output_file (filename, &our_pred->args.printf_vec);
848 else
849 open_stdout (&our_pred->args.printf_vec);
850 our_pred->side_effects = our_pred->no_default_print = true;
851 our_pred->need_stat = our_pred->need_type = false;
852 our_pred->est_success_rate = 1.0f;
853 return true;
857 static boolean
858 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
860 const char *filename;
861 if (collect_arg(argv, arg_ptr, &filename))
862 return insert_fprint(entry, filename);
863 else
864 return false;
867 static float estimate_fstype_success_rate(const char *fsname)
869 struct stat dir_stat;
870 const char *dir = "/";
871 if (0 == stat(dir, &dir_stat))
873 const char *fstype = filesystem_type(&dir_stat, dir);
874 /* Assume most files are on the same file system type as the root fs. */
875 if (0 == strcmp(fsname, fstype))
876 return 0.7f;
877 else
878 return 0.3f;
880 return 1.0f;
884 static boolean
885 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
887 const char *typename;
888 if (collect_arg(argv, arg_ptr, &typename))
890 struct predicate *our_pred = insert_primary (entry);
891 our_pred->args.str = typename;
893 /* This is an expensive operation, so although there are
894 * circumstances where it is selective, we ignore this fact
895 * because we probably don't want to promote this test to the
896 * front anyway.
898 our_pred->est_success_rate = estimate_fstype_success_rate(typename);
899 return true;
901 else
903 return false;
907 static boolean
908 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
910 struct predicate *p = insert_num (argv, arg_ptr, entry);
911 if (p)
913 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
914 return true;
916 else
918 return false;
923 static int
924 safe_atoi (const char *s)
926 long lval;
927 char *end;
929 errno = 0;
930 lval = strtol(s, &end, 10);
931 if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
933 /* max/min possible value, or an error. */
934 if (errno == ERANGE)
936 /* too big, or too small. */
937 error(1, errno, "%s", s);
939 else
941 /* not a valid number */
942 error(1, errno, "%s", s);
944 /* Otherwise, we do a range chack against INT_MAX and INT_MIN
945 * below.
949 if (lval > INT_MAX || lval < INT_MIN)
951 /* The number was in range for long, but not int. */
952 errno = ERANGE;
953 error(1, errno, "%s", s);
955 else if (*end)
957 error(1, errno, "Unexpected suffix %s on %s",
958 quotearg_n_style(0, options.err_quoting_style, end),
959 quotearg_n_style(1, options.err_quoting_style, s));
961 else if (end == s)
963 error(1, errno, "Expected an integer: %s",
964 quotearg_n_style(0, options.err_quoting_style, s));
966 return (int)lval;
970 static boolean
971 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
973 const char *groupname;
975 if (collect_arg(argv, arg_ptr, &groupname))
977 gid_t gid;
978 struct predicate *our_pred;
979 struct group *cur_gr = getgrnam(groupname);
980 endgrent();
981 if (cur_gr)
983 gid = cur_gr->gr_gid;
985 else
987 const int gid_len = strspn (groupname, "0123456789");
988 if (gid_len)
990 if (groupname[gid_len] == 0)
992 gid = safe_atoi (groupname);
994 else
996 /* XXX: no test in test suite for this */
997 error(1, 0, _("%s is not the name of an existing group and"
998 " it does not look like a numeric group ID "
999 "because it has the unexpected suffix %s"),
1000 quotearg_n_style(0, options.err_quoting_style, groupname),
1001 quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
1002 return false;
1005 else
1007 if (*groupname)
1009 /* XXX: no test in test suite for this */
1010 error(1, 0, _("%s is not the name of an existing group"),
1011 quotearg_n_style(0, options.err_quoting_style, groupname));
1013 else
1015 error(1, 0, _("argument to -group is empty, but should be a group name"));
1017 return false;
1020 our_pred = insert_primary (entry);
1021 our_pred->args.gid = gid;
1022 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1023 return true;
1025 return false;
1028 static boolean
1029 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
1031 (void) entry;
1032 (void) argv;
1033 (void) arg_ptr;
1035 usage(stdout, 0, NULL);
1036 puts (_("\n\
1037 default path is the current directory; default expression is -print\n\
1038 expression may consist of: operators, options, tests, and actions:\n"));
1039 puts (_("\
1040 operators (decreasing precedence; -and is implicit where no others are given):\n\
1041 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
1042 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1043 puts (_("\
1044 positional options (always true): -daystart -follow -regextype\n\n\
1045 normal options (always true, specified before other expressions):\n\
1046 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1047 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1048 puts (_("\
1049 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1050 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1051 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1052 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1053 puts (_("\
1054 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
1055 -readable -writable -executable\n\
1056 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1057 -used N -user NAME -xtype [bcdpfls]\n"));
1058 puts (_("\
1059 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1060 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1061 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1062 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1063 "));
1064 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1065 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1066 email to <bug-findutils@gnu.org>."));
1067 exit (0);
1070 static float
1071 estimate_pattern_match_rate(const char *pattern, int is_regex)
1073 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1075 /* A wildcard; assume the pattern matches most files. */
1076 return 0.8f;
1078 else
1080 return 0.1f;
1084 static boolean
1085 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1087 const char *name;
1088 if (collect_arg(argv, arg_ptr, &name))
1090 struct predicate *our_pred = insert_primary (entry);
1091 our_pred->args.str = name;
1092 /* Use the generic glob pattern estimator to figure out how many
1093 * links will match, but bear in mind that most files won't be links.
1095 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1096 return true;
1098 else
1100 return false;
1105 /* sanity check the fnmatch() function to make sure that case folding
1106 * is supported (as opposed to just having the flag ignored).
1108 static boolean
1109 fnmatch_sanitycheck(void)
1111 static boolean checked = false;
1112 if (!checked)
1114 if (0 != fnmatch("foo", "foo", 0)
1115 || 0 == fnmatch("Foo", "foo", 0)
1116 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1118 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1119 return false;
1121 checked = true;
1123 return checked;
1127 static boolean
1128 check_name_arg(const char *pred, const char *arg)
1130 if (options.warnings && strchr(arg, '/'))
1132 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'."),
1133 pred,
1134 safely_quote_err_filename(0, arg),
1135 safely_quote_err_filename(1, arg));
1137 return true; /* allow it anyway */
1142 static boolean
1143 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1145 const char *name;
1146 fnmatch_sanitycheck();
1147 if (collect_arg(argv, arg_ptr, &name))
1149 if (check_name_arg("-iname", name))
1151 struct predicate *our_pred = insert_primary (entry);
1152 our_pred->need_stat = our_pred->need_type = false;
1153 our_pred->args.str = name;
1154 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1155 return true;
1158 return false;
1161 static boolean
1162 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1164 struct predicate *p = insert_num (argv, arg_ptr, entry);
1165 if (p)
1167 /* inode number is exact match only, so very low proportions of
1168 * files match
1170 p->est_success_rate = 1e-6;
1171 return true;
1173 else
1175 return false;
1179 /* -ipath is deprecated (at RMS's request) in favour of
1180 * -iwholename. See the node "GNU Manuals" in standards.texi
1181 * for the rationale for this (basically, GNU prefers the use
1182 * of the phrase "file name" to "path name"
1184 static boolean
1185 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1187 error (0, 0,
1188 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1190 return parse_iwholename(entry, argv, arg_ptr);
1193 static boolean
1194 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1196 const char *name;
1198 fnmatch_sanitycheck();
1199 if (collect_arg(argv, arg_ptr, &name))
1201 struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
1202 our_pred->need_stat = our_pred->need_type = false;
1203 our_pred->args.str = name;
1204 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1205 return true;
1207 return false;
1210 static boolean
1211 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1213 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1216 static boolean
1217 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1219 struct predicate *p = insert_num (argv, arg_ptr, entry);
1220 if (p)
1222 if (p->args.numinfo.l_val == 1)
1223 p->est_success_rate = 0.99;
1224 else if (p->args.numinfo.l_val == 2)
1225 p->est_success_rate = 0.01;
1226 else
1227 p->est_success_rate = 1e-3;
1228 return true;
1230 else
1232 return false;
1236 static boolean
1237 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1239 const char *name;
1240 fnmatch_sanitycheck();
1241 if (collect_arg(argv, arg_ptr, &name))
1243 struct predicate *our_pred = insert_primary (entry);
1244 our_pred->args.str = name;
1245 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1246 return true;
1248 return false;
1251 static boolean
1252 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1254 (void) &argv;
1255 (void) &arg_ptr;
1256 return insert_fls(entry, NULL);
1259 static boolean
1260 insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
1261 int *limitptr)
1263 const char *depthstr;
1264 int depth_len;
1265 const char *predicate = argv[(*arg_ptr)-1];
1266 if (collect_arg(argv, arg_ptr, &depthstr))
1268 depth_len = strspn (depthstr, "0123456789");
1269 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1271 (*limitptr) = safe_atoi (depthstr);
1272 if (*limitptr >= 0)
1274 return parse_noop(entry, argv, arg_ptr);
1277 error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
1278 predicate,
1279 quotearg_n_style(0, options.err_quoting_style, depthstr));
1280 return false;
1282 /* missing argument */
1283 return false;
1287 static boolean
1288 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1290 return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
1293 static boolean
1294 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1296 return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
1300 static boolean
1301 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr, enum xval xv)
1303 const char *minutes;
1305 if (collect_arg(argv, arg_ptr, &minutes))
1307 struct time_val tval;
1308 tval.xval = xv;
1309 if (get_relative_timestamp(minutes, &tval,
1310 options.cur_day_start + DAYSECS, 60,
1311 "arithmetic overflow while converting %s "
1312 "minutes to a number of seconds"))
1314 struct predicate *our_pred = insert_primary (entry);
1315 our_pred->args.reftime = tval;
1316 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1317 return true;
1320 return false;
1322 static boolean
1323 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1325 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1328 static boolean
1329 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1331 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1335 static boolean
1336 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1338 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1341 static boolean
1342 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1344 const char *name;
1345 if (collect_arg(argv, arg_ptr, &name))
1347 fnmatch_sanitycheck();
1348 if (check_name_arg("-name", name))
1350 struct predicate *our_pred = insert_primary (entry);
1351 our_pred->need_stat = our_pred->need_type = false;
1352 our_pred->args.str = name;
1353 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1354 return true;
1357 return false;
1360 static boolean
1361 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1363 struct predicate *our_pred;
1365 (void) &argv;
1366 (void) &arg_ptr;
1368 our_pred = get_new_pred_chk_op (entry);
1369 our_pred->pred_func = pred_negate;
1370 our_pred->p_type = UNI_OP;
1371 our_pred->p_prec = NEGATE_PREC;
1372 our_pred->need_stat = our_pred->need_type = false;
1373 return true;
1376 static boolean
1377 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1379 struct predicate *our_pred;
1380 struct stat stat_newer;
1382 set_stat_placeholders(&stat_newer);
1383 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
1385 our_pred = insert_primary (entry);
1386 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1387 our_pred->args.reftime.xval = XVAL_MTIME;
1388 our_pred->args.reftime.kind = COMP_GT;
1389 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1390 return true;
1392 return false;
1396 static boolean
1397 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1399 (void) argv;
1400 (void) arg_ptr;
1402 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1404 return false;
1406 else if (8u != strlen(argv[*arg_ptr]))
1408 return false;
1410 else
1412 char x, y;
1413 const char validchars[] = "aBcmt";
1415 assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
1416 x = argv[*arg_ptr][6];
1417 y = argv[*arg_ptr][7];
1420 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1421 if ('B' == x || 'B' == y)
1423 error(0, 0,
1424 _("This system does not provide a way to find the birth time of a file."));
1425 return 0;
1427 #endif
1429 /* -newertY (for any Y) is invalid. */
1430 if (x == 't'
1431 || 0 == strchr(validchars, x)
1432 || 0 == strchr( validchars, y))
1434 return false;
1436 else
1438 struct predicate *our_pred;
1440 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1441 * past the test name (for most other tests, this is already done)
1443 (*arg_ptr)++;
1445 our_pred = insert_primary (entry);
1448 switch (x)
1450 case 'a':
1451 our_pred->args.reftime.xval = XVAL_ATIME;
1452 break;
1453 case 'B':
1454 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1455 break;
1456 case 'c':
1457 our_pred->args.reftime.xval = XVAL_CTIME;
1458 break;
1459 case 'm':
1460 our_pred->args.reftime.xval = XVAL_MTIME;
1461 break;
1462 default:
1463 assert (strchr(validchars, x));
1464 assert (0);
1467 if ('t' == y)
1469 if (!get_date(&our_pred->args.reftime.ts,
1470 argv[*arg_ptr],
1471 &options.start_time))
1473 error(1, 0,
1474 _("I cannot figure out how to interpret %s as a date or time"),
1475 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1478 else
1480 struct stat stat_newer;
1482 /* Stat the named file. */
1483 set_stat_placeholders(&stat_newer);
1484 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1485 fatal_file_error(argv[*arg_ptr]);
1487 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1489 /* We cannot extract a timestamp from the struct stat. */
1490 error(1, 0, _("Cannot obtain birth time of file %s"),
1491 safely_quote_err_filename(0, argv[*arg_ptr]));
1494 our_pred->args.reftime.kind = COMP_GT;
1495 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1496 (*arg_ptr)++;
1498 assert (our_pred->pred_func != NULL);
1499 assert (our_pred->pred_func == pred_newerXY);
1500 assert (our_pred->need_stat);
1501 return true;
1507 static boolean
1508 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1510 options.no_leaf_check = true;
1511 return parse_noop(entry, argv, arg_ptr);
1514 #ifdef CACHE_IDS
1515 /* Arbitrary amount by which to increase size
1516 of `uid_unused' and `gid_unused'. */
1517 #define ALLOC_STEP 2048
1519 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1520 char *uid_unused = NULL;
1522 /* Number of elements in `uid_unused'. */
1523 unsigned uid_allocated;
1525 /* Similar for GIDs and group entries. */
1526 char *gid_unused = NULL;
1527 unsigned gid_allocated;
1528 #endif
1530 static boolean
1531 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1533 struct predicate *our_pred;
1535 (void) &argv;
1536 (void) &arg_ptr;
1538 our_pred = insert_primary (entry);
1539 our_pred->est_success_rate = 1e-4;
1540 #ifdef CACHE_IDS
1541 if (gid_unused == NULL)
1543 struct group *gr;
1545 gid_allocated = ALLOC_STEP;
1546 gid_unused = xmalloc (gid_allocated);
1547 memset (gid_unused, 1, gid_allocated);
1548 setgrent ();
1549 while ((gr = getgrent ()) != NULL)
1551 if ((unsigned) gr->gr_gid >= gid_allocated)
1553 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1554 gid_unused = xrealloc (gid_unused, new_allocated);
1555 memset (gid_unused + gid_allocated, 1,
1556 new_allocated - gid_allocated);
1557 gid_allocated = new_allocated;
1559 gid_unused[(unsigned) gr->gr_gid] = 0;
1561 endgrent ();
1563 #endif
1564 return true;
1567 static boolean
1568 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1570 struct predicate *our_pred;
1571 (void) argv;
1572 (void) arg_ptr;
1575 our_pred = insert_primary (entry);
1576 our_pred->est_success_rate = 1e-3;
1577 #ifdef CACHE_IDS
1578 if (uid_unused == NULL)
1580 struct passwd *pw;
1582 uid_allocated = ALLOC_STEP;
1583 uid_unused = xmalloc (uid_allocated);
1584 memset (uid_unused, 1, uid_allocated);
1585 setpwent ();
1586 while ((pw = getpwent ()) != NULL)
1588 if ((unsigned) pw->pw_uid >= uid_allocated)
1590 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1591 uid_unused = xrealloc (uid_unused, new_allocated);
1592 memset (uid_unused + uid_allocated, 1,
1593 new_allocated - uid_allocated);
1594 uid_allocated = new_allocated;
1596 uid_unused[(unsigned) pw->pw_uid] = 0;
1598 endpwent ();
1600 #endif
1601 return true;
1604 static boolean
1605 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1607 options.warnings = false;
1608 return parse_noop(entry, argv, arg_ptr);
1611 static boolean
1612 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1614 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1617 static boolean
1618 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1620 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1623 boolean
1624 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1626 struct predicate *our_pred;
1628 (void) argv;
1629 (void) arg_ptr;
1631 our_pred = get_new_pred_chk_op (entry);
1632 our_pred->pred_func = pred_openparen;
1633 our_pred->p_type = OPEN_PAREN;
1634 our_pred->p_prec = NO_PREC;
1635 our_pred->need_stat = our_pred->need_type = false;
1636 return true;
1639 static boolean
1640 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1642 struct predicate *our_pred;
1644 (void) argv;
1645 (void) arg_ptr;
1647 our_pred = get_new_pred (entry);
1648 our_pred->pred_func = pred_or;
1649 our_pred->p_type = BI_OP;
1650 our_pred->p_prec = OR_PREC;
1651 our_pred->need_stat = our_pred->need_type = false;
1652 return true;
1655 /* -path is deprecated (at RMS's request) in favour of
1656 * -iwholename. See the node "GNU Manuals" in standards.texi
1657 * for the rationale for this (basically, GNU prefers the use
1658 * of the phrase "file name" to "path name".
1660 * We do not issue a warning that this usage is deprecated
1661 * since HPUX find supports this predicate also.
1663 static boolean
1664 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1666 return parse_wholename(entry, argv, arg_ptr);
1669 static boolean
1670 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1672 const char *name;
1673 if (collect_arg(argv, arg_ptr, &name))
1675 struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
1676 our_pred->need_stat = our_pred->need_type = false;
1677 our_pred->args.str = name;
1678 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1679 return true;
1681 return false;
1684 static boolean
1685 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1687 mode_t perm_val[2];
1688 float rate;
1689 int mode_start = 0;
1690 boolean havekind = false;
1691 enum permissions_type kind = PERM_EXACT;
1692 struct mode_change *change = NULL;
1693 struct predicate *our_pred;
1694 const char *perm_expr;
1696 if (!collect_arg(argv, arg_ptr, &perm_expr))
1697 return false;
1699 switch (perm_expr[0])
1701 case '-':
1702 mode_start = 1;
1703 kind = PERM_AT_LEAST;
1704 havekind = true;
1705 rate = 0.2;
1706 break;
1708 case '+':
1709 change = mode_compile (perm_expr);
1710 if (NULL == change)
1712 /* Most likely the caller is an old script that is still
1713 * using the obsolete GNU syntax '-perm +MODE'. This old
1714 * syntax was withdrawn in favor of '-perm /MODE' because
1715 * it is incompatible with POSIX in some cases, but we
1716 * still support uses of it that are not incompatible with
1717 * POSIX.
1719 mode_start = 1;
1720 kind = PERM_ANY;
1721 rate = 0.3;
1723 else
1725 /* This is a POSIX-compatible usage */
1726 mode_start = 0;
1727 kind = PERM_EXACT;
1728 rate = 0.1;
1730 havekind = true;
1731 break;
1733 case '/': /* GNU extension */
1734 mode_start = 1;
1735 kind = PERM_ANY;
1736 havekind = true;
1737 rate = 0.3;
1738 break;
1740 default:
1741 /* For example, '-perm 0644', which is valid and matches
1742 * only files whose mode is exactly 0644.
1744 mode_start = 0;
1745 kind = PERM_EXACT;
1746 havekind = true;
1747 rate = 0.01;
1748 break;
1751 if (NULL == change)
1753 change = mode_compile (perm_expr + mode_start);
1754 if (NULL == change)
1755 error (1, 0, _("invalid mode %s"),
1756 quotearg_n_style(0, options.err_quoting_style, perm_expr));
1758 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1759 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1760 free (change);
1762 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1764 /* The meaning of -perm /000 will change in the future. It
1765 * currently matches no files, but like -perm -000 it should
1766 * match all files.
1768 * Starting in 2005, we used to issue a warning message
1769 * informing the user that the behaviour would change in the
1770 * future. We have now changed the behaviour and issue a
1771 * warning message that the behaviour recently changed.
1773 error (0, 0,
1774 _("warning: you have specified a mode pattern %s (which is "
1775 "equivalent to /000). The meaning of -perm /000 has now been "
1776 "changed to be consistent with -perm -000; that is, while it "
1777 "used to match no files, it now matches all files."),
1778 perm_expr);
1780 kind = PERM_AT_LEAST;
1781 havekind = true;
1783 /* The "magic" number below is just the fraction of files on my
1784 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1785 * Actual totals are 1472 and 1073833.
1787 rate = 0.9986; /* probably matches anything but a broken symlink */
1790 our_pred = insert_primary (entry);
1791 our_pred->est_success_rate = rate;
1792 if (havekind)
1794 our_pred->args.perm.kind = kind;
1796 else
1799 switch (perm_expr[0])
1801 case '-':
1802 our_pred->args.perm.kind = PERM_AT_LEAST;
1803 break;
1804 case '+':
1805 our_pred->args.perm.kind = PERM_ANY;
1806 break;
1807 default:
1808 our_pred->args.perm.kind = PERM_EXACT;
1809 break;
1812 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1813 return true;
1816 boolean
1817 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1819 struct predicate *our_pred;
1821 (void) argv;
1822 (void) arg_ptr;
1824 our_pred = insert_primary (entry);
1825 /* -print has the side effect of printing. This prevents us
1826 from doing undesired multiple printing when the user has
1827 already specified -print. */
1828 our_pred->side_effects = our_pred->no_default_print = true;
1829 our_pred->need_stat = our_pred->need_type = false;
1830 open_stdout(&our_pred->args.printf_vec);
1831 return true;
1834 static boolean
1835 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1837 return insert_fprint(entry, NULL);
1840 static boolean
1841 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1843 const char *format;
1844 if (collect_arg(argv, arg_ptr, &format))
1846 struct format_val fmt;
1847 open_stdout(&fmt);
1848 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1850 return false;
1853 static boolean
1854 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1856 const char *format, *filename;
1857 if (collect_arg(argv, arg_ptr, &filename))
1859 if (collect_arg(argv, arg_ptr, &format))
1861 struct format_val fmt;
1862 open_output_file (filename, &fmt);
1863 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1866 return false;
1869 static boolean
1870 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1872 struct predicate *our_pred;
1874 (void) argv;
1875 (void) arg_ptr;
1877 our_pred = insert_primary (entry);
1878 our_pred->need_stat = our_pred->need_type = false;
1879 /* -prune has a side effect that it does not descend into
1880 the current directory. */
1881 our_pred->side_effects = true;
1882 our_pred->no_default_print = false;
1883 return true;
1886 static boolean
1887 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1889 struct predicate *our_pred = insert_primary (entry);
1890 (void) argv;
1891 (void) arg_ptr;
1892 our_pred->need_stat = our_pred->need_type = false;
1893 our_pred->side_effects = true; /* Exiting is a side effect... */
1894 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1895 our_pred->est_success_rate = 1.0f;
1896 return true;
1900 static boolean
1901 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1903 const char *type_name;
1904 if (collect_arg(argv, arg_ptr, &type_name))
1906 /* collect the regex type name */
1907 options.regex_options = get_regex_type(type_name);
1908 return parse_noop(entry, argv, arg_ptr);
1910 return false;
1914 static boolean
1915 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1917 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1920 static boolean
1921 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1923 const char *rx;
1924 if (collect_arg(argv, arg_ptr, &rx))
1926 struct re_pattern_buffer *re;
1927 const char *error_message;
1928 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
1929 our_pred->need_stat = our_pred->need_type = false;
1930 re = xmalloc (sizeof (struct re_pattern_buffer));
1931 our_pred->args.regex = re;
1932 re->allocated = 100;
1933 re->buffer = xmalloc (re->allocated);
1934 re->fastmap = NULL;
1936 re_set_syntax(regex_options);
1937 re->syntax = regex_options;
1938 re->translate = NULL;
1940 error_message = re_compile_pattern (rx, strlen(rx), re);
1941 if (error_message)
1942 error (1, 0, "%s", error_message);
1943 our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
1944 return true;
1946 return false;
1949 static boolean
1950 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1952 struct predicate *our_pred;
1953 uintmax_t num;
1954 char suffix;
1955 enum comparison_type c_type;
1957 int blksize = 512;
1958 int len;
1960 /* XXX: cannot (yet) convert to ue collect_arg() as this
1961 * function modifies the args in-place.
1963 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1964 return false;
1966 len = strlen (argv[*arg_ptr]);
1967 if (len == 0)
1968 error (1, 0, _("invalid null argument to -size"));
1970 suffix = argv[*arg_ptr][len - 1];
1971 switch (suffix)
1973 case 'b':
1974 blksize = 512;
1975 argv[*arg_ptr][len - 1] = '\0';
1976 break;
1978 case 'c':
1979 blksize = 1;
1980 argv[*arg_ptr][len - 1] = '\0';
1981 break;
1983 case 'k':
1984 blksize = 1024;
1985 argv[*arg_ptr][len - 1] = '\0';
1986 break;
1988 case 'M': /* Megabytes */
1989 blksize = 1024*1024;
1990 argv[*arg_ptr][len - 1] = '\0';
1991 break;
1993 case 'G': /* Gigabytes */
1994 blksize = 1024*1024*1024;
1995 argv[*arg_ptr][len - 1] = '\0';
1996 break;
1998 case 'w':
1999 blksize = 2;
2000 argv[*arg_ptr][len - 1] = '\0';
2001 break;
2003 case '0':
2004 case '1':
2005 case '2':
2006 case '3':
2007 case '4':
2008 case '5':
2009 case '6':
2010 case '7':
2011 case '8':
2012 case '9':
2013 break;
2015 default:
2016 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
2018 /* TODO: accept fractional megabytes etc. ? */
2019 if (!get_num (argv[*arg_ptr], &num, &c_type))
2021 error(1, 0, _("Invalid argument `%s%c' to -size"), argv[*arg_ptr], (int)suffix);
2022 return false;
2024 our_pred = insert_primary (entry);
2025 our_pred->args.size.kind = c_type;
2026 our_pred->args.size.blocksize = blksize;
2027 our_pred->args.size.size = num;
2028 our_pred->need_stat = true;
2029 our_pred->need_type = false;
2031 if (COMP_GT == c_type)
2032 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
2033 else if (COMP_LT == c_type)
2034 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
2035 else
2036 our_pred->est_success_rate = 0.01;
2038 (*arg_ptr)++;
2039 return true;
2043 static boolean
2044 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2046 /* General idea: stat the file, remember device and inode numbers.
2047 * If a candidate file matches those, it's the same file.
2049 struct predicate *our_pred;
2050 struct stat st, fst;
2051 int fd, openflags;
2053 set_stat_placeholders(&st);
2054 if (!collect_arg_stat_info(argv, arg_ptr, &st))
2055 return false;
2057 set_stat_placeholders(&fst);
2058 /* POSIX systems are free to re-use the inode number of a deleted
2059 * file. To ensure that we are not fooled by inode reuse, we hold
2060 * the file open if we can. This would prevent the system reusing
2061 * the file.
2063 fd = -3; /* means, uninitialised */
2064 openflags = O_RDONLY;
2066 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2068 if (options.open_nofollow_available)
2070 assert (O_NOFOLLOW != 0);
2071 openflags |= O_NOFOLLOW;
2072 fd = -1; /* safe to open it. */
2074 else
2076 if (S_ISLNK(st.st_mode))
2078 /* no way to ensure that a symlink will not be followed
2079 * by open(2), so fall back on using lstat(). Accept
2080 * the risk that the named file will be deleted and
2081 * replaced with another having the same inode.
2083 * Avoid opening the file.
2085 fd = -2; /* Do not open it */
2087 else
2089 fd = -1;
2090 /* Race condition here: the file might become a symlink here. */
2094 else
2096 /* We want to dereference the symlink anyway */
2097 fd = -1; /* safe to open it without O_NOFOLLOW */
2100 assert (fd != -3); /* check we made a decision */
2101 if (fd == -1)
2103 /* Race condition here. The file might become a
2104 * symbolic link in between out call to stat and
2105 * the call to open.
2107 fd = open(argv[*arg_ptr], openflags);
2109 if (fd >= 0)
2111 /* We stat the file again here to prevent a race condition
2112 * between the first stat and the call to open(2).
2114 if (0 != fstat(fd, &fst))
2116 fatal_file_error(argv[*arg_ptr]);
2118 else
2120 /* Worry about the race condition. If the file became a
2121 * symlink after our first stat and before our call to
2122 * open, fst may contain the stat information for the
2123 * destination of the link, not the link itself.
2125 if ((*options.xstat) (argv[*arg_ptr], &st))
2126 fatal_file_error(argv[*arg_ptr]);
2128 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2129 && (!options.open_nofollow_available))
2131 if (S_ISLNK(st.st_mode))
2133 /* We lost the race. Leave the data in st. The
2134 * file descriptor points to the wrong thing.
2136 close(fd);
2137 fd = -1;
2139 else
2141 /* Several possibilities here:
2142 * 1. There was no race
2143 * 2. The file changed into a symlink after the stat and
2144 * before the open, and then back into a non-symlink
2145 * before the second stat.
2147 * In case (1) there is no problem. In case (2),
2148 * the stat() and fstat() calls will have returned
2149 * different data. O_NOFOLLOW was not available,
2150 * so the open() call may have followed a symlink
2151 * even if the -P option is in effect.
2153 if ((st.st_dev == fst.st_dev)
2154 && (st.st_ino == fst.st_ino))
2156 /* No race. No need to copy fst to st,
2157 * since they should be identical (modulo
2158 * differences in padding bytes).
2161 else
2163 /* We lost the race. Leave the data in st. The
2164 * file descriptor points to the wrong thing.
2166 close(fd);
2167 fd = -1;
2171 else
2173 st = fst;
2179 our_pred = insert_primary (entry);
2180 our_pred->args.samefileid.ino = st.st_ino;
2181 our_pred->args.samefileid.dev = st.st_dev;
2182 our_pred->args.samefileid.fd = fd;
2183 our_pred->need_type = false;
2184 our_pred->need_stat = true;
2185 our_pred->est_success_rate = 0.01f;
2186 return true;
2189 #if 0
2190 /* This function is commented out partly because support for it is
2191 * uneven.
2193 static boolean
2194 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
2196 const char *arg;
2197 const char *errmsg = _("The -show-control-chars option takes a single argument which "
2198 "must be 'literal' or 'safe'");
2200 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2202 error (1, errno, "%s", errmsg);
2203 return false;
2205 else
2207 arg = argv[*arg_ptr];
2209 if (0 == strcmp("literal", arg))
2211 options.literal_control_chars = true;
2213 else if (0 == strcmp("safe", arg))
2215 options.literal_control_chars = false;
2217 else
2219 error (1, errno, "%s", errmsg);
2220 return false;
2222 (*arg_ptr)++; /* consume the argument. */
2223 return true;
2226 #endif
2229 static boolean
2230 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2232 struct predicate *our_pred;
2234 (void) argv;
2235 (void) arg_ptr;
2237 our_pred = insert_primary (entry);
2238 our_pred->need_stat = our_pred->need_type = false;
2239 our_pred->est_success_rate = 1.0f;
2240 return true;
2243 static boolean
2244 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2246 (void) entry;
2247 return parse_true(get_noop(), argv, arg_ptr);
2250 static boolean
2251 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2253 struct predicate *our_pred;
2254 (void) argv;
2255 (void) arg_ptr;
2256 our_pred = insert_primary (entry);
2257 our_pred->need_stat = our_pred->need_type = false;
2258 our_pred->side_effects = our_pred->no_default_print = false;
2259 if (pred_is(our_pred, pred_executable))
2260 our_pred->est_success_rate = 0.2;
2261 else
2262 our_pred->est_success_rate = 0.9;
2263 return true;
2266 static boolean
2267 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2269 return insert_type (argv, arg_ptr, entry, pred_type);
2272 static boolean
2273 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2275 struct predicate *p = insert_num (argv, arg_ptr, entry);
2276 if (p)
2278 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2279 return true;
2281 else
2283 return false;
2287 static boolean
2288 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2290 struct predicate *our_pred;
2291 struct time_val tval;
2292 const char *offset_str;
2293 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2295 if (collect_arg(argv, arg_ptr, &offset_str))
2297 /* The timespec is actually a delta value, so we use an origin of 0. */
2298 if (get_relative_timestamp(offset_str, &tval, 0, DAYSECS, errmsg))
2300 our_pred = insert_primary (entry);
2301 our_pred->args.reftime = tval;
2302 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2303 return true;
2305 else
2307 error(1, 0, _("Invalid argument %s to -used"), offset_str);
2308 return false;
2311 else
2313 return false; /* missing argument */
2317 static boolean
2318 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2320 const char *username;
2322 if (collect_arg(argv, arg_ptr, &username))
2324 struct predicate *our_pred;
2325 uid_t uid;
2326 struct passwd *cur_pwd = getpwnam(username);
2327 endpwent();
2328 if (cur_pwd != NULL)
2330 uid = cur_pwd->pw_uid;
2332 else
2334 int uid_len = strspn (username, "0123456789");
2335 if (uid_len && (username[uid_len]==0))
2336 uid = safe_atoi (username);
2337 else
2338 return false;
2340 our_pred = insert_primary (entry);
2341 our_pred->args.uid = uid;
2342 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2343 return true;
2345 return false;
2348 static boolean
2349 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2351 int features = 0;
2352 int flags;
2354 (void) argv;
2355 (void) arg_ptr;
2356 (void) entry;
2358 display_findutils_version("find");
2359 printf (_("Features enabled: "));
2361 #if CACHE_IDS
2362 printf("CACHE_IDS ");
2363 ++features;
2364 #endif
2365 #if DEBUG
2366 printf("DEBUG ");
2367 ++features;
2368 #endif
2369 #if DEBUG_STAT
2370 printf("DEBUG_STAT ");
2371 ++features;
2372 #endif
2373 #if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
2374 printf("D_TYPE ");
2375 ++features;
2376 #endif
2377 #if defined O_NOFOLLOW
2378 printf("O_NOFOLLOW(%s) ",
2379 (options.open_nofollow_available ? "enabled" : "disabled"));
2380 ++features;
2381 #endif
2382 #if defined LEAF_OPTIMISATION
2383 printf("LEAF_OPTIMISATION ");
2384 ++features;
2385 #endif
2387 flags = 0;
2388 if (is_fts_enabled(&flags))
2390 int nflags = 0;
2391 printf("FTS(");
2392 ++features;
2394 if (flags & FTS_CWDFD)
2396 if (nflags)
2398 printf(",");
2400 printf("FTS_CWDFD");
2401 ++nflags;
2403 printf(") ");
2406 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2407 ++features;
2409 if (0 == features)
2411 /* For the moment, leave this as English in case someone wants
2412 to parse these strings. */
2413 printf("none");
2415 printf("\n");
2417 exit (0);
2420 static boolean
2421 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2423 options.stay_on_filesystem = true;
2424 return parse_noop(entry, argv, arg_ptr);
2427 static boolean
2428 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2430 options.ignore_readdir_race = true;
2431 return parse_noop(entry, argv, arg_ptr);
2434 static boolean
2435 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2437 options.ignore_readdir_race = false;
2438 return parse_noop(entry, argv, arg_ptr);
2441 static boolean
2442 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2444 options.warnings = true;
2445 return parse_noop(entry, argv, arg_ptr);
2448 static boolean
2449 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2451 return insert_type (argv, arg_ptr, entry, pred_xtype);
2454 static boolean
2455 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2457 mode_t type_cell;
2458 struct predicate *our_pred;
2459 float rate = 0.5;
2460 const char *typeletter;
2462 if (collect_arg(argv, arg_ptr, &typeletter))
2464 if (strlen(typeletter) != 1u)
2466 error(1, 0, _("Arguments to -type should contain only one letter"));
2467 return false;
2470 switch (typeletter[0])
2472 case 'b': /* block special */
2473 type_cell = S_IFBLK;
2474 rate = 0.01f;
2475 break;
2476 case 'c': /* character special */
2477 type_cell = S_IFCHR;
2478 rate = 0.01f;
2479 break;
2480 case 'd': /* directory */
2481 type_cell = S_IFDIR;
2482 rate = 0.4f;
2483 break;
2484 case 'f': /* regular file */
2485 type_cell = S_IFREG;
2486 rate = 0.95f;
2487 break;
2488 #ifdef S_IFLNK
2489 case 'l': /* symbolic link */
2490 type_cell = S_IFLNK;
2491 rate = 0.1f;
2492 break;
2493 #endif
2494 #ifdef S_IFIFO
2495 case 'p': /* pipe */
2496 type_cell = S_IFIFO;
2497 rate = 0.01f;
2498 break;
2499 #endif
2500 #ifdef S_IFSOCK
2501 case 's': /* socket */
2502 type_cell = S_IFSOCK;
2503 rate = 0.01f;
2504 break;
2505 #endif
2506 #ifdef S_IFDOOR
2507 case 'D': /* Solaris door */
2508 type_cell = S_IFDOOR;
2509 rate = 0.01f;
2510 break;
2511 #endif
2512 default: /* None of the above ... nuke 'em. */
2513 error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
2514 return false;
2516 our_pred = insert_primary_withpred (entry, which_pred);
2517 our_pred->est_success_rate = rate;
2519 /* Figure out if we will need to stat the file, because if we don't
2520 * need to follow symlinks, we can avoid a stat call by using
2521 * struct dirent.d_type.
2523 if (which_pred == pred_xtype)
2525 our_pred->need_stat = true;
2526 our_pred->need_type = false;
2528 else
2530 our_pred->need_stat = false; /* struct dirent is enough */
2531 our_pred->need_type = true;
2533 our_pred->args.type = type_cell;
2534 return true;
2536 return false;
2540 /* Return true if the file accessed via FP is a terminal.
2542 static boolean
2543 stream_is_tty(FILE *fp)
2545 int fd = fileno(fp);
2546 if (-1 == fd)
2548 return false; /* not a valid stream */
2550 else
2552 return isatty(fd) ? true : false;
2560 /* XXX: do we need to pass FUNC to this function? */
2561 static boolean
2562 insert_fprintf (struct format_val *vec,
2563 const struct parser_table *entry, PRED_FUNC func,
2564 const char *format_const)
2566 char *format = (char*)format_const; /* XXX: casting away constness */
2567 register char *scan; /* Current address in scanning `format'. */
2568 register char *scan2; /* Address inside of element being scanned. */
2569 struct segment **segmentp; /* Address of current segment. */
2570 struct predicate *our_pred;
2572 our_pred = insert_primary_withpred (entry, func);
2573 our_pred->side_effects = our_pred->no_default_print = true;
2574 our_pred->args.printf_vec = *vec;
2575 our_pred->need_type = false;
2576 our_pred->need_stat = false;
2577 our_pred->p_cost = NeedsNothing;
2579 segmentp = &our_pred->args.printf_vec.segment;
2580 *segmentp = NULL;
2582 for (scan = format; *scan; scan++)
2584 if (*scan == '\\')
2586 scan2 = scan + 1;
2587 if (*scan2 >= '0' && *scan2 <= '7')
2589 register int n, i;
2591 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2592 i++, scan2++)
2593 n = 8 * n + *scan2 - '0';
2594 scan2--;
2595 *scan = n;
2597 else
2599 switch (*scan2)
2601 case 'a':
2602 *scan = 7;
2603 break;
2604 case 'b':
2605 *scan = '\b';
2606 break;
2607 case 'c':
2608 make_segment (segmentp, format, scan - format,
2609 KIND_STOP, 0, 0,
2610 our_pred);
2611 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2612 our_pred->p_cost = NeedsStatInfo;
2613 return true;
2614 case 'f':
2615 *scan = '\f';
2616 break;
2617 case 'n':
2618 *scan = '\n';
2619 break;
2620 case 'r':
2621 *scan = '\r';
2622 break;
2623 case 't':
2624 *scan = '\t';
2625 break;
2626 case 'v':
2627 *scan = '\v';
2628 break;
2629 case '\\':
2630 /* *scan = '\\'; * it already is */
2631 break;
2632 default:
2633 error (0, 0,
2634 _("warning: unrecognized escape `\\%c'"), *scan2);
2635 scan++;
2636 continue;
2639 segmentp = make_segment (segmentp, format, scan - format + 1,
2640 KIND_PLAIN, 0, 0,
2641 our_pred);
2642 format = scan2 + 1; /* Move past the escape. */
2643 scan = scan2; /* Incremented immediately by `for'. */
2645 else if (*scan == '%')
2647 if (scan[1] == 0)
2649 /* Trailing %. We don't like those. */
2650 error (1, 0, _("error: %s at end of format string"), scan);
2652 else if (scan[1] == '%')
2654 segmentp = make_segment (segmentp, format, scan - format + 1,
2655 KIND_PLAIN, 0, 0,
2656 our_pred);
2657 scan++;
2658 format = scan + 1;
2659 continue;
2661 /* Scan past flags, width and precision, to verify kind. */
2662 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2663 /* Do nothing. */ ;
2664 while (ISDIGIT (*scan2))
2665 scan2++;
2666 if (*scan2 == '.')
2667 for (scan2++; ISDIGIT (*scan2); scan2++)
2668 /* Do nothing. */ ;
2669 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2671 segmentp = make_segment (segmentp, format, scan2 - format,
2672 KIND_FORMAT, *scan2, 0,
2673 our_pred);
2674 scan = scan2;
2675 format = scan + 1;
2677 else if (strchr ("ABCT", *scan2) && scan2[1])
2679 segmentp = make_segment (segmentp, format, scan2 - format,
2680 KIND_FORMAT, scan2[0], scan2[1],
2681 our_pred);
2682 scan = scan2 + 1;
2683 format = scan + 1;
2684 continue;
2686 else
2688 /* An unrecognized % escape. Print the char after the %. */
2689 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2690 *scan2);
2691 segmentp = make_segment (segmentp, format, scan - format,
2692 KIND_PLAIN, 0, 0,
2693 our_pred);
2694 format = scan + 1;
2695 continue;
2700 if (scan > format)
2701 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2702 our_pred);
2703 return true;
2706 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2707 from the text in FORMAT, which has length LEN.
2708 Return the address of the `next' pointer of the new segment. */
2710 static struct segment **
2711 make_segment (struct segment **segment,
2712 char *format,
2713 int len,
2714 int kind,
2715 char format_char,
2716 char aux_format_char,
2717 struct predicate *pred)
2719 enum EvaluationCost mycost = NeedsNothing;
2720 char *fmt;
2722 *segment = xmalloc (sizeof (struct segment));
2724 (*segment)->segkind = kind;
2725 (*segment)->format_char[0] = format_char;
2726 (*segment)->format_char[1] = aux_format_char;
2727 (*segment)->next = NULL;
2728 (*segment)->text_len = len;
2730 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2731 strncpy (fmt, format, len);
2732 fmt += len;
2734 switch (kind)
2736 case KIND_PLAIN: /* Plain text string, no % conversion. */
2737 case KIND_STOP: /* Terminate argument, no newline. */
2738 assert (0 == format_char);
2739 assert (0 == aux_format_char);
2740 *fmt = '\0';
2741 if (mycost > pred->p_cost)
2742 pred->p_cost = NeedsNothing;
2743 return &(*segment)->next;
2744 break;
2747 assert (kind == KIND_FORMAT);
2748 switch (format_char)
2750 case 'l': /* object of symlink */
2751 pred->need_stat = true;
2752 mycost = NeedsLinkName;
2753 *fmt++ = 's';
2754 break;
2756 case 'y': /* file type */
2757 pred->need_type = true;
2758 mycost = NeedsType;
2759 *fmt++ = 's';
2760 break;
2762 case 'a': /* atime in `ctime' format */
2763 case 'A': /* atime in user-specified strftime format */
2764 case 'B': /* birth time in user-specified strftime format */
2765 case 'c': /* ctime in `ctime' format */
2766 case 'C': /* ctime in user-specified strftime format */
2767 case 'F': /* file system type */
2768 case 'g': /* group name */
2769 case 'i': /* inode number */
2770 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2771 case 's': /* size in bytes */
2772 case 't': /* mtime in `ctime' format */
2773 case 'T': /* mtime in user-specified strftime format */
2774 case 'u': /* user name */
2775 pred->need_stat = true;
2776 mycost = NeedsStatInfo;
2777 *fmt++ = 's';
2778 break;
2780 case 'S': /* sparseness */
2781 pred->need_stat = true;
2782 mycost = NeedsStatInfo;
2783 *fmt++ = 'g';
2784 break;
2786 case 'Y': /* symlink pointed file type */
2787 pred->need_stat = true;
2788 mycost = NeedsType; /* true for amortised effect */
2789 *fmt++ = 's';
2790 break;
2792 case 'f': /* basename of path */
2793 case 'h': /* leading directories part of path */
2794 case 'p': /* pathname */
2795 case 'P': /* pathname with ARGV element stripped */
2796 *fmt++ = 's';
2797 break;
2799 case 'H': /* ARGV element file was found under */
2800 *fmt++ = 's';
2801 break;
2803 /* Numeric items that one might expect to honour
2804 * #, 0, + flags but which do not.
2806 case 'G': /* GID number */
2807 case 'U': /* UID number */
2808 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2809 case 'D': /* Filesystem device on which the file exits */
2810 case 'k': /* size in 1K blocks */
2811 case 'n': /* number of links */
2812 pred->need_stat = true;
2813 mycost = NeedsStatInfo;
2814 *fmt++ = 's';
2815 break;
2817 /* Numeric items that DO honour #, 0, + flags.
2819 case 'd': /* depth in search tree (0 = ARGV element) */
2820 *fmt++ = 'd';
2821 break;
2823 case 'm': /* mode as octal number (perms only) */
2824 *fmt++ = 'o';
2825 pred->need_stat = true;
2826 mycost = NeedsStatInfo;
2827 break;
2829 case '{':
2830 case '[':
2831 case '(':
2832 error (1, 0,
2833 _("error: the format directive `%%%c' is reserved for future use"),
2834 (int)kind);
2835 /*NOTREACHED*/
2836 break;
2838 *fmt = '\0';
2840 if (mycost > pred->p_cost)
2841 pred->p_cost = mycost;
2842 return &(*segment)->next;
2845 static void
2846 check_path_safety(const char *action, char **argv)
2848 const char *path = getenv("PATH");
2849 char *s;
2851 (void)argv;
2853 s = next_element(path, 1);
2854 while ((s = next_element ((char *) NULL, 1)) != NULL)
2856 if (0 == strcmp(s, "."))
2858 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)"),
2859 action);
2861 else if ('/' != s[0])
2863 /* Relative paths are also dangerous in $PATH. */
2864 error(1, 0, _("The relative path %s is included in the PATH "
2865 "environment variable, which is insecure in "
2866 "combination with the %s action of find. "
2867 "Please remove that entry from $PATH"),
2868 safely_quote_err_filename(0, s),
2869 action);
2875 /* handles both exec and ok predicate */
2876 static boolean
2877 new_insert_exec_ok (const char *action,
2878 const struct parser_table *entry,
2879 int dirfd,
2880 char **argv,
2881 int *arg_ptr)
2883 int start, end; /* Indexes in ARGV of start & end of cmd. */
2884 int i; /* Index into cmd args */
2885 int saw_braces; /* True if previous arg was '{}'. */
2886 boolean allow_plus; /* True if + is a valid terminator */
2887 int brace_count; /* Number of instances of {}. */
2888 PRED_FUNC func = entry->pred_func;
2889 enum BC_INIT_STATUS bcstatus;
2891 struct predicate *our_pred;
2892 struct exec_val *execp; /* Pointer for efficiency. */
2894 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2895 return false;
2897 our_pred = insert_primary_withpred (entry, func);
2898 our_pred->side_effects = our_pred->no_default_print = true;
2899 our_pred->need_type = our_pred->need_stat = false;
2901 execp = &our_pred->args.exec_vec;
2903 if ((func != pred_okdir) && (func != pred_ok))
2905 allow_plus = true;
2906 execp->close_stdin = false;
2908 else
2910 allow_plus = false;
2911 /* If find reads stdin (i.e. for -ok and similar), close stdin
2912 * in the child to prevent some script from consiming the output
2913 * intended for find.
2915 execp->close_stdin = true;
2919 if ((func == pred_execdir) || (func == pred_okdir))
2921 options.ignore_readdir_race = false;
2922 check_path_safety(action, argv);
2923 execp->use_current_dir = true;
2925 else
2927 execp->use_current_dir = false;
2930 our_pred->args.exec_vec.multiple = 0;
2932 /* Count the number of args with path replacements, up until the ';'.
2933 * Also figure out if the command is terminated by ";" or by "+".
2935 start = *arg_ptr;
2936 for (end = start, saw_braces=0, brace_count=0;
2937 (argv[end] != NULL)
2938 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2939 end++)
2941 /* For -exec and -execdir, "{} +" can terminate the command. */
2942 if ( allow_plus
2943 && argv[end][0] == '+' && argv[end][1] == 0
2944 && saw_braces)
2946 our_pred->args.exec_vec.multiple = 1;
2947 break;
2950 saw_braces = 0;
2951 if (mbsstr (argv[end], "{}"))
2953 saw_braces = 1;
2954 ++brace_count;
2956 if (0 == end && (func == pred_execdir || func == pred_okdir))
2958 /* The POSIX standard says that {} replacement should
2959 * occur even in the utility name. This is insecure
2960 * since it means we will be executing a command whose
2961 * name is chosen according to whatever find finds in
2962 * the file system. That can be influenced by an
2963 * attacker. Hence for -execdir and -okdir this is not
2964 * allowed. We can specify this as those options are
2965 * not defined by POSIX.
2967 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2972 /* Fail if no command given or no semicolon found. */
2973 if ((end == start) || (argv[end] == NULL))
2975 *arg_ptr = end;
2976 free(our_pred);
2977 return false;
2980 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2983 const char *suffix;
2984 if (func == pred_execdir)
2985 suffix = "dir";
2986 else
2987 suffix = "";
2989 error(1, 0,
2990 _("Only one instance of {} is supported with -exec%s ... +"),
2991 suffix);
2994 /* We use a switch statement here so that the compiler warns us when
2995 * we forget to handle a newly invented enum value.
2997 * Like xargs, we allow 2KiB of headroom for the launched utility to
2998 * export its own environment variables before calling something
2999 * else.
3001 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
3002 switch (bcstatus)
3004 case BC_INIT_ENV_TOO_BIG:
3005 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
3006 error(1, 0,
3007 _("The environment is too large for exec()."));
3008 break;
3009 case BC_INIT_OK:
3010 /* Good news. Carry on. */
3011 break;
3013 bc_use_sensible_arg_max(&execp->ctl);
3016 execp->ctl.exec_callback = launch;
3018 if (our_pred->args.exec_vec.multiple)
3020 /* "+" terminator, so we can just append our arguments after the
3021 * command and initial arguments.
3023 execp->replace_vec = NULL;
3024 execp->ctl.replace_pat = NULL;
3025 execp->ctl.rplen = 0;
3026 execp->ctl.lines_per_exec = 0; /* no limit */
3027 execp->ctl.args_per_exec = 0; /* no limit */
3029 /* remember how many arguments there are */
3030 execp->ctl.initial_argc = (end-start) - 1;
3032 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
3033 bc_init_state(&execp->ctl, &execp->state, execp);
3035 /* Gather the initial arguments. Skip the {}. */
3036 for (i=start; i<end-1; ++i)
3038 bc_push_arg(&execp->ctl, &execp->state,
3039 argv[i], strlen(argv[i])+1,
3040 NULL, 0,
3044 else
3046 /* Semicolon terminator - more than one {} is supported, so we
3047 * have to do brace-replacement.
3049 execp->num_args = end - start;
3051 execp->ctl.replace_pat = "{}";
3052 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
3053 execp->ctl.lines_per_exec = 0; /* no limit */
3054 execp->ctl.args_per_exec = 0; /* no limit */
3055 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
3058 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3059 bc_init_state(&execp->ctl, &execp->state, execp);
3061 /* Remember the (pre-replacement) arguments for later. */
3062 for (i=0; i<execp->num_args; ++i)
3064 execp->replace_vec[i] = argv[i+start];
3068 if (argv[end] == NULL)
3069 *arg_ptr = end;
3070 else
3071 *arg_ptr = end + 1;
3073 return true;
3078 static boolean
3079 insert_exec_ok (const char *action, const struct parser_table *entry, int dirfd, char **argv, int *arg_ptr)
3081 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
3086 /* Get a timestamp and comparison type.
3088 STR is the ASCII representation.
3089 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3090 relative to ORIGIN (usually the current moment or midnight).
3091 Thus the sense of the comparison type appears to be reversed.
3092 Set *COMP_TYPE to the kind of comparison that is requested.
3093 Issue OVERFLOWMESSAGE if overflow occurs.
3094 Return true if all okay, false if input error.
3096 Used by -atime, -ctime and -mtime (parsers) to
3097 get the appropriate information for a time predicate processor. */
3099 static boolean
3100 get_relative_timestamp (const char *str,
3101 struct time_val *result,
3102 time_t origin,
3103 double sec_per_unit,
3104 const char *overflowmessage)
3106 uintmax_t checkval;
3107 double offset, seconds, f;
3109 if (get_comp_type(&str, &result->kind))
3111 /* Invert the sense of the comparison */
3112 switch (result->kind)
3114 case COMP_LT: result->kind = COMP_GT; break;
3115 case COMP_GT: result->kind = COMP_LT; break;
3116 default: break;
3119 /* Convert the ASCII number into floating-point. */
3120 if (xstrtod(str, NULL, &offset, strtod))
3122 /* Separate the floating point number the user specified
3123 * (which is a number of days, or minutes, etc) into an
3124 * integral number of seconds (SECONDS) and a fraction (F).
3126 f = modf(offset * sec_per_unit, &seconds);
3128 result->ts.tv_sec = origin - seconds;
3129 result->ts.tv_nsec = fabs(f * 1e9);
3131 /* Check for overflow. */
3132 checkval = (uintmax_t)origin - seconds;
3133 if (checkval != result->ts.tv_sec)
3135 /* an overflow has occurred. */
3136 error (1, 0, overflowmessage, str);
3138 return true;
3140 else
3142 /* Conversion from ASCII to double failed. */
3143 return false;
3146 else
3148 return false;
3152 /* Insert a time predicate based on the information in ENTRY.
3153 ARGV is a pointer to the argument array.
3154 ARG_PTR is a pointer to an index into the array, incremented if
3155 all went well.
3157 Return true if input is valid, false if not.
3159 A new predicate node is assigned, along with an argument node
3160 obtained with malloc.
3162 Used by -atime, -ctime, and -mtime parsers. */
3164 static boolean
3165 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3167 struct predicate *our_pred;
3168 struct time_val tval;
3169 enum comparison_type comp;
3170 const char *timearg, *orig_timearg;
3171 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
3172 time_t origin;
3174 if (!collect_arg(argv, arg_ptr, &timearg))
3175 return false;
3176 orig_timearg = timearg;
3178 /* Decide the origin by previewing the comparison type. */
3179 origin = options.cur_day_start;
3181 if (get_comp_type(&timearg, &comp))
3183 /* Remember, we invert the sense of the comparison, so this tests
3184 * against COMP_LT instead of COMP_GT...
3186 if (COMP_LT == comp)
3188 uintmax_t expected = origin + (DAYSECS-1);
3189 origin += (DAYSECS-1);
3190 if (origin != expected)
3192 error(1, 0,
3193 _("arithmetic overflow when trying to calculate the end of today"));
3197 /* We discard the value of comp here, as get_relative_timestamp
3198 * will set tval.kind. For that to work, we have to restore
3199 * timearg so that it points to the +/- prefix, if any. get_comp_type()
3200 * will have advanced timearg, so we restore it.
3202 timearg = orig_timearg;
3204 if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
3205 return false;
3207 our_pred = insert_primary (entry);
3208 our_pred->args.reftime = tval;
3209 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3211 if (options.debug_options & DebugExpressionTree)
3213 time_t t;
3215 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3216 fprintf (stderr, " type: %s %s ",
3217 (tval.kind == COMP_GT) ? "gt" :
3218 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3219 (tval.kind == COMP_GT) ? " >" :
3220 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3221 t = our_pred->args.reftime.ts.tv_sec;
3222 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3223 if (tval.kind == COMP_EQ)
3225 t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
3226 fprintf (stderr, " < %ju %s",
3227 (uintmax_t) t, ctime (&t));
3231 return true;
3234 /* Get the comparison type prefix (if any) from a number argument.
3235 The prefix is at *STR.
3236 Set *COMP_TYPE to the kind of comparison that is requested.
3237 Advance *STR beyond any initial comparison prefix.
3239 Return true if all okay, false if input error. */
3240 static boolean
3241 get_comp_type(const char **str, enum comparison_type *comp_type)
3243 switch (**str)
3245 case '+':
3246 *comp_type = COMP_GT;
3247 (*str)++;
3248 break;
3249 case '-':
3250 *comp_type = COMP_LT;
3251 (*str)++;
3252 break;
3253 default:
3254 *comp_type = COMP_EQ;
3255 break;
3257 return true;
3264 /* Get a number with comparison information.
3265 The sense of the comparison information is 'normal'; that is,
3266 '+' looks for a count > than the number and '-' less than.
3268 STR is the ASCII representation of the number.
3269 Set *NUM to the number.
3270 Set *COMP_TYPE to the kind of comparison that is requested.
3272 Return true if all okay, false if input error. */
3274 static boolean
3275 get_num (const char *str,
3276 uintmax_t *num,
3277 enum comparison_type *comp_type)
3279 char *pend;
3281 if (str == NULL)
3282 return false;
3284 /* Figure out the comparison type if the caller accepts one. */
3285 if (comp_type)
3287 if (!get_comp_type(&str, comp_type))
3288 return false;
3291 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3294 /* Insert a number predicate.
3295 ARGV is a pointer to the argument array.
3296 *ARG_PTR is an index into ARGV, incremented if all went well.
3297 *PRED is the predicate processor to insert.
3299 Return true if input is valid, false if error.
3301 A new predicate node is assigned, along with an argument node
3302 obtained with malloc.
3304 Used by -inum and -links parsers. */
3306 static struct predicate *
3307 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3309 const char *numstr;
3311 if (collect_arg(argv, arg_ptr, &numstr))
3313 uintmax_t num;
3314 enum comparison_type c_type;
3316 if (get_num (numstr, &num, &c_type))
3318 struct predicate *our_pred = insert_primary (entry);
3319 our_pred->args.numinfo.kind = c_type;
3320 our_pred->args.numinfo.l_val = num;
3322 if (options.debug_options & DebugExpressionTree)
3324 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3325 fprintf (stderr, " type: %s %s ",
3326 (c_type == COMP_GT) ? "gt" :
3327 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3328 (c_type == COMP_GT) ? " >" :
3329 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3330 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3332 return our_pred;
3335 return NULL;
3338 static void
3339 open_output_file (const char *path, struct format_val *p)
3341 p->segment = NULL;
3342 p->quote_opts = clone_quoting_options (NULL);
3344 if (!strcmp (path, "/dev/stderr"))
3346 p->stream = stderr;
3347 p->filename = _("standard error");
3349 else if (!strcmp (path, "/dev/stdout"))
3351 p->stream = stdout;
3352 p->filename = _("standard output");
3354 else
3356 p->stream = fopen_safer (path, "w");
3357 p->filename = path;
3359 if (p->stream == NULL)
3361 fatal_file_error(path);
3365 p->dest_is_tty = stream_is_tty(p->stream);
3368 static void
3369 open_stdout (struct format_val *p)
3371 open_output_file("/dev/stdout", p);