Fixed Savannah bug #18203 (find error messages can garble the console)
[findutils.git] / find / parser.c
bloba707546ed4aedf93947f3a8bc1406af6169eb885
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA.
22 #include "defs.h"
23 #include <ctype.h>
24 #include <math.h>
25 #include <assert.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <fnmatch.h>
29 #include "modechange.h"
30 #include "modetype.h"
31 #include "xstrtol.h"
32 #include "xalloc.h"
33 #include "quote.h"
34 #include "quotearg.h"
35 #include "buildcmd.h"
36 #include "nextelem.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
40 #include "xstrtod.h"
41 #include "fts_.h"
42 #include "gnulib-version.h"
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #else
47 #include <sys/file.h>
48 #endif
50 /* The presence of unistd.h is assumed by gnulib these days, so we
51 * might as well assume it too.
53 /* We need <unistd.h> for isatty(). */
54 #include <unistd.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 PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
167 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
168 int kind, char format_char, char aux_format_char,
169 struct predicate *pred));
170 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, int dirfd, char *argv[], int *arg_ptr));
171 static boolean get_comp_type PARAMS((char **str, enum comparison_type *comp_type));
172 static boolean get_relative_timestamp PARAMS((char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
173 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
174 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
175 static FILE *open_output_file PARAMS((char *path));
176 static boolean stream_is_tty(FILE *fp);
177 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
179 #define PASTE(x,y) x##y
180 #define STRINGIFY(s) #s
182 #define PARSE_OPTION(what,suffix) \
183 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_POSOPT(what,suffix) \
186 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
188 #define PARSE_TEST(what,suffix) \
189 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
191 #define PARSE_TEST_NP(what,suffix) \
192 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
194 #define PARSE_ACTION(what,suffix) \
195 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
197 #define PARSE_ACTION_NP(what,suffix) \
198 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
200 #define PARSE_PUNCTUATION(what,suffix) \
201 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
204 /* Predicates we cannot handle in the usual way */
205 static struct parser_table const parse_entry_newerXY =
207 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
210 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
211 If they are in some Unix versions of find, they are marked `Unix'. */
213 static struct parser_table const parse_table[] =
215 PARSE_PUNCTUATION("!", negate),
216 PARSE_PUNCTUATION("not", negate), /* GNU */
217 PARSE_PUNCTUATION("(", openparen),
218 PARSE_PUNCTUATION(")", closeparen),
219 PARSE_PUNCTUATION(",", comma), /* GNU */
220 PARSE_PUNCTUATION("a", and),
221 PARSE_TEST ("amin", amin), /* GNU */
222 PARSE_PUNCTUATION("and", and), /* GNU */
223 PARSE_TEST ("anewer", anewer), /* GNU */
224 {ARG_TEST, "atime", parse_time, pred_atime},
225 PARSE_TEST ("cmin", cmin), /* GNU */
226 PARSE_TEST ("cnewer", cnewer), /* GNU */
227 {ARG_TEST, "ctime", parse_time, pred_ctime},
228 PARSE_POSOPT ("daystart", daystart), /* GNU */
229 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
230 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
231 PARSE_OPTION ("depth", depth),
232 PARSE_TEST ("empty", empty), /* GNU */
233 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
234 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
235 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
236 PARSE_ACTION ("fls", fls), /* GNU */
237 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
238 PARSE_ACTION ("fprint", fprint), /* GNU */
239 PARSE_ACTION ("fprint0", fprint0), /* GNU */
240 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
241 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
242 PARSE_TEST ("gid", gid), /* GNU */
243 PARSE_TEST ("group", group),
244 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
245 PARSE_TEST ("ilname", ilname), /* GNU */
246 PARSE_TEST ("iname", iname), /* GNU */
247 PARSE_TEST ("inum", inum), /* GNU, Unix */
248 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
249 PARSE_TEST_NP ("iregex", iregex), /* GNU */
250 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
251 PARSE_TEST ("links", links),
252 PARSE_TEST ("lname", lname), /* GNU */
253 PARSE_ACTION ("ls", ls), /* GNU, Unix */
254 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
255 PARSE_OPTION ("mindepth", mindepth), /* GNU */
256 PARSE_TEST ("mmin", mmin), /* GNU */
257 PARSE_OPTION ("mount", xdev), /* Unix */
258 {ARG_TEST, "mtime", parse_time, pred_mtime},
259 PARSE_TEST ("name", name),
260 #ifdef UNIMPLEMENTED_UNIX
261 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
262 #endif
263 PARSE_TEST ("newer", newer),
264 {ARG_TEST, "atime", parse_time, pred_atime},
265 PARSE_OPTION ("noleaf", noleaf), /* GNU */
266 PARSE_TEST ("nogroup", nogroup),
267 PARSE_TEST ("nouser", nouser),
268 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
269 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
270 PARSE_PUNCTUATION("o", or),
271 PARSE_PUNCTUATION("or", or), /* GNU */
272 PARSE_ACTION ("ok", ok),
273 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
274 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
275 PARSE_TEST ("perm", perm),
276 PARSE_ACTION ("print", print),
277 PARSE_ACTION ("print0", print0), /* GNU */
278 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
279 PARSE_ACTION ("prune", prune),
280 PARSE_ACTION ("quit", quit), /* GNU */
281 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
282 PARSE_TEST ("regex", regex), /* GNU */
283 PARSE_OPTION ("regextype", regextype), /* GNU */
284 PARSE_TEST ("samefile", samefile), /* GNU */
285 #if 0
286 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
287 #endif
288 PARSE_TEST ("size", size),
289 PARSE_TEST ("type", type),
290 PARSE_TEST ("uid", uid), /* GNU */
291 PARSE_TEST ("used", used), /* GNU */
292 PARSE_TEST ("user", user),
293 PARSE_OPTION ("warn", warn), /* GNU */
294 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
295 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
296 PARSE_OPTION ("xdev", xdev),
297 PARSE_TEST ("xtype", xtype), /* GNU */
298 #ifdef UNIMPLEMENTED_UNIX
299 /* It's pretty ugly for find to know about archive formats.
300 Plus what it could do with cpio archives is very limited.
301 Better to leave it out. */
302 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
303 #endif
304 /* gnulib's stdbool.h might have made true and false into macros,
305 * so we can't leave named 'true' and 'false' tokens, so we have
306 * to expeant the relevant entries longhand.
308 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
309 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
310 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
312 /* Various other cases that don't fit neatly into our macro scheme. */
313 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
314 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
315 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
316 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
317 {0, 0, 0, 0}
321 static const char *first_nonoption_arg = NULL;
322 static const struct parser_table *noop = NULL;
325 static const struct parser_table*
326 get_noop(void)
328 int i;
329 if (NULL == noop)
331 for (i = 0; parse_table[i].parser_name != 0; i++)
333 if (ARG_NOOP ==parse_table[i].type)
335 noop = &(parse_table[i]);
336 break;
340 return noop;
343 static int
344 get_stat_Ytime(const struct stat *p,
345 char what,
346 struct timespec *ret)
348 switch (what)
350 case 'a':
351 *ret = get_stat_atime(p);
352 return 1;
353 case 'B':
354 *ret = get_stat_birthtime(p);
355 return (ret->tv_nsec >= 0);
356 case 'c':
357 *ret = get_stat_ctime(p);
358 return 1;
359 case 'm':
360 *ret = get_stat_mtime(p);
361 return 1;
362 default:
363 assert(0);
364 abort();
365 abort();
369 void
370 set_follow_state(enum SymlinkOption opt)
372 if (options.debug_options & DebugStat)
374 /* For DebugStat, the choice is made at runtime within debug_stat()
375 * by checking the contents of the symlink_handling variable.
377 options.xstat = debug_stat;
379 else
381 switch (opt)
383 case SYMLINK_ALWAYS_DEREF: /* -L */
384 options.xstat = optionl_stat;
385 options.no_leaf_check = true;
386 break;
388 case SYMLINK_NEVER_DEREF: /* -P (default) */
389 options.xstat = optionp_stat;
390 /* Can't turn no_leaf_check off because the user might have specified
391 * -noleaf anyway
393 break;
395 case SYMLINK_DEREF_ARGSONLY: /* -H */
396 options.xstat = optionh_stat;
397 options.no_leaf_check = true;
400 options.symlink_handling = opt;
404 void
405 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
407 (void) args;
408 (void) argno;
409 (void) last;
410 (void) predicates;
411 first_nonoption_arg = NULL;
414 void
415 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
417 /* does nothing */
418 (void) args;
419 (void) argno;
420 (void) last;
421 (void) predicates;
425 /* Check that it is legal to fid the given primary in its
426 * position and return it.
428 const struct parser_table*
429 found_parser(const char *original_arg, const struct parser_table *entry)
431 /* If this is an option, but we have already had a
432 * non-option argument, the user may be under the
433 * impression that the behaviour of the option
434 * argument is conditional on some preceding
435 * tests. This might typically be the case with,
436 * for example, -maxdepth.
438 * The options -daystart and -follow are exempt
439 * from this treatment, since their positioning
440 * in the command line does have an effect on
441 * subsequent tests but not previous ones. That
442 * might be intentional on the part of the user.
444 if (entry->type != ARG_POSITIONAL_OPTION)
446 /* Something other than -follow/-daystart.
447 * If this is an option, check if it followed
448 * a non-option and if so, issue a warning.
450 if (entry->type == ARG_OPTION)
452 if ((first_nonoption_arg != NULL)
453 && options.warnings )
455 /* option which follows a non-option */
456 error (0, 0,
457 _("warning: you have specified the %s "
458 "option after a non-option argument %s, "
459 "but options are not positional (%s affects "
460 "tests specified before it as well as those "
461 "specified after it). Please specify options "
462 "before other arguments.\n"),
463 original_arg,
464 first_nonoption_arg,
465 original_arg);
468 else
470 /* Not an option or a positional option,
471 * so remember we've seen it in order to
472 * use it in a possible future warning message.
474 if (first_nonoption_arg == NULL)
476 first_nonoption_arg = original_arg;
481 return entry;
485 /* Return a pointer to the parser function to invoke for predicate
486 SEARCH_NAME.
487 Return NULL if SEARCH_NAME is not a valid predicate name. */
489 const struct parser_table*
490 find_parser (char *search_name)
492 int i;
493 const struct parser_table *p;
494 const char *original_arg = search_name;
496 /* Ugh. Special case -newerXY. */
497 if (0 == strncmp("-newer", search_name, 6)
498 && (8 == strlen(search_name)))
500 return found_parser(original_arg, &parse_entry_newerXY);
503 if (*search_name == '-')
504 search_name++;
506 for (i = 0; parse_table[i].parser_name != 0; i++)
508 if (strcmp (parse_table[i].parser_name, search_name) == 0)
510 return found_parser(original_arg, &parse_table[i]);
513 return NULL;
516 static float
517 estimate_file_age_success_rate(float num_days)
519 if (num_days < 0.1)
521 /* Assume 1% of files have timestamps in the future */
522 return 0.01f;
524 else if (num_days < 1)
526 /* Assume 30% of files have timestamps today */
527 return 0.3f;
529 else if (num_days > 100)
531 /* Assume 30% of files are very old */
532 return 0.3f;
534 else
536 /* Assume 39% of files are between 1 and 100 days old. */
537 return 0.39f;
541 static float
542 estimate_timestamp_success_rate(time_t when)
544 int num_days = (options.cur_day_start - when) / 86400;
545 return estimate_file_age_success_rate(num_days);
548 /* The parsers are responsible to continue scanning ARGV for
549 their arguments. Each parser knows what is and isn't
550 allowed for itself.
552 ARGV is the argument array.
553 *ARG_PTR is the index to start at in ARGV,
554 updated to point beyond the last element consumed.
556 The predicate structure is updated with the new information. */
559 static boolean
560 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
562 struct predicate *our_pred;
564 (void) argv;
565 (void) arg_ptr;
567 our_pred = get_new_pred (entry);
568 our_pred->pred_func = pred_and;
569 our_pred->p_type = BI_OP;
570 our_pred->p_prec = AND_PREC;
571 our_pred->need_stat = our_pred->need_type = false;
572 return true;
575 static boolean
576 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
578 struct predicate *our_pred;
579 struct stat stat_newer;
581 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
582 return false;
583 set_stat_placeholders(&stat_newer);
584 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
585 fatal_file_error(argv[*arg_ptr]);
586 our_pred = insert_primary (entry);
587 our_pred->args.reftime.xval = XVAL_ATIME;
588 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
589 our_pred->args.reftime.kind = COMP_GT;
590 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
591 (*arg_ptr)++;
592 return true;
595 boolean
596 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
598 struct predicate *our_pred;
600 (void) argv;
601 (void) arg_ptr;
603 our_pred = get_new_pred (entry);
604 our_pred->pred_func = pred_closeparen;
605 our_pred->p_type = CLOSE_PAREN;
606 our_pred->p_prec = NO_PREC;
607 our_pred->need_stat = our_pred->need_type = false;
608 return true;
611 static boolean
612 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
614 struct predicate *our_pred;
615 struct stat stat_newer;
617 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
618 return false;
619 set_stat_placeholders(&stat_newer);
620 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
621 fatal_file_error(argv[*arg_ptr]);
622 our_pred = insert_primary (entry);
623 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
624 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
625 our_pred->args.reftime.kind = COMP_GT;
626 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
627 (*arg_ptr)++;
628 return true;
631 static boolean
632 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
634 struct predicate *our_pred;
636 (void) argv;
637 (void) arg_ptr;
639 our_pred = get_new_pred (entry);
640 our_pred->pred_func = pred_comma;
641 our_pred->p_type = BI_OP;
642 our_pred->p_prec = COMMA_PREC;
643 our_pred->need_stat = our_pred->need_type = false;
644 our_pred->est_success_rate = 1.0f;
645 return true;
648 static boolean
649 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
651 struct tm *local;
653 (void) entry;
654 (void) argv;
655 (void) arg_ptr;
657 if (options.full_days == false)
659 options.cur_day_start += DAYSECS;
660 local = localtime (&options.cur_day_start);
661 options.cur_day_start -= (local
662 ? (local->tm_sec + local->tm_min * 60
663 + local->tm_hour * 3600)
664 : options.cur_day_start % DAYSECS);
665 options.full_days = true;
667 return true;
670 static boolean
671 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
673 struct predicate *our_pred;
674 (void) argv;
675 (void) arg_ptr;
677 our_pred = insert_primary (entry);
678 our_pred->side_effects = our_pred->no_default_print = true;
679 /* -delete implies -depth */
680 options.do_dir_first = false;
682 /* We do not need stat information because we check for the case
683 * (errno==EISDIR) in pred_delete.
685 our_pred->need_stat = our_pred->need_type = false;
687 our_pred->est_success_rate = 1.0f;
688 return true;
691 static boolean
692 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
694 (void) entry;
695 (void) argv;
696 (void) arg_ptr;
698 options.do_dir_first = false;
699 return parse_noop(entry, argv, arg_ptr);
702 static boolean
703 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
705 (void) argv;
706 (void) arg_ptr;
708 if (options.warnings)
710 error (0, 0,
711 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
713 return parse_depth(entry, argv, arg_ptr);
716 static boolean
717 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
719 struct predicate *our_pred;
720 (void) argv;
721 (void) arg_ptr;
723 our_pred = insert_primary (entry);
724 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
725 return true;
728 static boolean
729 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
731 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
734 static boolean
735 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
737 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
740 static boolean
741 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
743 struct predicate *our_pred;
745 (void) argv;
746 (void) arg_ptr;
748 our_pred = insert_primary (entry);
749 our_pred->need_stat = our_pred->need_type = false;
750 our_pred->side_effects = our_pred->no_default_print = false;
751 our_pred->est_success_rate = 0.0f;
752 return true;
755 static boolean
756 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
758 struct predicate *our_pred;
760 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
761 return false;
762 our_pred = insert_primary (entry);
763 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
764 our_pred->side_effects = our_pred->no_default_print = true;
765 our_pred->est_success_rate = 1.0f;
766 (*arg_ptr)++;
767 return true;
770 static boolean
771 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
773 FILE *fp;
775 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
776 return false;
777 if (argv[*arg_ptr + 1] == NULL)
779 /* Ensure we get "missing arg" message, not "invalid arg". */
780 (*arg_ptr)++;
781 return false;
783 fp = open_output_file (argv[*arg_ptr]);
784 (*arg_ptr)++;
785 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
788 static boolean
789 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
791 (void) entry;
792 (void) argv;
793 (void) arg_ptr;
795 set_follow_state(SYMLINK_ALWAYS_DEREF);
796 return parse_noop(entry, argv, arg_ptr);
799 static boolean
800 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
802 struct predicate *our_pred;
804 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
805 return false;
806 our_pred = insert_primary (entry);
807 our_pred->args.printf_vec.segment = NULL;
808 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
809 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
810 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
811 our_pred->side_effects = our_pred->no_default_print = true;
812 our_pred->need_stat = our_pred->need_type = false;
813 our_pred->est_success_rate = 1.0f;
814 (*arg_ptr)++;
815 return true;
818 static boolean
819 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
821 struct predicate *our_pred;
823 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
824 return false;
825 our_pred = insert_primary (entry);
826 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
827 our_pred->side_effects = our_pred->no_default_print = true;
828 our_pred->need_stat = our_pred->need_type = false;
829 our_pred->est_success_rate = 1.0f;
830 (*arg_ptr)++;
831 return true;
834 static float estimate_fstype_success_rate(const char *fsname)
836 struct stat dir_stat;
837 const char *dir = "/";
838 if (0 == stat(dir, &dir_stat))
840 const char *fstype = filesystem_type(&dir_stat, dir);
841 /* Assume most files are on the same filesystem type as the root fs. */
842 if (0 == strcmp(fsname, fstype))
843 return 0.7f;
844 else
845 return 0.3f;
847 return 1.0f;
851 static boolean
852 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
854 struct predicate *our_pred;
856 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
857 return false;
858 our_pred = insert_primary (entry);
859 our_pred->args.str = argv[*arg_ptr];
861 /* This is an expensive operation, so although there are
862 * circumstances where it is selective, we ignore this fact because
863 * we probably don't want to promote this test to the front anyway.
865 our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
866 (*arg_ptr)++;
867 return true;
870 static boolean
871 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
873 struct predicate *p = insert_num (argv, arg_ptr, entry);
874 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
875 return p;
878 static boolean
879 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
881 struct group *cur_gr;
882 struct predicate *our_pred;
883 gid_t gid;
884 int gid_len;
886 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
887 return false;
888 cur_gr = getgrnam (argv[*arg_ptr]);
889 endgrent ();
890 if (cur_gr != NULL)
891 gid = cur_gr->gr_gid;
892 else
894 gid_len = strspn (argv[*arg_ptr], "0123456789");
895 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
896 return false;
897 gid = atoi (argv[*arg_ptr]);
899 our_pred = insert_primary (entry);
900 our_pred->args.gid = gid;
901 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
902 (*arg_ptr)++;
903 return true;
906 static boolean
907 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
909 (void) entry;
910 (void) argv;
911 (void) arg_ptr;
913 usage(stdout, 0, NULL);
914 puts (_("\n\
915 default path is the current directory; default expression is -print\n\
916 expression may consist of: operators, options, tests, and actions:\n"));
917 puts (_("\
918 operators (decreasing precedence; -and is implicit where no others are given):\n\
919 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
920 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
921 puts (_("\
922 positional options (always true): -daystart -follow -regextype\n\n\
923 normal options (always true, specified before other expressions):\n\
924 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
925 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
926 puts (_("\
927 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
928 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
929 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
930 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
931 puts (_("\
932 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
933 -readable -writable -executable\n\
934 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
935 -used N -user NAME -xtype [bcdpfls]\n"));
936 puts (_("\
937 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
938 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
939 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
940 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
941 "));
942 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
943 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
944 email to <bug-findutils@gnu.org>."));
945 exit (0);
948 static float
949 estimate_pattern_match_rate(const char *pattern, int is_regex)
951 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
953 /* A wildcard; assume the pattern matches most files. */
954 return 0.8f;
956 else
958 return 0.1f;
962 static boolean
963 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
965 struct predicate *our_pred;
967 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
968 return false;
969 our_pred = insert_primary (entry);
970 our_pred->args.str = argv[*arg_ptr];
971 /* Use the generic glob pattern estimator to figure out how many
972 * links will match, but bear in mind that most files won't be links.
974 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
975 (*arg_ptr)++;
976 return true;
980 /* sanity check the fnmatch() function to make sure
981 * it really is the GNU version.
983 static boolean
984 fnmatch_sanitycheck(void)
986 /* fprintf(stderr, "Performing find sanity check..."); */
987 if (0 != fnmatch("foo", "foo", 0)
988 || 0 == fnmatch("Foo", "foo", 0)
989 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
991 error (1, 0, _("sanity check of the fnmatch() library function failed."));
992 /* fprintf(stderr, "FAILED\n"); */
993 return false;
996 /* fprintf(stderr, "OK\n"); */
997 return true;
1001 static boolean
1002 check_name_arg(const char *pred, const char *arg)
1004 if (strchr(arg, '/'))
1006 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'."),
1007 pred,
1008 safely_quote_err_filename(0, arg),
1009 safely_quote_err_filename(1, arg));
1011 return true; /* allow it anyway */
1016 static boolean
1017 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1019 struct predicate *our_pred;
1021 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1022 return false;
1023 if (!check_name_arg("-iname", argv[*arg_ptr]))
1024 return false;
1026 fnmatch_sanitycheck();
1028 our_pred = insert_primary (entry);
1029 our_pred->need_stat = our_pred->need_type = false;
1030 our_pred->args.str = argv[*arg_ptr];
1031 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1032 (*arg_ptr)++;
1033 return true;
1036 static boolean
1037 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1039 struct predicate *p = insert_num (argv, arg_ptr, entry);
1040 /* inode number is exact match only, so very low proportions of files match */
1041 p->est_success_rate = 1e-6;
1042 return p;
1045 /* -ipath is deprecated (at RMS's request) in favour of
1046 * -iwholename. See the node "GNU Manuals" in standards.texi
1047 * for the rationale for this (basically, GNU prefers the use
1048 * of the phrase "file name" to "path name"
1050 static boolean
1051 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1053 error (0, 0,
1054 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1056 return parse_iwholename(entry, argv, arg_ptr);
1059 static boolean
1060 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1062 struct predicate *our_pred;
1064 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1065 return false;
1067 fnmatch_sanitycheck();
1069 our_pred = insert_primary_withpred (entry, pred_ipath);
1070 our_pred->need_stat = our_pred->need_type = false;
1071 our_pred->args.str = argv[*arg_ptr];
1072 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1073 (*arg_ptr)++;
1074 return true;
1077 static boolean
1078 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1080 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1083 static boolean
1084 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1086 struct predicate *p = insert_num (argv, arg_ptr, entry);
1087 if (p->args.numinfo.l_val == 1)
1088 p->est_success_rate = 0.99;
1089 else if (p->args.numinfo.l_val == 2)
1090 p->est_success_rate = 0.01;
1091 else
1092 p->est_success_rate = 1e-3;
1093 return p;
1096 static boolean
1097 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1099 struct predicate *our_pred;
1101 (void) argv;
1102 (void) arg_ptr;
1104 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1105 return false;
1107 fnmatch_sanitycheck();
1109 our_pred = insert_primary (entry);
1110 our_pred->args.str = argv[*arg_ptr];
1111 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
1112 (*arg_ptr)++;
1113 return true;
1116 static boolean
1117 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1119 struct predicate *our_pred;
1121 (void) &argv;
1122 (void) &arg_ptr;
1124 our_pred = insert_primary (entry);
1125 our_pred->side_effects = our_pred->no_default_print = true;
1126 return true;
1129 static boolean
1130 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1132 int depth_len;
1133 (void) entry;
1135 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1136 return false;
1137 depth_len = strspn (argv[*arg_ptr], "0123456789");
1138 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1139 return false;
1140 options.maxdepth = atoi (argv[*arg_ptr]);
1141 if (options.maxdepth < 0)
1142 return false;
1143 (*arg_ptr)++;
1144 return parse_noop(entry, argv, arg_ptr);
1147 static boolean
1148 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1150 int depth_len;
1151 (void) entry;
1153 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1154 return false;
1155 depth_len = strspn (argv[*arg_ptr], "0123456789");
1156 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1157 return false;
1158 options.mindepth = atoi (argv[*arg_ptr]);
1159 if (options.mindepth < 0)
1160 return false;
1161 (*arg_ptr)++;
1162 return parse_noop(entry, argv, arg_ptr);
1166 static boolean
1167 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr, enum xval xv)
1169 struct predicate *our_pred;
1170 struct time_val tval;
1172 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1173 return false;
1175 tval.xval = xv;
1176 if (!get_relative_timestamp(argv[*arg_ptr], &tval,
1177 options.cur_day_start + DAYSECS, 60,
1178 "arithmetic overflow while converting %s minutes to a number of seconds"))
1179 return false;
1181 our_pred = insert_primary (entry);
1182 our_pred->args.reftime = tval;
1183 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1184 (*arg_ptr)++;
1185 return true;
1187 static boolean
1188 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1190 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1193 static boolean
1194 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1196 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1200 static boolean
1201 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1203 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1206 static boolean
1207 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1209 struct predicate *our_pred;
1211 (void) argv;
1212 (void) arg_ptr;
1214 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1215 return false;
1216 if (!check_name_arg("-name", argv[*arg_ptr]))
1217 return false;
1218 fnmatch_sanitycheck();
1220 our_pred = insert_primary (entry);
1221 our_pred->need_stat = our_pred->need_type = false;
1222 our_pred->args.str = argv[*arg_ptr];
1223 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1224 (*arg_ptr)++;
1225 return true;
1228 static boolean
1229 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1231 struct predicate *our_pred;
1233 (void) &argv;
1234 (void) &arg_ptr;
1236 our_pred = get_new_pred_chk_op (entry);
1237 our_pred->pred_func = pred_negate;
1238 our_pred->p_type = UNI_OP;
1239 our_pred->p_prec = NEGATE_PREC;
1240 our_pred->need_stat = our_pred->need_type = false;
1241 return true;
1244 static boolean
1245 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1247 struct predicate *our_pred;
1248 struct stat stat_newer;
1250 (void) argv;
1251 (void) arg_ptr;
1253 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1254 return false;
1255 set_stat_placeholders(&stat_newer);
1256 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1257 fatal_file_error(argv[*arg_ptr]);
1258 our_pred = insert_primary (entry);
1259 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1260 our_pred->args.reftime.xval = XVAL_MTIME;
1261 our_pred->args.reftime.kind = COMP_GT;
1262 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1263 (*arg_ptr)++;
1264 return true;
1268 static boolean
1269 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1271 (void) argv;
1272 (void) arg_ptr;
1274 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1276 return false;
1278 else if (8u != strlen(argv[*arg_ptr]))
1280 return false;
1282 else
1284 char x, y;
1285 const char validchars[] = "aBcmt";
1287 assert(0 == strncmp("-newer", argv[*arg_ptr], 6));
1288 x = argv[*arg_ptr][6];
1289 y = argv[*arg_ptr][7];
1292 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1293 if ('B' == x || 'B' == y)
1295 error(0, 0,
1296 _("This system does not provide a way to find the birth time of a file."));
1297 return 0;
1299 #endif
1301 /* -newertY (for any Y) is invalid. */
1302 if (x == 't'
1303 || 0 == strchr(validchars, x)
1304 || 0 == strchr( validchars, y))
1306 return false;
1308 else
1310 struct predicate *our_pred;
1312 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1313 * past the test name (for most other tests, this is already done)
1315 (*arg_ptr)++;
1317 our_pred = insert_primary (entry);
1320 switch (x)
1322 case 'a':
1323 our_pred->args.reftime.xval = XVAL_ATIME;
1324 break;
1325 case 'B':
1326 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1327 break;
1328 case 'c':
1329 our_pred->args.reftime.xval = XVAL_CTIME;
1330 break;
1331 case 'm':
1332 our_pred->args.reftime.xval = XVAL_MTIME;
1333 break;
1334 default:
1335 assert(strchr(validchars, x));
1336 assert(0);
1339 if ('t' == y)
1341 if (!get_date(&our_pred->args.reftime.ts,
1342 argv[*arg_ptr],
1343 &options.start_time))
1345 error(1, 0,
1346 _("I cannot figure out how to interpret %s as a date or time"),
1347 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1350 else
1352 struct stat stat_newer;
1354 /* Stat the named file. */
1355 set_stat_placeholders(&stat_newer);
1356 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1357 fatal_file_error(argv[*arg_ptr]);
1359 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1361 /* We cannot extract a timestamp from the struct stat. */
1362 error(1, 0, _("Cannot obtain birth time of file %s"),
1363 safely_quote_err_filename(0, argv[*arg_ptr]));
1366 our_pred->args.reftime.kind = COMP_GT;
1367 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1368 (*arg_ptr)++;
1370 assert(our_pred->pred_func != NULL);
1371 assert(our_pred->pred_func == pred_newerXY);
1372 assert(our_pred->need_stat);
1373 return true;
1379 static boolean
1380 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1382 (void) &argv;
1383 (void) &arg_ptr;
1384 (void) entry;
1386 options.no_leaf_check = true;
1387 return parse_noop(entry, argv, arg_ptr);
1390 #ifdef CACHE_IDS
1391 /* Arbitrary amount by which to increase size
1392 of `uid_unused' and `gid_unused'. */
1393 #define ALLOC_STEP 2048
1395 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1396 char *uid_unused = NULL;
1398 /* Number of elements in `uid_unused'. */
1399 unsigned uid_allocated;
1401 /* Similar for GIDs and group entries. */
1402 char *gid_unused = NULL;
1403 unsigned gid_allocated;
1404 #endif
1406 static boolean
1407 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1409 struct predicate *our_pred;
1411 (void) &argv;
1412 (void) &arg_ptr;
1414 our_pred = insert_primary (entry);
1415 our_pred->est_success_rate = 1e-4;
1416 #ifdef CACHE_IDS
1417 if (gid_unused == NULL)
1419 struct group *gr;
1421 gid_allocated = ALLOC_STEP;
1422 gid_unused = xmalloc (gid_allocated);
1423 memset (gid_unused, 1, gid_allocated);
1424 setgrent ();
1425 while ((gr = getgrent ()) != NULL)
1427 if ((unsigned) gr->gr_gid >= gid_allocated)
1429 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1430 gid_unused = xrealloc (gid_unused, new_allocated);
1431 memset (gid_unused + gid_allocated, 1,
1432 new_allocated - gid_allocated);
1433 gid_allocated = new_allocated;
1435 gid_unused[(unsigned) gr->gr_gid] = 0;
1437 endgrent ();
1439 #endif
1440 return true;
1443 static boolean
1444 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1446 struct predicate *our_pred;
1447 (void) argv;
1448 (void) arg_ptr;
1451 our_pred = insert_primary (entry);
1452 our_pred->est_success_rate = 1e-3;
1453 #ifdef CACHE_IDS
1454 if (uid_unused == NULL)
1456 struct passwd *pw;
1458 uid_allocated = ALLOC_STEP;
1459 uid_unused = xmalloc (uid_allocated);
1460 memset (uid_unused, 1, uid_allocated);
1461 setpwent ();
1462 while ((pw = getpwent ()) != NULL)
1464 if ((unsigned) pw->pw_uid >= uid_allocated)
1466 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1467 uid_unused = xrealloc (uid_unused, new_allocated);
1468 memset (uid_unused + uid_allocated, 1,
1469 new_allocated - uid_allocated);
1470 uid_allocated = new_allocated;
1472 uid_unused[(unsigned) pw->pw_uid] = 0;
1474 endpwent ();
1476 #endif
1477 return true;
1480 static boolean
1481 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1483 (void) argv;
1484 (void) arg_ptr;
1485 (void) entry;
1487 options.warnings = false;
1488 return parse_noop(entry, argv, arg_ptr);
1491 static boolean
1492 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1494 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1497 static boolean
1498 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1500 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1503 boolean
1504 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1506 struct predicate *our_pred;
1508 (void) argv;
1509 (void) arg_ptr;
1511 our_pred = get_new_pred_chk_op (entry);
1512 our_pred->pred_func = pred_openparen;
1513 our_pred->p_type = OPEN_PAREN;
1514 our_pred->p_prec = NO_PREC;
1515 our_pred->need_stat = our_pred->need_type = false;
1516 return true;
1519 static boolean
1520 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1522 struct predicate *our_pred;
1524 (void) argv;
1525 (void) arg_ptr;
1527 our_pred = get_new_pred (entry);
1528 our_pred->pred_func = pred_or;
1529 our_pred->p_type = BI_OP;
1530 our_pred->p_prec = OR_PREC;
1531 our_pred->need_stat = our_pred->need_type = false;
1532 return true;
1535 /* -path is deprecated (at RMS's request) in favour of
1536 * -iwholename. See the node "GNU Manuals" in standards.texi
1537 * for the rationale for this (basically, GNU prefers the use
1538 * of the phrase "file name" to "path name".
1540 * We do not issue a warning that this usage is deprecated
1541 * since HPUX find supports this predicate also.
1543 static boolean
1544 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1546 return parse_wholename(entry, argv, arg_ptr);
1549 static boolean
1550 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1552 struct predicate *our_pred;
1554 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1555 return false;
1556 our_pred = insert_primary_withpred (entry, pred_path);
1557 our_pred->need_stat = our_pred->need_type = false;
1558 our_pred->args.str = argv[*arg_ptr];
1559 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1560 (*arg_ptr)++;
1561 return true;
1564 static boolean
1565 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1567 mode_t perm_val[2];
1568 float rate;
1569 int mode_start = 0;
1570 boolean havekind = false;
1571 enum permissions_type kind = PERM_EXACT;
1572 struct mode_change *change = NULL;
1573 struct predicate *our_pred;
1575 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1576 return false;
1578 switch (argv[*arg_ptr][0])
1580 case '-':
1581 mode_start = 1;
1582 kind = PERM_AT_LEAST;
1583 havekind = true;
1584 rate = 0.2;
1585 break;
1587 case '+':
1588 change = mode_compile (argv[*arg_ptr]);
1589 if (NULL == change)
1591 /* Most likely the caller is an old script that is still
1592 * using the obsolete GNU syntax '-perm +MODE'. This old
1593 * syntax was withdrawn in favor of '-perm /MODE' because
1594 * it is incompatible with POSIX in some cases, but we
1595 * still support uses of it that are not incompatible with
1596 * POSIX.
1598 mode_start = 1;
1599 kind = PERM_ANY;
1600 rate = 0.3;
1602 else
1604 /* This is a POSIX-compatible usage */
1605 mode_start = 0;
1606 kind = PERM_EXACT;
1607 rate = 0.1;
1609 havekind = true;
1610 break;
1612 case '/': /* GNU extension */
1613 mode_start = 1;
1614 kind = PERM_ANY;
1615 havekind = true;
1616 rate = 0.3;
1617 break;
1619 default:
1620 /* For example, '-perm 0644', which is valid and matches
1621 * only files whose mode is exactly 0644.
1623 mode_start = 0;
1624 kind = PERM_EXACT;
1625 havekind = true;
1626 rate = 0.01;
1627 break;
1630 if (NULL == change)
1632 change = mode_compile (argv[*arg_ptr] + mode_start);
1633 if (NULL == change)
1634 error (1, 0, _("invalid mode %s"),
1635 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1637 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1638 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1639 free (change);
1641 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1643 /* The meaning of -perm /000 will change in the future. It
1644 * currently matches no files, but like -perm -000 it should
1645 * match all files.
1647 * Starting in 2005, we used to issue a warning message
1648 * informing the user that the behaviour would change in the
1649 * future. We have now changed the behaviour and issue a
1650 * warning message that the behaviour recently changed.
1652 error (0, 0,
1653 _("warning: you have specified a mode pattern %s (which is "
1654 "equivalent to /000). The meaning of -perm /000 has now been "
1655 "changed to be consistent with -perm -000; that is, while it "
1656 "used to match no files, it now matches all files."),
1657 argv[*arg_ptr]);
1659 kind = PERM_AT_LEAST;
1660 havekind = true;
1662 /* The "magic" number below is just the fraction of files on my
1663 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1664 * Actual totals are 1472 and 1073833.
1666 rate = 0.9986; /* probably matches anything but a broken symlink */
1669 our_pred = insert_primary (entry);
1670 our_pred->est_success_rate = rate;
1671 if (havekind)
1673 our_pred->args.perm.kind = kind;
1675 else
1678 switch (argv[*arg_ptr][0])
1680 case '-':
1681 our_pred->args.perm.kind = PERM_AT_LEAST;
1682 break;
1683 case '+':
1684 our_pred->args.perm.kind = PERM_ANY;
1685 break;
1686 default:
1687 our_pred->args.perm.kind = PERM_EXACT;
1688 break;
1691 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1692 (*arg_ptr)++;
1693 return true;
1696 boolean
1697 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1699 struct predicate *our_pred;
1701 (void) argv;
1702 (void) arg_ptr;
1704 our_pred = insert_primary (entry);
1705 /* -print has the side effect of printing. This prevents us
1706 from doing undesired multiple printing when the user has
1707 already specified -print. */
1708 our_pred->side_effects = our_pred->no_default_print = true;
1709 our_pred->need_stat = our_pred->need_type = false;
1710 our_pred->args.printf_vec.segment = NULL;
1711 our_pred->args.printf_vec.stream = stdout;
1712 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1713 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1715 return true;
1718 static boolean
1719 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1721 struct predicate *our_pred;
1723 (void) argv;
1724 (void) arg_ptr;
1726 our_pred = insert_primary (entry);
1727 /* -print0 has the side effect of printing. This prevents us
1728 from doing undesired multiple printing when the user has
1729 already specified -print0. */
1730 our_pred->side_effects = our_pred->no_default_print = true;
1731 our_pred->need_stat = our_pred->need_type = false;
1732 return true;
1735 static boolean
1736 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1738 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1739 return false;
1740 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1743 static boolean
1744 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1746 struct predicate *our_pred;
1748 (void) argv;
1749 (void) arg_ptr;
1751 our_pred = insert_primary (entry);
1752 our_pred->need_stat = our_pred->need_type = false;
1753 /* -prune has a side effect that it does not descend into
1754 the current directory. */
1755 our_pred->side_effects = true;
1756 our_pred->no_default_print = false;
1757 return true;
1760 static boolean
1761 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1763 struct predicate *our_pred = insert_primary (entry);
1764 (void) argv;
1765 (void) arg_ptr;
1766 our_pred->need_stat = our_pred->need_type = false;
1767 our_pred->side_effects = true; /* Exiting is a side effect... */
1768 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1769 our_pred->est_success_rate = 1.0f;
1770 return true;
1774 static boolean
1775 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1777 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1778 return false;
1780 /* collect the regex type name */
1781 options.regex_options = get_regex_type(argv[*arg_ptr]);
1782 (*arg_ptr)++;
1784 return parse_noop(entry, argv, arg_ptr);
1788 static boolean
1789 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1791 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1794 static boolean
1795 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1797 struct predicate *our_pred;
1798 struct re_pattern_buffer *re;
1799 const char *error_message;
1801 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1802 return false;
1803 our_pred = insert_primary_withpred (entry, pred_regex);
1804 our_pred->need_stat = our_pred->need_type = false;
1805 re = (struct re_pattern_buffer *)
1806 xmalloc (sizeof (struct re_pattern_buffer));
1807 our_pred->args.regex = re;
1808 re->allocated = 100;
1809 re->buffer = (unsigned char *) xmalloc (re->allocated);
1810 re->fastmap = NULL;
1812 re_set_syntax(regex_options);
1813 re->syntax = regex_options;
1814 re->translate = NULL;
1816 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1817 re);
1818 if (error_message)
1819 error (1, 0, "%s", error_message);
1820 our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
1821 (*arg_ptr)++;
1822 return true;
1825 static boolean
1826 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1828 struct predicate *our_pred;
1829 uintmax_t num;
1830 enum comparison_type c_type;
1831 int blksize = 512;
1832 int len;
1834 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1835 return false;
1836 len = strlen (argv[*arg_ptr]);
1837 if (len == 0)
1838 error (1, 0, _("invalid null argument to -size"));
1839 switch (argv[*arg_ptr][len - 1])
1841 case 'b':
1842 blksize = 512;
1843 argv[*arg_ptr][len - 1] = '\0';
1844 break;
1846 case 'c':
1847 blksize = 1;
1848 argv[*arg_ptr][len - 1] = '\0';
1849 break;
1851 case 'k':
1852 blksize = 1024;
1853 argv[*arg_ptr][len - 1] = '\0';
1854 break;
1856 case 'M': /* Megabytes */
1857 blksize = 1024*1024;
1858 argv[*arg_ptr][len - 1] = '\0';
1859 break;
1861 case 'G': /* Gigabytes */
1862 blksize = 1024*1024*1024;
1863 argv[*arg_ptr][len - 1] = '\0';
1864 break;
1866 case 'w':
1867 blksize = 2;
1868 argv[*arg_ptr][len - 1] = '\0';
1869 break;
1871 case '0':
1872 case '1':
1873 case '2':
1874 case '3':
1875 case '4':
1876 case '5':
1877 case '6':
1878 case '7':
1879 case '8':
1880 case '9':
1881 break;
1883 default:
1884 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1886 /* TODO: accept fractional megabytes etc. ? */
1887 if (!get_num (argv[*arg_ptr], &num, &c_type))
1888 return false;
1889 our_pred = insert_primary (entry);
1890 our_pred->args.size.kind = c_type;
1891 our_pred->args.size.blocksize = blksize;
1892 our_pred->args.size.size = num;
1893 our_pred->need_stat = true;
1894 our_pred->need_type = false;
1896 if (COMP_GT == c_type)
1897 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1898 else if (COMP_LT == c_type)
1899 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1900 else
1901 our_pred->est_success_rate = 0.01;
1903 (*arg_ptr)++;
1904 return true;
1908 static boolean
1909 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1911 struct predicate *our_pred;
1912 struct stat st;
1914 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1915 return false;
1916 set_stat_placeholders(&st);
1917 if ((*options.xstat) (argv[*arg_ptr], &st))
1918 fatal_file_error(argv[*arg_ptr]);
1920 our_pred = insert_primary (entry);
1921 our_pred->args.fileid.ino = st.st_ino;
1922 our_pred->args.fileid.dev = st.st_dev;
1923 our_pred->need_type = false;
1924 our_pred->need_stat = true;
1925 our_pred->est_success_rate = 0.01f;
1926 (*arg_ptr)++;
1927 return true;
1930 #if 0
1931 /* This function is commented out partly because support for it is
1932 * uneven.
1934 static boolean
1935 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1937 const char *arg;
1938 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1939 "must be 'literal' or 'safe'");
1941 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1943 error (1, errno, "%s", errmsg);
1944 return false;
1946 else
1948 arg = argv[*arg_ptr];
1950 if (0 == strcmp("literal", arg))
1952 options.literal_control_chars = true;
1954 else if (0 == strcmp("safe", arg))
1956 options.literal_control_chars = false;
1958 else
1960 error (1, errno, "%s", errmsg);
1961 return false;
1963 (*arg_ptr)++; /* consume the argument. */
1964 return true;
1967 #endif
1970 static boolean
1971 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1973 struct predicate *our_pred;
1975 (void) argv;
1976 (void) arg_ptr;
1978 our_pred = insert_primary (entry);
1979 our_pred->need_stat = our_pred->need_type = false;
1980 our_pred->est_success_rate = 1.0f;
1981 return true;
1984 static boolean
1985 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
1987 (void) entry;
1988 return parse_true(get_noop(), argv, arg_ptr);
1991 static boolean
1992 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1994 struct predicate *our_pred;
1995 (void) argv;
1996 (void) arg_ptr;
1997 our_pred = insert_primary (entry);
1998 our_pred->need_stat = our_pred->need_type = false;
1999 our_pred->side_effects = our_pred->no_default_print = false;
2000 if (pred_is(our_pred, pred_executable))
2001 our_pred->est_success_rate = 0.2;
2002 else
2003 our_pred->est_success_rate = 0.9;
2004 return true;
2007 static boolean
2008 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2010 return insert_type (argv, arg_ptr, entry, pred_type);
2013 static boolean
2014 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2016 struct predicate *p = insert_num (argv, arg_ptr, entry);
2017 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2018 return p;
2021 static boolean
2022 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2024 struct predicate *our_pred;
2025 struct time_val tval;
2026 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2028 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2029 return false;
2031 /* The timespec is actually a delta value, so we use an origin of 0. */
2032 if (!get_relative_timestamp(argv[*arg_ptr], &tval, 0, DAYSECS, errmsg))
2033 return false;
2035 our_pred = insert_primary (entry);
2036 our_pred->args.reftime = tval;
2037 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2038 (*arg_ptr)++;
2039 return true;
2042 static boolean
2043 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2045 struct passwd *cur_pwd;
2046 struct predicate *our_pred;
2047 uid_t uid;
2048 int uid_len;
2050 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2051 return false;
2052 cur_pwd = getpwnam (argv[*arg_ptr]);
2053 endpwent ();
2054 if (cur_pwd != NULL)
2055 uid = cur_pwd->pw_uid;
2056 else
2058 uid_len = strspn (argv[*arg_ptr], "0123456789");
2059 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
2060 return false;
2061 uid = atoi (argv[*arg_ptr]);
2063 our_pred = insert_primary (entry);
2064 our_pred->args.uid = uid;
2065 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2066 (*arg_ptr)++;
2067 return true;
2070 static boolean
2071 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2073 extern char *version_string;
2074 int features = 0;
2075 int flags;
2077 (void) argv;
2078 (void) arg_ptr;
2079 (void) entry;
2081 fflush (stderr);
2082 printf (_("GNU find version %s\n"), version_string);
2083 printf (_("Built using GNU gnulib version %s\n"), gnulib_version);
2084 printf (_("Features enabled: "));
2086 #if CACHE_IDS
2087 printf("CACHE_IDS ");
2088 ++features;
2089 #endif
2090 #if DEBUG
2091 printf("DEBUG ");
2092 ++features;
2093 #endif
2094 #if DEBUG_STAT
2095 printf("DEBUG_STAT ");
2096 ++features;
2097 #endif
2098 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
2099 printf("D_TYPE ");
2100 ++features;
2101 #endif
2102 #if defined(O_NOFOLLOW)
2103 printf("O_NOFOLLOW(%s) ",
2104 (options.open_nofollow_available ? "enabled" : "disabled"));
2105 ++features;
2106 #endif
2107 #if defined(LEAF_OPTIMISATION)
2108 printf("LEAF_OPTIMISATION ");
2109 ++features;
2110 #endif
2112 flags = 0;
2113 if (is_fts_enabled(&flags))
2115 int nflags = 0;
2116 printf("FTS(");
2117 ++features;
2119 if (flags & FTS_CWDFD)
2121 if (nflags)
2123 printf(",");
2125 printf("FTS_CWDFD");
2126 ++nflags;
2128 printf(") ");
2131 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2132 ++features;
2134 if (0 == features)
2136 /* For the moment, leave this as English in case someone wants
2137 to parse these strings. */
2138 printf("none");
2140 printf("\n");
2142 exit (0);
2145 static boolean
2146 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2148 (void) argv;
2149 (void) arg_ptr;
2150 (void) entry;
2151 options.stay_on_filesystem = true;
2152 return parse_noop(entry, argv, arg_ptr);
2155 static boolean
2156 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2158 (void) argv;
2159 (void) arg_ptr;
2160 (void) entry;
2161 options.ignore_readdir_race = true;
2162 return parse_noop(entry, argv, arg_ptr);
2165 static boolean
2166 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2168 (void) argv;
2169 (void) arg_ptr;
2170 (void) entry;
2171 options.ignore_readdir_race = false;
2172 return parse_noop(entry, argv, arg_ptr);
2175 static boolean
2176 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2178 (void) argv;
2179 (void) arg_ptr;
2180 (void) entry;
2181 options.warnings = true;
2182 return parse_noop(entry, argv, arg_ptr);
2185 static boolean
2186 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2188 (void) argv;
2189 (void) arg_ptr;
2190 return insert_type (argv, arg_ptr, entry, pred_xtype);
2193 static boolean
2194 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2196 mode_t type_cell;
2197 struct predicate *our_pred;
2198 float rate = 0.5;
2200 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
2201 || (strlen (argv[*arg_ptr]) != 1))
2202 return false;
2203 switch (argv[*arg_ptr][0])
2205 case 'b': /* block special */
2206 type_cell = S_IFBLK;
2207 rate = 0.01f;
2208 break;
2209 case 'c': /* character special */
2210 type_cell = S_IFCHR;
2211 rate = 0.01f;
2212 break;
2213 case 'd': /* directory */
2214 type_cell = S_IFDIR;
2215 rate = 0.4f;
2216 break;
2217 case 'f': /* regular file */
2218 type_cell = S_IFREG;
2219 rate = 0.95f;
2220 break;
2221 #ifdef S_IFLNK
2222 case 'l': /* symbolic link */
2223 type_cell = S_IFLNK;
2224 rate = 0.1f;
2225 break;
2226 #endif
2227 #ifdef S_IFIFO
2228 case 'p': /* pipe */
2229 type_cell = S_IFIFO;
2230 rate = 0.01f;
2231 break;
2232 #endif
2233 #ifdef S_IFSOCK
2234 case 's': /* socket */
2235 type_cell = S_IFSOCK;
2236 rate = 0.01f;
2237 break;
2238 #endif
2239 #ifdef S_IFDOOR
2240 case 'D': /* Solaris door */
2241 type_cell = S_IFDOOR;
2242 rate = 0.01f;
2243 break;
2244 #endif
2245 default: /* None of the above ... nuke 'em. */
2246 return false;
2248 our_pred = insert_primary_withpred (entry, which_pred);
2249 our_pred->est_success_rate = rate;
2251 /* Figure out if we will need to stat the file, because if we don't
2252 * need to follow symlinks, we can avoid a stat call by using
2253 * struct dirent.d_type.
2255 if (which_pred == pred_xtype)
2257 our_pred->need_stat = true;
2258 our_pred->need_type = false;
2260 else
2262 our_pred->need_stat = false; /* struct dirent is enough */
2263 our_pred->need_type = true;
2265 our_pred->args.type = type_cell;
2266 (*arg_ptr)++; /* Move on to next argument. */
2267 return true;
2271 /* Return true if the file accessed via FP is a terminal.
2273 static boolean
2274 stream_is_tty(FILE *fp)
2276 int fd = fileno(fp);
2277 if (-1 == fd)
2279 return false; /* not a valid stream */
2281 else
2283 return isatty(fd) ? true : false;
2291 /* XXX: do we need to pass FUNC to this function? */
2292 static boolean
2293 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
2295 char *format; /* Beginning of unprocessed format string. */
2296 register char *scan; /* Current address in scanning `format'. */
2297 register char *scan2; /* Address inside of element being scanned. */
2298 struct segment **segmentp; /* Address of current segment. */
2299 struct predicate *our_pred;
2301 format = argv[(*arg_ptr)++];
2303 our_pred = insert_primary_withpred (entry, func);
2304 our_pred->side_effects = our_pred->no_default_print = true;
2305 our_pred->args.printf_vec.stream = fp;
2306 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
2307 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2308 our_pred->need_type = false;
2309 our_pred->need_stat = false;
2310 our_pred->p_cost = NeedsNothing;
2312 segmentp = &our_pred->args.printf_vec.segment;
2313 *segmentp = NULL;
2315 for (scan = format; *scan; scan++)
2317 if (*scan == '\\')
2319 scan2 = scan + 1;
2320 if (*scan2 >= '0' && *scan2 <= '7')
2322 register int n, i;
2324 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2325 i++, scan2++)
2326 n = 8 * n + *scan2 - '0';
2327 scan2--;
2328 *scan = n;
2330 else
2332 switch (*scan2)
2334 case 'a':
2335 *scan = 7;
2336 break;
2337 case 'b':
2338 *scan = '\b';
2339 break;
2340 case 'c':
2341 make_segment (segmentp, format, scan - format,
2342 KIND_STOP, 0, 0,
2343 our_pred);
2344 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2345 our_pred->p_cost = NeedsStatInfo;
2346 return true;
2347 case 'f':
2348 *scan = '\f';
2349 break;
2350 case 'n':
2351 *scan = '\n';
2352 break;
2353 case 'r':
2354 *scan = '\r';
2355 break;
2356 case 't':
2357 *scan = '\t';
2358 break;
2359 case 'v':
2360 *scan = '\v';
2361 break;
2362 case '\\':
2363 /* *scan = '\\'; * it already is */
2364 break;
2365 default:
2366 error (0, 0,
2367 _("warning: unrecognized escape `\\%c'"), *scan2);
2368 scan++;
2369 continue;
2372 segmentp = make_segment (segmentp, format, scan - format + 1,
2373 KIND_PLAIN, 0, 0,
2374 our_pred);
2375 format = scan2 + 1; /* Move past the escape. */
2376 scan = scan2; /* Incremented immediately by `for'. */
2378 else if (*scan == '%')
2380 if (scan[1] == 0)
2382 /* Trailing %. We don't like those. */
2383 error (1, 0, _("error: %s at end of format string"), scan);
2385 else if (scan[1] == '%')
2387 segmentp = make_segment (segmentp, format, scan - format + 1,
2388 KIND_PLAIN, 0, 0,
2389 our_pred);
2390 scan++;
2391 format = scan + 1;
2392 continue;
2394 /* Scan past flags, width and precision, to verify kind. */
2395 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2396 /* Do nothing. */ ;
2397 while (ISDIGIT (*scan2))
2398 scan2++;
2399 if (*scan2 == '.')
2400 for (scan2++; ISDIGIT (*scan2); scan2++)
2401 /* Do nothing. */ ;
2402 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2404 segmentp = make_segment (segmentp, format, scan2 - format,
2405 KIND_FORMAT, *scan2, 0,
2406 our_pred);
2407 scan = scan2;
2408 format = scan + 1;
2410 else if (strchr ("ABCT", *scan2) && scan2[1])
2412 segmentp = make_segment (segmentp, format, scan2 - format,
2413 KIND_FORMAT, scan2[0], scan2[1],
2414 our_pred);
2415 scan = scan2 + 1;
2416 format = scan + 1;
2417 continue;
2419 else
2421 /* An unrecognized % escape. Print the char after the %. */
2422 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2423 *scan2);
2424 segmentp = make_segment (segmentp, format, scan - format,
2425 KIND_PLAIN, 0, 0,
2426 our_pred);
2427 format = scan + 1;
2428 continue;
2433 if (scan > format)
2434 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2435 our_pred);
2436 return true;
2439 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2440 from the text in FORMAT, which has length LEN.
2441 Return the address of the `next' pointer of the new segment. */
2443 static struct segment **
2444 make_segment (struct segment **segment,
2445 char *format,
2446 int len,
2447 int kind,
2448 char format_char,
2449 char aux_format_char,
2450 struct predicate *pred)
2452 enum EvaluationCost mycost = NeedsNothing;
2453 char *fmt;
2455 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2457 (*segment)->segkind = kind;
2458 (*segment)->format_char[0] = format_char;
2459 (*segment)->format_char[1] = aux_format_char;
2460 (*segment)->next = NULL;
2461 (*segment)->text_len = len;
2463 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2464 strncpy (fmt, format, len);
2465 fmt += len;
2467 switch (kind)
2469 case KIND_PLAIN: /* Plain text string, no % conversion. */
2470 case KIND_STOP: /* Terminate argument, no newline. */
2471 assert(0 == format_char);
2472 assert(0 == aux_format_char);
2473 *fmt = '\0';
2474 if (mycost > pred->p_cost)
2475 pred->p_cost = NeedsNothing;
2476 return &(*segment)->next;
2477 break;
2480 assert(kind == KIND_FORMAT);
2481 switch (format_char)
2483 case 'l': /* object of symlink */
2484 pred->need_stat = true;
2485 mycost = NeedsLinkName;
2486 *fmt++ = 's';
2487 break;
2489 case 'y': /* file type */
2490 pred->need_type = true;
2491 mycost = NeedsType;
2492 *fmt++ = 's';
2493 break;
2495 case 'a': /* atime in `ctime' format */
2496 case 'A': /* atime in user-specified strftime format */
2497 case 'B': /* birth time in user-specified strftime format */
2498 case 'c': /* ctime in `ctime' format */
2499 case 'C': /* ctime in user-specified strftime format */
2500 case 'F': /* filesystem type */
2501 case 'g': /* group name */
2502 case 'i': /* inode number */
2503 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2504 case 's': /* size in bytes */
2505 case 't': /* mtime in `ctime' format */
2506 case 'T': /* mtime in user-specified strftime format */
2507 case 'u': /* user name */
2508 pred->need_stat = true;
2509 mycost = NeedsStatInfo;
2510 *fmt++ = 's';
2511 break;
2513 case 'S': /* sparseness */
2514 pred->need_stat = true;
2515 mycost = NeedsStatInfo;
2516 *fmt++ = 'g';
2517 break;
2519 case 'Y': /* symlink pointed file type */
2520 pred->need_stat = true;
2521 mycost = NeedsType; /* true for amortised effect */
2522 *fmt++ = 's';
2523 break;
2525 case 'f': /* basename of path */
2526 case 'h': /* leading directories part of path */
2527 case 'p': /* pathname */
2528 case 'P': /* pathname with ARGV element stripped */
2529 *fmt++ = 's';
2530 break;
2532 case 'H': /* ARGV element file was found under */
2533 *fmt++ = 's';
2534 break;
2536 /* Numeric items that one might expect to honour
2537 * #, 0, + flags but which do not.
2539 case 'G': /* GID number */
2540 case 'U': /* UID number */
2541 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2542 case 'D': /* Filesystem device on which the file exits */
2543 case 'k': /* size in 1K blocks */
2544 case 'n': /* number of links */
2545 pred->need_stat = true;
2546 mycost = NeedsStatInfo;
2547 *fmt++ = 's';
2548 break;
2550 /* Numeric items that DO honour #, 0, + flags.
2552 case 'd': /* depth in search tree (0 = ARGV element) */
2553 *fmt++ = 'd';
2554 break;
2556 case 'm': /* mode as octal number (perms only) */
2557 *fmt++ = 'o';
2558 pred->need_stat = true;
2559 mycost = NeedsStatInfo;
2560 break;
2562 case '{':
2563 case '[':
2564 case '(':
2565 error (1, 0,
2566 _("error: the format directive `%%%c' is reserved for future use"),
2567 (int)kind);
2568 /*NOTREACHED*/
2569 break;
2571 *fmt = '\0';
2573 if (mycost > pred->p_cost)
2574 pred->p_cost = mycost;
2575 return &(*segment)->next;
2578 static void
2579 check_path_safety(const char *action, char **argv)
2581 const char *path = getenv("PATH");
2583 (void)argv;
2585 char *s;
2586 s = next_element(path, 1);
2587 while ((s = next_element ((char *) NULL, 1)) != NULL)
2589 if (0 == strcmp(s, "."))
2591 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)"),
2592 action);
2594 else if ('/' != s[0])
2596 /* Relative paths are also dangerous in $PATH. */
2597 error(1, 0, _("The ralative path %s is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove that entry from $PATH"),
2598 safely_quote_err_filename(0, s),
2599 action);
2605 /* handles both exec and ok predicate */
2606 static boolean
2607 new_insert_exec_ok (const char *action,
2608 const struct parser_table *entry,
2609 int dirfd,
2610 char **argv,
2611 int *arg_ptr)
2613 int start, end; /* Indexes in ARGV of start & end of cmd. */
2614 int i; /* Index into cmd args */
2615 int saw_braces; /* True if previous arg was '{}'. */
2616 boolean allow_plus; /* True if + is a valid terminator */
2617 int brace_count; /* Number of instances of {}. */
2618 PRED_FUNC func = entry->pred_func;
2619 enum BC_INIT_STATUS bcstatus;
2621 struct predicate *our_pred;
2622 struct exec_val *execp; /* Pointer for efficiency. */
2624 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2625 return false;
2627 our_pred = insert_primary_withpred (entry, func);
2628 our_pred->side_effects = our_pred->no_default_print = true;
2629 our_pred->need_type = our_pred->need_stat = false;
2631 execp = &our_pred->args.exec_vec;
2633 if ((func != pred_okdir) && (func != pred_ok))
2635 allow_plus = true;
2636 execp->close_stdin = false;
2638 else
2640 allow_plus = false;
2641 /* If find reads stdin (i.e. for -ok and similar), close stdin
2642 * in the child to prevent some script from consiming the output
2643 * intended for find.
2645 execp->close_stdin = true;
2649 if ((func == pred_execdir) || (func == pred_okdir))
2651 options.ignore_readdir_race = false;
2652 check_path_safety(action, argv);
2653 execp->use_current_dir = true;
2655 else
2657 execp->use_current_dir = false;
2660 our_pred->args.exec_vec.multiple = 0;
2662 /* Count the number of args with path replacements, up until the ';'.
2663 * Also figure out if the command is terminated by ";" or by "+".
2665 start = *arg_ptr;
2666 for (end = start, saw_braces=0, brace_count=0;
2667 (argv[end] != NULL)
2668 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2669 end++)
2671 /* For -exec and -execdir, "{} +" can terminate the command. */
2672 if ( allow_plus
2673 && argv[end][0] == '+' && argv[end][1] == 0
2674 && saw_braces)
2676 our_pred->args.exec_vec.multiple = 1;
2677 break;
2680 saw_braces = 0;
2681 if (mbsstr (argv[end], "{}"))
2683 saw_braces = 1;
2684 ++brace_count;
2686 if (0 == end && (func == pred_execdir || func == pred_okdir))
2688 /* The POSIX standard says that {} replacement should
2689 * occur even in the utility name. This is insecure
2690 * since it means we will be executing a command whose
2691 * name is chosen according to whatever find finds in
2692 * the filesystem. That can be influenced by an
2693 * attacker. Hence for -execdir and -okdir this is not
2694 * allowed. We can specify this as those options are
2695 * not defined by POSIX.
2697 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2702 /* Fail if no command given or no semicolon found. */
2703 if ((end == start) || (argv[end] == NULL))
2705 *arg_ptr = end;
2706 free(our_pred);
2707 return false;
2710 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2713 const char *suffix;
2714 if (func == pred_execdir)
2715 suffix = "dir";
2716 else
2717 suffix = "";
2719 error(1, 0,
2720 _("Only one instance of {} is supported with -exec%s ... +"),
2721 suffix);
2724 /* We use a switch statement here so that the compiler warns us when
2725 * we forget to handle a newly invented enum value.
2727 * Like xargs, we allow 2KiB of headroom for the launched utility to
2728 * export its own environment variables before calling something
2729 * else.
2731 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
2732 switch (bcstatus)
2734 case BC_INIT_ENV_TOO_BIG:
2735 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
2736 error(1, 0,
2737 _("The environment is too large for exec()."));
2738 break;
2739 case BC_INIT_OK:
2740 /* Good news. Carry on. */
2741 break;
2743 bc_use_sensible_arg_max(&execp->ctl);
2746 execp->ctl.exec_callback = launch;
2748 if (our_pred->args.exec_vec.multiple)
2750 /* "+" terminator, so we can just append our arguments after the
2751 * command and initial arguments.
2753 execp->replace_vec = NULL;
2754 execp->ctl.replace_pat = NULL;
2755 execp->ctl.rplen = 0;
2756 execp->ctl.lines_per_exec = 0; /* no limit */
2757 execp->ctl.args_per_exec = 0; /* no limit */
2759 /* remember how many arguments there are */
2760 execp->ctl.initial_argc = (end-start) - 1;
2762 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2763 bc_init_state(&execp->ctl, &execp->state, execp);
2765 /* Gather the initial arguments. Skip the {}. */
2766 for (i=start; i<end-1; ++i)
2768 bc_push_arg(&execp->ctl, &execp->state,
2769 argv[i], strlen(argv[i])+1,
2770 NULL, 0,
2774 else
2776 /* Semicolon terminator - more than one {} is supported, so we
2777 * have to do brace-replacement.
2779 execp->num_args = end - start;
2781 execp->ctl.replace_pat = "{}";
2782 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2783 execp->ctl.lines_per_exec = 0; /* no limit */
2784 execp->ctl.args_per_exec = 0; /* no limit */
2785 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2788 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2789 bc_init_state(&execp->ctl, &execp->state, execp);
2791 /* Remember the (pre-replacement) arguments for later. */
2792 for (i=0; i<execp->num_args; ++i)
2794 execp->replace_vec[i] = argv[i+start];
2798 if (argv[end] == NULL)
2799 *arg_ptr = end;
2800 else
2801 *arg_ptr = end + 1;
2803 return true;
2808 static boolean
2809 insert_exec_ok (const char *action, const struct parser_table *entry, int dirfd, char **argv, int *arg_ptr)
2811 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
2816 /* Get a timestamp and comparison type.
2818 STR is the ASCII representation.
2819 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
2820 relative to ORIGIN (usually the current moment or midnight).
2821 Thus the sense of the comparison type appears to be reversed.
2822 Set *COMP_TYPE to the kind of comparison that is requested.
2823 Issue OVERFLOWMESSAGE if overflow occurs.
2824 Return true if all okay, false if input error.
2826 Used by -atime, -ctime and -mtime (parsers) to
2827 get the appropriate information for a time predicate processor. */
2829 static boolean
2830 get_relative_timestamp (char *str,
2831 struct time_val *result,
2832 time_t origin,
2833 double sec_per_unit,
2834 const char *overflowmessage)
2836 uintmax_t checkval;
2837 double offset, seconds, f;
2839 if (get_comp_type(&str, &result->kind))
2841 /* Invert the sense of the comparison */
2842 switch (result->kind)
2844 case COMP_LT: result->kind = COMP_GT; break;
2845 case COMP_GT: result->kind = COMP_LT; break;
2846 default: break;
2849 /* Convert the ASCII number into floating-point. */
2850 if (xstrtod(str, NULL, &offset, strtod))
2852 /* Separate the floating point number the user specified
2853 * (which is a number of days, or minutes, etc) into an
2854 * integral number of seconds (SECONDS) and a fraction (F).
2856 f = modf(offset * sec_per_unit, &seconds);
2858 result->ts.tv_sec = origin - seconds;
2859 result->ts.tv_nsec = fabs(f * 1e9);
2861 /* Check for overflow. */
2862 checkval = (uintmax_t)origin - seconds;
2863 if (checkval != result->ts.tv_sec)
2865 /* an overflow has occurred. */
2866 error (1, 0, overflowmessage, str);
2868 return true;
2870 else
2872 /* Conversion from ASCII to double failed. */
2873 return false;
2876 else
2878 return false;
2882 /* Insert a time predicate based on the information in ENTRY.
2883 ARGV is a pointer to the argument array.
2884 ARG_PTR is a pointer to an index into the array, incremented if
2885 all went well.
2887 Return true if input is valid, false if not.
2889 A new predicate node is assigned, along with an argument node
2890 obtained with malloc.
2892 Used by -atime, -ctime, and -mtime parsers. */
2894 static boolean
2895 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
2897 struct predicate *our_pred;
2898 struct time_val tval;
2899 enum comparison_type comp;
2900 char *s;
2901 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2902 time_t origin;
2904 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2905 return false;
2907 /* Decide the origin by previewing the comparison type. */
2908 origin = options.cur_day_start;
2909 s = argv[*arg_ptr];
2910 if (get_comp_type(&s, &comp))
2912 /* Remember, we invert the sense of the comparison, so this tests against COMP_LT instead of COMP_GT... */
2913 if (COMP_LT == tval.kind)
2915 uintmax_t expected = origin + (DAYSECS-1);
2916 origin += (DAYSECS-1);
2917 if (origin != expected)
2919 error(1, 0,
2920 _("arithmetic overflow when trying to calculate the end of today"));
2923 /* We discard the value of comp here, as get_relative_timestamp
2924 * will set tval.kind.
2928 if (!get_relative_timestamp(argv[*arg_ptr], &tval, origin, DAYSECS, errmsg))
2929 return false;
2931 our_pred = insert_primary (entry);
2932 our_pred->args.reftime = tval;
2933 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
2934 (*arg_ptr)++;
2936 if (options.debug_options & DebugExpressionTree)
2938 time_t t;
2940 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2941 fprintf (stderr, " type: %s %s ",
2942 (tval.kind == COMP_GT) ? "gt" :
2943 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
2944 (tval.kind == COMP_GT) ? " >" :
2945 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
2946 t = our_pred->args.reftime.ts.tv_sec;
2947 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
2948 if (tval.kind == COMP_EQ)
2950 t = our_pred->args.reftime.ts.tv_sec += DAYSECS;
2951 fprintf (stderr, " < %ju %s",
2952 (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
2953 our_pred->args.reftime.ts.tv_sec -= DAYSECS;
2957 return true;
2960 /* Get the comparison type prefix (if any) from a number argument.
2961 The prefix is at *STR.
2962 Set *COMP_TYPE to the kind of comparison that is requested.
2963 Advance *STR beyond any initial comparison prefix.
2965 Return true if all okay, false if input error. */
2966 static boolean
2967 get_comp_type(char **str, enum comparison_type *comp_type)
2969 switch (**str)
2971 case '+':
2972 *comp_type = COMP_GT;
2973 (*str)++;
2974 break;
2975 case '-':
2976 *comp_type = COMP_LT;
2977 (*str)++;
2978 break;
2979 default:
2980 *comp_type = COMP_EQ;
2981 break;
2983 return true;
2990 /* Get a number with comparison information.
2991 The sense of the comparison information is 'normal'; that is,
2992 '+' looks for a count > than the number and '-' less than.
2994 STR is the ASCII representation of the number.
2995 Set *NUM to the number.
2996 Set *COMP_TYPE to the kind of comparison that is requested.
2998 Return true if all okay, false if input error. */
3000 static boolean
3001 get_num (char *str,
3002 uintmax_t *num,
3003 enum comparison_type *comp_type)
3005 char *pend;
3007 if (str == NULL)
3008 return false;
3010 /* Figure out the comparison type if the caller accepts one. */
3011 if (comp_type)
3013 if (!get_comp_type(&str, comp_type))
3014 return false;
3017 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3020 /* Insert a number predicate.
3021 ARGV is a pointer to the argument array.
3022 *ARG_PTR is an index into ARGV, incremented if all went well.
3023 *PRED is the predicate processor to insert.
3025 Return true if input is valid, false if error.
3027 A new predicate node is assigned, along with an argument node
3028 obtained with malloc.
3030 Used by -inum and -links parsers. */
3032 static struct predicate *
3033 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3035 struct predicate *our_pred;
3036 uintmax_t num;
3037 enum comparison_type c_type;
3039 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
3040 return NULL;
3041 if (!get_num (argv[*arg_ptr], &num, &c_type))
3042 return NULL;
3043 our_pred = insert_primary (entry);
3044 our_pred->args.numinfo.kind = c_type;
3045 our_pred->args.numinfo.l_val = num;
3046 (*arg_ptr)++;
3048 if (options.debug_options & DebugExpressionTree)
3050 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3051 fprintf (stderr, " type: %s %s ",
3052 (c_type == COMP_GT) ? "gt" :
3053 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3054 (c_type == COMP_GT) ? " >" :
3055 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3056 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3058 return our_pred;
3061 static FILE *
3062 open_output_file (char *path)
3064 FILE *f;
3066 if (!strcmp (path, "/dev/stderr"))
3067 return stderr;
3068 else if (!strcmp (path, "/dev/stdout"))
3069 return stdout;
3070 f = fopen_safer (path, "w");
3071 if (f == NULL)
3072 fatal_file_error(path);
3073 return f;