Fixed bug #20128, compilation error for find/tree.c for GCC on AIX
[findutils.git] / find / parser.c
blobe8c146630ca36b781dfac27f61fc856986c8b608
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 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.
21 #include <config.h>
23 #include "defs.h"
24 #include <ctype.h>
25 #include <math.h>
26 #include <assert.h>
27 #include <pwd.h>
28 #include <errno.h>
29 #include <grp.h>
30 #include <fnmatch.h>
31 #include "modechange.h"
32 #include "modetype.h"
33 #include "xstrtol.h"
34 #include "xalloc.h"
35 #include "quote.h"
36 #include "quotearg.h"
37 #include "buildcmd.h"
38 #include "nextelem.h"
39 #include "stdio-safer.h"
40 #include "regextype.h"
41 #include "stat-time.h"
42 #include "xstrtod.h"
43 #include "fts_.h"
44 #include "getdate.h"
45 #include "error.h"
46 #include "gnulib-version.h"
48 #ifdef HAVE_FCNTL_H
49 #include <fcntl.h>
50 #else
51 #include <sys/file.h>
52 #endif
54 /* The presence of unistd.h is assumed by gnulib these days, so we
55 * might as well assume it too.
57 /* We need <unistd.h> for isatty(). */
58 #include <unistd.h>
60 #if ENABLE_NLS
61 # include <libintl.h>
62 # define _(Text) gettext (Text)
63 #else
64 # define _(Text) Text
65 #endif
66 #ifdef gettext_noop
67 # define N_(String) gettext_noop (String)
68 #else
69 /* See locate.c for explanation as to why not use (String) */
70 # define N_(String) String
71 #endif
73 #if !defined (isascii) || defined (STDC_HEADERS)
74 #ifdef isascii
75 #undef isascii
76 #endif
77 #define isascii(c) 1
78 #endif
80 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
81 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
83 #ifndef HAVE_ENDGRENT
84 #define endgrent()
85 #endif
86 #ifndef HAVE_ENDPWENT
87 #define endpwent()
88 #endif
90 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
91 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 #if 0
146 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 #endif
148 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
159 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
161 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
162 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
164 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
167 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
168 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
169 static boolean insert_fprintf (struct format_val *vec,
170 const struct parser_table *entry,
171 PRED_FUNC func,
172 const char *format);
174 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
175 int kind, char format_char, char aux_format_char,
176 struct predicate *pred));
177 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, int dirfd, char *argv[], int *arg_ptr));
178 static boolean get_comp_type PARAMS((const char **str, enum comparison_type *comp_type));
179 static boolean get_relative_timestamp PARAMS((const char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
180 static boolean get_num PARAMS((const char *str, uintmax_t *num, enum comparison_type *comp_type));
181 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
182 static void open_output_file (const char *path, struct format_val *p);
183 static void open_stdout (struct format_val *p);
184 static boolean stream_is_tty(FILE *fp);
185 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
187 #define PASTE(x,y) x##y
188 #define STRINGIFY(s) #s
190 #define PARSE_OPTION(what,suffix) \
191 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
193 #define PARSE_POSOPT(what,suffix) \
194 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
196 #define PARSE_TEST(what,suffix) \
197 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
199 #define PARSE_TEST_NP(what,suffix) \
200 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
202 #define PARSE_ACTION(what,suffix) \
203 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
205 #define PARSE_ACTION_NP(what,suffix) \
206 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
208 #define PARSE_PUNCTUATION(what,suffix) \
209 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
212 /* Predicates we cannot handle in the usual way. If you add an entry
213 * to this table, double-check the switch statement in
214 * pred_sanity_check() to make sure that the new case is being
215 * correctly handled.
217 static struct parser_table const parse_entry_newerXY =
219 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
222 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
223 If they are in some Unix versions of find, they are marked `Unix'. */
225 static struct parser_table const parse_table[] =
227 PARSE_PUNCTUATION("!", negate),
228 PARSE_PUNCTUATION("not", negate), /* GNU */
229 PARSE_PUNCTUATION("(", openparen),
230 PARSE_PUNCTUATION(")", closeparen),
231 PARSE_PUNCTUATION(",", comma), /* GNU */
232 PARSE_PUNCTUATION("a", and),
233 PARSE_TEST ("amin", amin), /* GNU */
234 PARSE_PUNCTUATION("and", and), /* GNU */
235 PARSE_TEST ("anewer", anewer), /* GNU */
236 {ARG_TEST, "atime", parse_time, pred_atime},
237 PARSE_TEST ("cmin", cmin), /* GNU */
238 PARSE_TEST ("cnewer", cnewer), /* GNU */
239 {ARG_TEST, "ctime", parse_time, pred_ctime},
240 PARSE_POSOPT ("daystart", daystart), /* GNU */
241 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
242 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
243 PARSE_OPTION ("depth", depth),
244 PARSE_TEST ("empty", empty), /* GNU */
245 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
246 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
247 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
248 PARSE_ACTION ("fls", fls), /* GNU */
249 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
250 PARSE_ACTION ("fprint", fprint), /* GNU */
251 PARSE_ACTION ("fprint0", fprint0), /* GNU */
252 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
253 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
254 PARSE_TEST ("gid", gid), /* GNU */
255 PARSE_TEST ("group", group),
256 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
257 PARSE_TEST ("ilname", ilname), /* GNU */
258 PARSE_TEST ("iname", iname), /* GNU */
259 PARSE_TEST ("inum", inum), /* GNU, Unix */
260 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
261 PARSE_TEST_NP ("iregex", iregex), /* GNU */
262 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
263 PARSE_TEST ("links", links),
264 PARSE_TEST ("lname", lname), /* GNU */
265 PARSE_ACTION ("ls", ls), /* GNU, Unix */
266 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
267 PARSE_OPTION ("mindepth", mindepth), /* GNU */
268 PARSE_TEST ("mmin", mmin), /* GNU */
269 PARSE_OPTION ("mount", xdev), /* Unix */
270 {ARG_TEST, "mtime", parse_time, pred_mtime},
271 PARSE_TEST ("name", name),
272 #ifdef UNIMPLEMENTED_UNIX
273 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
274 #endif
275 PARSE_TEST ("newer", newer),
276 {ARG_TEST, "atime", parse_time, pred_atime},
277 PARSE_OPTION ("noleaf", noleaf), /* GNU */
278 PARSE_TEST ("nogroup", nogroup),
279 PARSE_TEST ("nouser", nouser),
280 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
281 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
282 PARSE_PUNCTUATION("o", or),
283 PARSE_PUNCTUATION("or", or), /* GNU */
284 PARSE_ACTION ("ok", ok),
285 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
286 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
287 PARSE_TEST ("perm", perm),
288 PARSE_ACTION ("print", print),
289 PARSE_ACTION ("print0", print0), /* GNU */
290 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
291 PARSE_ACTION ("prune", prune),
292 PARSE_ACTION ("quit", quit), /* GNU */
293 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
294 PARSE_TEST ("regex", regex), /* GNU */
295 PARSE_OPTION ("regextype", regextype), /* GNU */
296 PARSE_TEST ("samefile", samefile), /* GNU */
297 #if 0
298 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
299 #endif
300 PARSE_TEST ("size", size),
301 PARSE_TEST ("type", type),
302 PARSE_TEST ("uid", uid), /* GNU */
303 PARSE_TEST ("used", used), /* GNU */
304 PARSE_TEST ("user", user),
305 PARSE_OPTION ("warn", warn), /* GNU */
306 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
307 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
308 PARSE_OPTION ("xdev", xdev),
309 PARSE_TEST ("xtype", xtype), /* GNU */
310 #ifdef UNIMPLEMENTED_UNIX
311 /* It's pretty ugly for find to know about archive formats.
312 Plus what it could do with cpio archives is very limited.
313 Better to leave it out. */
314 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
315 #endif
316 /* gnulib's stdbool.h might have made true and false into macros,
317 * so we can't leave named 'true' and 'false' tokens, so we have
318 * to expeant the relevant entries longhand.
320 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
321 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
322 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
324 /* Various other cases that don't fit neatly into our macro scheme. */
325 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
326 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
327 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
328 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
329 {0, 0, 0, 0}
333 static const char *first_nonoption_arg = NULL;
334 static const struct parser_table *noop = NULL;
337 static const struct parser_table*
338 get_noop(void)
340 int i;
341 if (NULL == noop)
343 for (i = 0; parse_table[i].parser_name != 0; i++)
345 if (ARG_NOOP ==parse_table[i].type)
347 noop = &(parse_table[i]);
348 break;
352 return noop;
355 static int
356 get_stat_Ytime(const struct stat *p,
357 char what,
358 struct timespec *ret)
360 switch (what)
362 case 'a':
363 *ret = get_stat_atime(p);
364 return 1;
365 case 'B':
366 *ret = get_stat_birthtime(p);
367 return (ret->tv_nsec >= 0);
368 case 'c':
369 *ret = get_stat_ctime(p);
370 return 1;
371 case 'm':
372 *ret = get_stat_mtime(p);
373 return 1;
374 default:
375 assert(0);
376 abort();
377 abort();
381 void
382 set_follow_state(enum SymlinkOption opt)
384 if (options.debug_options & DebugStat)
386 /* For DebugStat, the choice is made at runtime within debug_stat()
387 * by checking the contents of the symlink_handling variable.
389 options.xstat = debug_stat;
391 else
393 switch (opt)
395 case SYMLINK_ALWAYS_DEREF: /* -L */
396 options.xstat = optionl_stat;
397 options.no_leaf_check = true;
398 break;
400 case SYMLINK_NEVER_DEREF: /* -P (default) */
401 options.xstat = optionp_stat;
402 /* Can't turn no_leaf_check off because the user might have specified
403 * -noleaf anyway
405 break;
407 case SYMLINK_DEREF_ARGSONLY: /* -H */
408 options.xstat = optionh_stat;
409 options.no_leaf_check = true;
412 options.symlink_handling = opt;
416 void
417 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
419 (void) args;
420 (void) argno;
421 (void) last;
422 (void) predicates;
423 first_nonoption_arg = NULL;
426 void
427 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
429 /* does nothing */
430 (void) args;
431 (void) argno;
432 (void) last;
433 (void) predicates;
437 /* Check that it is legal to fid the given primary in its
438 * position and return it.
440 const struct parser_table*
441 found_parser(const char *original_arg, const struct parser_table *entry)
443 /* If this is an option, but we have already had a
444 * non-option argument, the user may be under the
445 * impression that the behaviour of the option
446 * argument is conditional on some preceding
447 * tests. This might typically be the case with,
448 * for example, -maxdepth.
450 * The options -daystart and -follow are exempt
451 * from this treatment, since their positioning
452 * in the command line does have an effect on
453 * subsequent tests but not previous ones. That
454 * might be intentional on the part of the user.
456 if (entry->type != ARG_POSITIONAL_OPTION)
458 /* Something other than -follow/-daystart.
459 * If this is an option, check if it followed
460 * a non-option and if so, issue a warning.
462 if (entry->type == ARG_OPTION)
464 if ((first_nonoption_arg != NULL)
465 && options.warnings )
467 /* option which follows a non-option */
468 error (0, 0,
469 _("warning: you have specified the %s "
470 "option after a non-option argument %s, "
471 "but options are not positional (%s affects "
472 "tests specified before it as well as those "
473 "specified after it). Please specify options "
474 "before other arguments.\n"),
475 original_arg,
476 first_nonoption_arg,
477 original_arg);
480 else
482 /* Not an option or a positional option,
483 * so remember we've seen it in order to
484 * use it in a possible future warning message.
486 if (first_nonoption_arg == NULL)
488 first_nonoption_arg = original_arg;
493 return entry;
497 /* Return a pointer to the parser function to invoke for predicate
498 SEARCH_NAME.
499 Return NULL if SEARCH_NAME is not a valid predicate name. */
501 const struct parser_table*
502 find_parser (char *search_name)
504 int i;
505 const char *original_arg = search_name;
507 /* Ugh. Special case -newerXY. */
508 if (0 == strncmp("-newer", search_name, 6)
509 && (8 == strlen(search_name)))
511 return found_parser(original_arg, &parse_entry_newerXY);
514 if (*search_name == '-')
515 search_name++;
517 for (i = 0; parse_table[i].parser_name != 0; i++)
519 if (strcmp (parse_table[i].parser_name, search_name) == 0)
521 return found_parser(original_arg, &parse_table[i]);
524 return NULL;
527 static float
528 estimate_file_age_success_rate(float num_days)
530 if (num_days < 0.1)
532 /* Assume 1% of files have timestamps in the future */
533 return 0.01f;
535 else if (num_days < 1)
537 /* Assume 30% of files have timestamps today */
538 return 0.3f;
540 else if (num_days > 100)
542 /* Assume 30% of files are very old */
543 return 0.3f;
545 else
547 /* Assume 39% of files are between 1 and 100 days old. */
548 return 0.39f;
552 static float
553 estimate_timestamp_success_rate(time_t when)
555 int num_days = (options.cur_day_start - when) / 86400;
556 return estimate_file_age_success_rate(num_days);
559 /* Collect an argument from the argument list, or
560 * return false.
562 static boolean
563 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
565 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
567 *collected_arg = NULL;
568 return false;
570 else
572 *collected_arg = argv[*arg_ptr];
573 (*arg_ptr)++;
574 return true;
578 static boolean
579 collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
581 const char *filename;
582 if (collect_arg(argv, arg_ptr, &filename))
584 if (0 == (options.xstat)(filename, p))
586 return true;
588 else
590 fatal_file_error(filename);
593 else
595 return false;
599 /* The parsers are responsible to continue scanning ARGV for
600 their arguments. Each parser knows what is and isn't
601 allowed for itself.
603 ARGV is the argument array.
604 *ARG_PTR is the index to start at in ARGV,
605 updated to point beyond the last element consumed.
607 The predicate structure is updated with the new information. */
610 static boolean
611 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
613 struct predicate *our_pred;
615 (void) argv;
616 (void) arg_ptr;
618 our_pred = get_new_pred (entry);
619 our_pred->pred_func = pred_and;
620 our_pred->p_type = BI_OP;
621 our_pred->p_prec = AND_PREC;
622 our_pred->need_stat = our_pred->need_type = false;
623 return true;
626 static boolean
627 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
629 struct stat stat_newer;
631 set_stat_placeholders(&stat_newer);
632 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
634 struct predicate *our_pred = insert_primary (entry);
635 our_pred->args.reftime.xval = XVAL_ATIME;
636 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
637 our_pred->args.reftime.kind = COMP_GT;
638 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
639 return true;
641 return false;
644 boolean
645 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
647 struct predicate *our_pred;
649 (void) argv;
650 (void) arg_ptr;
652 our_pred = get_new_pred (entry);
653 our_pred->pred_func = pred_closeparen;
654 our_pred->p_type = CLOSE_PAREN;
655 our_pred->p_prec = NO_PREC;
656 our_pred->need_stat = our_pred->need_type = false;
657 return true;
660 static boolean
661 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
663 struct stat stat_newer;
665 set_stat_placeholders(&stat_newer);
666 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
668 struct predicate *our_pred = insert_primary (entry);
669 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
670 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
671 our_pred->args.reftime.kind = COMP_GT;
672 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
673 return true;
675 return false;
678 static boolean
679 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
681 struct predicate *our_pred;
683 (void) argv;
684 (void) arg_ptr;
686 our_pred = get_new_pred (entry);
687 our_pred->pred_func = pred_comma;
688 our_pred->p_type = BI_OP;
689 our_pred->p_prec = COMMA_PREC;
690 our_pred->need_stat = our_pred->need_type = false;
691 our_pred->est_success_rate = 1.0f;
692 return true;
695 static boolean
696 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
698 struct tm *local;
700 (void) entry;
701 (void) argv;
702 (void) arg_ptr;
704 if (options.full_days == false)
706 options.cur_day_start += DAYSECS;
707 local = localtime (&options.cur_day_start);
708 options.cur_day_start -= (local
709 ? (local->tm_sec + local->tm_min * 60
710 + local->tm_hour * 3600)
711 : options.cur_day_start % DAYSECS);
712 options.full_days = true;
714 return true;
717 static boolean
718 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
720 struct predicate *our_pred;
721 (void) argv;
722 (void) arg_ptr;
724 our_pred = insert_primary (entry);
725 our_pred->side_effects = our_pred->no_default_print = true;
726 /* -delete implies -depth */
727 options.do_dir_first = false;
729 /* We do not need stat information because we check for the case
730 * (errno==EISDIR) in pred_delete.
732 our_pred->need_stat = our_pred->need_type = false;
734 our_pred->est_success_rate = 1.0f;
735 return true;
738 static boolean
739 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
741 (void) entry;
742 (void) argv;
744 options.do_dir_first = false;
745 return parse_noop(entry, argv, arg_ptr);
748 static boolean
749 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
751 if (options.warnings)
753 error (0, 0,
754 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
756 return parse_depth(entry, argv, arg_ptr);
759 static boolean
760 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
762 struct predicate *our_pred;
763 (void) argv;
764 (void) arg_ptr;
766 our_pred = insert_primary (entry);
767 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
768 return true;
771 static boolean
772 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
774 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
777 static boolean
778 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
780 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
783 static boolean
784 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
786 struct predicate *our_pred;
788 (void) argv;
789 (void) arg_ptr;
791 our_pred = insert_primary (entry);
792 our_pred->need_stat = our_pred->need_type = false;
793 our_pred->side_effects = our_pred->no_default_print = false;
794 our_pred->est_success_rate = 0.0f;
795 return true;
798 static boolean
799 insert_fls (const struct parser_table* entry, const char *filename)
801 struct predicate *our_pred = insert_primary (entry);
802 if (filename)
803 open_output_file (filename, &our_pred->args.printf_vec);
804 else
805 open_stdout (&our_pred->args.printf_vec);
806 our_pred->side_effects = our_pred->no_default_print = true;
807 our_pred->est_success_rate = 1.0f;
808 return true;
812 static boolean
813 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
815 const char *filename;
816 return collect_arg(argv, arg_ptr, &filename)
817 && insert_fls(entry, filename);
820 static boolean
821 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
823 set_follow_state(SYMLINK_ALWAYS_DEREF);
824 return parse_noop(entry, argv, arg_ptr);
827 static boolean
828 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
830 struct predicate *our_pred;
831 const char *filename;
832 if (collect_arg(argv, arg_ptr, &filename))
834 our_pred = insert_primary (entry);
835 open_output_file (filename, &our_pred->args.printf_vec);
836 our_pred->side_effects = our_pred->no_default_print = true;
837 our_pred->need_stat = our_pred->need_type = false;
838 our_pred->est_success_rate = 1.0f;
839 return true;
841 else
843 return false;
847 static boolean
848 insert_fprint(const struct parser_table* entry, const char *filename)
850 struct predicate *our_pred = insert_primary (entry);
851 if (filename)
852 open_output_file (filename, &our_pred->args.printf_vec);
853 else
854 open_stdout (&our_pred->args.printf_vec);
855 our_pred->side_effects = our_pred->no_default_print = true;
856 our_pred->need_stat = our_pred->need_type = false;
857 our_pred->est_success_rate = 1.0f;
858 return true;
862 static boolean
863 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
865 const char *filename;
866 if (collect_arg(argv, arg_ptr, &filename))
867 return insert_fprint(entry, filename);
868 else
869 return false;
872 static float estimate_fstype_success_rate(const char *fsname)
874 struct stat dir_stat;
875 const char *dir = "/";
876 if (0 == stat(dir, &dir_stat))
878 const char *fstype = filesystem_type(&dir_stat, dir);
879 /* Assume most files are on the same filesystem type as the root fs. */
880 if (0 == strcmp(fsname, fstype))
881 return 0.7f;
882 else
883 return 0.3f;
885 return 1.0f;
889 static boolean
890 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
892 const char *typename;
893 if (collect_arg(argv, arg_ptr, &typename))
895 struct predicate *our_pred = insert_primary (entry);
896 our_pred->args.str = typename;
898 /* This is an expensive operation, so although there are
899 * circumstances where it is selective, we ignore this fact
900 * because we probably don't want to promote this test to the
901 * front anyway.
903 our_pred->est_success_rate = estimate_fstype_success_rate(typename);
904 return true;
906 else
908 return false;
912 static boolean
913 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
915 struct predicate *p = insert_num (argv, arg_ptr, entry);
916 if (p)
918 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
919 return true;
921 else
923 return false;
928 static int
929 safe_atoi (const char *s)
931 long lval;
932 char *end;
934 errno = 0;
935 lval = strtol(s, &end, 10);
936 if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
938 /* max/min possible value, or an error. */
939 if (errno == ERANGE)
941 /* too big, or too small. */
942 error(1, errno, "%s", s);
944 else
946 /* not a valid number */
947 error(1, errno, "%s", s);
949 /* Otherwise, we do a range chack against INT_MAX and INT_MIN
950 * below.
954 if (lval > INT_MAX || lval < INT_MIN)
956 /* The number was in range for long, but not int. */
957 errno = ERANGE;
958 error(1, errno, "%s", s);
960 else if (*end)
962 error(1, errno, "Unexpected suffix %s on %s",
963 quotearg_n_style(0, options.err_quoting_style, end),
964 quotearg_n_style(1, options.err_quoting_style, s));
966 else if (end == s)
968 error(1, errno, "Expected an integer: %s",
969 quotearg_n_style(0, options.err_quoting_style, s));
971 return (int)lval;
975 static boolean
976 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
978 const char *groupname;
980 if (collect_arg(argv, arg_ptr, &groupname))
982 gid_t gid;
983 struct predicate *our_pred;
984 struct group *cur_gr = getgrnam(groupname);
985 endgrent();
986 if (cur_gr)
988 gid = cur_gr->gr_gid;
990 else
992 const int gid_len = strspn (groupname, "0123456789");
993 if (gid_len)
995 if (groupname[gid_len] == 0)
997 gid = safe_atoi (groupname);
999 else
1001 /* XXX: no test in test suite for this */
1002 error(1, 0, _("%s is not the name of an existing group and"
1003 " it does not look like a numeric group ID "
1004 "because it has the unexpected suffix %s"),
1005 quotearg_n_style(0, options.err_quoting_style, groupname),
1006 quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
1007 return false;
1010 else
1012 if (*groupname)
1014 /* XXX: no test in test suite for this */
1015 error(1, 0, _("%s is not the name of an existing group"),
1016 quotearg_n_style(0, options.err_quoting_style, groupname));
1018 else
1020 error(1, 0, _("argument to -group is empty, but should be a group name"));
1022 return false;
1025 our_pred = insert_primary (entry);
1026 our_pred->args.gid = gid;
1027 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1028 return true;
1030 return false;
1033 static boolean
1034 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
1036 (void) entry;
1037 (void) argv;
1038 (void) arg_ptr;
1040 usage(stdout, 0, NULL);
1041 puts (_("\n\
1042 default path is the current directory; default expression is -print\n\
1043 expression may consist of: operators, options, tests, and actions:\n"));
1044 puts (_("\
1045 operators (decreasing precedence; -and is implicit where no others are given):\n\
1046 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
1047 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1048 puts (_("\
1049 positional options (always true): -daystart -follow -regextype\n\n\
1050 normal options (always true, specified before other expressions):\n\
1051 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1052 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1053 puts (_("\
1054 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1055 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1056 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1057 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1058 puts (_("\
1059 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
1060 -readable -writable -executable\n\
1061 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1062 -used N -user NAME -xtype [bcdpfls]\n"));
1063 puts (_("\
1064 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1065 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1066 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1067 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1068 "));
1069 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1070 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1071 email to <bug-findutils@gnu.org>."));
1072 exit (0);
1075 static float
1076 estimate_pattern_match_rate(const char *pattern, int is_regex)
1078 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1080 /* A wildcard; assume the pattern matches most files. */
1081 return 0.8f;
1083 else
1085 return 0.1f;
1089 static boolean
1090 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1092 const char *name;
1093 if (collect_arg(argv, arg_ptr, &name))
1095 struct predicate *our_pred = insert_primary (entry);
1096 our_pred->args.str = name;
1097 /* Use the generic glob pattern estimator to figure out how many
1098 * links will match, but bear in mind that most files won't be links.
1100 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1101 return true;
1103 else
1105 return false;
1110 /* sanity check the fnmatch() function to make sure that case folding
1111 * is supported (as opposed to just having the flag ignored).
1113 static boolean
1114 fnmatch_sanitycheck(void)
1116 static boolean checked = false;
1117 if (!checked)
1119 if (0 != fnmatch("foo", "foo", 0)
1120 || 0 == fnmatch("Foo", "foo", 0)
1121 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1123 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1124 return false;
1126 checked = true;
1128 return checked;
1132 static boolean
1133 check_name_arg(const char *pred, const char *arg)
1135 if (strchr(arg, '/'))
1137 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'."),
1138 pred,
1139 safely_quote_err_filename(0, arg),
1140 safely_quote_err_filename(1, arg));
1142 return true; /* allow it anyway */
1147 static boolean
1148 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1150 const char *name;
1151 fnmatch_sanitycheck();
1152 if (collect_arg(argv, arg_ptr, &name))
1154 if (check_name_arg("-iname", name))
1156 struct predicate *our_pred = insert_primary (entry);
1157 our_pred->need_stat = our_pred->need_type = false;
1158 our_pred->args.str = name;
1159 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1160 return true;
1163 return false;
1166 static boolean
1167 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1169 struct predicate *p = insert_num (argv, arg_ptr, entry);
1170 if (p)
1172 /* inode number is exact match only, so very low proportions of
1173 * files match
1175 p->est_success_rate = 1e-6;
1176 return true;
1178 else
1180 return false;
1184 /* -ipath is deprecated (at RMS's request) in favour of
1185 * -iwholename. See the node "GNU Manuals" in standards.texi
1186 * for the rationale for this (basically, GNU prefers the use
1187 * of the phrase "file name" to "path name"
1189 static boolean
1190 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1192 error (0, 0,
1193 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1195 return parse_iwholename(entry, argv, arg_ptr);
1198 static boolean
1199 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1201 const char *name;
1203 fnmatch_sanitycheck();
1204 if (collect_arg(argv, arg_ptr, &name))
1206 struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
1207 our_pred->need_stat = our_pred->need_type = false;
1208 our_pred->args.str = name;
1209 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1210 return true;
1212 return false;
1215 static boolean
1216 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1218 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1221 static boolean
1222 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1224 struct predicate *p = insert_num (argv, arg_ptr, entry);
1225 if (p)
1227 if (p->args.numinfo.l_val == 1)
1228 p->est_success_rate = 0.99;
1229 else if (p->args.numinfo.l_val == 2)
1230 p->est_success_rate = 0.01;
1231 else
1232 p->est_success_rate = 1e-3;
1233 return true;
1235 else
1237 return false;
1241 static boolean
1242 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1244 const char *name;
1245 fnmatch_sanitycheck();
1246 if (collect_arg(argv, arg_ptr, &name))
1248 struct predicate *our_pred = insert_primary (entry);
1249 our_pred->args.str = name;
1250 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1251 return true;
1253 return false;
1256 static boolean
1257 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1259 (void) &argv;
1260 (void) &arg_ptr;
1261 return insert_fls(entry, NULL);
1264 static boolean
1265 insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
1266 int *limitptr)
1268 const char *depthstr;
1269 int depth_len;
1270 const char *predicate = argv[(*arg_ptr)-1];
1271 if (collect_arg(argv, arg_ptr, &depthstr))
1273 depth_len = strspn (depthstr, "0123456789");
1274 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1276 (*limitptr) = safe_atoi (depthstr);
1277 if (*limitptr >= 0)
1279 return parse_noop(entry, argv, arg_ptr);
1282 error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
1283 predicate,
1284 quotearg_n_style(0, options.err_quoting_style, depthstr));
1285 return false;
1287 /* missing argument */
1288 return false;
1292 static boolean
1293 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1295 return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
1298 static boolean
1299 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1301 return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
1305 static boolean
1306 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr, enum xval xv)
1308 const char *minutes;
1310 if (collect_arg(argv, arg_ptr, &minutes))
1312 struct time_val tval;
1313 tval.xval = xv;
1314 if (get_relative_timestamp(minutes, &tval,
1315 options.cur_day_start + DAYSECS, 60,
1316 "arithmetic overflow while converting %s "
1317 "minutes to a number of seconds"))
1319 struct predicate *our_pred = insert_primary (entry);
1320 our_pred->args.reftime = tval;
1321 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1322 return true;
1325 return false;
1327 static boolean
1328 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1330 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1333 static boolean
1334 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1336 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1340 static boolean
1341 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1343 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1346 static boolean
1347 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1349 const char *name;
1350 if (collect_arg(argv, arg_ptr, &name))
1352 fnmatch_sanitycheck();
1353 if (check_name_arg("-name", name))
1355 struct predicate *our_pred = insert_primary (entry);
1356 our_pred->need_stat = our_pred->need_type = false;
1357 our_pred->args.str = name;
1358 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1359 return true;
1362 return false;
1365 static boolean
1366 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1368 struct predicate *our_pred;
1370 (void) &argv;
1371 (void) &arg_ptr;
1373 our_pred = get_new_pred_chk_op (entry);
1374 our_pred->pred_func = pred_negate;
1375 our_pred->p_type = UNI_OP;
1376 our_pred->p_prec = NEGATE_PREC;
1377 our_pred->need_stat = our_pred->need_type = false;
1378 return true;
1381 static boolean
1382 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1384 struct predicate *our_pred;
1385 struct stat stat_newer;
1387 set_stat_placeholders(&stat_newer);
1388 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
1390 our_pred = insert_primary (entry);
1391 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1392 our_pred->args.reftime.xval = XVAL_MTIME;
1393 our_pred->args.reftime.kind = COMP_GT;
1394 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1395 return true;
1397 return false;
1401 static boolean
1402 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1404 (void) argv;
1405 (void) arg_ptr;
1407 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1409 return false;
1411 else if (8u != strlen(argv[*arg_ptr]))
1413 return false;
1415 else
1417 char x, y;
1418 const char validchars[] = "aBcmt";
1420 assert(0 == strncmp("-newer", argv[*arg_ptr], 6));
1421 x = argv[*arg_ptr][6];
1422 y = argv[*arg_ptr][7];
1425 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1426 if ('B' == x || 'B' == y)
1428 error(0, 0,
1429 _("This system does not provide a way to find the birth time of a file."));
1430 return 0;
1432 #endif
1434 /* -newertY (for any Y) is invalid. */
1435 if (x == 't'
1436 || 0 == strchr(validchars, x)
1437 || 0 == strchr( validchars, y))
1439 return false;
1441 else
1443 struct predicate *our_pred;
1445 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1446 * past the test name (for most other tests, this is already done)
1448 (*arg_ptr)++;
1450 our_pred = insert_primary (entry);
1453 switch (x)
1455 case 'a':
1456 our_pred->args.reftime.xval = XVAL_ATIME;
1457 break;
1458 case 'B':
1459 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1460 break;
1461 case 'c':
1462 our_pred->args.reftime.xval = XVAL_CTIME;
1463 break;
1464 case 'm':
1465 our_pred->args.reftime.xval = XVAL_MTIME;
1466 break;
1467 default:
1468 assert(strchr(validchars, x));
1469 assert(0);
1472 if ('t' == y)
1474 if (!get_date(&our_pred->args.reftime.ts,
1475 argv[*arg_ptr],
1476 &options.start_time))
1478 error(1, 0,
1479 _("I cannot figure out how to interpret %s as a date or time"),
1480 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1483 else
1485 struct stat stat_newer;
1487 /* Stat the named file. */
1488 set_stat_placeholders(&stat_newer);
1489 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1490 fatal_file_error(argv[*arg_ptr]);
1492 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1494 /* We cannot extract a timestamp from the struct stat. */
1495 error(1, 0, _("Cannot obtain birth time of file %s"),
1496 safely_quote_err_filename(0, argv[*arg_ptr]));
1499 our_pred->args.reftime.kind = COMP_GT;
1500 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1501 (*arg_ptr)++;
1503 assert(our_pred->pred_func != NULL);
1504 assert(our_pred->pred_func == pred_newerXY);
1505 assert(our_pred->need_stat);
1506 return true;
1512 static boolean
1513 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1515 options.no_leaf_check = true;
1516 return parse_noop(entry, argv, arg_ptr);
1519 #ifdef CACHE_IDS
1520 /* Arbitrary amount by which to increase size
1521 of `uid_unused' and `gid_unused'. */
1522 #define ALLOC_STEP 2048
1524 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1525 char *uid_unused = NULL;
1527 /* Number of elements in `uid_unused'. */
1528 unsigned uid_allocated;
1530 /* Similar for GIDs and group entries. */
1531 char *gid_unused = NULL;
1532 unsigned gid_allocated;
1533 #endif
1535 static boolean
1536 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1538 struct predicate *our_pred;
1540 (void) &argv;
1541 (void) &arg_ptr;
1543 our_pred = insert_primary (entry);
1544 our_pred->est_success_rate = 1e-4;
1545 #ifdef CACHE_IDS
1546 if (gid_unused == NULL)
1548 struct group *gr;
1550 gid_allocated = ALLOC_STEP;
1551 gid_unused = xmalloc (gid_allocated);
1552 memset (gid_unused, 1, gid_allocated);
1553 setgrent ();
1554 while ((gr = getgrent ()) != NULL)
1556 if ((unsigned) gr->gr_gid >= gid_allocated)
1558 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1559 gid_unused = xrealloc (gid_unused, new_allocated);
1560 memset (gid_unused + gid_allocated, 1,
1561 new_allocated - gid_allocated);
1562 gid_allocated = new_allocated;
1564 gid_unused[(unsigned) gr->gr_gid] = 0;
1566 endgrent ();
1568 #endif
1569 return true;
1572 static boolean
1573 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1575 struct predicate *our_pred;
1576 (void) argv;
1577 (void) arg_ptr;
1580 our_pred = insert_primary (entry);
1581 our_pred->est_success_rate = 1e-3;
1582 #ifdef CACHE_IDS
1583 if (uid_unused == NULL)
1585 struct passwd *pw;
1587 uid_allocated = ALLOC_STEP;
1588 uid_unused = xmalloc (uid_allocated);
1589 memset (uid_unused, 1, uid_allocated);
1590 setpwent ();
1591 while ((pw = getpwent ()) != NULL)
1593 if ((unsigned) pw->pw_uid >= uid_allocated)
1595 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1596 uid_unused = xrealloc (uid_unused, new_allocated);
1597 memset (uid_unused + uid_allocated, 1,
1598 new_allocated - uid_allocated);
1599 uid_allocated = new_allocated;
1601 uid_unused[(unsigned) pw->pw_uid] = 0;
1603 endpwent ();
1605 #endif
1606 return true;
1609 static boolean
1610 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1612 options.warnings = false;
1613 return parse_noop(entry, argv, arg_ptr);
1616 static boolean
1617 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1619 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1622 static boolean
1623 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1625 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1628 boolean
1629 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1631 struct predicate *our_pred;
1633 (void) argv;
1634 (void) arg_ptr;
1636 our_pred = get_new_pred_chk_op (entry);
1637 our_pred->pred_func = pred_openparen;
1638 our_pred->p_type = OPEN_PAREN;
1639 our_pred->p_prec = NO_PREC;
1640 our_pred->need_stat = our_pred->need_type = false;
1641 return true;
1644 static boolean
1645 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1647 struct predicate *our_pred;
1649 (void) argv;
1650 (void) arg_ptr;
1652 our_pred = get_new_pred (entry);
1653 our_pred->pred_func = pred_or;
1654 our_pred->p_type = BI_OP;
1655 our_pred->p_prec = OR_PREC;
1656 our_pred->need_stat = our_pred->need_type = false;
1657 return true;
1660 /* -path is deprecated (at RMS's request) in favour of
1661 * -iwholename. See the node "GNU Manuals" in standards.texi
1662 * for the rationale for this (basically, GNU prefers the use
1663 * of the phrase "file name" to "path name".
1665 * We do not issue a warning that this usage is deprecated
1666 * since HPUX find supports this predicate also.
1668 static boolean
1669 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1671 return parse_wholename(entry, argv, arg_ptr);
1674 static boolean
1675 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1677 const char *name;
1678 if (collect_arg(argv, arg_ptr, &name))
1680 struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
1681 our_pred->need_stat = our_pred->need_type = false;
1682 our_pred->args.str = name;
1683 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1684 return true;
1686 return false;
1689 static boolean
1690 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1692 mode_t perm_val[2];
1693 float rate;
1694 int mode_start = 0;
1695 boolean havekind = false;
1696 enum permissions_type kind = PERM_EXACT;
1697 struct mode_change *change = NULL;
1698 struct predicate *our_pred;
1699 const char *perm_expr;
1701 if (!collect_arg(argv, arg_ptr, &perm_expr))
1702 return false;
1704 switch (perm_expr[0])
1706 case '-':
1707 mode_start = 1;
1708 kind = PERM_AT_LEAST;
1709 havekind = true;
1710 rate = 0.2;
1711 break;
1713 case '+':
1714 change = mode_compile (perm_expr);
1715 if (NULL == change)
1717 /* Most likely the caller is an old script that is still
1718 * using the obsolete GNU syntax '-perm +MODE'. This old
1719 * syntax was withdrawn in favor of '-perm /MODE' because
1720 * it is incompatible with POSIX in some cases, but we
1721 * still support uses of it that are not incompatible with
1722 * POSIX.
1724 mode_start = 1;
1725 kind = PERM_ANY;
1726 rate = 0.3;
1728 else
1730 /* This is a POSIX-compatible usage */
1731 mode_start = 0;
1732 kind = PERM_EXACT;
1733 rate = 0.1;
1735 havekind = true;
1736 break;
1738 case '/': /* GNU extension */
1739 mode_start = 1;
1740 kind = PERM_ANY;
1741 havekind = true;
1742 rate = 0.3;
1743 break;
1745 default:
1746 /* For example, '-perm 0644', which is valid and matches
1747 * only files whose mode is exactly 0644.
1749 mode_start = 0;
1750 kind = PERM_EXACT;
1751 havekind = true;
1752 rate = 0.01;
1753 break;
1756 if (NULL == change)
1758 change = mode_compile (perm_expr + mode_start);
1759 if (NULL == change)
1760 error (1, 0, _("invalid mode %s"),
1761 quotearg_n_style(0, options.err_quoting_style, perm_expr));
1763 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1764 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1765 free (change);
1767 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1769 /* The meaning of -perm /000 will change in the future. It
1770 * currently matches no files, but like -perm -000 it should
1771 * match all files.
1773 * Starting in 2005, we used to issue a warning message
1774 * informing the user that the behaviour would change in the
1775 * future. We have now changed the behaviour and issue a
1776 * warning message that the behaviour recently changed.
1778 error (0, 0,
1779 _("warning: you have specified a mode pattern %s (which is "
1780 "equivalent to /000). The meaning of -perm /000 has now been "
1781 "changed to be consistent with -perm -000; that is, while it "
1782 "used to match no files, it now matches all files."),
1783 perm_expr);
1785 kind = PERM_AT_LEAST;
1786 havekind = true;
1788 /* The "magic" number below is just the fraction of files on my
1789 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1790 * Actual totals are 1472 and 1073833.
1792 rate = 0.9986; /* probably matches anything but a broken symlink */
1795 our_pred = insert_primary (entry);
1796 our_pred->est_success_rate = rate;
1797 if (havekind)
1799 our_pred->args.perm.kind = kind;
1801 else
1804 switch (perm_expr[0])
1806 case '-':
1807 our_pred->args.perm.kind = PERM_AT_LEAST;
1808 break;
1809 case '+':
1810 our_pred->args.perm.kind = PERM_ANY;
1811 break;
1812 default:
1813 our_pred->args.perm.kind = PERM_EXACT;
1814 break;
1817 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1818 return true;
1821 boolean
1822 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1824 struct predicate *our_pred;
1826 (void) argv;
1827 (void) arg_ptr;
1829 our_pred = insert_primary (entry);
1830 /* -print has the side effect of printing. This prevents us
1831 from doing undesired multiple printing when the user has
1832 already specified -print. */
1833 our_pred->side_effects = our_pred->no_default_print = true;
1834 our_pred->need_stat = our_pred->need_type = false;
1835 open_stdout(&our_pred->args.printf_vec);
1836 return true;
1839 static boolean
1840 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1842 return insert_fprint(entry, NULL);
1845 static boolean
1846 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1848 const char *format;
1849 if (collect_arg(argv, arg_ptr, &format))
1851 struct format_val fmt;
1852 open_stdout(&fmt);
1853 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1855 return false;
1858 static boolean
1859 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1861 const char *format, *filename;
1862 if (collect_arg(argv, arg_ptr, &filename))
1864 if (collect_arg(argv, arg_ptr, &format))
1866 struct format_val fmt;
1867 open_output_file (filename, &fmt);
1868 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1871 return false;
1874 static boolean
1875 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1877 struct predicate *our_pred;
1879 (void) argv;
1880 (void) arg_ptr;
1882 our_pred = insert_primary (entry);
1883 our_pred->need_stat = our_pred->need_type = false;
1884 /* -prune has a side effect that it does not descend into
1885 the current directory. */
1886 our_pred->side_effects = true;
1887 our_pred->no_default_print = false;
1888 return true;
1891 static boolean
1892 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1894 struct predicate *our_pred = insert_primary (entry);
1895 (void) argv;
1896 (void) arg_ptr;
1897 our_pred->need_stat = our_pred->need_type = false;
1898 our_pred->side_effects = true; /* Exiting is a side effect... */
1899 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1900 our_pred->est_success_rate = 1.0f;
1901 return true;
1905 static boolean
1906 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1908 const char *type_name;
1909 if (collect_arg(argv, arg_ptr, &type_name))
1911 /* collect the regex type name */
1912 options.regex_options = get_regex_type(type_name);
1913 return parse_noop(entry, argv, arg_ptr);
1915 return false;
1919 static boolean
1920 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1922 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1925 static boolean
1926 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1928 const char *rx;
1929 if (collect_arg(argv, arg_ptr, &rx))
1931 struct re_pattern_buffer *re;
1932 const char *error_message;
1933 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
1934 our_pred->need_stat = our_pred->need_type = false;
1935 re = (struct re_pattern_buffer *)
1936 xmalloc (sizeof (struct re_pattern_buffer));
1937 our_pred->args.regex = re;
1938 re->allocated = 100;
1939 re->buffer = (unsigned char *) xmalloc (re->allocated);
1940 re->fastmap = NULL;
1942 re_set_syntax(regex_options);
1943 re->syntax = regex_options;
1944 re->translate = NULL;
1946 error_message = re_compile_pattern (rx, strlen(rx), re);
1947 if (error_message)
1948 error (1, 0, "%s", error_message);
1949 our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
1950 return true;
1952 return false;
1955 static boolean
1956 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1958 struct predicate *our_pred;
1959 uintmax_t num;
1960 char suffix;
1961 enum comparison_type c_type;
1963 int blksize = 512;
1964 int len;
1966 /* XXX: cannot (yet) convert to ue collect_arg() as this
1967 * function modifies the args in-place.
1969 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1970 return false;
1972 len = strlen (argv[*arg_ptr]);
1973 if (len == 0)
1974 error (1, 0, _("invalid null argument to -size"));
1976 suffix = argv[*arg_ptr][len - 1];
1977 switch (suffix)
1979 case 'b':
1980 blksize = 512;
1981 argv[*arg_ptr][len - 1] = '\0';
1982 break;
1984 case 'c':
1985 blksize = 1;
1986 argv[*arg_ptr][len - 1] = '\0';
1987 break;
1989 case 'k':
1990 blksize = 1024;
1991 argv[*arg_ptr][len - 1] = '\0';
1992 break;
1994 case 'M': /* Megabytes */
1995 blksize = 1024*1024;
1996 argv[*arg_ptr][len - 1] = '\0';
1997 break;
1999 case 'G': /* Gigabytes */
2000 blksize = 1024*1024*1024;
2001 argv[*arg_ptr][len - 1] = '\0';
2002 break;
2004 case 'w':
2005 blksize = 2;
2006 argv[*arg_ptr][len - 1] = '\0';
2007 break;
2009 case '0':
2010 case '1':
2011 case '2':
2012 case '3':
2013 case '4':
2014 case '5':
2015 case '6':
2016 case '7':
2017 case '8':
2018 case '9':
2019 break;
2021 default:
2022 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
2024 /* TODO: accept fractional megabytes etc. ? */
2025 if (!get_num (argv[*arg_ptr], &num, &c_type))
2027 error(1, 0, _("Invalid argument `%s%c' to -size"), argv[*arg_ptr], (int)suffix);
2028 return false;
2030 our_pred = insert_primary (entry);
2031 our_pred->args.size.kind = c_type;
2032 our_pred->args.size.blocksize = blksize;
2033 our_pred->args.size.size = num;
2034 our_pred->need_stat = true;
2035 our_pred->need_type = false;
2037 if (COMP_GT == c_type)
2038 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
2039 else if (COMP_LT == c_type)
2040 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
2041 else
2042 our_pred->est_success_rate = 0.01;
2044 (*arg_ptr)++;
2045 return true;
2049 static boolean
2050 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2052 /* General idea: stat the file, remember device and inode numbers.
2053 * If a candidate file matches those, it's the same file.
2055 struct predicate *our_pred;
2056 struct stat st, fst;
2057 int fd, openflags;
2059 set_stat_placeholders(&st);
2060 if (!collect_arg_stat_info(argv, arg_ptr, &st))
2061 return false;
2063 set_stat_placeholders(&fst);
2064 /* POSIX systems are free to re-use the inode number of a deleted
2065 * file. To ensure that we are not fooled by inode reuse, we hold
2066 * the file open if we can. This would prevent the system reusing
2067 * the file.
2069 fd = -3; /* means, uninitialised */
2070 openflags = O_RDONLY;
2072 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2074 if (options.open_nofollow_available)
2076 assert(O_NOFOLLOW != 0);
2077 openflags |= O_NOFOLLOW;
2078 fd = -1; /* safe to open it. */
2080 else
2082 if (S_ISLNK(st.st_mode))
2084 /* no way to ensure that a symlink will not be followed
2085 * by open(2), so fall back on using lstat(). Accept
2086 * the risk that the named file will be deleted and
2087 * replaced with another having the same inode.
2089 * Avoid opening the file.
2091 fd = -2; /* Do not open it */
2093 else
2095 fd = -1;
2096 /* Race condition here: the file might become a symlink here. */
2100 else
2102 /* We want to dereference the symlink anyway */
2103 fd = -1; /* safe to open it without O_NOFOLLOW */
2106 assert(fd != -3); /* check we made a decision */
2107 if (fd == -1)
2109 /* Race condition here. The file might become a
2110 * symbolic link in between out call to stat and
2111 * the call to open.
2113 fd = open(argv[*arg_ptr], openflags);
2115 if (fd >= 0)
2117 /* We stat the file again here to prevent a race condition
2118 * between the first stat and the call to open(2).
2120 if (0 != fstat(fd, &fst))
2122 fatal_file_error(argv[*arg_ptr]);
2124 else
2126 /* Worry about the race condition. If the file became a
2127 * symlink after our first stat and before our call to
2128 * open, fst may contain the stat information for the
2129 * destination of the link, not the link itself.
2131 if ((*options.xstat) (argv[*arg_ptr], &st))
2132 fatal_file_error(argv[*arg_ptr]);
2134 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2135 && (!options.open_nofollow_available))
2137 if (S_ISLNK(st.st_mode))
2139 /* We lost the race. Leave the data in st. The
2140 * file descriptor points to the wrong thing.
2142 close(fd);
2143 fd = -1;
2145 else
2147 /* Several possibilities here:
2148 * 1. There was no race
2149 * 2. The file changed into a symlink after the stat and
2150 * before the open, and then back into a non-symlink
2151 * before the second stat.
2153 * In case (1) there is no problem. In case (2),
2154 * the stat() and fstat() calls will have returned
2155 * different data. O_NOFOLLOW was not available,
2156 * so the open() call may have followed a symlink
2157 * even if the -P option is in effect.
2159 if ((st.st_dev == fst.st_dev)
2160 && (st.st_ino == fst.st_ino))
2162 /* No race. No need to copy fst to st,
2163 * since they should be identical (modulo
2164 * differences in padding bytes).
2167 else
2169 /* We lost the race. Leave the data in st. The
2170 * file descriptor points to the wrong thing.
2172 close(fd);
2173 fd = -1;
2177 else
2179 st = fst;
2185 our_pred = insert_primary (entry);
2186 our_pred->args.samefileid.ino = st.st_ino;
2187 our_pred->args.samefileid.dev = st.st_dev;
2188 our_pred->args.samefileid.fd = fd;
2189 our_pred->need_type = false;
2190 our_pred->need_stat = true;
2191 our_pred->est_success_rate = 0.01f;
2192 return true;
2195 #if 0
2196 /* This function is commented out partly because support for it is
2197 * uneven.
2199 static boolean
2200 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
2202 const char *arg;
2203 const char *errmsg = _("The -show-control-chars option takes a single argument which "
2204 "must be 'literal' or 'safe'");
2206 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2208 error (1, errno, "%s", errmsg);
2209 return false;
2211 else
2213 arg = argv[*arg_ptr];
2215 if (0 == strcmp("literal", arg))
2217 options.literal_control_chars = true;
2219 else if (0 == strcmp("safe", arg))
2221 options.literal_control_chars = false;
2223 else
2225 error (1, errno, "%s", errmsg);
2226 return false;
2228 (*arg_ptr)++; /* consume the argument. */
2229 return true;
2232 #endif
2235 static boolean
2236 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2238 struct predicate *our_pred;
2240 (void) argv;
2241 (void) arg_ptr;
2243 our_pred = insert_primary (entry);
2244 our_pred->need_stat = our_pred->need_type = false;
2245 our_pred->est_success_rate = 1.0f;
2246 return true;
2249 static boolean
2250 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2252 (void) entry;
2253 return parse_true(get_noop(), argv, arg_ptr);
2256 static boolean
2257 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2259 struct predicate *our_pred;
2260 (void) argv;
2261 (void) arg_ptr;
2262 our_pred = insert_primary (entry);
2263 our_pred->need_stat = our_pred->need_type = false;
2264 our_pred->side_effects = our_pred->no_default_print = false;
2265 if (pred_is(our_pred, pred_executable))
2266 our_pred->est_success_rate = 0.2;
2267 else
2268 our_pred->est_success_rate = 0.9;
2269 return true;
2272 static boolean
2273 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2275 return insert_type (argv, arg_ptr, entry, pred_type);
2278 static boolean
2279 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2281 struct predicate *p = insert_num (argv, arg_ptr, entry);
2282 if (p)
2284 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2285 return true;
2287 else
2289 return false;
2293 static boolean
2294 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2296 struct predicate *our_pred;
2297 struct time_val tval;
2298 const char *offset_str;
2299 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2301 if (collect_arg(argv, arg_ptr, &offset_str))
2303 /* The timespec is actually a delta value, so we use an origin of 0. */
2304 if (get_relative_timestamp(offset_str, &tval, 0, DAYSECS, errmsg))
2306 our_pred = insert_primary (entry);
2307 our_pred->args.reftime = tval;
2308 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2309 return true;
2311 else
2313 error(1, 0, _("Invalid argument %s to -used"), offset_str);
2314 return false;
2317 else
2319 return false; /* missing argument */
2323 static boolean
2324 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2326 const char *username;
2328 if (collect_arg(argv, arg_ptr, &username))
2330 struct predicate *our_pred;
2331 uid_t uid;
2332 struct passwd *cur_pwd = getpwnam(username);
2333 endpwent();
2334 if (cur_pwd != NULL)
2336 uid = cur_pwd->pw_uid;
2338 else
2340 int uid_len = strspn (username, "0123456789");
2341 if (uid_len && (username[uid_len]==0))
2342 uid = safe_atoi (username);
2343 else
2344 return false;
2346 our_pred = insert_primary (entry);
2347 our_pred->args.uid = uid;
2348 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2349 return true;
2351 return false;
2354 static boolean
2355 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2357 extern char *version_string;
2358 int features = 0;
2359 int flags;
2361 (void) argv;
2362 (void) arg_ptr;
2363 (void) entry;
2365 fflush (stderr);
2366 printf (_("GNU find version %s\n"), version_string);
2367 printf (_("Built using GNU gnulib version %s\n"), gnulib_version);
2368 printf (_("Features enabled: "));
2370 #if CACHE_IDS
2371 printf("CACHE_IDS ");
2372 ++features;
2373 #endif
2374 #if DEBUG
2375 printf("DEBUG ");
2376 ++features;
2377 #endif
2378 #if DEBUG_STAT
2379 printf("DEBUG_STAT ");
2380 ++features;
2381 #endif
2382 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
2383 printf("D_TYPE ");
2384 ++features;
2385 #endif
2386 #if defined(O_NOFOLLOW)
2387 printf("O_NOFOLLOW(%s) ",
2388 (options.open_nofollow_available ? "enabled" : "disabled"));
2389 ++features;
2390 #endif
2391 #if defined(LEAF_OPTIMISATION)
2392 printf("LEAF_OPTIMISATION ");
2393 ++features;
2394 #endif
2396 flags = 0;
2397 if (is_fts_enabled(&flags))
2399 int nflags = 0;
2400 printf("FTS(");
2401 ++features;
2403 if (flags & FTS_CWDFD)
2405 if (nflags)
2407 printf(",");
2409 printf("FTS_CWDFD");
2410 ++nflags;
2412 printf(") ");
2415 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2416 ++features;
2418 if (0 == features)
2420 /* For the moment, leave this as English in case someone wants
2421 to parse these strings. */
2422 printf("none");
2424 printf("\n");
2426 exit (0);
2429 static boolean
2430 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2432 options.stay_on_filesystem = true;
2433 return parse_noop(entry, argv, arg_ptr);
2436 static boolean
2437 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2439 options.ignore_readdir_race = true;
2440 return parse_noop(entry, argv, arg_ptr);
2443 static boolean
2444 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2446 options.ignore_readdir_race = false;
2447 return parse_noop(entry, argv, arg_ptr);
2450 static boolean
2451 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2453 options.warnings = true;
2454 return parse_noop(entry, argv, arg_ptr);
2457 static boolean
2458 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2460 return insert_type (argv, arg_ptr, entry, pred_xtype);
2463 static boolean
2464 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2466 mode_t type_cell;
2467 struct predicate *our_pred;
2468 float rate = 0.5;
2469 const char *typeletter;
2471 if (collect_arg(argv, arg_ptr, &typeletter))
2473 if (strlen(typeletter) != 1u)
2475 error(1, 0, _("Arguments to -type should contain only one letter"));
2476 return false;
2479 switch (typeletter[0])
2481 case 'b': /* block special */
2482 type_cell = S_IFBLK;
2483 rate = 0.01f;
2484 break;
2485 case 'c': /* character special */
2486 type_cell = S_IFCHR;
2487 rate = 0.01f;
2488 break;
2489 case 'd': /* directory */
2490 type_cell = S_IFDIR;
2491 rate = 0.4f;
2492 break;
2493 case 'f': /* regular file */
2494 type_cell = S_IFREG;
2495 rate = 0.95f;
2496 break;
2497 #ifdef S_IFLNK
2498 case 'l': /* symbolic link */
2499 type_cell = S_IFLNK;
2500 rate = 0.1f;
2501 break;
2502 #endif
2503 #ifdef S_IFIFO
2504 case 'p': /* pipe */
2505 type_cell = S_IFIFO;
2506 rate = 0.01f;
2507 break;
2508 #endif
2509 #ifdef S_IFSOCK
2510 case 's': /* socket */
2511 type_cell = S_IFSOCK;
2512 rate = 0.01f;
2513 break;
2514 #endif
2515 #ifdef S_IFDOOR
2516 case 'D': /* Solaris door */
2517 type_cell = S_IFDOOR;
2518 rate = 0.01f;
2519 break;
2520 #endif
2521 default: /* None of the above ... nuke 'em. */
2522 error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
2523 return false;
2525 our_pred = insert_primary_withpred (entry, which_pred);
2526 our_pred->est_success_rate = rate;
2528 /* Figure out if we will need to stat the file, because if we don't
2529 * need to follow symlinks, we can avoid a stat call by using
2530 * struct dirent.d_type.
2532 if (which_pred == pred_xtype)
2534 our_pred->need_stat = true;
2535 our_pred->need_type = false;
2537 else
2539 our_pred->need_stat = false; /* struct dirent is enough */
2540 our_pred->need_type = true;
2542 our_pred->args.type = type_cell;
2543 return true;
2545 return false;
2549 /* Return true if the file accessed via FP is a terminal.
2551 static boolean
2552 stream_is_tty(FILE *fp)
2554 int fd = fileno(fp);
2555 if (-1 == fd)
2557 return false; /* not a valid stream */
2559 else
2561 return isatty(fd) ? true : false;
2569 /* XXX: do we need to pass FUNC to this function? */
2570 static boolean
2571 insert_fprintf (struct format_val *vec,
2572 const struct parser_table *entry, PRED_FUNC func,
2573 const char *format_const)
2575 char *format = (char*)format_const; /* XXX: casting away constness */
2576 register char *scan; /* Current address in scanning `format'. */
2577 register char *scan2; /* Address inside of element being scanned. */
2578 struct segment **segmentp; /* Address of current segment. */
2579 struct predicate *our_pred;
2581 our_pred = insert_primary_withpred (entry, func);
2582 our_pred->side_effects = our_pred->no_default_print = true;
2583 our_pred->args.printf_vec = *vec;
2584 our_pred->need_type = false;
2585 our_pred->need_stat = false;
2586 our_pred->p_cost = NeedsNothing;
2588 segmentp = &our_pred->args.printf_vec.segment;
2589 *segmentp = NULL;
2591 for (scan = format; *scan; scan++)
2593 if (*scan == '\\')
2595 scan2 = scan + 1;
2596 if (*scan2 >= '0' && *scan2 <= '7')
2598 register int n, i;
2600 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2601 i++, scan2++)
2602 n = 8 * n + *scan2 - '0';
2603 scan2--;
2604 *scan = n;
2606 else
2608 switch (*scan2)
2610 case 'a':
2611 *scan = 7;
2612 break;
2613 case 'b':
2614 *scan = '\b';
2615 break;
2616 case 'c':
2617 make_segment (segmentp, format, scan - format,
2618 KIND_STOP, 0, 0,
2619 our_pred);
2620 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2621 our_pred->p_cost = NeedsStatInfo;
2622 return true;
2623 case 'f':
2624 *scan = '\f';
2625 break;
2626 case 'n':
2627 *scan = '\n';
2628 break;
2629 case 'r':
2630 *scan = '\r';
2631 break;
2632 case 't':
2633 *scan = '\t';
2634 break;
2635 case 'v':
2636 *scan = '\v';
2637 break;
2638 case '\\':
2639 /* *scan = '\\'; * it already is */
2640 break;
2641 default:
2642 error (0, 0,
2643 _("warning: unrecognized escape `\\%c'"), *scan2);
2644 scan++;
2645 continue;
2648 segmentp = make_segment (segmentp, format, scan - format + 1,
2649 KIND_PLAIN, 0, 0,
2650 our_pred);
2651 format = scan2 + 1; /* Move past the escape. */
2652 scan = scan2; /* Incremented immediately by `for'. */
2654 else if (*scan == '%')
2656 if (scan[1] == 0)
2658 /* Trailing %. We don't like those. */
2659 error (1, 0, _("error: %s at end of format string"), scan);
2661 else if (scan[1] == '%')
2663 segmentp = make_segment (segmentp, format, scan - format + 1,
2664 KIND_PLAIN, 0, 0,
2665 our_pred);
2666 scan++;
2667 format = scan + 1;
2668 continue;
2670 /* Scan past flags, width and precision, to verify kind. */
2671 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2672 /* Do nothing. */ ;
2673 while (ISDIGIT (*scan2))
2674 scan2++;
2675 if (*scan2 == '.')
2676 for (scan2++; ISDIGIT (*scan2); scan2++)
2677 /* Do nothing. */ ;
2678 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2680 segmentp = make_segment (segmentp, format, scan2 - format,
2681 KIND_FORMAT, *scan2, 0,
2682 our_pred);
2683 scan = scan2;
2684 format = scan + 1;
2686 else if (strchr ("ABCT", *scan2) && scan2[1])
2688 segmentp = make_segment (segmentp, format, scan2 - format,
2689 KIND_FORMAT, scan2[0], scan2[1],
2690 our_pred);
2691 scan = scan2 + 1;
2692 format = scan + 1;
2693 continue;
2695 else
2697 /* An unrecognized % escape. Print the char after the %. */
2698 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2699 *scan2);
2700 segmentp = make_segment (segmentp, format, scan - format,
2701 KIND_PLAIN, 0, 0,
2702 our_pred);
2703 format = scan + 1;
2704 continue;
2709 if (scan > format)
2710 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2711 our_pred);
2712 return true;
2715 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2716 from the text in FORMAT, which has length LEN.
2717 Return the address of the `next' pointer of the new segment. */
2719 static struct segment **
2720 make_segment (struct segment **segment,
2721 char *format,
2722 int len,
2723 int kind,
2724 char format_char,
2725 char aux_format_char,
2726 struct predicate *pred)
2728 enum EvaluationCost mycost = NeedsNothing;
2729 char *fmt;
2731 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2733 (*segment)->segkind = kind;
2734 (*segment)->format_char[0] = format_char;
2735 (*segment)->format_char[1] = aux_format_char;
2736 (*segment)->next = NULL;
2737 (*segment)->text_len = len;
2739 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2740 strncpy (fmt, format, len);
2741 fmt += len;
2743 switch (kind)
2745 case KIND_PLAIN: /* Plain text string, no % conversion. */
2746 case KIND_STOP: /* Terminate argument, no newline. */
2747 assert(0 == format_char);
2748 assert(0 == aux_format_char);
2749 *fmt = '\0';
2750 if (mycost > pred->p_cost)
2751 pred->p_cost = NeedsNothing;
2752 return &(*segment)->next;
2753 break;
2756 assert(kind == KIND_FORMAT);
2757 switch (format_char)
2759 case 'l': /* object of symlink */
2760 pred->need_stat = true;
2761 mycost = NeedsLinkName;
2762 *fmt++ = 's';
2763 break;
2765 case 'y': /* file type */
2766 pred->need_type = true;
2767 mycost = NeedsType;
2768 *fmt++ = 's';
2769 break;
2771 case 'a': /* atime in `ctime' format */
2772 case 'A': /* atime in user-specified strftime format */
2773 case 'B': /* birth time in user-specified strftime format */
2774 case 'c': /* ctime in `ctime' format */
2775 case 'C': /* ctime in user-specified strftime format */
2776 case 'F': /* filesystem type */
2777 case 'g': /* group name */
2778 case 'i': /* inode number */
2779 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2780 case 's': /* size in bytes */
2781 case 't': /* mtime in `ctime' format */
2782 case 'T': /* mtime in user-specified strftime format */
2783 case 'u': /* user name */
2784 pred->need_stat = true;
2785 mycost = NeedsStatInfo;
2786 *fmt++ = 's';
2787 break;
2789 case 'S': /* sparseness */
2790 pred->need_stat = true;
2791 mycost = NeedsStatInfo;
2792 *fmt++ = 'g';
2793 break;
2795 case 'Y': /* symlink pointed file type */
2796 pred->need_stat = true;
2797 mycost = NeedsType; /* true for amortised effect */
2798 *fmt++ = 's';
2799 break;
2801 case 'f': /* basename of path */
2802 case 'h': /* leading directories part of path */
2803 case 'p': /* pathname */
2804 case 'P': /* pathname with ARGV element stripped */
2805 *fmt++ = 's';
2806 break;
2808 case 'H': /* ARGV element file was found under */
2809 *fmt++ = 's';
2810 break;
2812 /* Numeric items that one might expect to honour
2813 * #, 0, + flags but which do not.
2815 case 'G': /* GID number */
2816 case 'U': /* UID number */
2817 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2818 case 'D': /* Filesystem device on which the file exits */
2819 case 'k': /* size in 1K blocks */
2820 case 'n': /* number of links */
2821 pred->need_stat = true;
2822 mycost = NeedsStatInfo;
2823 *fmt++ = 's';
2824 break;
2826 /* Numeric items that DO honour #, 0, + flags.
2828 case 'd': /* depth in search tree (0 = ARGV element) */
2829 *fmt++ = 'd';
2830 break;
2832 case 'm': /* mode as octal number (perms only) */
2833 *fmt++ = 'o';
2834 pred->need_stat = true;
2835 mycost = NeedsStatInfo;
2836 break;
2838 case '{':
2839 case '[':
2840 case '(':
2841 error (1, 0,
2842 _("error: the format directive `%%%c' is reserved for future use"),
2843 (int)kind);
2844 /*NOTREACHED*/
2845 break;
2847 *fmt = '\0';
2849 if (mycost > pred->p_cost)
2850 pred->p_cost = mycost;
2851 return &(*segment)->next;
2854 static void
2855 check_path_safety(const char *action, char **argv)
2857 const char *path = getenv("PATH");
2858 char *s;
2860 (void)argv;
2862 s = next_element(path, 1);
2863 while ((s = next_element ((char *) NULL, 1)) != NULL)
2865 if (0 == strcmp(s, "."))
2867 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)"),
2868 action);
2870 else if ('/' != s[0])
2872 /* Relative paths are also dangerous in $PATH. */
2873 error(1, 0, _("The relative path %s is included in the PATH "
2874 "environment variable, which is insecure in "
2875 "combination with the %s action of find. "
2876 "Please remove that entry from $PATH"),
2877 safely_quote_err_filename(0, s),
2878 action);
2884 /* handles both exec and ok predicate */
2885 static boolean
2886 new_insert_exec_ok (const char *action,
2887 const struct parser_table *entry,
2888 int dirfd,
2889 char **argv,
2890 int *arg_ptr)
2892 int start, end; /* Indexes in ARGV of start & end of cmd. */
2893 int i; /* Index into cmd args */
2894 int saw_braces; /* True if previous arg was '{}'. */
2895 boolean allow_plus; /* True if + is a valid terminator */
2896 int brace_count; /* Number of instances of {}. */
2897 PRED_FUNC func = entry->pred_func;
2898 enum BC_INIT_STATUS bcstatus;
2900 struct predicate *our_pred;
2901 struct exec_val *execp; /* Pointer for efficiency. */
2903 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2904 return false;
2906 our_pred = insert_primary_withpred (entry, func);
2907 our_pred->side_effects = our_pred->no_default_print = true;
2908 our_pred->need_type = our_pred->need_stat = false;
2910 execp = &our_pred->args.exec_vec;
2912 if ((func != pred_okdir) && (func != pred_ok))
2914 allow_plus = true;
2915 execp->close_stdin = false;
2917 else
2919 allow_plus = false;
2920 /* If find reads stdin (i.e. for -ok and similar), close stdin
2921 * in the child to prevent some script from consiming the output
2922 * intended for find.
2924 execp->close_stdin = true;
2928 if ((func == pred_execdir) || (func == pred_okdir))
2930 options.ignore_readdir_race = false;
2931 check_path_safety(action, argv);
2932 execp->use_current_dir = true;
2934 else
2936 execp->use_current_dir = false;
2939 our_pred->args.exec_vec.multiple = 0;
2941 /* Count the number of args with path replacements, up until the ';'.
2942 * Also figure out if the command is terminated by ";" or by "+".
2944 start = *arg_ptr;
2945 for (end = start, saw_braces=0, brace_count=0;
2946 (argv[end] != NULL)
2947 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2948 end++)
2950 /* For -exec and -execdir, "{} +" can terminate the command. */
2951 if ( allow_plus
2952 && argv[end][0] == '+' && argv[end][1] == 0
2953 && saw_braces)
2955 our_pred->args.exec_vec.multiple = 1;
2956 break;
2959 saw_braces = 0;
2960 if (mbsstr (argv[end], "{}"))
2962 saw_braces = 1;
2963 ++brace_count;
2965 if (0 == end && (func == pred_execdir || func == pred_okdir))
2967 /* The POSIX standard says that {} replacement should
2968 * occur even in the utility name. This is insecure
2969 * since it means we will be executing a command whose
2970 * name is chosen according to whatever find finds in
2971 * the filesystem. That can be influenced by an
2972 * attacker. Hence for -execdir and -okdir this is not
2973 * allowed. We can specify this as those options are
2974 * not defined by POSIX.
2976 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2981 /* Fail if no command given or no semicolon found. */
2982 if ((end == start) || (argv[end] == NULL))
2984 *arg_ptr = end;
2985 free(our_pred);
2986 return false;
2989 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2992 const char *suffix;
2993 if (func == pred_execdir)
2994 suffix = "dir";
2995 else
2996 suffix = "";
2998 error(1, 0,
2999 _("Only one instance of {} is supported with -exec%s ... +"),
3000 suffix);
3003 /* We use a switch statement here so that the compiler warns us when
3004 * we forget to handle a newly invented enum value.
3006 * Like xargs, we allow 2KiB of headroom for the launched utility to
3007 * export its own environment variables before calling something
3008 * else.
3010 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
3011 switch (bcstatus)
3013 case BC_INIT_ENV_TOO_BIG:
3014 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
3015 error(1, 0,
3016 _("The environment is too large for exec()."));
3017 break;
3018 case BC_INIT_OK:
3019 /* Good news. Carry on. */
3020 break;
3022 bc_use_sensible_arg_max(&execp->ctl);
3025 execp->ctl.exec_callback = launch;
3027 if (our_pred->args.exec_vec.multiple)
3029 /* "+" terminator, so we can just append our arguments after the
3030 * command and initial arguments.
3032 execp->replace_vec = NULL;
3033 execp->ctl.replace_pat = NULL;
3034 execp->ctl.rplen = 0;
3035 execp->ctl.lines_per_exec = 0; /* no limit */
3036 execp->ctl.args_per_exec = 0; /* no limit */
3038 /* remember how many arguments there are */
3039 execp->ctl.initial_argc = (end-start) - 1;
3041 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
3042 bc_init_state(&execp->ctl, &execp->state, execp);
3044 /* Gather the initial arguments. Skip the {}. */
3045 for (i=start; i<end-1; ++i)
3047 bc_push_arg(&execp->ctl, &execp->state,
3048 argv[i], strlen(argv[i])+1,
3049 NULL, 0,
3053 else
3055 /* Semicolon terminator - more than one {} is supported, so we
3056 * have to do brace-replacement.
3058 execp->num_args = end - start;
3060 execp->ctl.replace_pat = "{}";
3061 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
3062 execp->ctl.lines_per_exec = 0; /* no limit */
3063 execp->ctl.args_per_exec = 0; /* no limit */
3064 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
3067 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3068 bc_init_state(&execp->ctl, &execp->state, execp);
3070 /* Remember the (pre-replacement) arguments for later. */
3071 for (i=0; i<execp->num_args; ++i)
3073 execp->replace_vec[i] = argv[i+start];
3077 if (argv[end] == NULL)
3078 *arg_ptr = end;
3079 else
3080 *arg_ptr = end + 1;
3082 return true;
3087 static boolean
3088 insert_exec_ok (const char *action, const struct parser_table *entry, int dirfd, char **argv, int *arg_ptr)
3090 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
3095 /* Get a timestamp and comparison type.
3097 STR is the ASCII representation.
3098 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3099 relative to ORIGIN (usually the current moment or midnight).
3100 Thus the sense of the comparison type appears to be reversed.
3101 Set *COMP_TYPE to the kind of comparison that is requested.
3102 Issue OVERFLOWMESSAGE if overflow occurs.
3103 Return true if all okay, false if input error.
3105 Used by -atime, -ctime and -mtime (parsers) to
3106 get the appropriate information for a time predicate processor. */
3108 static boolean
3109 get_relative_timestamp (const char *str,
3110 struct time_val *result,
3111 time_t origin,
3112 double sec_per_unit,
3113 const char *overflowmessage)
3115 uintmax_t checkval;
3116 double offset, seconds, f;
3118 if (get_comp_type(&str, &result->kind))
3120 /* Invert the sense of the comparison */
3121 switch (result->kind)
3123 case COMP_LT: result->kind = COMP_GT; break;
3124 case COMP_GT: result->kind = COMP_LT; break;
3125 default: break;
3128 /* Convert the ASCII number into floating-point. */
3129 if (xstrtod(str, NULL, &offset, strtod))
3131 /* Separate the floating point number the user specified
3132 * (which is a number of days, or minutes, etc) into an
3133 * integral number of seconds (SECONDS) and a fraction (F).
3135 f = modf(offset * sec_per_unit, &seconds);
3137 result->ts.tv_sec = origin - seconds;
3138 result->ts.tv_nsec = fabs(f * 1e9);
3140 /* Check for overflow. */
3141 checkval = (uintmax_t)origin - seconds;
3142 if (checkval != result->ts.tv_sec)
3144 /* an overflow has occurred. */
3145 error (1, 0, overflowmessage, str);
3147 return true;
3149 else
3151 /* Conversion from ASCII to double failed. */
3152 return false;
3155 else
3157 return false;
3161 /* Insert a time predicate based on the information in ENTRY.
3162 ARGV is a pointer to the argument array.
3163 ARG_PTR is a pointer to an index into the array, incremented if
3164 all went well.
3166 Return true if input is valid, false if not.
3168 A new predicate node is assigned, along with an argument node
3169 obtained with malloc.
3171 Used by -atime, -ctime, and -mtime parsers. */
3173 static boolean
3174 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3176 struct predicate *our_pred;
3177 struct time_val tval;
3178 enum comparison_type comp;
3179 const char *timearg, *orig_timearg;
3180 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
3181 time_t origin;
3183 if (!collect_arg(argv, arg_ptr, &timearg))
3184 return false;
3185 orig_timearg = timearg;
3187 /* Decide the origin by previewing the comparison type. */
3188 origin = options.cur_day_start;
3190 if (get_comp_type(&timearg, &comp))
3192 /* Remember, we invert the sense of the comparison, so this tests
3193 * against COMP_LT instead of COMP_GT...
3195 if (COMP_LT == tval.kind)
3197 uintmax_t expected = origin + (DAYSECS-1);
3198 origin += (DAYSECS-1);
3199 if (origin != expected)
3201 error(1, 0,
3202 _("arithmetic overflow when trying to calculate the end of today"));
3206 /* We discard the value of comp here, as get_relative_timestamp
3207 * will set tval.kind. For that to work, we have to restore
3208 * timearg so that it points to the +/- prefix, if any. get_comp_type()
3209 * will have advanced timearg, so we restore it.
3211 timearg = orig_timearg;
3213 if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
3214 return false;
3216 our_pred = insert_primary (entry);
3217 our_pred->args.reftime = tval;
3218 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3220 if (options.debug_options & DebugExpressionTree)
3222 time_t t;
3224 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3225 fprintf (stderr, " type: %s %s ",
3226 (tval.kind == COMP_GT) ? "gt" :
3227 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3228 (tval.kind == COMP_GT) ? " >" :
3229 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3230 t = our_pred->args.reftime.ts.tv_sec;
3231 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3232 if (tval.kind == COMP_EQ)
3234 t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
3235 fprintf (stderr, " < %ju %s",
3236 (uintmax_t) t, ctime (&t));
3240 return true;
3243 /* Get the comparison type prefix (if any) from a number argument.
3244 The prefix is at *STR.
3245 Set *COMP_TYPE to the kind of comparison that is requested.
3246 Advance *STR beyond any initial comparison prefix.
3248 Return true if all okay, false if input error. */
3249 static boolean
3250 get_comp_type(const char **str, enum comparison_type *comp_type)
3252 switch (**str)
3254 case '+':
3255 *comp_type = COMP_GT;
3256 (*str)++;
3257 break;
3258 case '-':
3259 *comp_type = COMP_LT;
3260 (*str)++;
3261 break;
3262 default:
3263 *comp_type = COMP_EQ;
3264 break;
3266 return true;
3273 /* Get a number with comparison information.
3274 The sense of the comparison information is 'normal'; that is,
3275 '+' looks for a count > than the number and '-' less than.
3277 STR is the ASCII representation of the number.
3278 Set *NUM to the number.
3279 Set *COMP_TYPE to the kind of comparison that is requested.
3281 Return true if all okay, false if input error. */
3283 static boolean
3284 get_num (const char *str,
3285 uintmax_t *num,
3286 enum comparison_type *comp_type)
3288 char *pend;
3290 if (str == NULL)
3291 return false;
3293 /* Figure out the comparison type if the caller accepts one. */
3294 if (comp_type)
3296 if (!get_comp_type(&str, comp_type))
3297 return false;
3300 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3303 /* Insert a number predicate.
3304 ARGV is a pointer to the argument array.
3305 *ARG_PTR is an index into ARGV, incremented if all went well.
3306 *PRED is the predicate processor to insert.
3308 Return true if input is valid, false if error.
3310 A new predicate node is assigned, along with an argument node
3311 obtained with malloc.
3313 Used by -inum and -links parsers. */
3315 static struct predicate *
3316 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3318 const char *numstr;
3320 if (collect_arg(argv, arg_ptr, &numstr))
3322 uintmax_t num;
3323 enum comparison_type c_type;
3325 if (get_num (numstr, &num, &c_type))
3327 struct predicate *our_pred = insert_primary (entry);
3328 our_pred->args.numinfo.kind = c_type;
3329 our_pred->args.numinfo.l_val = num;
3331 if (options.debug_options & DebugExpressionTree)
3333 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3334 fprintf (stderr, " type: %s %s ",
3335 (c_type == COMP_GT) ? "gt" :
3336 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3337 (c_type == COMP_GT) ? " >" :
3338 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3339 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3341 return our_pred;
3344 return NULL;
3347 static void
3348 open_output_file (const char *path, struct format_val *p)
3350 p->segment = NULL;
3351 p->quote_opts = clone_quoting_options (NULL);
3353 if (!strcmp (path, "/dev/stderr"))
3355 p->stream = stderr;
3356 p->filename = _("standard error");
3358 else if (!strcmp (path, "/dev/stdout"))
3360 p->stream = stdout;
3361 p->filename = _("standard output");
3363 else
3365 p->stream = fopen_safer (path, "w");
3366 p->filename = path;
3368 if (p->stream == NULL)
3370 fatal_file_error(path);
3374 p->dest_is_tty = stream_is_tty(p->stream);
3377 static void
3378 open_stdout (struct format_val *p)
3380 open_output_file("/dev/stdout", p);