cvsimport
[findutils.git] / find / parser.c
blob18d26cc9e228c5e936db7355ff198f6476b29aa6
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #include "defs.h"
22 #include <ctype.h>
23 #include <math.h>
24 #include <assert.h>
25 #include <pwd.h>
26 #include <errno.h>
27 #include <grp.h>
28 #include <fnmatch.h>
29 #include "modechange.h"
30 #include "modetype.h"
31 #include "xstrtol.h"
32 #include "xalloc.h"
33 #include "quote.h"
34 #include "quotearg.h"
35 #include "buildcmd.h"
36 #include "nextelem.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
40 #include "xstrtod.h"
41 #include "fts_.h"
42 #include "getdate.h"
43 #include "error.h"
44 #include "findutils-version.h"
46 #include <fcntl.h>
49 /* The presence of unistd.h is assumed by gnulib these days, so we
50 * might as well assume it too.
52 /* We need <unistd.h> for isatty(). */
53 #include <unistd.h>
54 #include <sys/stat.h>
56 #if ENABLE_NLS
57 # include <libintl.h>
58 # define _(Text) gettext (Text)
59 #else
60 # define _(Text) Text
61 #endif
62 #ifdef gettext_noop
63 # define N_(String) gettext_noop (String)
64 #else
65 /* See locate.c for explanation as to why not use (String) */
66 # define N_(String) String
67 #endif
69 #if !defined (isascii) || defined (STDC_HEADERS)
70 #ifdef isascii
71 #undef isascii
72 #endif
73 #define isascii(c) 1
74 #endif
76 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
77 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
79 #ifndef HAVE_ENDGRENT
80 #define endgrent()
81 #endif
82 #ifndef HAVE_ENDPWENT
83 #define endpwent()
84 #endif
86 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
87 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 #if 0
142 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 #endif
144 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
163 static boolean insert_type PARAMS((char **argv, int *arg_ptr,
164 const struct parser_table *entry,
165 PRED_FUNC which_pred));
166 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr,
167 const struct parser_table *entry,
168 int regex_options));
169 static boolean insert_fprintf (struct format_val *vec,
170 const struct parser_table *entry,
171 PRED_FUNC func,
172 const char *format);
174 static struct segment **make_segment PARAMS((struct segment **segment,
175 char *format, int len,
176 int kind, char format_char,
177 char aux_format_char,
178 struct predicate *pred));
179 static boolean insert_exec_ok PARAMS((const char *action,
180 const struct parser_table *entry,
181 int dirfd,
182 char *argv[],
183 int *arg_ptr));
184 static boolean get_comp_type PARAMS((const char **str,
185 enum comparison_type *comp_type));
186 static boolean get_relative_timestamp PARAMS((const char *str,
187 struct time_val *tval,
188 time_t origin,
189 double sec_per_unit,
190 const char *overflowmessage));
191 static boolean get_num PARAMS((const char *str,
192 uintmax_t *num,
193 enum comparison_type *comp_type));
194 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr,
195 const struct parser_table *entry));
196 static void open_output_file (const char *path, struct format_val *p);
197 static void open_stdout (struct format_val *p);
198 static boolean stream_is_tty(FILE *fp);
199 static boolean parse_noop PARAMS((const struct parser_table* entry,
200 char **argv, int *arg_ptr));
202 #define PASTE(x,y) x##y
203 #define STRINGIFY(s) #s
205 #define PARSE_OPTION(what,suffix) \
206 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
208 #define PARSE_POSOPT(what,suffix) \
209 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
211 #define PARSE_TEST(what,suffix) \
212 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
214 #define PARSE_TEST_NP(what,suffix) \
215 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
217 #define PARSE_ACTION(what,suffix) \
218 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
220 #define PARSE_ACTION_NP(what,suffix) \
221 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
223 #define PARSE_PUNCTUATION(what,suffix) \
224 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
227 /* Predicates we cannot handle in the usual way. If you add an entry
228 * to this table, double-check the switch statement in
229 * pred_sanity_check() to make sure that the new case is being
230 * correctly handled.
232 static struct parser_table const parse_entry_newerXY =
234 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
237 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
238 If they are in some Unix versions of find, they are marked `Unix'. */
240 static struct parser_table const parse_table[] =
242 PARSE_PUNCTUATION("!", negate), /* POSIX */
243 PARSE_PUNCTUATION("not", negate), /* GNU */
244 PARSE_PUNCTUATION("(", openparen), /* POSIX */
245 PARSE_PUNCTUATION(")", closeparen), /* POSIX */
246 PARSE_PUNCTUATION(",", comma), /* GNU */
247 PARSE_PUNCTUATION("a", and), /* POSIX */
248 PARSE_TEST ("amin", amin), /* GNU */
249 PARSE_PUNCTUATION("and", and), /* GNU */
250 PARSE_TEST ("anewer", anewer), /* GNU */
251 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
252 PARSE_TEST ("cmin", cmin), /* GNU */
253 PARSE_TEST ("cnewer", cnewer), /* GNU */
254 {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
255 PARSE_POSOPT ("daystart", daystart), /* GNU */
256 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
257 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
258 PARSE_OPTION ("depth", depth), /* POSIX */
259 PARSE_TEST ("empty", empty), /* GNU */
260 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
261 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
262 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
263 PARSE_ACTION ("fls", fls), /* GNU */
264 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
265 PARSE_ACTION ("fprint", fprint), /* GNU */
266 PARSE_ACTION ("fprint0", fprint0), /* GNU */
267 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
268 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
269 PARSE_TEST ("gid", gid), /* GNU */
270 PARSE_TEST ("group", group), /* POSIX */
271 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
272 PARSE_TEST ("ilname", ilname), /* GNU */
273 PARSE_TEST ("iname", iname), /* GNU */
274 PARSE_TEST ("inum", inum), /* GNU, Unix */
275 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
276 PARSE_TEST_NP ("iregex", iregex), /* GNU */
277 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
278 PARSE_TEST ("links", links), /* POSIX */
279 PARSE_TEST ("lname", lname), /* GNU */
280 PARSE_ACTION ("ls", ls), /* GNU, Unix */
281 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
282 PARSE_OPTION ("mindepth", mindepth), /* GNU */
283 PARSE_TEST ("mmin", mmin), /* GNU */
284 PARSE_OPTION ("mount", xdev), /* Unix */
285 {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
286 PARSE_TEST ("name", name),
287 #ifdef UNIMPLEMENTED_UNIX
288 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
289 #endif
290 PARSE_TEST ("newer", newer), /* POSIX */
291 {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
292 PARSE_OPTION ("noleaf", noleaf), /* GNU */
293 PARSE_TEST ("nogroup", nogroup), /* POSIX */
294 PARSE_TEST ("nouser", nouser), /* POSIX */
295 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
296 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
297 PARSE_PUNCTUATION("o", or), /* POSIX */
298 PARSE_PUNCTUATION("or", or), /* GNU */
299 PARSE_ACTION ("ok", ok), /* POSIX */
300 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
301 PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
302 PARSE_TEST ("perm", perm), /* POSIX */
303 PARSE_ACTION ("print", print), /* POSIX */
304 PARSE_ACTION ("print0", print0), /* GNU */
305 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
306 PARSE_ACTION ("prune", prune), /* POSIX */
307 PARSE_ACTION ("quit", quit), /* GNU */
308 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
309 PARSE_TEST ("regex", regex), /* GNU */
310 PARSE_OPTION ("regextype", regextype), /* GNU */
311 PARSE_TEST ("samefile", samefile), /* GNU */
312 #if 0
313 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
314 #endif
315 PARSE_TEST ("size", size), /* POSIX */
316 PARSE_TEST ("type", type), /* POSIX */
317 PARSE_TEST ("uid", uid), /* GNU */
318 PARSE_TEST ("used", used), /* GNU */
319 PARSE_TEST ("user", user), /* POSIX */
320 PARSE_OPTION ("warn", warn), /* GNU */
321 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
322 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
323 PARSE_OPTION ("xdev", xdev), /* POSIX */
324 PARSE_TEST ("xtype", xtype), /* GNU */
325 #ifdef UNIMPLEMENTED_UNIX
326 /* It's pretty ugly for find to know about archive formats.
327 Plus what it could do with cpio archives is very limited.
328 Better to leave it out. */
329 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
330 #endif
331 /* gnulib's stdbool.h might have made true and false into macros,
332 * so we can't leave named 'true' and 'false' tokens, so we have
333 * to expeant the relevant entries longhand.
335 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
336 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
337 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
339 /* Various other cases that don't fit neatly into our macro scheme. */
340 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
341 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
342 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
343 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
344 {0, 0, 0, 0}
348 static const char *first_nonoption_arg = NULL;
349 static const struct parser_table *noop = NULL;
352 static const struct parser_table*
353 get_noop(void)
355 int i;
356 if (NULL == noop)
358 for (i = 0; parse_table[i].parser_name != 0; i++)
360 if (ARG_NOOP ==parse_table[i].type)
362 noop = &(parse_table[i]);
363 break;
367 return noop;
370 static int
371 get_stat_Ytime(const struct stat *p,
372 char what,
373 struct timespec *ret)
375 switch (what)
377 case 'a':
378 *ret = get_stat_atime(p);
379 return 1;
380 case 'B':
381 *ret = get_stat_birthtime(p);
382 return (ret->tv_nsec >= 0);
383 case 'c':
384 *ret = get_stat_ctime(p);
385 return 1;
386 case 'm':
387 *ret = get_stat_mtime(p);
388 return 1;
389 default:
390 assert (0);
391 abort();
395 void
396 set_follow_state(enum SymlinkOption opt)
398 if (options.debug_options & DebugStat)
400 /* For DebugStat, the choice is made at runtime within debug_stat()
401 * by checking the contents of the symlink_handling variable.
403 options.xstat = debug_stat;
405 else
407 switch (opt)
409 case SYMLINK_ALWAYS_DEREF: /* -L */
410 options.xstat = optionl_stat;
411 options.no_leaf_check = true;
412 break;
414 case SYMLINK_NEVER_DEREF: /* -P (default) */
415 options.xstat = optionp_stat;
416 /* Can't turn no_leaf_check off because the user might have specified
417 * -noleaf anyway
419 break;
421 case SYMLINK_DEREF_ARGSONLY: /* -H */
422 options.xstat = optionh_stat;
423 options.no_leaf_check = true;
426 options.symlink_handling = opt;
430 void
431 parse_begin_user_args (char **args, int argno,
432 const struct predicate *last,
433 const struct predicate *predicates)
435 (void) args;
436 (void) argno;
437 (void) last;
438 (void) predicates;
439 first_nonoption_arg = NULL;
442 void
443 parse_end_user_args (char **args, int argno,
444 const struct predicate *last,
445 const struct predicate *predicates)
447 /* does nothing */
448 (void) args;
449 (void) argno;
450 (void) last;
451 (void) predicates;
455 /* Check that it is legal to fid the given primary in its
456 * position and return it.
458 const struct parser_table*
459 found_parser(const char *original_arg, const struct parser_table *entry)
461 /* If this is an option, but we have already had a
462 * non-option argument, the user may be under the
463 * impression that the behaviour of the option
464 * argument is conditional on some preceding
465 * tests. This might typically be the case with,
466 * for example, -maxdepth.
468 * The options -daystart and -follow are exempt
469 * from this treatment, since their positioning
470 * in the command line does have an effect on
471 * subsequent tests but not previous ones. That
472 * might be intentional on the part of the user.
474 if (entry->type != ARG_POSITIONAL_OPTION)
476 /* Something other than -follow/-daystart.
477 * If this is an option, check if it followed
478 * a non-option and if so, issue a warning.
480 if (entry->type == ARG_OPTION)
482 if ((first_nonoption_arg != NULL)
483 && options.warnings )
485 /* option which follows a non-option */
486 error (0, 0,
487 _("warning: you have specified the %s "
488 "option after a non-option argument %s, "
489 "but options are not positional (%s affects "
490 "tests specified before it as well as those "
491 "specified after it). Please specify options "
492 "before other arguments.\n"),
493 original_arg,
494 first_nonoption_arg,
495 original_arg);
498 else
500 /* Not an option or a positional option,
501 * so remember we've seen it in order to
502 * use it in a possible future warning message.
504 if (first_nonoption_arg == NULL)
506 first_nonoption_arg = original_arg;
511 return entry;
515 /* Return a pointer to the parser function to invoke for predicate
516 SEARCH_NAME.
517 Return NULL if SEARCH_NAME is not a valid predicate name. */
519 const struct parser_table*
520 find_parser (char *search_name)
522 int i;
523 const char *original_arg = search_name;
525 /* Ugh. Special case -newerXY. */
526 if (0 == strncmp("-newer", search_name, 6)
527 && (8 == strlen(search_name)))
529 return found_parser(original_arg, &parse_entry_newerXY);
532 if (*search_name == '-')
533 search_name++;
535 for (i = 0; parse_table[i].parser_name != 0; i++)
537 if (strcmp (parse_table[i].parser_name, search_name) == 0)
539 return found_parser(original_arg, &parse_table[i]);
542 return NULL;
545 static float
546 estimate_file_age_success_rate(float num_days)
548 if (num_days < 0.1)
550 /* Assume 1% of files have timestamps in the future */
551 return 0.01f;
553 else if (num_days < 1)
555 /* Assume 30% of files have timestamps today */
556 return 0.3f;
558 else if (num_days > 100)
560 /* Assume 30% of files are very old */
561 return 0.3f;
563 else
565 /* Assume 39% of files are between 1 and 100 days old. */
566 return 0.39f;
570 static float
571 estimate_timestamp_success_rate(time_t when)
573 int num_days = (options.cur_day_start - when) / 86400;
574 return estimate_file_age_success_rate(num_days);
577 /* Collect an argument from the argument list, or
578 * return false.
580 static boolean
581 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
583 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
585 *collected_arg = NULL;
586 return false;
588 else
590 *collected_arg = argv[*arg_ptr];
591 (*arg_ptr)++;
592 return true;
596 static boolean
597 collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
599 const char *filename;
600 if (collect_arg(argv, arg_ptr, &filename))
602 if (0 == (options.xstat)(filename, p))
604 return true;
606 else
608 fatal_file_error(filename);
611 else
613 return false;
617 /* The parsers are responsible to continue scanning ARGV for
618 their arguments. Each parser knows what is and isn't
619 allowed for itself.
621 ARGV is the argument array.
622 *ARG_PTR is the index to start at in ARGV,
623 updated to point beyond the last element consumed.
625 The predicate structure is updated with the new information. */
628 static boolean
629 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
631 struct predicate *our_pred;
633 (void) argv;
634 (void) arg_ptr;
636 our_pred = get_new_pred (entry);
637 our_pred->pred_func = pred_and;
638 our_pred->p_type = BI_OP;
639 our_pred->p_prec = AND_PREC;
640 our_pred->need_stat = our_pred->need_type = false;
641 return true;
644 static boolean
645 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
647 struct stat stat_newer;
649 set_stat_placeholders(&stat_newer);
650 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
652 struct predicate *our_pred = insert_primary (entry);
653 our_pred->args.reftime.xval = XVAL_ATIME;
654 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
655 our_pred->args.reftime.kind = COMP_GT;
656 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
657 return true;
659 return false;
662 boolean
663 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
665 struct predicate *our_pred;
667 (void) argv;
668 (void) arg_ptr;
670 our_pred = get_new_pred (entry);
671 our_pred->pred_func = pred_closeparen;
672 our_pred->p_type = CLOSE_PAREN;
673 our_pred->p_prec = NO_PREC;
674 our_pred->need_stat = our_pred->need_type = false;
675 return true;
678 static boolean
679 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
681 struct stat stat_newer;
683 set_stat_placeholders(&stat_newer);
684 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
686 struct predicate *our_pred = insert_primary (entry);
687 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
688 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
689 our_pred->args.reftime.kind = COMP_GT;
690 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
691 return true;
693 return false;
696 static boolean
697 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
699 struct predicate *our_pred;
701 (void) argv;
702 (void) arg_ptr;
704 our_pred = get_new_pred (entry);
705 our_pred->pred_func = pred_comma;
706 our_pred->p_type = BI_OP;
707 our_pred->p_prec = COMMA_PREC;
708 our_pred->need_stat = our_pred->need_type = false;
709 our_pred->est_success_rate = 1.0f;
710 return true;
713 static boolean
714 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
716 struct tm *local;
718 (void) entry;
719 (void) argv;
720 (void) arg_ptr;
722 if (options.full_days == false)
724 options.cur_day_start += DAYSECS;
725 local = localtime (&options.cur_day_start);
726 options.cur_day_start -= (local
727 ? (local->tm_sec + local->tm_min * 60
728 + local->tm_hour * 3600)
729 : options.cur_day_start % DAYSECS);
730 options.full_days = true;
732 return true;
735 static boolean
736 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
738 struct predicate *our_pred;
739 (void) argv;
740 (void) arg_ptr;
742 our_pred = insert_primary (entry);
743 our_pred->side_effects = our_pred->no_default_print = true;
744 /* -delete implies -depth */
745 options.do_dir_first = false;
747 /* We do not need stat information because we check for the case
748 * (errno==EISDIR) in pred_delete.
750 our_pred->need_stat = our_pred->need_type = false;
752 our_pred->est_success_rate = 1.0f;
753 return true;
756 static boolean
757 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
759 (void) entry;
760 (void) argv;
762 options.do_dir_first = false;
763 return parse_noop(entry, argv, arg_ptr);
766 static boolean
767 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
769 if (options.warnings)
771 error (0, 0,
772 _("warning: the -d option is deprecated; please use "
773 "-depth instead, because the latter is a "
774 "POSIX-compliant feature."));
776 return parse_depth(entry, argv, arg_ptr);
779 static boolean
780 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
782 struct predicate *our_pred;
783 (void) argv;
784 (void) arg_ptr;
786 our_pred = insert_primary (entry);
787 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
788 return true;
791 static boolean
792 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
794 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
797 static boolean
798 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
800 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
803 static boolean
804 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
806 struct predicate *our_pred;
808 (void) argv;
809 (void) arg_ptr;
811 our_pred = insert_primary (entry);
812 our_pred->need_stat = our_pred->need_type = false;
813 our_pred->side_effects = our_pred->no_default_print = false;
814 our_pred->est_success_rate = 0.0f;
815 return true;
818 static boolean
819 insert_fls (const struct parser_table* entry, const char *filename)
821 struct predicate *our_pred = insert_primary (entry);
822 if (filename)
823 open_output_file (filename, &our_pred->args.printf_vec);
824 else
825 open_stdout (&our_pred->args.printf_vec);
826 our_pred->side_effects = our_pred->no_default_print = true;
827 our_pred->est_success_rate = 1.0f;
828 return true;
832 static boolean
833 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
835 const char *filename;
836 return collect_arg(argv, arg_ptr, &filename)
837 && insert_fls(entry, filename);
840 static boolean
841 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
843 set_follow_state(SYMLINK_ALWAYS_DEREF);
844 return parse_noop(entry, argv, arg_ptr);
847 static boolean
848 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
850 struct predicate *our_pred;
851 const char *filename;
852 if (collect_arg(argv, arg_ptr, &filename))
854 our_pred = insert_primary (entry);
855 open_output_file (filename, &our_pred->args.printf_vec);
856 our_pred->side_effects = our_pred->no_default_print = true;
857 our_pred->need_stat = our_pred->need_type = false;
858 our_pred->est_success_rate = 1.0f;
859 return true;
861 else
863 return false;
867 static boolean
868 insert_fprint(const struct parser_table* entry, const char *filename)
870 struct predicate *our_pred = insert_primary (entry);
871 if (filename)
872 open_output_file (filename, &our_pred->args.printf_vec);
873 else
874 open_stdout (&our_pred->args.printf_vec);
875 our_pred->side_effects = our_pred->no_default_print = true;
876 our_pred->need_stat = our_pred->need_type = false;
877 our_pred->est_success_rate = 1.0f;
878 return true;
882 static boolean
883 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
885 const char *filename;
886 if (collect_arg(argv, arg_ptr, &filename))
887 return insert_fprint(entry, filename);
888 else
889 return false;
892 static float estimate_fstype_success_rate(const char *fsname)
894 struct stat dir_stat;
895 const char *dir = "/";
896 if (0 == stat(dir, &dir_stat))
898 const char *fstype = filesystem_type(&dir_stat, dir);
899 /* Assume most files are on the same file system type as the root fs. */
900 if (0 == strcmp(fsname, fstype))
901 return 0.7f;
902 else
903 return 0.3f;
905 return 1.0f;
909 static boolean
910 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
912 const char *typename;
913 if (collect_arg(argv, arg_ptr, &typename))
915 struct predicate *our_pred = insert_primary (entry);
916 our_pred->args.str = typename;
918 /* This is an expensive operation, so although there are
919 * circumstances where it is selective, we ignore this fact
920 * because we probably don't want to promote this test to the
921 * front anyway.
923 our_pred->est_success_rate = estimate_fstype_success_rate(typename);
924 return true;
926 else
928 return false;
932 static boolean
933 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
935 struct predicate *p = insert_num (argv, arg_ptr, entry);
936 if (p)
938 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
939 return true;
941 else
943 return false;
948 static int
949 safe_atoi (const char *s)
951 long lval;
952 char *end;
954 errno = 0;
955 lval = strtol(s, &end, 10);
956 if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
958 /* max/min possible value, or an error. */
959 if (errno == ERANGE)
961 /* too big, or too small. */
962 error(1, errno, "%s", s);
964 else
966 /* not a valid number */
967 error(1, errno, "%s", s);
969 /* Otherwise, we do a range chack against INT_MAX and INT_MIN
970 * below.
974 if (lval > INT_MAX || lval < INT_MIN)
976 /* The number was in range for long, but not int. */
977 errno = ERANGE;
978 error(1, errno, "%s", s);
980 else if (*end)
982 error(1, errno, "Unexpected suffix %s on %s",
983 quotearg_n_style(0, options.err_quoting_style, end),
984 quotearg_n_style(1, options.err_quoting_style, s));
986 else if (end == s)
988 error(1, errno, "Expected an integer: %s",
989 quotearg_n_style(0, options.err_quoting_style, s));
991 return (int)lval;
995 static boolean
996 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
998 const char *groupname;
1000 if (collect_arg(argv, arg_ptr, &groupname))
1002 gid_t gid;
1003 struct predicate *our_pred;
1004 struct group *cur_gr = getgrnam(groupname);
1005 endgrent();
1006 if (cur_gr)
1008 gid = cur_gr->gr_gid;
1010 else
1012 const int gid_len = strspn (groupname, "0123456789");
1013 if (gid_len)
1015 if (groupname[gid_len] == 0)
1017 gid = safe_atoi (groupname);
1019 else
1021 /* XXX: no test in test suite for this */
1022 error(1, 0, _("%s is not the name of an existing group and"
1023 " it does not look like a numeric group ID "
1024 "because it has the unexpected suffix %s"),
1025 quotearg_n_style(0, options.err_quoting_style, groupname),
1026 quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
1027 return false;
1030 else
1032 if (*groupname)
1034 /* XXX: no test in test suite for this */
1035 error(1, 0, _("%s is not the name of an existing group"),
1036 quotearg_n_style(0, options.err_quoting_style, groupname));
1038 else
1040 error(1, 0, _("argument to -group is empty, but should be a group name"));
1042 return false;
1045 our_pred = insert_primary (entry);
1046 our_pred->args.gid = gid;
1047 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1048 return true;
1050 return false;
1053 static boolean
1054 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
1056 (void) entry;
1057 (void) argv;
1058 (void) arg_ptr;
1060 usage(stdout, 0, NULL);
1061 puts (_("\n\
1062 default path is the current directory; default expression is -print\n\
1063 expression may consist of: operators, options, tests, and actions:\n"));
1064 puts (_("\
1065 operators (decreasing precedence; -and is implicit where no others are given):\n\
1066 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
1067 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1068 puts (_("\
1069 positional options (always true): -daystart -follow -regextype\n\n\
1070 normal options (always true, specified before other expressions):\n\
1071 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1072 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1073 puts (_("\
1074 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1075 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1076 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1077 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1078 puts (_("\
1079 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
1080 -readable -writable -executable\n\
1081 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1082 -used N -user NAME -xtype [bcdpfls]\n"));
1083 puts (_("\
1084 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1085 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1086 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1087 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1088 "));
1089 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1090 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1091 email to <bug-findutils@gnu.org>."));
1092 exit (0);
1095 static float
1096 estimate_pattern_match_rate(const char *pattern, int is_regex)
1098 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1100 /* A wildcard; assume the pattern matches most files. */
1101 return 0.8f;
1103 else
1105 return 0.1f;
1109 static boolean
1110 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1112 const char *name;
1113 if (collect_arg(argv, arg_ptr, &name))
1115 struct predicate *our_pred = insert_primary (entry);
1116 our_pred->args.str = name;
1117 /* Use the generic glob pattern estimator to figure out how many
1118 * links will match, but bear in mind that most files won't be links.
1120 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1121 return true;
1123 else
1125 return false;
1130 /* sanity check the fnmatch() function to make sure that case folding
1131 * is supported (as opposed to just having the flag ignored).
1133 static boolean
1134 fnmatch_sanitycheck(void)
1136 static boolean checked = false;
1137 if (!checked)
1139 if (0 != fnmatch("foo", "foo", 0)
1140 || 0 == fnmatch("Foo", "foo", 0)
1141 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1143 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1144 return false;
1146 checked = true;
1148 return checked;
1152 static boolean
1153 check_name_arg(const char *pred, const char *arg)
1155 if (options.warnings && strchr(arg, '/'))
1157 error(0, 0,_("warning: Unix filenames usually don't contain slashes "
1158 "(though pathnames do). That means that '%s %s' will "
1159 "probably evaluate to false all the time on this system. "
1160 "You might find the '-wholename' test more useful, or "
1161 "perhaps '-samefile'. Alternatively, if you are using "
1162 "GNU grep, you could "
1163 "use 'find ... -print0 | grep -FzZ %s'."),
1164 pred,
1165 safely_quote_err_filename(0, arg),
1166 safely_quote_err_filename(1, arg));
1168 return true; /* allow it anyway */
1173 static boolean
1174 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1176 const char *name;
1177 fnmatch_sanitycheck();
1178 if (collect_arg(argv, arg_ptr, &name))
1180 if (check_name_arg("-iname", name))
1182 struct predicate *our_pred = insert_primary (entry);
1183 our_pred->need_stat = our_pred->need_type = false;
1184 our_pred->args.str = name;
1185 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1186 return true;
1189 return false;
1192 static boolean
1193 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1195 struct predicate *p = insert_num (argv, arg_ptr, entry);
1196 if (p)
1198 /* inode number is exact match only, so very low proportions of
1199 * files match
1201 p->est_success_rate = 1e-6;
1202 return true;
1204 else
1206 return false;
1210 /* -ipath is deprecated (at RMS's request) in favour of
1211 * -iwholename. See the node "GNU Manuals" in standards.texi
1212 * for the rationale for this (basically, GNU prefers the use
1213 * of the phrase "file name" to "path name"
1215 static boolean
1216 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1218 const char *name;
1220 fnmatch_sanitycheck ();
1221 if (collect_arg (argv, arg_ptr, &name))
1223 struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
1224 our_pred->need_stat = our_pred->need_type = false;
1225 our_pred->args.str = name;
1226 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1227 return true;
1229 return false;
1232 static boolean
1233 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1235 return parse_ipath (entry, argv, arg_ptr);
1238 static boolean
1239 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1241 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1244 static boolean
1245 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1247 struct predicate *p = insert_num (argv, arg_ptr, entry);
1248 if (p)
1250 if (p->args.numinfo.l_val == 1)
1251 p->est_success_rate = 0.99;
1252 else if (p->args.numinfo.l_val == 2)
1253 p->est_success_rate = 0.01;
1254 else
1255 p->est_success_rate = 1e-3;
1256 return true;
1258 else
1260 return false;
1264 static boolean
1265 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1267 const char *name;
1268 fnmatch_sanitycheck();
1269 if (collect_arg(argv, arg_ptr, &name))
1271 struct predicate *our_pred = insert_primary (entry);
1272 our_pred->args.str = name;
1273 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1274 return true;
1276 return false;
1279 static boolean
1280 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1282 (void) &argv;
1283 (void) &arg_ptr;
1284 return insert_fls(entry, NULL);
1287 static boolean
1288 insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
1289 int *limitptr)
1291 const char *depthstr;
1292 int depth_len;
1293 const char *predicate = argv[(*arg_ptr)-1];
1294 if (collect_arg(argv, arg_ptr, &depthstr))
1296 depth_len = strspn (depthstr, "0123456789");
1297 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1299 (*limitptr) = safe_atoi (depthstr);
1300 if (*limitptr >= 0)
1302 return parse_noop(entry, argv, arg_ptr);
1305 error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
1306 predicate,
1307 quotearg_n_style(0, options.err_quoting_style, depthstr));
1308 return false;
1310 /* missing argument */
1311 return false;
1315 static boolean
1316 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1318 return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
1321 static boolean
1322 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1324 return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
1328 static boolean
1329 do_parse_xmin (const struct parser_table* entry,
1330 char **argv,
1331 int *arg_ptr,
1332 enum xval xv)
1334 const char *minutes;
1336 if (collect_arg(argv, arg_ptr, &minutes))
1338 struct time_val tval;
1339 tval.xval = xv;
1340 if (get_relative_timestamp(minutes, &tval,
1341 options.cur_day_start + DAYSECS, 60,
1342 "arithmetic overflow while converting %s "
1343 "minutes to a number of seconds"))
1345 struct predicate *our_pred = insert_primary (entry);
1346 our_pred->args.reftime = tval;
1347 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1348 return true;
1351 return false;
1353 static boolean
1354 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1356 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1359 static boolean
1360 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1362 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1366 static boolean
1367 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1369 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1372 static boolean
1373 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1375 const char *name;
1376 if (collect_arg(argv, arg_ptr, &name))
1378 fnmatch_sanitycheck();
1379 if (check_name_arg("-name", name))
1381 struct predicate *our_pred = insert_primary (entry);
1382 our_pred->need_stat = our_pred->need_type = false;
1383 our_pred->args.str = name;
1384 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1385 return true;
1388 return false;
1391 static boolean
1392 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1394 struct predicate *our_pred;
1396 (void) &argv;
1397 (void) &arg_ptr;
1399 our_pred = get_new_pred_chk_op (entry);
1400 our_pred->pred_func = pred_negate;
1401 our_pred->p_type = UNI_OP;
1402 our_pred->p_prec = NEGATE_PREC;
1403 our_pred->need_stat = our_pred->need_type = false;
1404 return true;
1407 static boolean
1408 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1410 struct predicate *our_pred;
1411 struct stat stat_newer;
1413 set_stat_placeholders(&stat_newer);
1414 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
1416 our_pred = insert_primary (entry);
1417 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1418 our_pred->args.reftime.xval = XVAL_MTIME;
1419 our_pred->args.reftime.kind = COMP_GT;
1420 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1421 return true;
1423 return false;
1427 static boolean
1428 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1430 (void) argv;
1431 (void) arg_ptr;
1433 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1435 return false;
1437 else if (8u != strlen(argv[*arg_ptr]))
1439 return false;
1441 else
1443 char x, y;
1444 const char validchars[] = "aBcmt";
1446 assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
1447 x = argv[*arg_ptr][6];
1448 y = argv[*arg_ptr][7];
1451 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1452 if ('B' == x || 'B' == y)
1454 error(0, 0,
1455 _("This system does not provide a way to find the birth time of a file."));
1456 return 0;
1458 #endif
1460 /* -newertY (for any Y) is invalid. */
1461 if (x == 't'
1462 || 0 == strchr(validchars, x)
1463 || 0 == strchr( validchars, y))
1465 return false;
1467 else
1469 struct predicate *our_pred;
1471 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1472 * past the test name (for most other tests, this is already done)
1474 (*arg_ptr)++;
1476 our_pred = insert_primary (entry);
1479 switch (x)
1481 case 'a':
1482 our_pred->args.reftime.xval = XVAL_ATIME;
1483 break;
1484 case 'B':
1485 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1486 break;
1487 case 'c':
1488 our_pred->args.reftime.xval = XVAL_CTIME;
1489 break;
1490 case 'm':
1491 our_pred->args.reftime.xval = XVAL_MTIME;
1492 break;
1493 default:
1494 assert (strchr(validchars, x));
1495 assert (0);
1498 if ('t' == y)
1500 if (!get_date(&our_pred->args.reftime.ts,
1501 argv[*arg_ptr],
1502 &options.start_time))
1504 error(1, 0,
1505 _("I cannot figure out how to interpret %s as a date or time"),
1506 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1509 else
1511 struct stat stat_newer;
1513 /* Stat the named file. */
1514 set_stat_placeholders(&stat_newer);
1515 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1516 fatal_file_error(argv[*arg_ptr]);
1518 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1520 /* We cannot extract a timestamp from the struct stat. */
1521 error(1, 0, _("Cannot obtain birth time of file %s"),
1522 safely_quote_err_filename(0, argv[*arg_ptr]));
1525 our_pred->args.reftime.kind = COMP_GT;
1526 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1527 (*arg_ptr)++;
1529 assert (our_pred->pred_func != NULL);
1530 assert (our_pred->pred_func == pred_newerXY);
1531 assert (our_pred->need_stat);
1532 return true;
1538 static boolean
1539 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1541 options.no_leaf_check = true;
1542 return parse_noop(entry, argv, arg_ptr);
1545 #ifdef CACHE_IDS
1546 /* Arbitrary amount by which to increase size
1547 of `uid_unused' and `gid_unused'. */
1548 #define ALLOC_STEP 2048
1550 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1551 char *uid_unused = NULL;
1553 /* Number of elements in `uid_unused'. */
1554 unsigned uid_allocated;
1556 /* Similar for GIDs and group entries. */
1557 char *gid_unused = NULL;
1558 unsigned gid_allocated;
1559 #endif
1561 static boolean
1562 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1564 struct predicate *our_pred;
1566 (void) &argv;
1567 (void) &arg_ptr;
1569 our_pred = insert_primary (entry);
1570 our_pred->est_success_rate = 1e-4;
1571 #ifdef CACHE_IDS
1572 if (gid_unused == NULL)
1574 struct group *gr;
1576 gid_allocated = ALLOC_STEP;
1577 gid_unused = xmalloc (gid_allocated);
1578 memset (gid_unused, 1, gid_allocated);
1579 setgrent ();
1580 while ((gr = getgrent ()) != NULL)
1582 if ((unsigned) gr->gr_gid >= gid_allocated)
1584 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1585 gid_unused = xrealloc (gid_unused, new_allocated);
1586 memset (gid_unused + gid_allocated, 1,
1587 new_allocated - gid_allocated);
1588 gid_allocated = new_allocated;
1590 gid_unused[(unsigned) gr->gr_gid] = 0;
1592 endgrent ();
1594 #endif
1595 return true;
1598 static boolean
1599 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1601 struct predicate *our_pred;
1602 (void) argv;
1603 (void) arg_ptr;
1606 our_pred = insert_primary (entry);
1607 our_pred->est_success_rate = 1e-3;
1608 #ifdef CACHE_IDS
1609 if (uid_unused == NULL)
1611 struct passwd *pw;
1613 uid_allocated = ALLOC_STEP;
1614 uid_unused = xmalloc (uid_allocated);
1615 memset (uid_unused, 1, uid_allocated);
1616 setpwent ();
1617 while ((pw = getpwent ()) != NULL)
1619 if ((unsigned) pw->pw_uid >= uid_allocated)
1621 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1622 uid_unused = xrealloc (uid_unused, new_allocated);
1623 memset (uid_unused + uid_allocated, 1,
1624 new_allocated - uid_allocated);
1625 uid_allocated = new_allocated;
1627 uid_unused[(unsigned) pw->pw_uid] = 0;
1629 endpwent ();
1631 #endif
1632 return true;
1635 static boolean
1636 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1638 options.warnings = false;
1639 return parse_noop(entry, argv, arg_ptr);
1642 static boolean
1643 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1645 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1648 static boolean
1649 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1651 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1654 boolean
1655 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1657 struct predicate *our_pred;
1659 (void) argv;
1660 (void) arg_ptr;
1662 our_pred = get_new_pred_chk_op (entry);
1663 our_pred->pred_func = pred_openparen;
1664 our_pred->p_type = OPEN_PAREN;
1665 our_pred->p_prec = NO_PREC;
1666 our_pred->need_stat = our_pred->need_type = false;
1667 return true;
1670 static boolean
1671 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1673 struct predicate *our_pred;
1675 (void) argv;
1676 (void) arg_ptr;
1678 our_pred = get_new_pred (entry);
1679 our_pred->pred_func = pred_or;
1680 our_pred->p_type = BI_OP;
1681 our_pred->p_prec = OR_PREC;
1682 our_pred->need_stat = our_pred->need_type = false;
1683 return true;
1686 /* For some time, -path was deprecated (at RMS's request) in favour of
1687 * -iwholename. See the node "GNU Manuals" in standards.texi for the
1688 * rationale for this (basically, GNU prefers the use of the phrase
1689 * "file name" to "path name".
1691 * We do not issue a warning that this usage is deprecated
1692 * since
1693 * (a) HPUX find supports this predicate also and
1694 * (b) it will soon be in POSIX anyway.
1696 static boolean
1697 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1699 const char *name;
1700 if (collect_arg(argv, arg_ptr, &name))
1702 struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
1703 our_pred->need_stat = our_pred->need_type = false;
1704 our_pred->args.str = name;
1705 our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
1706 return true;
1708 return false;
1711 static boolean
1712 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1714 return parse_path (entry, argv, arg_ptr);
1717 static void
1718 non_posix_mode(const char *mode)
1720 if (options.posixly_correct)
1722 error (1, 0, _("Mode %s is not valid when POSIXLY_CORRECT is on."),
1723 quotearg_n_style(0, options.err_quoting_style, mode));
1728 static boolean
1729 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1731 mode_t perm_val[2];
1732 float rate;
1733 int mode_start = 0;
1734 boolean havekind = false;
1735 enum permissions_type kind = PERM_EXACT;
1736 struct mode_change *change = NULL;
1737 struct predicate *our_pred;
1738 const char *perm_expr;
1740 if (!collect_arg(argv, arg_ptr, &perm_expr))
1741 return false;
1743 switch (perm_expr[0])
1745 case '-':
1746 mode_start = 1;
1747 kind = PERM_AT_LEAST;
1748 havekind = true;
1749 rate = 0.2;
1750 break;
1752 case '+':
1753 change = mode_compile (perm_expr);
1754 if (NULL == change)
1756 /* Most likely the caller is an old script that is still
1757 * using the obsolete GNU syntax '-perm +MODE'. This old
1758 * syntax was withdrawn in favor of '-perm /MODE' because
1759 * it is incompatible with POSIX in some cases, but we
1760 * still support uses of it that are not incompatible with
1761 * POSIX.
1763 * Example: POSIXLY_CORRECT=y find -perm +a+x
1765 non_posix_mode(perm_expr);
1767 /* support the previous behaviour. */
1768 mode_start = 1;
1769 kind = PERM_ANY;
1770 rate = 0.3;
1772 else
1774 /* This is a POSIX-compatible usage */
1775 mode_start = 0;
1776 kind = PERM_EXACT;
1777 rate = 0.1;
1779 havekind = true;
1780 break;
1782 case '/': /* GNU extension */
1783 non_posix_mode(perm_expr);
1784 mode_start = 1;
1785 kind = PERM_ANY;
1786 havekind = true;
1787 rate = 0.3;
1788 break;
1790 default:
1791 /* For example, '-perm 0644', which is valid and matches
1792 * only files whose mode is exactly 0644.
1794 mode_start = 0;
1795 kind = PERM_EXACT;
1796 havekind = true;
1797 rate = 0.01;
1798 break;
1801 if (NULL == change)
1803 change = mode_compile (perm_expr + mode_start);
1804 if (NULL == change)
1805 error (1, 0, _("invalid mode %s"),
1806 quotearg_n_style(0, options.err_quoting_style, perm_expr));
1808 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1809 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1810 free (change);
1812 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1814 /* The meaning of -perm /000 will change in the future. It
1815 * currently matches no files, but like -perm -000 it should
1816 * match all files.
1818 * Starting in 2005, we used to issue a warning message
1819 * informing the user that the behaviour would change in the
1820 * future. We have now changed the behaviour and issue a
1821 * warning message that the behaviour recently changed.
1823 error (0, 0,
1824 _("warning: you have specified a mode pattern %s (which is "
1825 "equivalent to /000). The meaning of -perm /000 has now been "
1826 "changed to be consistent with -perm -000; that is, while it "
1827 "used to match no files, it now matches all files."),
1828 perm_expr);
1830 kind = PERM_AT_LEAST;
1831 havekind = true;
1833 /* The "magic" number below is just the fraction of files on my
1834 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1835 * Actual totals are 1472 and 1073833.
1837 rate = 0.9986; /* probably matches anything but a broken symlink */
1840 our_pred = insert_primary (entry);
1841 our_pred->est_success_rate = rate;
1842 if (havekind)
1844 our_pred->args.perm.kind = kind;
1846 else
1849 switch (perm_expr[0])
1851 case '-':
1852 our_pred->args.perm.kind = PERM_AT_LEAST;
1853 break;
1854 case '+':
1855 our_pred->args.perm.kind = PERM_ANY;
1856 break;
1857 default:
1858 our_pred->args.perm.kind = PERM_EXACT;
1859 break;
1862 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1863 return true;
1866 boolean
1867 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1869 struct predicate *our_pred;
1871 (void) argv;
1872 (void) arg_ptr;
1874 our_pred = insert_primary (entry);
1875 /* -print has the side effect of printing. This prevents us
1876 from doing undesired multiple printing when the user has
1877 already specified -print. */
1878 our_pred->side_effects = our_pred->no_default_print = true;
1879 our_pred->need_stat = our_pred->need_type = false;
1880 open_stdout(&our_pred->args.printf_vec);
1881 return true;
1884 static boolean
1885 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1887 return insert_fprint(entry, NULL);
1890 static boolean
1891 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1893 const char *format;
1894 if (collect_arg(argv, arg_ptr, &format))
1896 struct format_val fmt;
1897 open_stdout(&fmt);
1898 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1900 return false;
1903 static boolean
1904 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1906 const char *format, *filename;
1907 if (collect_arg(argv, arg_ptr, &filename))
1909 if (collect_arg(argv, arg_ptr, &format))
1911 struct format_val fmt;
1912 open_output_file (filename, &fmt);
1913 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1916 return false;
1919 static boolean
1920 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1922 struct predicate *our_pred;
1924 (void) argv;
1925 (void) arg_ptr;
1927 our_pred = insert_primary (entry);
1928 our_pred->need_stat = our_pred->need_type = false;
1929 /* -prune has a side effect that it does not descend into
1930 the current directory. */
1931 our_pred->side_effects = true;
1932 our_pred->no_default_print = false;
1933 return true;
1936 static boolean
1937 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1939 struct predicate *our_pred = insert_primary (entry);
1940 (void) argv;
1941 (void) arg_ptr;
1942 our_pred->need_stat = our_pred->need_type = false;
1943 our_pred->side_effects = true; /* Exiting is a side effect... */
1944 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1945 our_pred->est_success_rate = 1.0f;
1946 return true;
1950 static boolean
1951 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1953 const char *type_name;
1954 if (collect_arg(argv, arg_ptr, &type_name))
1956 /* collect the regex type name */
1957 options.regex_options = get_regex_type(type_name);
1958 return parse_noop(entry, argv, arg_ptr);
1960 return false;
1964 static boolean
1965 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1967 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1970 static boolean
1971 insert_regex (char **argv,
1972 int *arg_ptr,
1973 const struct parser_table *entry,
1974 int regex_options)
1976 const char *rx;
1977 if (collect_arg(argv, arg_ptr, &rx))
1979 struct re_pattern_buffer *re;
1980 const char *error_message;
1981 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
1982 our_pred->need_stat = our_pred->need_type = false;
1983 re = xmalloc (sizeof (struct re_pattern_buffer));
1984 our_pred->args.regex = re;
1985 re->allocated = 100;
1986 re->buffer = xmalloc (re->allocated);
1987 re->fastmap = NULL;
1989 re_set_syntax(regex_options);
1990 re->syntax = regex_options;
1991 re->translate = NULL;
1993 error_message = re_compile_pattern (rx, strlen(rx), re);
1994 if (error_message)
1995 error (1, 0, "%s", error_message);
1996 our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
1997 return true;
1999 return false;
2002 static boolean
2003 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
2005 struct predicate *our_pred;
2006 uintmax_t num;
2007 char suffix;
2008 enum comparison_type c_type;
2010 int blksize = 512;
2011 int len;
2013 /* XXX: cannot (yet) convert to ue collect_arg() as this
2014 * function modifies the args in-place.
2016 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2017 return false;
2019 len = strlen (argv[*arg_ptr]);
2020 if (len == 0)
2021 error (1, 0, _("invalid null argument to -size"));
2023 suffix = argv[*arg_ptr][len - 1];
2024 switch (suffix)
2026 case 'b':
2027 blksize = 512;
2028 argv[*arg_ptr][len - 1] = '\0';
2029 break;
2031 case 'c':
2032 blksize = 1;
2033 argv[*arg_ptr][len - 1] = '\0';
2034 break;
2036 case 'k':
2037 blksize = 1024;
2038 argv[*arg_ptr][len - 1] = '\0';
2039 break;
2041 case 'M': /* Megabytes */
2042 blksize = 1024*1024;
2043 argv[*arg_ptr][len - 1] = '\0';
2044 break;
2046 case 'G': /* Gigabytes */
2047 blksize = 1024*1024*1024;
2048 argv[*arg_ptr][len - 1] = '\0';
2049 break;
2051 case 'w':
2052 blksize = 2;
2053 argv[*arg_ptr][len - 1] = '\0';
2054 break;
2056 case '0':
2057 case '1':
2058 case '2':
2059 case '3':
2060 case '4':
2061 case '5':
2062 case '6':
2063 case '7':
2064 case '8':
2065 case '9':
2066 break;
2068 default:
2069 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
2071 /* TODO: accept fractional megabytes etc. ? */
2072 if (!get_num (argv[*arg_ptr], &num, &c_type))
2074 error(1, 0,
2075 _("Invalid argument `%s%c' to -size"),
2076 argv[*arg_ptr], (int)suffix);
2077 return false;
2079 our_pred = insert_primary (entry);
2080 our_pred->args.size.kind = c_type;
2081 our_pred->args.size.blocksize = blksize;
2082 our_pred->args.size.size = num;
2083 our_pred->need_stat = true;
2084 our_pred->need_type = false;
2086 if (COMP_GT == c_type)
2087 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
2088 else if (COMP_LT == c_type)
2089 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
2090 else
2091 our_pred->est_success_rate = 0.01;
2093 (*arg_ptr)++;
2094 return true;
2098 static boolean
2099 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2101 /* General idea: stat the file, remember device and inode numbers.
2102 * If a candidate file matches those, it's the same file.
2104 struct predicate *our_pred;
2105 struct stat st, fst;
2106 int fd, openflags;
2108 set_stat_placeholders(&st);
2109 if (!collect_arg_stat_info(argv, arg_ptr, &st))
2110 return false;
2112 set_stat_placeholders(&fst);
2113 /* POSIX systems are free to re-use the inode number of a deleted
2114 * file. To ensure that we are not fooled by inode reuse, we hold
2115 * the file open if we can. This would prevent the system reusing
2116 * the file.
2118 fd = -3; /* means, uninitialised */
2119 openflags = O_RDONLY;
2121 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2123 if (options.open_nofollow_available)
2125 assert (O_NOFOLLOW != 0);
2126 openflags |= O_NOFOLLOW;
2127 fd = -1; /* safe to open it. */
2129 else
2131 if (S_ISLNK(st.st_mode))
2133 /* no way to ensure that a symlink will not be followed
2134 * by open(2), so fall back on using lstat(). Accept
2135 * the risk that the named file will be deleted and
2136 * replaced with another having the same inode.
2138 * Avoid opening the file.
2140 fd = -2; /* Do not open it */
2142 else
2144 fd = -1;
2145 /* Race condition here: the file might become a symlink here. */
2149 else
2151 /* We want to dereference the symlink anyway */
2152 fd = -1; /* safe to open it without O_NOFOLLOW */
2155 assert (fd != -3); /* check we made a decision */
2156 if (fd == -1)
2158 /* Race condition here. The file might become a
2159 * symbolic link in between out call to stat and
2160 * the call to open.
2162 fd = open(argv[*arg_ptr], openflags);
2164 if (fd >= 0)
2166 /* We stat the file again here to prevent a race condition
2167 * between the first stat and the call to open(2).
2169 if (0 != fstat(fd, &fst))
2171 fatal_file_error(argv[*arg_ptr]);
2173 else
2175 /* Worry about the race condition. If the file became a
2176 * symlink after our first stat and before our call to
2177 * open, fst may contain the stat information for the
2178 * destination of the link, not the link itself.
2180 if ((*options.xstat) (argv[*arg_ptr], &st))
2181 fatal_file_error(argv[*arg_ptr]);
2183 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2184 && (!options.open_nofollow_available))
2186 if (S_ISLNK(st.st_mode))
2188 /* We lost the race. Leave the data in st. The
2189 * file descriptor points to the wrong thing.
2191 close(fd);
2192 fd = -1;
2194 else
2196 /* Several possibilities here:
2197 * 1. There was no race
2198 * 2. The file changed into a symlink after the stat and
2199 * before the open, and then back into a non-symlink
2200 * before the second stat.
2202 * In case (1) there is no problem. In case (2),
2203 * the stat() and fstat() calls will have returned
2204 * different data. O_NOFOLLOW was not available,
2205 * so the open() call may have followed a symlink
2206 * even if the -P option is in effect.
2208 if ((st.st_dev == fst.st_dev)
2209 && (st.st_ino == fst.st_ino))
2211 /* No race. No need to copy fst to st,
2212 * since they should be identical (modulo
2213 * differences in padding bytes).
2216 else
2218 /* We lost the race. Leave the data in st. The
2219 * file descriptor points to the wrong thing.
2221 close(fd);
2222 fd = -1;
2226 else
2228 st = fst;
2234 our_pred = insert_primary (entry);
2235 our_pred->args.samefileid.ino = st.st_ino;
2236 our_pred->args.samefileid.dev = st.st_dev;
2237 our_pred->args.samefileid.fd = fd;
2238 our_pred->need_type = false;
2239 our_pred->need_stat = true;
2240 our_pred->est_success_rate = 0.01f;
2241 return true;
2244 #if 0
2245 /* This function is commented out partly because support for it is
2246 * uneven.
2248 static boolean
2249 parse_show_control_chars (const struct parser_table* entry,
2250 char **argv,
2251 int *arg_ptr)
2253 const char *arg;
2254 const char *errmsg = _("The -show-control-chars option takes "
2255 "a single argument which "
2256 "must be 'literal' or 'safe'");
2258 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2260 error (1, errno, "%s", errmsg);
2261 return false;
2263 else
2265 arg = argv[*arg_ptr];
2267 if (0 == strcmp("literal", arg))
2269 options.literal_control_chars = true;
2271 else if (0 == strcmp("safe", arg))
2273 options.literal_control_chars = false;
2275 else
2277 error (1, errno, "%s", errmsg);
2278 return false;
2280 (*arg_ptr)++; /* consume the argument. */
2281 return true;
2284 #endif
2287 static boolean
2288 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2290 struct predicate *our_pred;
2292 (void) argv;
2293 (void) arg_ptr;
2295 our_pred = insert_primary (entry);
2296 our_pred->need_stat = our_pred->need_type = false;
2297 our_pred->est_success_rate = 1.0f;
2298 return true;
2301 static boolean
2302 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2304 (void) entry;
2305 return parse_true(get_noop(), argv, arg_ptr);
2308 static boolean
2309 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2311 struct predicate *our_pred;
2312 (void) argv;
2313 (void) arg_ptr;
2314 our_pred = insert_primary (entry);
2315 our_pred->need_stat = our_pred->need_type = false;
2316 our_pred->side_effects = our_pred->no_default_print = false;
2317 if (pred_is(our_pred, pred_executable))
2318 our_pred->est_success_rate = 0.2;
2319 else
2320 our_pred->est_success_rate = 0.9;
2321 return true;
2324 static boolean
2325 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2327 return insert_type (argv, arg_ptr, entry, pred_type);
2330 static boolean
2331 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2333 struct predicate *p = insert_num (argv, arg_ptr, entry);
2334 if (p)
2336 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2337 return true;
2339 else
2341 return false;
2345 static boolean
2346 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2348 struct predicate *our_pred;
2349 struct time_val tval;
2350 const char *offset_str;
2351 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2353 if (collect_arg(argv, arg_ptr, &offset_str))
2355 /* The timespec is actually a delta value, so we use an origin of 0. */
2356 if (get_relative_timestamp(offset_str, &tval, 0, DAYSECS, errmsg))
2358 our_pred = insert_primary (entry);
2359 our_pred->args.reftime = tval;
2360 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2361 return true;
2363 else
2365 error(1, 0, _("Invalid argument %s to -used"), offset_str);
2366 return false;
2369 else
2371 return false; /* missing argument */
2375 static boolean
2376 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2378 const char *username;
2380 if (collect_arg(argv, arg_ptr, &username))
2382 struct predicate *our_pred;
2383 uid_t uid;
2384 struct passwd *cur_pwd = getpwnam(username);
2385 endpwent();
2386 if (cur_pwd != NULL)
2388 uid = cur_pwd->pw_uid;
2390 else
2392 int uid_len = strspn (username, "0123456789");
2393 if (uid_len && (username[uid_len]==0))
2394 uid = safe_atoi (username);
2395 else
2396 return false;
2398 our_pred = insert_primary (entry);
2399 our_pred->args.uid = uid;
2400 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2401 return true;
2403 return false;
2406 static boolean
2407 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2409 int features = 0;
2410 int flags;
2412 (void) argv;
2413 (void) arg_ptr;
2414 (void) entry;
2416 display_findutils_version("find");
2417 printf (_("Features enabled: "));
2419 #if CACHE_IDS
2420 printf("CACHE_IDS ");
2421 ++features;
2422 #endif
2423 #if DEBUG
2424 printf("DEBUG ");
2425 ++features;
2426 #endif
2427 #if DEBUG_STAT
2428 printf("DEBUG_STAT ");
2429 ++features;
2430 #endif
2431 #if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
2432 printf("D_TYPE ");
2433 ++features;
2434 #endif
2435 #if defined O_NOFOLLOW
2436 printf("O_NOFOLLOW(%s) ",
2437 (options.open_nofollow_available ? "enabled" : "disabled"));
2438 ++features;
2439 #endif
2440 #if defined LEAF_OPTIMISATION
2441 printf("LEAF_OPTIMISATION ");
2442 ++features;
2443 #endif
2445 flags = 0;
2446 if (is_fts_enabled(&flags))
2448 int nflags = 0;
2449 printf("FTS(");
2450 ++features;
2452 if (flags & FTS_CWDFD)
2454 if (nflags)
2456 printf(",");
2458 printf("FTS_CWDFD");
2459 ++nflags;
2461 printf(") ");
2464 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2465 ++features;
2467 if (0 == features)
2469 /* For the moment, leave this as English in case someone wants
2470 to parse these strings. */
2471 printf("none");
2473 printf("\n");
2475 exit (0);
2478 static boolean
2479 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2481 options.stay_on_filesystem = true;
2482 return parse_noop(entry, argv, arg_ptr);
2485 static boolean
2486 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2488 options.ignore_readdir_race = true;
2489 return parse_noop(entry, argv, arg_ptr);
2492 static boolean
2493 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2495 options.ignore_readdir_race = false;
2496 return parse_noop(entry, argv, arg_ptr);
2499 static boolean
2500 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2502 options.warnings = true;
2503 return parse_noop(entry, argv, arg_ptr);
2506 static boolean
2507 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2509 return insert_type (argv, arg_ptr, entry, pred_xtype);
2512 static boolean
2513 insert_type (char **argv, int *arg_ptr,
2514 const struct parser_table *entry,
2515 PRED_FUNC which_pred)
2517 mode_t type_cell;
2518 struct predicate *our_pred;
2519 float rate = 0.5;
2520 const char *typeletter;
2522 if (collect_arg(argv, arg_ptr, &typeletter))
2524 if (strlen(typeletter) != 1u)
2526 error(1, 0, _("Arguments to -type should contain only one letter"));
2527 return false;
2530 switch (typeletter[0])
2532 case 'b': /* block special */
2533 type_cell = S_IFBLK;
2534 rate = 0.01f;
2535 break;
2536 case 'c': /* character special */
2537 type_cell = S_IFCHR;
2538 rate = 0.01f;
2539 break;
2540 case 'd': /* directory */
2541 type_cell = S_IFDIR;
2542 rate = 0.4f;
2543 break;
2544 case 'f': /* regular file */
2545 type_cell = S_IFREG;
2546 rate = 0.95f;
2547 break;
2548 #ifdef S_IFLNK
2549 case 'l': /* symbolic link */
2550 type_cell = S_IFLNK;
2551 rate = 0.1f;
2552 break;
2553 #endif
2554 #ifdef S_IFIFO
2555 case 'p': /* pipe */
2556 type_cell = S_IFIFO;
2557 rate = 0.01f;
2558 break;
2559 #endif
2560 #ifdef S_IFSOCK
2561 case 's': /* socket */
2562 type_cell = S_IFSOCK;
2563 rate = 0.01f;
2564 break;
2565 #endif
2566 #ifdef S_IFDOOR
2567 case 'D': /* Solaris door */
2568 type_cell = S_IFDOOR;
2569 rate = 0.01f;
2570 break;
2571 #endif
2572 default: /* None of the above ... nuke 'em. */
2573 error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
2574 return false;
2576 our_pred = insert_primary_withpred (entry, which_pred);
2577 our_pred->est_success_rate = rate;
2579 /* Figure out if we will need to stat the file, because if we don't
2580 * need to follow symlinks, we can avoid a stat call by using
2581 * struct dirent.d_type.
2583 if (which_pred == pred_xtype)
2585 our_pred->need_stat = true;
2586 our_pred->need_type = false;
2588 else
2590 our_pred->need_stat = false; /* struct dirent is enough */
2591 our_pred->need_type = true;
2593 our_pred->args.type = type_cell;
2594 return true;
2596 return false;
2600 /* Return true if the file accessed via FP is a terminal.
2602 static boolean
2603 stream_is_tty(FILE *fp)
2605 int fd = fileno(fp);
2606 if (-1 == fd)
2608 return false; /* not a valid stream */
2610 else
2612 return isatty(fd) ? true : false;
2620 /* XXX: do we need to pass FUNC to this function? */
2621 static boolean
2622 insert_fprintf (struct format_val *vec,
2623 const struct parser_table *entry, PRED_FUNC func,
2624 const char *format_const)
2626 char *format = (char*)format_const; /* XXX: casting away constness */
2627 register char *scan; /* Current address in scanning `format'. */
2628 register char *scan2; /* Address inside of element being scanned. */
2629 struct segment **segmentp; /* Address of current segment. */
2630 struct predicate *our_pred;
2632 our_pred = insert_primary_withpred (entry, func);
2633 our_pred->side_effects = our_pred->no_default_print = true;
2634 our_pred->args.printf_vec = *vec;
2635 our_pred->need_type = false;
2636 our_pred->need_stat = false;
2637 our_pred->p_cost = NeedsNothing;
2639 segmentp = &our_pred->args.printf_vec.segment;
2640 *segmentp = NULL;
2642 for (scan = format; *scan; scan++)
2644 if (*scan == '\\')
2646 scan2 = scan + 1;
2647 if (*scan2 >= '0' && *scan2 <= '7')
2649 register int n, i;
2651 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2652 i++, scan2++)
2653 n = 8 * n + *scan2 - '0';
2654 scan2--;
2655 *scan = n;
2657 else
2659 switch (*scan2)
2661 case 'a':
2662 *scan = 7;
2663 break;
2664 case 'b':
2665 *scan = '\b';
2666 break;
2667 case 'c':
2668 make_segment (segmentp, format, scan - format,
2669 KIND_STOP, 0, 0,
2670 our_pred);
2671 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2672 our_pred->p_cost = NeedsStatInfo;
2673 return true;
2674 case 'f':
2675 *scan = '\f';
2676 break;
2677 case 'n':
2678 *scan = '\n';
2679 break;
2680 case 'r':
2681 *scan = '\r';
2682 break;
2683 case 't':
2684 *scan = '\t';
2685 break;
2686 case 'v':
2687 *scan = '\v';
2688 break;
2689 case '\\':
2690 /* *scan = '\\'; * it already is */
2691 break;
2692 default:
2693 error (0, 0,
2694 _("warning: unrecognized escape `\\%c'"), *scan2);
2695 scan++;
2696 continue;
2699 segmentp = make_segment (segmentp, format, scan - format + 1,
2700 KIND_PLAIN, 0, 0,
2701 our_pred);
2702 format = scan2 + 1; /* Move past the escape. */
2703 scan = scan2; /* Incremented immediately by `for'. */
2705 else if (*scan == '%')
2707 if (scan[1] == 0)
2709 /* Trailing %. We don't like those. */
2710 error (1, 0, _("error: %s at end of format string"), scan);
2712 else if (scan[1] == '%')
2714 segmentp = make_segment (segmentp, format, scan - format + 1,
2715 KIND_PLAIN, 0, 0,
2716 our_pred);
2717 scan++;
2718 format = scan + 1;
2719 continue;
2721 /* Scan past flags, width and precision, to verify kind. */
2722 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2723 /* Do nothing. */ ;
2724 while (ISDIGIT (*scan2))
2725 scan2++;
2726 if (*scan2 == '.')
2727 for (scan2++; ISDIGIT (*scan2); scan2++)
2728 /* Do nothing. */ ;
2729 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2731 segmentp = make_segment (segmentp, format, scan2 - format,
2732 KIND_FORMAT, *scan2, 0,
2733 our_pred);
2734 scan = scan2;
2735 format = scan + 1;
2737 else if (strchr ("ABCT", *scan2) && scan2[1])
2739 segmentp = make_segment (segmentp, format, scan2 - format,
2740 KIND_FORMAT, scan2[0], scan2[1],
2741 our_pred);
2742 scan = scan2 + 1;
2743 format = scan + 1;
2744 continue;
2746 else
2748 /* An unrecognized % escape. Print the char after the %. */
2749 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2750 *scan2);
2751 segmentp = make_segment (segmentp, format, scan - format,
2752 KIND_PLAIN, 0, 0,
2753 our_pred);
2754 format = scan + 1;
2755 continue;
2760 if (scan > format)
2761 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2762 our_pred);
2763 return true;
2766 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2767 from the text in FORMAT, which has length LEN.
2768 Return the address of the `next' pointer of the new segment. */
2770 static struct segment **
2771 make_segment (struct segment **segment,
2772 char *format,
2773 int len,
2774 int kind,
2775 char format_char,
2776 char aux_format_char,
2777 struct predicate *pred)
2779 enum EvaluationCost mycost = NeedsNothing;
2780 char *fmt;
2782 *segment = xmalloc (sizeof (struct segment));
2784 (*segment)->segkind = kind;
2785 (*segment)->format_char[0] = format_char;
2786 (*segment)->format_char[1] = aux_format_char;
2787 (*segment)->next = NULL;
2788 (*segment)->text_len = len;
2790 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2791 strncpy (fmt, format, len);
2792 fmt += len;
2794 switch (kind)
2796 case KIND_PLAIN: /* Plain text string, no % conversion. */
2797 case KIND_STOP: /* Terminate argument, no newline. */
2798 assert (0 == format_char);
2799 assert (0 == aux_format_char);
2800 *fmt = '\0';
2801 if (mycost > pred->p_cost)
2802 pred->p_cost = NeedsNothing;
2803 return &(*segment)->next;
2804 break;
2807 assert (kind == KIND_FORMAT);
2808 switch (format_char)
2810 case 'l': /* object of symlink */
2811 pred->need_stat = true;
2812 mycost = NeedsLinkName;
2813 *fmt++ = 's';
2814 break;
2816 case 'y': /* file type */
2817 pred->need_type = true;
2818 mycost = NeedsType;
2819 *fmt++ = 's';
2820 break;
2822 case 'a': /* atime in `ctime' format */
2823 case 'A': /* atime in user-specified strftime format */
2824 case 'B': /* birth time in user-specified strftime format */
2825 case 'c': /* ctime in `ctime' format */
2826 case 'C': /* ctime in user-specified strftime format */
2827 case 'F': /* file system type */
2828 case 'g': /* group name */
2829 case 'i': /* inode number */
2830 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2831 case 's': /* size in bytes */
2832 case 't': /* mtime in `ctime' format */
2833 case 'T': /* mtime in user-specified strftime format */
2834 case 'u': /* user name */
2835 pred->need_stat = true;
2836 mycost = NeedsStatInfo;
2837 *fmt++ = 's';
2838 break;
2840 case 'S': /* sparseness */
2841 pred->need_stat = true;
2842 mycost = NeedsStatInfo;
2843 *fmt++ = 'g';
2844 break;
2846 case 'Y': /* symlink pointed file type */
2847 pred->need_stat = true;
2848 mycost = NeedsType; /* true for amortised effect */
2849 *fmt++ = 's';
2850 break;
2852 case 'f': /* basename of path */
2853 case 'h': /* leading directories part of path */
2854 case 'p': /* pathname */
2855 case 'P': /* pathname with ARGV element stripped */
2856 *fmt++ = 's';
2857 break;
2859 case 'H': /* ARGV element file was found under */
2860 *fmt++ = 's';
2861 break;
2863 /* Numeric items that one might expect to honour
2864 * #, 0, + flags but which do not.
2866 case 'G': /* GID number */
2867 case 'U': /* UID number */
2868 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2869 case 'D': /* Filesystem device on which the file exits */
2870 case 'k': /* size in 1K blocks */
2871 case 'n': /* number of links */
2872 pred->need_stat = true;
2873 mycost = NeedsStatInfo;
2874 *fmt++ = 's';
2875 break;
2877 /* Numeric items that DO honour #, 0, + flags.
2879 case 'd': /* depth in search tree (0 = ARGV element) */
2880 *fmt++ = 'd';
2881 break;
2883 case 'm': /* mode as octal number (perms only) */
2884 *fmt++ = 'o';
2885 pred->need_stat = true;
2886 mycost = NeedsStatInfo;
2887 break;
2889 case '{':
2890 case '[':
2891 case '(':
2892 error (1, 0,
2893 _("error: the format directive `%%%c' is reserved for future use"),
2894 (int)kind);
2895 /*NOTREACHED*/
2896 break;
2898 *fmt = '\0';
2900 if (mycost > pred->p_cost)
2901 pred->p_cost = mycost;
2902 return &(*segment)->next;
2905 static void
2906 check_path_safety(const char *action, char **argv)
2908 char *s;
2909 const char *path = getenv("PATH");
2910 if (NULL == path)
2912 /* $PATH is not set. Assume the OS default is safe.
2913 * That may not be true on Windows, but I'm not aware
2914 * of a way to get Windows to avoid searching the
2915 * current directory anyway.
2917 return;
2920 (void)argv;
2922 s = next_element(path, 1);
2923 while ((s = next_element ((char *) NULL, 1)) != NULL)
2925 if (0 == strcmp(s, "."))
2927 error(1, 0, _("The current directory is included in the PATH "
2928 "environment variable, which is insecure in "
2929 "combination with the %s action of find. "
2930 "Please remove the current directory from your "
2931 "$PATH (that is, remove \".\" or leading or trailing "
2932 "colons)"),
2933 action);
2935 else if ('/' != s[0])
2937 /* Relative paths are also dangerous in $PATH. */
2938 error(1, 0, _("The relative path %s is included in the PATH "
2939 "environment variable, which is insecure in "
2940 "combination with the %s action of find. "
2941 "Please remove that entry from $PATH"),
2942 safely_quote_err_filename(0, s),
2943 action);
2949 /* handles both exec and ok predicate */
2950 static boolean
2951 new_insert_exec_ok (const char *action,
2952 const struct parser_table *entry,
2953 int dirfd,
2954 char **argv,
2955 int *arg_ptr)
2957 int start, end; /* Indexes in ARGV of start & end of cmd. */
2958 int i; /* Index into cmd args */
2959 int saw_braces; /* True if previous arg was '{}'. */
2960 boolean allow_plus; /* True if + is a valid terminator */
2961 int brace_count; /* Number of instances of {}. */
2962 PRED_FUNC func = entry->pred_func;
2963 enum BC_INIT_STATUS bcstatus;
2965 struct predicate *our_pred;
2966 struct exec_val *execp; /* Pointer for efficiency. */
2968 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2969 return false;
2971 our_pred = insert_primary_withpred (entry, func);
2972 our_pred->side_effects = our_pred->no_default_print = true;
2973 our_pred->need_type = our_pred->need_stat = false;
2975 execp = &our_pred->args.exec_vec;
2977 if ((func != pred_okdir) && (func != pred_ok))
2979 allow_plus = true;
2980 execp->close_stdin = false;
2982 else
2984 allow_plus = false;
2985 /* If find reads stdin (i.e. for -ok and similar), close stdin
2986 * in the child to prevent some script from consiming the output
2987 * intended for find.
2989 execp->close_stdin = true;
2993 if ((func == pred_execdir) || (func == pred_okdir))
2995 options.ignore_readdir_race = false;
2996 check_path_safety(action, argv);
2997 execp->use_current_dir = true;
2999 else
3001 execp->use_current_dir = false;
3004 our_pred->args.exec_vec.multiple = 0;
3006 /* Count the number of args with path replacements, up until the ';'.
3007 * Also figure out if the command is terminated by ";" or by "+".
3009 start = *arg_ptr;
3010 for (end = start, saw_braces=0, brace_count=0;
3011 (argv[end] != NULL)
3012 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
3013 end++)
3015 /* For -exec and -execdir, "{} +" can terminate the command. */
3016 if ( allow_plus
3017 && argv[end][0] == '+' && argv[end][1] == 0
3018 && saw_braces)
3020 our_pred->args.exec_vec.multiple = 1;
3021 break;
3024 saw_braces = 0;
3025 if (mbsstr (argv[end], "{}"))
3027 saw_braces = 1;
3028 ++brace_count;
3030 if (0 == end && (func == pred_execdir || func == pred_okdir))
3032 /* The POSIX standard says that {} replacement should
3033 * occur even in the utility name. This is insecure
3034 * since it means we will be executing a command whose
3035 * name is chosen according to whatever find finds in
3036 * the file system. That can be influenced by an
3037 * attacker. Hence for -execdir and -okdir this is not
3038 * allowed. We can specify this as those options are
3039 * not defined by POSIX.
3041 error(1, 0, _("You may not use {} within the utility name for "
3042 "-execdir and -okdir, because this is a potential "
3043 "security problem."));
3048 /* Fail if no command given or no semicolon found. */
3049 if ((end == start) || (argv[end] == NULL))
3051 *arg_ptr = end;
3052 free(our_pred);
3053 return false;
3056 if (our_pred->args.exec_vec.multiple && brace_count > 1)
3059 const char *suffix;
3060 if (func == pred_execdir)
3061 suffix = "dir";
3062 else
3063 suffix = "";
3065 error(1, 0,
3066 _("Only one instance of {} is supported with -exec%s ... +"),
3067 suffix);
3070 /* We use a switch statement here so that the compiler warns us when
3071 * we forget to handle a newly invented enum value.
3073 * Like xargs, we allow 2KiB of headroom for the launched utility to
3074 * export its own environment variables before calling something
3075 * else.
3077 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
3078 switch (bcstatus)
3080 case BC_INIT_ENV_TOO_BIG:
3081 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
3082 error(1, 0,
3083 _("The environment is too large for exec()."));
3084 break;
3085 case BC_INIT_OK:
3086 /* Good news. Carry on. */
3087 break;
3089 bc_use_sensible_arg_max(&execp->ctl);
3092 execp->ctl.exec_callback = launch;
3094 if (our_pred->args.exec_vec.multiple)
3096 /* "+" terminator, so we can just append our arguments after the
3097 * command and initial arguments.
3099 execp->replace_vec = NULL;
3100 execp->ctl.replace_pat = NULL;
3101 execp->ctl.rplen = 0;
3102 execp->ctl.lines_per_exec = 0; /* no limit */
3103 execp->ctl.args_per_exec = 0; /* no limit */
3105 /* remember how many arguments there are */
3106 execp->ctl.initial_argc = (end-start) - 1;
3108 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
3109 bc_init_state(&execp->ctl, &execp->state, execp);
3111 /* Gather the initial arguments. Skip the {}. */
3112 for (i=start; i<end-1; ++i)
3114 bc_push_arg(&execp->ctl, &execp->state,
3115 argv[i], strlen(argv[i])+1,
3116 NULL, 0,
3120 else
3122 /* Semicolon terminator - more than one {} is supported, so we
3123 * have to do brace-replacement.
3125 execp->num_args = end - start;
3127 execp->ctl.replace_pat = "{}";
3128 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
3129 execp->ctl.lines_per_exec = 0; /* no limit */
3130 execp->ctl.args_per_exec = 0; /* no limit */
3131 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
3134 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3135 bc_init_state(&execp->ctl, &execp->state, execp);
3137 /* Remember the (pre-replacement) arguments for later. */
3138 for (i=0; i<execp->num_args; ++i)
3140 execp->replace_vec[i] = argv[i+start];
3144 if (argv[end] == NULL)
3145 *arg_ptr = end;
3146 else
3147 *arg_ptr = end + 1;
3149 return true;
3154 static boolean
3155 insert_exec_ok (const char *action,
3156 const struct parser_table *entry,
3157 int dirfd,
3158 char **argv,
3159 int *arg_ptr)
3161 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
3166 /* Get a timestamp and comparison type.
3168 STR is the ASCII representation.
3169 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3170 relative to ORIGIN (usually the current moment or midnight).
3171 Thus the sense of the comparison type appears to be reversed.
3172 Set *COMP_TYPE to the kind of comparison that is requested.
3173 Issue OVERFLOWMESSAGE if overflow occurs.
3174 Return true if all okay, false if input error.
3176 Used by -atime, -ctime and -mtime (parsers) to
3177 get the appropriate information for a time predicate processor. */
3179 static boolean
3180 get_relative_timestamp (const char *str,
3181 struct time_val *result,
3182 time_t origin,
3183 double sec_per_unit,
3184 const char *overflowmessage)
3186 uintmax_t checkval;
3187 double offset, seconds, f;
3189 if (get_comp_type(&str, &result->kind))
3191 /* Invert the sense of the comparison */
3192 switch (result->kind)
3194 case COMP_LT: result->kind = COMP_GT; break;
3195 case COMP_GT: result->kind = COMP_LT; break;
3196 default: break;
3199 /* Convert the ASCII number into floating-point. */
3200 if (xstrtod(str, NULL, &offset, strtod))
3202 /* Separate the floating point number the user specified
3203 * (which is a number of days, or minutes, etc) into an
3204 * integral number of seconds (SECONDS) and a fraction (F).
3206 f = modf(offset * sec_per_unit, &seconds);
3208 result->ts.tv_sec = origin - seconds;
3209 result->ts.tv_nsec = fabs(f * 1e9);
3211 /* Check for overflow. */
3212 checkval = (uintmax_t)origin - seconds;
3213 if (checkval != result->ts.tv_sec)
3215 /* an overflow has occurred. */
3216 error (1, 0, overflowmessage, str);
3218 return true;
3220 else
3222 /* Conversion from ASCII to double failed. */
3223 return false;
3226 else
3228 return false;
3232 /* Insert a time predicate based on the information in ENTRY.
3233 ARGV is a pointer to the argument array.
3234 ARG_PTR is a pointer to an index into the array, incremented if
3235 all went well.
3237 Return true if input is valid, false if not.
3239 A new predicate node is assigned, along with an argument node
3240 obtained with malloc.
3242 Used by -atime, -ctime, and -mtime parsers. */
3244 static boolean
3245 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3247 struct predicate *our_pred;
3248 struct time_val tval;
3249 enum comparison_type comp;
3250 const char *timearg, *orig_timearg;
3251 const char *errmsg = "arithmetic overflow while converting %s "
3252 "days to a number of seconds";
3253 time_t origin;
3255 if (!collect_arg(argv, arg_ptr, &timearg))
3256 return false;
3257 orig_timearg = timearg;
3259 /* Decide the origin by previewing the comparison type. */
3260 origin = options.cur_day_start;
3262 if (get_comp_type(&timearg, &comp))
3264 /* Remember, we invert the sense of the comparison, so this tests
3265 * against COMP_LT instead of COMP_GT...
3267 if (COMP_LT == comp)
3269 uintmax_t expected = origin + (DAYSECS-1);
3270 origin += (DAYSECS-1);
3271 if (origin != expected)
3273 error(1, 0,
3274 _("arithmetic overflow when trying to calculate the end of today"));
3278 /* We discard the value of comp here, as get_relative_timestamp
3279 * will set tval.kind. For that to work, we have to restore
3280 * timearg so that it points to the +/- prefix, if any. get_comp_type()
3281 * will have advanced timearg, so we restore it.
3283 timearg = orig_timearg;
3285 if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
3286 return false;
3288 our_pred = insert_primary (entry);
3289 our_pred->args.reftime = tval;
3290 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3292 if (options.debug_options & DebugExpressionTree)
3294 time_t t;
3296 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3297 fprintf (stderr, " type: %s %s ",
3298 (tval.kind == COMP_GT) ? "gt" :
3299 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3300 (tval.kind == COMP_GT) ? " >" :
3301 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3302 t = our_pred->args.reftime.ts.tv_sec;
3303 fprintf (stderr, "%ju %s",
3304 (uintmax_t) our_pred->args.reftime.ts.tv_sec,
3305 ctime (&t));
3306 if (tval.kind == COMP_EQ)
3308 t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
3309 fprintf (stderr, " < %ju %s",
3310 (uintmax_t) t, ctime (&t));
3314 return true;
3317 /* Get the comparison type prefix (if any) from a number argument.
3318 The prefix is at *STR.
3319 Set *COMP_TYPE to the kind of comparison that is requested.
3320 Advance *STR beyond any initial comparison prefix.
3322 Return true if all okay, false if input error. */
3323 static boolean
3324 get_comp_type(const char **str, enum comparison_type *comp_type)
3326 switch (**str)
3328 case '+':
3329 *comp_type = COMP_GT;
3330 (*str)++;
3331 break;
3332 case '-':
3333 *comp_type = COMP_LT;
3334 (*str)++;
3335 break;
3336 default:
3337 *comp_type = COMP_EQ;
3338 break;
3340 return true;
3347 /* Get a number with comparison information.
3348 The sense of the comparison information is 'normal'; that is,
3349 '+' looks for a count > than the number and '-' less than.
3351 STR is the ASCII representation of the number.
3352 Set *NUM to the number.
3353 Set *COMP_TYPE to the kind of comparison that is requested.
3355 Return true if all okay, false if input error. */
3357 static boolean
3358 get_num (const char *str,
3359 uintmax_t *num,
3360 enum comparison_type *comp_type)
3362 char *pend;
3364 if (str == NULL)
3365 return false;
3367 /* Figure out the comparison type if the caller accepts one. */
3368 if (comp_type)
3370 if (!get_comp_type(&str, comp_type))
3371 return false;
3374 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3377 /* Insert a number predicate.
3378 ARGV is a pointer to the argument array.
3379 *ARG_PTR is an index into ARGV, incremented if all went well.
3380 *PRED is the predicate processor to insert.
3382 Return true if input is valid, false if error.
3384 A new predicate node is assigned, along with an argument node
3385 obtained with malloc.
3387 Used by -inum and -links parsers. */
3389 static struct predicate *
3390 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3392 const char *numstr;
3394 if (collect_arg(argv, arg_ptr, &numstr))
3396 uintmax_t num;
3397 enum comparison_type c_type;
3399 if (get_num (numstr, &num, &c_type))
3401 struct predicate *our_pred = insert_primary (entry);
3402 our_pred->args.numinfo.kind = c_type;
3403 our_pred->args.numinfo.l_val = num;
3405 if (options.debug_options & DebugExpressionTree)
3407 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3408 fprintf (stderr, " type: %s %s ",
3409 (c_type == COMP_GT) ? "gt" :
3410 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3411 (c_type == COMP_GT) ? " >" :
3412 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3413 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3415 return our_pred;
3418 return NULL;
3421 static void
3422 open_output_file (const char *path, struct format_val *p)
3424 p->segment = NULL;
3425 p->quote_opts = clone_quoting_options (NULL);
3427 if (!strcmp (path, "/dev/stderr"))
3429 p->stream = stderr;
3430 p->filename = _("standard error");
3432 else if (!strcmp (path, "/dev/stdout"))
3434 p->stream = stdout;
3435 p->filename = _("standard output");
3437 else
3439 p->stream = fopen_safer (path, "w");
3440 p->filename = path;
3442 if (p->stream == NULL)
3444 fatal_file_error(path);
3448 p->dest_is_tty = stream_is_tty(p->stream);
3451 static void
3452 open_stdout (struct format_val *p)
3454 open_output_file("/dev/stdout", p);