Document the %S printf format.
[findutils.git] / find / parser.c
blob59af41c0078931a030279362049872c4955598af
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA.
22 #include "defs.h"
23 #include <ctype.h>
24 #include <math.h>
25 #include <assert.h>
26 #include <pwd.h>
27 #include <errno.h>
28 #include <grp.h>
29 #include <fnmatch.h>
30 #include "modechange.h"
31 #include "modetype.h"
32 #include "xstrtol.h"
33 #include "xalloc.h"
34 #include "quote.h"
35 #include "quotearg.h"
36 #include "buildcmd.h"
37 #include "nextelem.h"
38 #include "stdio-safer.h"
39 #include "regextype.h"
40 #include "stat-time.h"
41 #include "xstrtod.h"
42 #include "fts_.h"
43 #include "getdate.h"
44 #include "error.h"
45 #include "gnulib-version.h"
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #else
50 #include <sys/file.h>
51 #endif
53 /* The presence of unistd.h is assumed by gnulib these days, so we
54 * might as well assume it too.
56 /* We need <unistd.h> for isatty(). */
57 #include <unistd.h>
59 #if ENABLE_NLS
60 # include <libintl.h>
61 # define _(Text) gettext (Text)
62 #else
63 # define _(Text) Text
64 #endif
65 #ifdef gettext_noop
66 # define N_(String) gettext_noop (String)
67 #else
68 /* See locate.c for explanation as to why not use (String) */
69 # define N_(String) String
70 #endif
72 #if !defined (isascii) || defined (STDC_HEADERS)
73 #ifdef isascii
74 #undef isascii
75 #endif
76 #define isascii(c) 1
77 #endif
79 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
80 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
82 #ifndef HAVE_ENDGRENT
83 #define endgrent()
84 #endif
85 #ifndef HAVE_ENDPWENT
86 #define endpwent()
87 #endif
89 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
90 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 #if 0
145 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 #endif
147 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
159 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
160 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
161 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
163 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
166 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
167 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
168 static boolean insert_fprintf (struct format_val *vec,
169 const struct parser_table *entry,
170 PRED_FUNC func,
171 const char *format);
173 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
174 int kind, char format_char, char aux_format_char,
175 struct predicate *pred));
176 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, int dirfd, char *argv[], int *arg_ptr));
177 static boolean get_comp_type PARAMS((const char **str, enum comparison_type *comp_type));
178 static boolean get_relative_timestamp PARAMS((const char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
179 static boolean get_num PARAMS((const char *str, uintmax_t *num, enum comparison_type *comp_type));
180 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
181 static void open_output_file (const char *path, struct format_val *p);
182 static void open_stdout (struct format_val *p);
183 static boolean stream_is_tty(FILE *fp);
184 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
186 #define PASTE(x,y) x##y
187 #define STRINGIFY(s) #s
189 #define PARSE_OPTION(what,suffix) \
190 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
192 #define PARSE_POSOPT(what,suffix) \
193 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
195 #define PARSE_TEST(what,suffix) \
196 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
198 #define PARSE_TEST_NP(what,suffix) \
199 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
201 #define PARSE_ACTION(what,suffix) \
202 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
204 #define PARSE_ACTION_NP(what,suffix) \
205 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
207 #define PARSE_PUNCTUATION(what,suffix) \
208 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
211 /* Predicates we cannot handle in the usual way. If you add an entry
212 * to this table, double-check the switch statement in
213 * pred_sanity_check() to make sure that the new case is being
214 * correctly handled.
216 static struct parser_table const parse_entry_newerXY =
218 ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
221 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
222 If they are in some Unix versions of find, they are marked `Unix'. */
224 static struct parser_table const parse_table[] =
226 PARSE_PUNCTUATION("!", negate),
227 PARSE_PUNCTUATION("not", negate), /* GNU */
228 PARSE_PUNCTUATION("(", openparen),
229 PARSE_PUNCTUATION(")", closeparen),
230 PARSE_PUNCTUATION(",", comma), /* GNU */
231 PARSE_PUNCTUATION("a", and),
232 PARSE_TEST ("amin", amin), /* GNU */
233 PARSE_PUNCTUATION("and", and), /* GNU */
234 PARSE_TEST ("anewer", anewer), /* GNU */
235 {ARG_TEST, "atime", parse_time, pred_atime},
236 PARSE_TEST ("cmin", cmin), /* GNU */
237 PARSE_TEST ("cnewer", cnewer), /* GNU */
238 {ARG_TEST, "ctime", parse_time, pred_ctime},
239 PARSE_POSOPT ("daystart", daystart), /* GNU */
240 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
241 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
242 PARSE_OPTION ("depth", depth),
243 PARSE_TEST ("empty", empty), /* GNU */
244 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
245 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
246 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
247 PARSE_ACTION ("fls", fls), /* GNU */
248 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
249 PARSE_ACTION ("fprint", fprint), /* GNU */
250 PARSE_ACTION ("fprint0", fprint0), /* GNU */
251 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
252 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
253 PARSE_TEST ("gid", gid), /* GNU */
254 PARSE_TEST ("group", group),
255 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
256 PARSE_TEST ("ilname", ilname), /* GNU */
257 PARSE_TEST ("iname", iname), /* GNU */
258 PARSE_TEST ("inum", inum), /* GNU, Unix */
259 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
260 PARSE_TEST_NP ("iregex", iregex), /* GNU */
261 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
262 PARSE_TEST ("links", links),
263 PARSE_TEST ("lname", lname), /* GNU */
264 PARSE_ACTION ("ls", ls), /* GNU, Unix */
265 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
266 PARSE_OPTION ("mindepth", mindepth), /* GNU */
267 PARSE_TEST ("mmin", mmin), /* GNU */
268 PARSE_OPTION ("mount", xdev), /* Unix */
269 {ARG_TEST, "mtime", parse_time, pred_mtime},
270 PARSE_TEST ("name", name),
271 #ifdef UNIMPLEMENTED_UNIX
272 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
273 #endif
274 PARSE_TEST ("newer", newer),
275 {ARG_TEST, "atime", parse_time, pred_atime},
276 PARSE_OPTION ("noleaf", noleaf), /* GNU */
277 PARSE_TEST ("nogroup", nogroup),
278 PARSE_TEST ("nouser", nouser),
279 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
280 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
281 PARSE_PUNCTUATION("o", or),
282 PARSE_PUNCTUATION("or", or), /* GNU */
283 PARSE_ACTION ("ok", ok),
284 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
285 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
286 PARSE_TEST ("perm", perm),
287 PARSE_ACTION ("print", print),
288 PARSE_ACTION ("print0", print0), /* GNU */
289 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
290 PARSE_ACTION ("prune", prune),
291 PARSE_ACTION ("quit", quit), /* GNU */
292 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
293 PARSE_TEST ("regex", regex), /* GNU */
294 PARSE_OPTION ("regextype", regextype), /* GNU */
295 PARSE_TEST ("samefile", samefile), /* GNU */
296 #if 0
297 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
298 #endif
299 PARSE_TEST ("size", size),
300 PARSE_TEST ("type", type),
301 PARSE_TEST ("uid", uid), /* GNU */
302 PARSE_TEST ("used", used), /* GNU */
303 PARSE_TEST ("user", user),
304 PARSE_OPTION ("warn", warn), /* GNU */
305 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
306 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
307 PARSE_OPTION ("xdev", xdev),
308 PARSE_TEST ("xtype", xtype), /* GNU */
309 #ifdef UNIMPLEMENTED_UNIX
310 /* It's pretty ugly for find to know about archive formats.
311 Plus what it could do with cpio archives is very limited.
312 Better to leave it out. */
313 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
314 #endif
315 /* gnulib's stdbool.h might have made true and false into macros,
316 * so we can't leave named 'true' and 'false' tokens, so we have
317 * to expeant the relevant entries longhand.
319 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
320 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
321 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
323 /* Various other cases that don't fit neatly into our macro scheme. */
324 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
325 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
326 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
327 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
328 {0, 0, 0, 0}
332 static const char *first_nonoption_arg = NULL;
333 static const struct parser_table *noop = NULL;
336 static const struct parser_table*
337 get_noop(void)
339 int i;
340 if (NULL == noop)
342 for (i = 0; parse_table[i].parser_name != 0; i++)
344 if (ARG_NOOP ==parse_table[i].type)
346 noop = &(parse_table[i]);
347 break;
351 return noop;
354 static int
355 get_stat_Ytime(const struct stat *p,
356 char what,
357 struct timespec *ret)
359 switch (what)
361 case 'a':
362 *ret = get_stat_atime(p);
363 return 1;
364 case 'B':
365 *ret = get_stat_birthtime(p);
366 return (ret->tv_nsec >= 0);
367 case 'c':
368 *ret = get_stat_ctime(p);
369 return 1;
370 case 'm':
371 *ret = get_stat_mtime(p);
372 return 1;
373 default:
374 assert(0);
375 abort();
376 abort();
380 void
381 set_follow_state(enum SymlinkOption opt)
383 if (options.debug_options & DebugStat)
385 /* For DebugStat, the choice is made at runtime within debug_stat()
386 * by checking the contents of the symlink_handling variable.
388 options.xstat = debug_stat;
390 else
392 switch (opt)
394 case SYMLINK_ALWAYS_DEREF: /* -L */
395 options.xstat = optionl_stat;
396 options.no_leaf_check = true;
397 break;
399 case SYMLINK_NEVER_DEREF: /* -P (default) */
400 options.xstat = optionp_stat;
401 /* Can't turn no_leaf_check off because the user might have specified
402 * -noleaf anyway
404 break;
406 case SYMLINK_DEREF_ARGSONLY: /* -H */
407 options.xstat = optionh_stat;
408 options.no_leaf_check = true;
411 options.symlink_handling = opt;
415 void
416 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
418 (void) args;
419 (void) argno;
420 (void) last;
421 (void) predicates;
422 first_nonoption_arg = NULL;
425 void
426 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
428 /* does nothing */
429 (void) args;
430 (void) argno;
431 (void) last;
432 (void) predicates;
436 /* Check that it is legal to fid the given primary in its
437 * position and return it.
439 const struct parser_table*
440 found_parser(const char *original_arg, const struct parser_table *entry)
442 /* If this is an option, but we have already had a
443 * non-option argument, the user may be under the
444 * impression that the behaviour of the option
445 * argument is conditional on some preceding
446 * tests. This might typically be the case with,
447 * for example, -maxdepth.
449 * The options -daystart and -follow are exempt
450 * from this treatment, since their positioning
451 * in the command line does have an effect on
452 * subsequent tests but not previous ones. That
453 * might be intentional on the part of the user.
455 if (entry->type != ARG_POSITIONAL_OPTION)
457 /* Something other than -follow/-daystart.
458 * If this is an option, check if it followed
459 * a non-option and if so, issue a warning.
461 if (entry->type == ARG_OPTION)
463 if ((first_nonoption_arg != NULL)
464 && options.warnings )
466 /* option which follows a non-option */
467 error (0, 0,
468 _("warning: you have specified the %s "
469 "option after a non-option argument %s, "
470 "but options are not positional (%s affects "
471 "tests specified before it as well as those "
472 "specified after it). Please specify options "
473 "before other arguments.\n"),
474 original_arg,
475 first_nonoption_arg,
476 original_arg);
479 else
481 /* Not an option or a positional option,
482 * so remember we've seen it in order to
483 * use it in a possible future warning message.
485 if (first_nonoption_arg == NULL)
487 first_nonoption_arg = original_arg;
492 return entry;
496 /* Return a pointer to the parser function to invoke for predicate
497 SEARCH_NAME.
498 Return NULL if SEARCH_NAME is not a valid predicate name. */
500 const struct parser_table*
501 find_parser (char *search_name)
503 int i;
504 const char *original_arg = search_name;
506 /* Ugh. Special case -newerXY. */
507 if (0 == strncmp("-newer", search_name, 6)
508 && (8 == strlen(search_name)))
510 return found_parser(original_arg, &parse_entry_newerXY);
513 if (*search_name == '-')
514 search_name++;
516 for (i = 0; parse_table[i].parser_name != 0; i++)
518 if (strcmp (parse_table[i].parser_name, search_name) == 0)
520 return found_parser(original_arg, &parse_table[i]);
523 return NULL;
526 static float
527 estimate_file_age_success_rate(float num_days)
529 if (num_days < 0.1)
531 /* Assume 1% of files have timestamps in the future */
532 return 0.01f;
534 else if (num_days < 1)
536 /* Assume 30% of files have timestamps today */
537 return 0.3f;
539 else if (num_days > 100)
541 /* Assume 30% of files are very old */
542 return 0.3f;
544 else
546 /* Assume 39% of files are between 1 and 100 days old. */
547 return 0.39f;
551 static float
552 estimate_timestamp_success_rate(time_t when)
554 int num_days = (options.cur_day_start - when) / 86400;
555 return estimate_file_age_success_rate(num_days);
558 /* Collect an argument from the argument list, or
559 * return false.
561 static boolean
562 collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
564 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
566 *collected_arg = NULL;
567 return false;
569 else
571 *collected_arg = argv[*arg_ptr];
572 (*arg_ptr)++;
573 return true;
577 static boolean
578 collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
580 const char *filename;
581 if (collect_arg(argv, arg_ptr, &filename))
583 if (0 == (options.xstat)(filename, p))
585 return true;
587 else
589 fatal_file_error(filename);
592 else
594 return false;
598 /* The parsers are responsible to continue scanning ARGV for
599 their arguments. Each parser knows what is and isn't
600 allowed for itself.
602 ARGV is the argument array.
603 *ARG_PTR is the index to start at in ARGV,
604 updated to point beyond the last element consumed.
606 The predicate structure is updated with the new information. */
609 static boolean
610 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
612 struct predicate *our_pred;
614 (void) argv;
615 (void) arg_ptr;
617 our_pred = get_new_pred (entry);
618 our_pred->pred_func = pred_and;
619 our_pred->p_type = BI_OP;
620 our_pred->p_prec = AND_PREC;
621 our_pred->need_stat = our_pred->need_type = false;
622 return true;
625 static boolean
626 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
628 struct stat stat_newer;
630 set_stat_placeholders(&stat_newer);
631 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
633 struct predicate *our_pred = insert_primary (entry);
634 our_pred->args.reftime.xval = XVAL_ATIME;
635 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
636 our_pred->args.reftime.kind = COMP_GT;
637 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
638 return true;
640 return false;
643 boolean
644 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
646 struct predicate *our_pred;
648 (void) argv;
649 (void) arg_ptr;
651 our_pred = get_new_pred (entry);
652 our_pred->pred_func = pred_closeparen;
653 our_pred->p_type = CLOSE_PAREN;
654 our_pred->p_prec = NO_PREC;
655 our_pred->need_stat = our_pred->need_type = false;
656 return true;
659 static boolean
660 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
662 struct stat stat_newer;
664 set_stat_placeholders(&stat_newer);
665 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
667 struct predicate *our_pred = insert_primary (entry);
668 our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
669 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
670 our_pred->args.reftime.kind = COMP_GT;
671 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
672 return true;
674 return false;
677 static boolean
678 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
680 struct predicate *our_pred;
682 (void) argv;
683 (void) arg_ptr;
685 our_pred = get_new_pred (entry);
686 our_pred->pred_func = pred_comma;
687 our_pred->p_type = BI_OP;
688 our_pred->p_prec = COMMA_PREC;
689 our_pred->need_stat = our_pred->need_type = false;
690 our_pred->est_success_rate = 1.0f;
691 return true;
694 static boolean
695 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
697 struct tm *local;
699 (void) entry;
700 (void) argv;
701 (void) arg_ptr;
703 if (options.full_days == false)
705 options.cur_day_start += DAYSECS;
706 local = localtime (&options.cur_day_start);
707 options.cur_day_start -= (local
708 ? (local->tm_sec + local->tm_min * 60
709 + local->tm_hour * 3600)
710 : options.cur_day_start % DAYSECS);
711 options.full_days = true;
713 return true;
716 static boolean
717 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
719 struct predicate *our_pred;
720 (void) argv;
721 (void) arg_ptr;
723 our_pred = insert_primary (entry);
724 our_pred->side_effects = our_pred->no_default_print = true;
725 /* -delete implies -depth */
726 options.do_dir_first = false;
728 /* We do not need stat information because we check for the case
729 * (errno==EISDIR) in pred_delete.
731 our_pred->need_stat = our_pred->need_type = false;
733 our_pred->est_success_rate = 1.0f;
734 return true;
737 static boolean
738 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
740 (void) entry;
741 (void) argv;
743 options.do_dir_first = false;
744 return parse_noop(entry, argv, arg_ptr);
747 static boolean
748 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
750 if (options.warnings)
752 error (0, 0,
753 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
755 return parse_depth(entry, argv, arg_ptr);
758 static boolean
759 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
761 struct predicate *our_pred;
762 (void) argv;
763 (void) arg_ptr;
765 our_pred = insert_primary (entry);
766 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
767 return true;
770 static boolean
771 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
773 return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
776 static boolean
777 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
779 return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
782 static boolean
783 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
785 struct predicate *our_pred;
787 (void) argv;
788 (void) arg_ptr;
790 our_pred = insert_primary (entry);
791 our_pred->need_stat = our_pred->need_type = false;
792 our_pred->side_effects = our_pred->no_default_print = false;
793 our_pred->est_success_rate = 0.0f;
794 return true;
797 static boolean
798 insert_fls (const struct parser_table* entry, const char *filename)
800 struct predicate *our_pred = insert_primary (entry);
801 if (filename)
802 open_output_file (filename, &our_pred->args.printf_vec);
803 else
804 open_stdout (&our_pred->args.printf_vec);
805 our_pred->side_effects = our_pred->no_default_print = true;
806 our_pred->est_success_rate = 1.0f;
807 return true;
811 static boolean
812 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
814 const char *filename;
815 return collect_arg(argv, arg_ptr, &filename)
816 && insert_fls(entry, filename);
819 static boolean
820 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
822 set_follow_state(SYMLINK_ALWAYS_DEREF);
823 return parse_noop(entry, argv, arg_ptr);
826 static boolean
827 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
829 struct predicate *our_pred;
830 const char *filename;
831 if (collect_arg(argv, arg_ptr, &filename))
833 our_pred = insert_primary (entry);
834 open_output_file (filename, &our_pred->args.printf_vec);
835 our_pred->side_effects = our_pred->no_default_print = true;
836 our_pred->need_stat = our_pred->need_type = false;
837 our_pred->est_success_rate = 1.0f;
838 return true;
840 else
842 return false;
846 static boolean
847 insert_fprint(const struct parser_table* entry, const char *filename)
849 struct predicate *our_pred = insert_primary (entry);
850 if (filename)
851 open_output_file (filename, &our_pred->args.printf_vec);
852 else
853 open_stdout (&our_pred->args.printf_vec);
854 our_pred->side_effects = our_pred->no_default_print = true;
855 our_pred->need_stat = our_pred->need_type = false;
856 our_pred->est_success_rate = 1.0f;
857 return true;
861 static boolean
862 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
864 const char *filename;
865 if (collect_arg(argv, arg_ptr, &filename))
866 return insert_fprint(entry, filename);
867 else
868 return false;
871 static float estimate_fstype_success_rate(const char *fsname)
873 struct stat dir_stat;
874 const char *dir = "/";
875 if (0 == stat(dir, &dir_stat))
877 const char *fstype = filesystem_type(&dir_stat, dir);
878 /* Assume most files are on the same filesystem type as the root fs. */
879 if (0 == strcmp(fsname, fstype))
880 return 0.7f;
881 else
882 return 0.3f;
884 return 1.0f;
888 static boolean
889 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
891 const char *typename;
892 if (collect_arg(argv, arg_ptr, &typename))
894 struct predicate *our_pred = insert_primary (entry);
895 our_pred->args.str = typename;
897 /* This is an expensive operation, so although there are
898 * circumstances where it is selective, we ignore this fact
899 * because we probably don't want to promote this test to the
900 * front anyway.
902 our_pred->est_success_rate = estimate_fstype_success_rate(typename);
903 return true;
905 else
907 return false;
911 static boolean
912 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
914 struct predicate *p = insert_num (argv, arg_ptr, entry);
915 if (p)
917 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
918 return true;
920 else
922 return false;
926 static boolean
927 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
929 const char *groupname;
931 if (collect_arg(argv, arg_ptr, &groupname))
933 gid_t gid;
934 struct predicate *our_pred;
935 struct group *cur_gr = getgrnam(groupname);
936 endgrent();
937 if (cur_gr)
939 gid = cur_gr->gr_gid;
941 else
943 const int gid_len = strspn (groupname, "0123456789");
944 if (gid_len)
946 if (groupname[gid_len] == 0)
948 gid = atoi (groupname);
949 #warning "no error checking on the previous line"
951 else
953 /* XXX: no test in test suite for this */
954 error(1, 0, _("%s is not the name of an existing group and"
955 " it does not look like a numeic group ID because "
956 "it has the unexpected suffix %s"),
957 quotearg_n_style(0, options.err_quoting_style, groupname),
958 quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
959 return false;
962 else
964 if (*groupname)
966 /* XXX: no test in test suite for this */
967 error(1, 0, _("%s is not the name of an existing group"),
968 quotearg_n_style(0, options.err_quoting_style, groupname));
970 else
972 error(1, 0, _("argument to -group is empty, but should be a group name"));
974 return false;
977 our_pred = insert_primary (entry);
978 our_pred->args.gid = gid;
979 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
980 return true;
982 return false;
985 static boolean
986 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
988 (void) entry;
989 (void) argv;
990 (void) arg_ptr;
992 usage(stdout, 0, NULL);
993 puts (_("\n\
994 default path is the current directory; default expression is -print\n\
995 expression may consist of: operators, options, tests, and actions:\n"));
996 puts (_("\
997 operators (decreasing precedence; -and is implicit where no others are given):\n\
998 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
999 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
1000 puts (_("\
1001 positional options (always true): -daystart -follow -regextype\n\n\
1002 normal options (always true, specified before other expressions):\n\
1003 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
1004 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
1005 puts (_("\
1006 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
1007 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
1008 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
1009 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
1010 puts (_("\
1011 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
1012 -readable -writable -executable\n\
1013 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
1014 -used N -user NAME -xtype [bcdpfls]\n"));
1015 puts (_("\
1016 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
1017 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
1018 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
1019 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
1020 "));
1021 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
1022 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
1023 email to <bug-findutils@gnu.org>."));
1024 exit (0);
1027 static float
1028 estimate_pattern_match_rate(const char *pattern, int is_regex)
1030 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
1032 /* A wildcard; assume the pattern matches most files. */
1033 return 0.8f;
1035 else
1037 return 0.1f;
1041 static boolean
1042 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
1044 const char *name;
1045 if (collect_arg(argv, arg_ptr, &name))
1047 struct predicate *our_pred = insert_primary (entry);
1048 our_pred->args.str = name;
1049 /* Use the generic glob pattern estimator to figure out how many
1050 * links will match, but bear in mind that most files won't be links.
1052 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1053 return true;
1055 else
1057 return false;
1062 /* sanity check the fnmatch() function to make sure that case folding
1063 * is supported (as opposed to just having the flag ignored).
1065 static boolean
1066 fnmatch_sanitycheck(void)
1068 static boolean checked = false;
1069 if (!checked)
1071 if (0 != fnmatch("foo", "foo", 0)
1072 || 0 == fnmatch("Foo", "foo", 0)
1073 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
1075 error (1, 0, _("sanity check of the fnmatch() library function failed."));
1076 return false;
1078 checked = true;
1080 return checked;
1084 static boolean
1085 check_name_arg(const char *pred, const char *arg)
1087 if (strchr(arg, '/'))
1089 error(0, 0,_("warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '%s %s' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ %s'."),
1090 pred,
1091 safely_quote_err_filename(0, arg),
1092 safely_quote_err_filename(1, arg));
1094 return true; /* allow it anyway */
1099 static boolean
1100 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
1102 const char *name;
1103 fnmatch_sanitycheck();
1104 if (collect_arg(argv, arg_ptr, &name))
1106 if (check_name_arg("-iname", name))
1108 struct predicate *our_pred = insert_primary (entry);
1109 our_pred->need_stat = our_pred->need_type = false;
1110 our_pred->args.str = name;
1111 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1112 return true;
1115 return false;
1118 static boolean
1119 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1121 struct predicate *p = insert_num (argv, arg_ptr, entry);
1122 if (p)
1124 /* inode number is exact match only, so very low proportions of
1125 * files match
1127 p->est_success_rate = 1e-6;
1128 return true;
1130 else
1132 return false;
1136 /* -ipath is deprecated (at RMS's request) in favour of
1137 * -iwholename. See the node "GNU Manuals" in standards.texi
1138 * for the rationale for this (basically, GNU prefers the use
1139 * of the phrase "file name" to "path name"
1141 static boolean
1142 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1144 error (0, 0,
1145 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1147 return parse_iwholename(entry, argv, arg_ptr);
1150 static boolean
1151 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1153 const char *name;
1155 fnmatch_sanitycheck();
1156 if (collect_arg(argv, arg_ptr, &name))
1158 struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
1159 our_pred->need_stat = our_pred->need_type = false;
1160 our_pred->args.str = name;
1161 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1162 return true;
1164 return false;
1167 static boolean
1168 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1170 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1173 static boolean
1174 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1176 struct predicate *p = insert_num (argv, arg_ptr, entry);
1177 if (p)
1179 if (p->args.numinfo.l_val == 1)
1180 p->est_success_rate = 0.99;
1181 else if (p->args.numinfo.l_val == 2)
1182 p->est_success_rate = 0.01;
1183 else
1184 p->est_success_rate = 1e-3;
1185 return true;
1187 else
1189 return false;
1193 static boolean
1194 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1196 const char *name;
1197 fnmatch_sanitycheck();
1198 if (collect_arg(argv, arg_ptr, &name))
1200 struct predicate *our_pred = insert_primary (entry);
1201 our_pred->args.str = name;
1202 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
1203 return true;
1205 return false;
1208 static boolean
1209 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1211 (void) &argv;
1212 (void) &arg_ptr;
1213 return insert_fls(entry, NULL);
1216 static boolean
1217 insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
1218 int *limitptr)
1220 const char *depthstr;
1221 int depth_len;
1222 const char *predicate = argv[(*arg_ptr)-1];
1223 if (collect_arg(argv, arg_ptr, &depthstr))
1225 depth_len = strspn (depthstr, "0123456789");
1226 if ((depth_len > 0) && (depthstr[depth_len] == 0))
1228 (*limitptr) = atoi (depthstr);
1229 #warning "consider replacing all calls to atio with a utility function"
1230 if (*limitptr >= 0)
1232 return parse_noop(entry, argv, arg_ptr);
1235 error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
1236 predicate,
1237 quotearg_n_style(0, options.err_quoting_style, depthstr));
1238 return false;
1240 /* missing argument */
1241 return false;
1245 static boolean
1246 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1248 return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
1251 static boolean
1252 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1254 return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
1258 static boolean
1259 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr, enum xval xv)
1261 const char *minutes;
1263 if (collect_arg(argv, arg_ptr, &minutes))
1265 struct time_val tval;
1266 tval.xval = xv;
1267 if (get_relative_timestamp(minutes, &tval,
1268 options.cur_day_start + DAYSECS, 60,
1269 "arithmetic overflow while converting %s "
1270 "minutes to a number of seconds"))
1272 struct predicate *our_pred = insert_primary (entry);
1273 our_pred->args.reftime = tval;
1274 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1275 return true;
1278 return false;
1280 static boolean
1281 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1283 return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
1286 static boolean
1287 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1289 return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
1293 static boolean
1294 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1296 return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
1299 static boolean
1300 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1302 const char *name;
1303 if (collect_arg(argv, arg_ptr, &name))
1305 fnmatch_sanitycheck();
1306 if (check_name_arg("-name", name))
1308 struct predicate *our_pred = insert_primary (entry);
1309 our_pred->need_stat = our_pred->need_type = false;
1310 our_pred->args.str = name;
1311 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1312 return true;
1315 return false;
1318 static boolean
1319 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1321 struct predicate *our_pred;
1323 (void) &argv;
1324 (void) &arg_ptr;
1326 our_pred = get_new_pred_chk_op (entry);
1327 our_pred->pred_func = pred_negate;
1328 our_pred->p_type = UNI_OP;
1329 our_pred->p_prec = NEGATE_PREC;
1330 our_pred->need_stat = our_pred->need_type = false;
1331 return true;
1334 static boolean
1335 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1337 struct predicate *our_pred;
1338 struct stat stat_newer;
1340 set_stat_placeholders(&stat_newer);
1341 if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
1343 our_pred = insert_primary (entry);
1344 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1345 our_pred->args.reftime.xval = XVAL_MTIME;
1346 our_pred->args.reftime.kind = COMP_GT;
1347 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1348 return true;
1350 return false;
1354 static boolean
1355 parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
1357 (void) argv;
1358 (void) arg_ptr;
1360 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1362 return false;
1364 else if (8u != strlen(argv[*arg_ptr]))
1366 return false;
1368 else
1370 char x, y;
1371 const char validchars[] = "aBcmt";
1373 assert(0 == strncmp("-newer", argv[*arg_ptr], 6));
1374 x = argv[*arg_ptr][6];
1375 y = argv[*arg_ptr][7];
1378 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1379 if ('B' == x || 'B' == y)
1381 error(0, 0,
1382 _("This system does not provide a way to find the birth time of a file."));
1383 return 0;
1385 #endif
1387 /* -newertY (for any Y) is invalid. */
1388 if (x == 't'
1389 || 0 == strchr(validchars, x)
1390 || 0 == strchr( validchars, y))
1392 return false;
1394 else
1396 struct predicate *our_pred;
1398 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1399 * past the test name (for most other tests, this is already done)
1401 (*arg_ptr)++;
1403 our_pred = insert_primary (entry);
1406 switch (x)
1408 case 'a':
1409 our_pred->args.reftime.xval = XVAL_ATIME;
1410 break;
1411 case 'B':
1412 our_pred->args.reftime.xval = XVAL_BIRTHTIME;
1413 break;
1414 case 'c':
1415 our_pred->args.reftime.xval = XVAL_CTIME;
1416 break;
1417 case 'm':
1418 our_pred->args.reftime.xval = XVAL_MTIME;
1419 break;
1420 default:
1421 assert(strchr(validchars, x));
1422 assert(0);
1425 if ('t' == y)
1427 if (!get_date(&our_pred->args.reftime.ts,
1428 argv[*arg_ptr],
1429 &options.start_time))
1431 error(1, 0,
1432 _("I cannot figure out how to interpret %s as a date or time"),
1433 quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
1436 else
1438 struct stat stat_newer;
1440 /* Stat the named file. */
1441 set_stat_placeholders(&stat_newer);
1442 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1443 fatal_file_error(argv[*arg_ptr]);
1445 if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
1447 /* We cannot extract a timestamp from the struct stat. */
1448 error(1, 0, _("Cannot obtain birth time of file %s"),
1449 safely_quote_err_filename(0, argv[*arg_ptr]));
1452 our_pred->args.reftime.kind = COMP_GT;
1453 our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
1454 (*arg_ptr)++;
1456 assert(our_pred->pred_func != NULL);
1457 assert(our_pred->pred_func == pred_newerXY);
1458 assert(our_pred->need_stat);
1459 return true;
1465 static boolean
1466 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1468 options.no_leaf_check = true;
1469 return parse_noop(entry, argv, arg_ptr);
1472 #ifdef CACHE_IDS
1473 /* Arbitrary amount by which to increase size
1474 of `uid_unused' and `gid_unused'. */
1475 #define ALLOC_STEP 2048
1477 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1478 char *uid_unused = NULL;
1480 /* Number of elements in `uid_unused'. */
1481 unsigned uid_allocated;
1483 /* Similar for GIDs and group entries. */
1484 char *gid_unused = NULL;
1485 unsigned gid_allocated;
1486 #endif
1488 static boolean
1489 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1491 struct predicate *our_pred;
1493 (void) &argv;
1494 (void) &arg_ptr;
1496 our_pred = insert_primary (entry);
1497 our_pred->est_success_rate = 1e-4;
1498 #ifdef CACHE_IDS
1499 if (gid_unused == NULL)
1501 struct group *gr;
1503 gid_allocated = ALLOC_STEP;
1504 gid_unused = xmalloc (gid_allocated);
1505 memset (gid_unused, 1, gid_allocated);
1506 setgrent ();
1507 while ((gr = getgrent ()) != NULL)
1509 if ((unsigned) gr->gr_gid >= gid_allocated)
1511 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1512 gid_unused = xrealloc (gid_unused, new_allocated);
1513 memset (gid_unused + gid_allocated, 1,
1514 new_allocated - gid_allocated);
1515 gid_allocated = new_allocated;
1517 gid_unused[(unsigned) gr->gr_gid] = 0;
1519 endgrent ();
1521 #endif
1522 return true;
1525 static boolean
1526 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1528 struct predicate *our_pred;
1529 (void) argv;
1530 (void) arg_ptr;
1533 our_pred = insert_primary (entry);
1534 our_pred->est_success_rate = 1e-3;
1535 #ifdef CACHE_IDS
1536 if (uid_unused == NULL)
1538 struct passwd *pw;
1540 uid_allocated = ALLOC_STEP;
1541 uid_unused = xmalloc (uid_allocated);
1542 memset (uid_unused, 1, uid_allocated);
1543 setpwent ();
1544 while ((pw = getpwent ()) != NULL)
1546 if ((unsigned) pw->pw_uid >= uid_allocated)
1548 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1549 uid_unused = xrealloc (uid_unused, new_allocated);
1550 memset (uid_unused + uid_allocated, 1,
1551 new_allocated - uid_allocated);
1552 uid_allocated = new_allocated;
1554 uid_unused[(unsigned) pw->pw_uid] = 0;
1556 endpwent ();
1558 #endif
1559 return true;
1562 static boolean
1563 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1565 options.warnings = false;
1566 return parse_noop(entry, argv, arg_ptr);
1569 static boolean
1570 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1572 return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
1575 static boolean
1576 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1578 return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
1581 boolean
1582 parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
1584 struct predicate *our_pred;
1586 (void) argv;
1587 (void) arg_ptr;
1589 our_pred = get_new_pred_chk_op (entry);
1590 our_pred->pred_func = pred_openparen;
1591 our_pred->p_type = OPEN_PAREN;
1592 our_pred->p_prec = NO_PREC;
1593 our_pred->need_stat = our_pred->need_type = false;
1594 return true;
1597 static boolean
1598 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1600 struct predicate *our_pred;
1602 (void) argv;
1603 (void) arg_ptr;
1605 our_pred = get_new_pred (entry);
1606 our_pred->pred_func = pred_or;
1607 our_pred->p_type = BI_OP;
1608 our_pred->p_prec = OR_PREC;
1609 our_pred->need_stat = our_pred->need_type = false;
1610 return true;
1613 /* -path is deprecated (at RMS's request) in favour of
1614 * -iwholename. See the node "GNU Manuals" in standards.texi
1615 * for the rationale for this (basically, GNU prefers the use
1616 * of the phrase "file name" to "path name".
1618 * We do not issue a warning that this usage is deprecated
1619 * since HPUX find supports this predicate also.
1621 static boolean
1622 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1624 return parse_wholename(entry, argv, arg_ptr);
1627 static boolean
1628 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1630 const char *name;
1631 if (collect_arg(argv, arg_ptr, &name))
1633 struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
1634 our_pred->need_stat = our_pred->need_type = false;
1635 our_pred->args.str = name;
1636 our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
1637 return true;
1639 return false;
1642 static boolean
1643 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1645 mode_t perm_val[2];
1646 float rate;
1647 int mode_start = 0;
1648 boolean havekind = false;
1649 enum permissions_type kind = PERM_EXACT;
1650 struct mode_change *change = NULL;
1651 struct predicate *our_pred;
1652 const char *perm_expr;
1654 if (!collect_arg(argv, arg_ptr, &perm_expr))
1655 return false;
1657 switch (perm_expr[0])
1659 case '-':
1660 mode_start = 1;
1661 kind = PERM_AT_LEAST;
1662 havekind = true;
1663 rate = 0.2;
1664 break;
1666 case '+':
1667 change = mode_compile (perm_expr);
1668 if (NULL == change)
1670 /* Most likely the caller is an old script that is still
1671 * using the obsolete GNU syntax '-perm +MODE'. This old
1672 * syntax was withdrawn in favor of '-perm /MODE' because
1673 * it is incompatible with POSIX in some cases, but we
1674 * still support uses of it that are not incompatible with
1675 * POSIX.
1677 mode_start = 1;
1678 kind = PERM_ANY;
1679 rate = 0.3;
1681 else
1683 /* This is a POSIX-compatible usage */
1684 mode_start = 0;
1685 kind = PERM_EXACT;
1686 rate = 0.1;
1688 havekind = true;
1689 break;
1691 case '/': /* GNU extension */
1692 mode_start = 1;
1693 kind = PERM_ANY;
1694 havekind = true;
1695 rate = 0.3;
1696 break;
1698 default:
1699 /* For example, '-perm 0644', which is valid and matches
1700 * only files whose mode is exactly 0644.
1702 mode_start = 0;
1703 kind = PERM_EXACT;
1704 havekind = true;
1705 rate = 0.01;
1706 break;
1709 if (NULL == change)
1711 change = mode_compile (perm_expr + mode_start);
1712 if (NULL == change)
1713 error (1, 0, _("invalid mode %s"),
1714 quotearg_n_style(0, options.err_quoting_style, perm_expr));
1716 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1717 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1718 free (change);
1720 if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1722 /* The meaning of -perm /000 will change in the future. It
1723 * currently matches no files, but like -perm -000 it should
1724 * match all files.
1726 * Starting in 2005, we used to issue a warning message
1727 * informing the user that the behaviour would change in the
1728 * future. We have now changed the behaviour and issue a
1729 * warning message that the behaviour recently changed.
1731 error (0, 0,
1732 _("warning: you have specified a mode pattern %s (which is "
1733 "equivalent to /000). The meaning of -perm /000 has now been "
1734 "changed to be consistent with -perm -000; that is, while it "
1735 "used to match no files, it now matches all files."),
1736 perm_expr);
1738 kind = PERM_AT_LEAST;
1739 havekind = true;
1741 /* The "magic" number below is just the fraction of files on my
1742 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1743 * Actual totals are 1472 and 1073833.
1745 rate = 0.9986; /* probably matches anything but a broken symlink */
1748 our_pred = insert_primary (entry);
1749 our_pred->est_success_rate = rate;
1750 if (havekind)
1752 our_pred->args.perm.kind = kind;
1754 else
1757 switch (perm_expr[0])
1759 case '-':
1760 our_pred->args.perm.kind = PERM_AT_LEAST;
1761 break;
1762 case '+':
1763 our_pred->args.perm.kind = PERM_ANY;
1764 break;
1765 default:
1766 our_pred->args.perm.kind = PERM_EXACT;
1767 break;
1770 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1771 return true;
1774 boolean
1775 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1777 struct predicate *our_pred;
1779 (void) argv;
1780 (void) arg_ptr;
1782 our_pred = insert_primary (entry);
1783 /* -print has the side effect of printing. This prevents us
1784 from doing undesired multiple printing when the user has
1785 already specified -print. */
1786 our_pred->side_effects = our_pred->no_default_print = true;
1787 our_pred->need_stat = our_pred->need_type = false;
1788 open_stdout(&our_pred->args.printf_vec);
1789 return true;
1792 static boolean
1793 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1795 return insert_fprint(entry, NULL);
1798 static boolean
1799 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1801 const char *format;
1802 if (collect_arg(argv, arg_ptr, &format))
1804 struct format_val fmt;
1805 open_stdout(&fmt);
1806 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1808 return false;
1811 static boolean
1812 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
1814 const char *format, *filename;
1815 if (collect_arg(argv, arg_ptr, &filename))
1817 if (collect_arg(argv, arg_ptr, &format))
1819 struct format_val fmt;
1820 open_output_file (filename, &fmt);
1821 return insert_fprintf (&fmt, entry, pred_fprintf, format);
1824 return false;
1827 static boolean
1828 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1830 struct predicate *our_pred;
1832 (void) argv;
1833 (void) arg_ptr;
1835 our_pred = insert_primary (entry);
1836 our_pred->need_stat = our_pred->need_type = false;
1837 /* -prune has a side effect that it does not descend into
1838 the current directory. */
1839 our_pred->side_effects = true;
1840 our_pred->no_default_print = false;
1841 return true;
1844 static boolean
1845 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1847 struct predicate *our_pred = insert_primary (entry);
1848 (void) argv;
1849 (void) arg_ptr;
1850 our_pred->need_stat = our_pred->need_type = false;
1851 our_pred->side_effects = true; /* Exiting is a side effect... */
1852 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1853 our_pred->est_success_rate = 1.0f;
1854 return true;
1858 static boolean
1859 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1861 const char *type_name;
1862 if (collect_arg(argv, arg_ptr, &type_name))
1864 /* collect the regex type name */
1865 options.regex_options = get_regex_type(type_name);
1866 return parse_noop(entry, argv, arg_ptr);
1868 return false;
1872 static boolean
1873 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1875 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1878 static boolean
1879 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1881 const char *rx;
1882 if (collect_arg(argv, arg_ptr, &rx))
1884 struct re_pattern_buffer *re;
1885 const char *error_message;
1886 struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
1887 our_pred->need_stat = our_pred->need_type = false;
1888 re = (struct re_pattern_buffer *)
1889 xmalloc (sizeof (struct re_pattern_buffer));
1890 our_pred->args.regex = re;
1891 re->allocated = 100;
1892 re->buffer = (unsigned char *) xmalloc (re->allocated);
1893 re->fastmap = NULL;
1895 re_set_syntax(regex_options);
1896 re->syntax = regex_options;
1897 re->translate = NULL;
1899 error_message = re_compile_pattern (rx, strlen(rx), re);
1900 if (error_message)
1901 error (1, 0, "%s", error_message);
1902 our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
1903 return true;
1905 return false;
1908 static boolean
1909 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1911 struct predicate *our_pred;
1912 uintmax_t num;
1913 char suffix;
1914 enum comparison_type c_type;
1916 int blksize = 512;
1917 int len;
1919 /* XXX: cannot (yet) convert to ue collect_arg() as this
1920 * function modifies the args in-place.
1922 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1923 return false;
1925 len = strlen (argv[*arg_ptr]);
1926 if (len == 0)
1927 error (1, 0, _("invalid null argument to -size"));
1929 suffix = argv[*arg_ptr][len - 1];
1930 switch (suffix)
1932 case 'b':
1933 blksize = 512;
1934 argv[*arg_ptr][len - 1] = '\0';
1935 break;
1937 case 'c':
1938 blksize = 1;
1939 argv[*arg_ptr][len - 1] = '\0';
1940 break;
1942 case 'k':
1943 blksize = 1024;
1944 argv[*arg_ptr][len - 1] = '\0';
1945 break;
1947 case 'M': /* Megabytes */
1948 blksize = 1024*1024;
1949 argv[*arg_ptr][len - 1] = '\0';
1950 break;
1952 case 'G': /* Gigabytes */
1953 blksize = 1024*1024*1024;
1954 argv[*arg_ptr][len - 1] = '\0';
1955 break;
1957 case 'w':
1958 blksize = 2;
1959 argv[*arg_ptr][len - 1] = '\0';
1960 break;
1962 case '0':
1963 case '1':
1964 case '2':
1965 case '3':
1966 case '4':
1967 case '5':
1968 case '6':
1969 case '7':
1970 case '8':
1971 case '9':
1972 break;
1974 default:
1975 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1977 /* TODO: accept fractional megabytes etc. ? */
1978 if (!get_num (argv[*arg_ptr], &num, &c_type))
1980 error(1, 0, _("Invalid argument `%s%c' to -size"), argv[*arg_ptr], (int)suffix);
1981 return false;
1983 our_pred = insert_primary (entry);
1984 our_pred->args.size.kind = c_type;
1985 our_pred->args.size.blocksize = blksize;
1986 our_pred->args.size.size = num;
1987 our_pred->need_stat = true;
1988 our_pred->need_type = false;
1990 if (COMP_GT == c_type)
1991 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1992 else if (COMP_LT == c_type)
1993 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1994 else
1995 our_pred->est_success_rate = 0.01;
1997 (*arg_ptr)++;
1998 return true;
2002 static boolean
2003 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
2005 /* General idea: stat the file, remember device and inode numbers.
2006 * If a candidate file matches those, it's the same file.
2008 struct predicate *our_pred;
2009 struct stat st, fst;
2010 int fd, openflags;
2012 set_stat_placeholders(&st);
2013 if (!collect_arg_stat_info(argv, arg_ptr, &st))
2014 return false;
2016 set_stat_placeholders(&fst);
2017 /* POSIX systems are free to re-use the inode number of a deleted
2018 * file. To ensure that we are not fooled by inode reuse, we hold
2019 * the file open if we can. This would prevent the system reusing
2020 * the file.
2022 fd = -3; /* means, uninitialised */
2023 openflags = O_RDONLY;
2025 if (options.symlink_handling == SYMLINK_NEVER_DEREF)
2027 if (options.open_nofollow_available)
2029 assert(O_NOFOLLOW != 0);
2030 openflags |= O_NOFOLLOW;
2031 fd = -1; /* safe to open it. */
2033 else
2035 if (S_ISLNK(st.st_mode))
2037 /* no way to ensure that a symlink will not be followed
2038 * by open(2), so fall back on using lstat(). Accept
2039 * the risk that the named file will be deleted and
2040 * replaced with another having the same inode.
2042 * Avoid opening the file.
2044 fd = -2; /* Do not open it */
2046 else
2048 fd = -1;
2049 /* Race condition here: the file might become a symlink here. */
2053 else
2055 /* We want to dereference the symlink anyway */
2056 fd = -1; /* safe to open it without O_NOFOLLOW */
2059 assert(fd != -3); /* check we made a decision */
2060 if (fd == -1)
2062 /* Race condition here. The file might become a
2063 * symbolic link in between out call to stat and
2064 * the call to open.
2066 fd = open(argv[*arg_ptr], openflags);
2068 if (fd >= 0)
2070 /* We stat the file again here to prevent a race condition
2071 * between the first stat and the call to open(2).
2073 if (0 != fstat(fd, &fst))
2075 fatal_file_error(argv[*arg_ptr]);
2077 else
2079 /* Worry about the race condition. If the file became a
2080 * symlink after our first stat and before our call to
2081 * open, fst may contain the stat information for the
2082 * destination of the link, not the link itself.
2084 if ((*options.xstat) (argv[*arg_ptr], &st))
2085 fatal_file_error(argv[*arg_ptr]);
2087 if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
2088 && (!options.open_nofollow_available))
2090 if (S_ISLNK(st.st_mode))
2092 /* We lost the race. Leave the data in st. The
2093 * file descriptor points to the wrong thing.
2095 close(fd);
2096 fd = -1;
2098 else
2100 /* Several possibilities here:
2101 * 1. There was no race
2102 * 2. The file changed into a symlink after the stat and
2103 * before the open, and then back into a non-symlink
2104 * before the second stat.
2106 * In case (1) there is no problem. In case (2),
2107 * the stat() and fstat() calls will have returned
2108 * different data. O_NOFOLLOW was not available,
2109 * so the open() call may have followed a symlink
2110 * even if the -P option is in effect.
2112 if ((st.st_dev == fst.st_dev)
2113 && (st.st_ino == fst.st_ino))
2115 /* No race. No need to copy fst to st,
2116 * since they should be identical (modulo
2117 * differences in padding bytes).
2120 else
2122 /* We lost the race. Leave the data in st. The
2123 * file descriptor points to the wrong thing.
2125 close(fd);
2126 fd = -1;
2130 else
2132 st = fst;
2138 our_pred = insert_primary (entry);
2139 our_pred->args.samefileid.ino = st.st_ino;
2140 our_pred->args.samefileid.dev = st.st_dev;
2141 our_pred->args.samefileid.fd = fd;
2142 our_pred->need_type = false;
2143 our_pred->need_stat = true;
2144 our_pred->est_success_rate = 0.01f;
2145 return true;
2148 #if 0
2149 /* This function is commented out partly because support for it is
2150 * uneven.
2152 static boolean
2153 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
2155 const char *arg;
2156 const char *errmsg = _("The -show-control-chars option takes a single argument which "
2157 "must be 'literal' or 'safe'");
2159 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2161 error (1, errno, "%s", errmsg);
2162 return false;
2164 else
2166 arg = argv[*arg_ptr];
2168 if (0 == strcmp("literal", arg))
2170 options.literal_control_chars = true;
2172 else if (0 == strcmp("safe", arg))
2174 options.literal_control_chars = false;
2176 else
2178 error (1, errno, "%s", errmsg);
2179 return false;
2181 (*arg_ptr)++; /* consume the argument. */
2182 return true;
2185 #endif
2188 static boolean
2189 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
2191 struct predicate *our_pred;
2193 (void) argv;
2194 (void) arg_ptr;
2196 our_pred = insert_primary (entry);
2197 our_pred->need_stat = our_pred->need_type = false;
2198 our_pred->est_success_rate = 1.0f;
2199 return true;
2202 static boolean
2203 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
2205 (void) entry;
2206 return parse_true(get_noop(), argv, arg_ptr);
2209 static boolean
2210 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
2212 struct predicate *our_pred;
2213 (void) argv;
2214 (void) arg_ptr;
2215 our_pred = insert_primary (entry);
2216 our_pred->need_stat = our_pred->need_type = false;
2217 our_pred->side_effects = our_pred->no_default_print = false;
2218 if (pred_is(our_pred, pred_executable))
2219 our_pred->est_success_rate = 0.2;
2220 else
2221 our_pred->est_success_rate = 0.9;
2222 return true;
2225 static boolean
2226 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
2228 return insert_type (argv, arg_ptr, entry, pred_type);
2231 static boolean
2232 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
2234 struct predicate *p = insert_num (argv, arg_ptr, entry);
2235 if (p)
2237 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
2238 return true;
2240 else
2242 return false;
2246 static boolean
2247 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
2249 struct predicate *our_pred;
2250 struct time_val tval;
2251 const char *offset_str;
2252 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2254 if (collect_arg(argv, arg_ptr, &offset_str))
2256 /* The timespec is actually a delta value, so we use an origin of 0. */
2257 if (get_relative_timestamp(offset_str, &tval, 0, DAYSECS, errmsg))
2259 our_pred = insert_primary (entry);
2260 our_pred->args.reftime = tval;
2261 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
2262 return true;
2264 else
2266 error(1, 0, _("Invalid argument %s to -used"), offset_str);
2267 return false;
2270 else
2272 return false; /* missing argument */
2276 static boolean
2277 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
2279 const char *username;
2281 if (collect_arg(argv, arg_ptr, &username))
2283 struct predicate *our_pred;
2284 uid_t uid;
2285 struct passwd *cur_pwd = getpwnam(username);
2286 endpwent();
2287 if (cur_pwd != NULL)
2289 uid = cur_pwd->pw_uid;
2291 else
2293 int uid_len = strspn (username, "0123456789");
2294 if (uid_len && (username[uid_len]==0))
2295 uid = atoi (username);
2296 else
2297 return false;
2298 #warning "no success checking has occured in atoi on previous line"
2300 our_pred = insert_primary (entry);
2301 our_pred->args.uid = uid;
2302 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
2303 return true;
2305 return false;
2308 static boolean
2309 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
2311 extern char *version_string;
2312 int features = 0;
2313 int flags;
2315 (void) argv;
2316 (void) arg_ptr;
2317 (void) entry;
2319 fflush (stderr);
2320 printf (_("GNU find version %s\n"), version_string);
2321 printf (_("Built using GNU gnulib version %s\n"), gnulib_version);
2322 printf (_("Features enabled: "));
2324 #if CACHE_IDS
2325 printf("CACHE_IDS ");
2326 ++features;
2327 #endif
2328 #if DEBUG
2329 printf("DEBUG ");
2330 ++features;
2331 #endif
2332 #if DEBUG_STAT
2333 printf("DEBUG_STAT ");
2334 ++features;
2335 #endif
2336 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
2337 printf("D_TYPE ");
2338 ++features;
2339 #endif
2340 #if defined(O_NOFOLLOW)
2341 printf("O_NOFOLLOW(%s) ",
2342 (options.open_nofollow_available ? "enabled" : "disabled"));
2343 ++features;
2344 #endif
2345 #if defined(LEAF_OPTIMISATION)
2346 printf("LEAF_OPTIMISATION ");
2347 ++features;
2348 #endif
2350 flags = 0;
2351 if (is_fts_enabled(&flags))
2353 int nflags = 0;
2354 printf("FTS(");
2355 ++features;
2357 if (flags & FTS_CWDFD)
2359 if (nflags)
2361 printf(",");
2363 printf("FTS_CWDFD");
2364 ++nflags;
2366 printf(") ");
2369 printf("CBO(level=%d) ", (int)(options.optimisation_level));
2370 ++features;
2372 if (0 == features)
2374 /* For the moment, leave this as English in case someone wants
2375 to parse these strings. */
2376 printf("none");
2378 printf("\n");
2380 exit (0);
2383 static boolean
2384 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
2386 options.stay_on_filesystem = true;
2387 return parse_noop(entry, argv, arg_ptr);
2390 static boolean
2391 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2393 options.ignore_readdir_race = true;
2394 return parse_noop(entry, argv, arg_ptr);
2397 static boolean
2398 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
2400 options.ignore_readdir_race = false;
2401 return parse_noop(entry, argv, arg_ptr);
2404 static boolean
2405 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2407 options.warnings = true;
2408 return parse_noop(entry, argv, arg_ptr);
2411 static boolean
2412 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2414 return insert_type (argv, arg_ptr, entry, pred_xtype);
2417 static boolean
2418 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2420 mode_t type_cell;
2421 struct predicate *our_pred;
2422 float rate = 0.5;
2423 const char *typeletter;
2425 if (collect_arg(argv, arg_ptr, &typeletter))
2427 if (strlen(typeletter) != 1u)
2429 error(1, 0, _("Arguments to -type should contain only one letter"));
2430 return false;
2433 switch (typeletter[0])
2435 case 'b': /* block special */
2436 type_cell = S_IFBLK;
2437 rate = 0.01f;
2438 break;
2439 case 'c': /* character special */
2440 type_cell = S_IFCHR;
2441 rate = 0.01f;
2442 break;
2443 case 'd': /* directory */
2444 type_cell = S_IFDIR;
2445 rate = 0.4f;
2446 break;
2447 case 'f': /* regular file */
2448 type_cell = S_IFREG;
2449 rate = 0.95f;
2450 break;
2451 #ifdef S_IFLNK
2452 case 'l': /* symbolic link */
2453 type_cell = S_IFLNK;
2454 rate = 0.1f;
2455 break;
2456 #endif
2457 #ifdef S_IFIFO
2458 case 'p': /* pipe */
2459 type_cell = S_IFIFO;
2460 rate = 0.01f;
2461 break;
2462 #endif
2463 #ifdef S_IFSOCK
2464 case 's': /* socket */
2465 type_cell = S_IFSOCK;
2466 rate = 0.01f;
2467 break;
2468 #endif
2469 #ifdef S_IFDOOR
2470 case 'D': /* Solaris door */
2471 type_cell = S_IFDOOR;
2472 rate = 0.01f;
2473 break;
2474 #endif
2475 default: /* None of the above ... nuke 'em. */
2476 error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
2477 return false;
2479 our_pred = insert_primary_withpred (entry, which_pred);
2480 our_pred->est_success_rate = rate;
2482 /* Figure out if we will need to stat the file, because if we don't
2483 * need to follow symlinks, we can avoid a stat call by using
2484 * struct dirent.d_type.
2486 if (which_pred == pred_xtype)
2488 our_pred->need_stat = true;
2489 our_pred->need_type = false;
2491 else
2493 our_pred->need_stat = false; /* struct dirent is enough */
2494 our_pred->need_type = true;
2496 our_pred->args.type = type_cell;
2497 return true;
2499 return false;
2503 /* Return true if the file accessed via FP is a terminal.
2505 static boolean
2506 stream_is_tty(FILE *fp)
2508 int fd = fileno(fp);
2509 if (-1 == fd)
2511 return false; /* not a valid stream */
2513 else
2515 return isatty(fd) ? true : false;
2523 /* XXX: do we need to pass FUNC to this function? */
2524 static boolean
2525 insert_fprintf (struct format_val *vec,
2526 const struct parser_table *entry, PRED_FUNC func,
2527 const char *format_const)
2529 char *format = (char*)format_const; /* XXX: casting away constness */
2530 register char *scan; /* Current address in scanning `format'. */
2531 register char *scan2; /* Address inside of element being scanned. */
2532 struct segment **segmentp; /* Address of current segment. */
2533 struct predicate *our_pred;
2535 our_pred = insert_primary_withpred (entry, func);
2536 our_pred->side_effects = our_pred->no_default_print = true;
2537 our_pred->args.printf_vec = *vec;
2538 our_pred->need_type = false;
2539 our_pred->need_stat = false;
2540 our_pred->p_cost = NeedsNothing;
2542 segmentp = &our_pred->args.printf_vec.segment;
2543 *segmentp = NULL;
2545 for (scan = format; *scan; scan++)
2547 if (*scan == '\\')
2549 scan2 = scan + 1;
2550 if (*scan2 >= '0' && *scan2 <= '7')
2552 register int n, i;
2554 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2555 i++, scan2++)
2556 n = 8 * n + *scan2 - '0';
2557 scan2--;
2558 *scan = n;
2560 else
2562 switch (*scan2)
2564 case 'a':
2565 *scan = 7;
2566 break;
2567 case 'b':
2568 *scan = '\b';
2569 break;
2570 case 'c':
2571 make_segment (segmentp, format, scan - format,
2572 KIND_STOP, 0, 0,
2573 our_pred);
2574 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2575 our_pred->p_cost = NeedsStatInfo;
2576 return true;
2577 case 'f':
2578 *scan = '\f';
2579 break;
2580 case 'n':
2581 *scan = '\n';
2582 break;
2583 case 'r':
2584 *scan = '\r';
2585 break;
2586 case 't':
2587 *scan = '\t';
2588 break;
2589 case 'v':
2590 *scan = '\v';
2591 break;
2592 case '\\':
2593 /* *scan = '\\'; * it already is */
2594 break;
2595 default:
2596 error (0, 0,
2597 _("warning: unrecognized escape `\\%c'"), *scan2);
2598 scan++;
2599 continue;
2602 segmentp = make_segment (segmentp, format, scan - format + 1,
2603 KIND_PLAIN, 0, 0,
2604 our_pred);
2605 format = scan2 + 1; /* Move past the escape. */
2606 scan = scan2; /* Incremented immediately by `for'. */
2608 else if (*scan == '%')
2610 if (scan[1] == 0)
2612 /* Trailing %. We don't like those. */
2613 error (1, 0, _("error: %s at end of format string"), scan);
2615 else if (scan[1] == '%')
2617 segmentp = make_segment (segmentp, format, scan - format + 1,
2618 KIND_PLAIN, 0, 0,
2619 our_pred);
2620 scan++;
2621 format = scan + 1;
2622 continue;
2624 /* Scan past flags, width and precision, to verify kind. */
2625 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2626 /* Do nothing. */ ;
2627 while (ISDIGIT (*scan2))
2628 scan2++;
2629 if (*scan2 == '.')
2630 for (scan2++; ISDIGIT (*scan2); scan2++)
2631 /* Do nothing. */ ;
2632 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2634 segmentp = make_segment (segmentp, format, scan2 - format,
2635 KIND_FORMAT, *scan2, 0,
2636 our_pred);
2637 scan = scan2;
2638 format = scan + 1;
2640 else if (strchr ("ABCT", *scan2) && scan2[1])
2642 segmentp = make_segment (segmentp, format, scan2 - format,
2643 KIND_FORMAT, scan2[0], scan2[1],
2644 our_pred);
2645 scan = scan2 + 1;
2646 format = scan + 1;
2647 continue;
2649 else
2651 /* An unrecognized % escape. Print the char after the %. */
2652 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2653 *scan2);
2654 segmentp = make_segment (segmentp, format, scan - format,
2655 KIND_PLAIN, 0, 0,
2656 our_pred);
2657 format = scan + 1;
2658 continue;
2663 if (scan > format)
2664 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2665 our_pred);
2666 return true;
2669 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2670 from the text in FORMAT, which has length LEN.
2671 Return the address of the `next' pointer of the new segment. */
2673 static struct segment **
2674 make_segment (struct segment **segment,
2675 char *format,
2676 int len,
2677 int kind,
2678 char format_char,
2679 char aux_format_char,
2680 struct predicate *pred)
2682 enum EvaluationCost mycost = NeedsNothing;
2683 char *fmt;
2685 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2687 (*segment)->segkind = kind;
2688 (*segment)->format_char[0] = format_char;
2689 (*segment)->format_char[1] = aux_format_char;
2690 (*segment)->next = NULL;
2691 (*segment)->text_len = len;
2693 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2694 strncpy (fmt, format, len);
2695 fmt += len;
2697 switch (kind)
2699 case KIND_PLAIN: /* Plain text string, no % conversion. */
2700 case KIND_STOP: /* Terminate argument, no newline. */
2701 assert(0 == format_char);
2702 assert(0 == aux_format_char);
2703 *fmt = '\0';
2704 if (mycost > pred->p_cost)
2705 pred->p_cost = NeedsNothing;
2706 return &(*segment)->next;
2707 break;
2710 assert(kind == KIND_FORMAT);
2711 switch (format_char)
2713 case 'l': /* object of symlink */
2714 pred->need_stat = true;
2715 mycost = NeedsLinkName;
2716 *fmt++ = 's';
2717 break;
2719 case 'y': /* file type */
2720 pred->need_type = true;
2721 mycost = NeedsType;
2722 *fmt++ = 's';
2723 break;
2725 case 'a': /* atime in `ctime' format */
2726 case 'A': /* atime in user-specified strftime format */
2727 case 'B': /* birth time in user-specified strftime format */
2728 case 'c': /* ctime in `ctime' format */
2729 case 'C': /* ctime in user-specified strftime format */
2730 case 'F': /* filesystem type */
2731 case 'g': /* group name */
2732 case 'i': /* inode number */
2733 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2734 case 's': /* size in bytes */
2735 case 't': /* mtime in `ctime' format */
2736 case 'T': /* mtime in user-specified strftime format */
2737 case 'u': /* user name */
2738 pred->need_stat = true;
2739 mycost = NeedsStatInfo;
2740 *fmt++ = 's';
2741 break;
2743 case 'S': /* sparseness */
2744 pred->need_stat = true;
2745 mycost = NeedsStatInfo;
2746 *fmt++ = 'g';
2747 break;
2749 case 'Y': /* symlink pointed file type */
2750 pred->need_stat = true;
2751 mycost = NeedsType; /* true for amortised effect */
2752 *fmt++ = 's';
2753 break;
2755 case 'f': /* basename of path */
2756 case 'h': /* leading directories part of path */
2757 case 'p': /* pathname */
2758 case 'P': /* pathname with ARGV element stripped */
2759 *fmt++ = 's';
2760 break;
2762 case 'H': /* ARGV element file was found under */
2763 *fmt++ = 's';
2764 break;
2766 /* Numeric items that one might expect to honour
2767 * #, 0, + flags but which do not.
2769 case 'G': /* GID number */
2770 case 'U': /* UID number */
2771 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2772 case 'D': /* Filesystem device on which the file exits */
2773 case 'k': /* size in 1K blocks */
2774 case 'n': /* number of links */
2775 pred->need_stat = true;
2776 mycost = NeedsStatInfo;
2777 *fmt++ = 's';
2778 break;
2780 /* Numeric items that DO honour #, 0, + flags.
2782 case 'd': /* depth in search tree (0 = ARGV element) */
2783 *fmt++ = 'd';
2784 break;
2786 case 'm': /* mode as octal number (perms only) */
2787 *fmt++ = 'o';
2788 pred->need_stat = true;
2789 mycost = NeedsStatInfo;
2790 break;
2792 case '{':
2793 case '[':
2794 case '(':
2795 error (1, 0,
2796 _("error: the format directive `%%%c' is reserved for future use"),
2797 (int)kind);
2798 /*NOTREACHED*/
2799 break;
2801 *fmt = '\0';
2803 if (mycost > pred->p_cost)
2804 pred->p_cost = mycost;
2805 return &(*segment)->next;
2808 static void
2809 check_path_safety(const char *action, char **argv)
2811 const char *path = getenv("PATH");
2812 char *s;
2814 (void)argv;
2816 s = next_element(path, 1);
2817 while ((s = next_element ((char *) NULL, 1)) != NULL)
2819 if (0 == strcmp(s, "."))
2821 error(1, 0, _("The current directory is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove the current directory from your $PATH (that is, remove \".\" or leading or trailing colons)"),
2822 action);
2824 else if ('/' != s[0])
2826 /* Relative paths are also dangerous in $PATH. */
2827 error(1, 0, _("The ralative path %s is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove that entry from $PATH"),
2828 safely_quote_err_filename(0, s),
2829 action);
2835 /* handles both exec and ok predicate */
2836 static boolean
2837 new_insert_exec_ok (const char *action,
2838 const struct parser_table *entry,
2839 int dirfd,
2840 char **argv,
2841 int *arg_ptr)
2843 int start, end; /* Indexes in ARGV of start & end of cmd. */
2844 int i; /* Index into cmd args */
2845 int saw_braces; /* True if previous arg was '{}'. */
2846 boolean allow_plus; /* True if + is a valid terminator */
2847 int brace_count; /* Number of instances of {}. */
2848 PRED_FUNC func = entry->pred_func;
2849 enum BC_INIT_STATUS bcstatus;
2851 struct predicate *our_pred;
2852 struct exec_val *execp; /* Pointer for efficiency. */
2854 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2855 return false;
2857 our_pred = insert_primary_withpred (entry, func);
2858 our_pred->side_effects = our_pred->no_default_print = true;
2859 our_pred->need_type = our_pred->need_stat = false;
2861 execp = &our_pred->args.exec_vec;
2863 if ((func != pred_okdir) && (func != pred_ok))
2865 allow_plus = true;
2866 execp->close_stdin = false;
2868 else
2870 allow_plus = false;
2871 /* If find reads stdin (i.e. for -ok and similar), close stdin
2872 * in the child to prevent some script from consiming the output
2873 * intended for find.
2875 execp->close_stdin = true;
2879 if ((func == pred_execdir) || (func == pred_okdir))
2881 options.ignore_readdir_race = false;
2882 check_path_safety(action, argv);
2883 execp->use_current_dir = true;
2885 else
2887 execp->use_current_dir = false;
2890 our_pred->args.exec_vec.multiple = 0;
2892 /* Count the number of args with path replacements, up until the ';'.
2893 * Also figure out if the command is terminated by ";" or by "+".
2895 start = *arg_ptr;
2896 for (end = start, saw_braces=0, brace_count=0;
2897 (argv[end] != NULL)
2898 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2899 end++)
2901 /* For -exec and -execdir, "{} +" can terminate the command. */
2902 if ( allow_plus
2903 && argv[end][0] == '+' && argv[end][1] == 0
2904 && saw_braces)
2906 our_pred->args.exec_vec.multiple = 1;
2907 break;
2910 saw_braces = 0;
2911 if (mbsstr (argv[end], "{}"))
2913 saw_braces = 1;
2914 ++brace_count;
2916 if (0 == end && (func == pred_execdir || func == pred_okdir))
2918 /* The POSIX standard says that {} replacement should
2919 * occur even in the utility name. This is insecure
2920 * since it means we will be executing a command whose
2921 * name is chosen according to whatever find finds in
2922 * the filesystem. That can be influenced by an
2923 * attacker. Hence for -execdir and -okdir this is not
2924 * allowed. We can specify this as those options are
2925 * not defined by POSIX.
2927 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2932 /* Fail if no command given or no semicolon found. */
2933 if ((end == start) || (argv[end] == NULL))
2935 *arg_ptr = end;
2936 free(our_pred);
2937 return false;
2940 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2943 const char *suffix;
2944 if (func == pred_execdir)
2945 suffix = "dir";
2946 else
2947 suffix = "";
2949 error(1, 0,
2950 _("Only one instance of {} is supported with -exec%s ... +"),
2951 suffix);
2954 /* We use a switch statement here so that the compiler warns us when
2955 * we forget to handle a newly invented enum value.
2957 * Like xargs, we allow 2KiB of headroom for the launched utility to
2958 * export its own environment variables before calling something
2959 * else.
2961 bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
2962 switch (bcstatus)
2964 case BC_INIT_ENV_TOO_BIG:
2965 case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
2966 error(1, 0,
2967 _("The environment is too large for exec()."));
2968 break;
2969 case BC_INIT_OK:
2970 /* Good news. Carry on. */
2971 break;
2973 bc_use_sensible_arg_max(&execp->ctl);
2976 execp->ctl.exec_callback = launch;
2978 if (our_pred->args.exec_vec.multiple)
2980 /* "+" terminator, so we can just append our arguments after the
2981 * command and initial arguments.
2983 execp->replace_vec = NULL;
2984 execp->ctl.replace_pat = NULL;
2985 execp->ctl.rplen = 0;
2986 execp->ctl.lines_per_exec = 0; /* no limit */
2987 execp->ctl.args_per_exec = 0; /* no limit */
2989 /* remember how many arguments there are */
2990 execp->ctl.initial_argc = (end-start) - 1;
2992 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2993 bc_init_state(&execp->ctl, &execp->state, execp);
2995 /* Gather the initial arguments. Skip the {}. */
2996 for (i=start; i<end-1; ++i)
2998 bc_push_arg(&execp->ctl, &execp->state,
2999 argv[i], strlen(argv[i])+1,
3000 NULL, 0,
3004 else
3006 /* Semicolon terminator - more than one {} is supported, so we
3007 * have to do brace-replacement.
3009 execp->num_args = end - start;
3011 execp->ctl.replace_pat = "{}";
3012 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
3013 execp->ctl.lines_per_exec = 0; /* no limit */
3014 execp->ctl.args_per_exec = 0; /* no limit */
3015 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
3018 /* execp->state = xmalloc(sizeof(*(execp->state))); */
3019 bc_init_state(&execp->ctl, &execp->state, execp);
3021 /* Remember the (pre-replacement) arguments for later. */
3022 for (i=0; i<execp->num_args; ++i)
3024 execp->replace_vec[i] = argv[i+start];
3028 if (argv[end] == NULL)
3029 *arg_ptr = end;
3030 else
3031 *arg_ptr = end + 1;
3033 return true;
3038 static boolean
3039 insert_exec_ok (const char *action, const struct parser_table *entry, int dirfd, char **argv, int *arg_ptr)
3041 return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
3046 /* Get a timestamp and comparison type.
3048 STR is the ASCII representation.
3049 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
3050 relative to ORIGIN (usually the current moment or midnight).
3051 Thus the sense of the comparison type appears to be reversed.
3052 Set *COMP_TYPE to the kind of comparison that is requested.
3053 Issue OVERFLOWMESSAGE if overflow occurs.
3054 Return true if all okay, false if input error.
3056 Used by -atime, -ctime and -mtime (parsers) to
3057 get the appropriate information for a time predicate processor. */
3059 static boolean
3060 get_relative_timestamp (const char *str,
3061 struct time_val *result,
3062 time_t origin,
3063 double sec_per_unit,
3064 const char *overflowmessage)
3066 uintmax_t checkval;
3067 double offset, seconds, f;
3069 if (get_comp_type(&str, &result->kind))
3071 /* Invert the sense of the comparison */
3072 switch (result->kind)
3074 case COMP_LT: result->kind = COMP_GT; break;
3075 case COMP_GT: result->kind = COMP_LT; break;
3076 default: break;
3079 /* Convert the ASCII number into floating-point. */
3080 if (xstrtod(str, NULL, &offset, strtod))
3082 /* Separate the floating point number the user specified
3083 * (which is a number of days, or minutes, etc) into an
3084 * integral number of seconds (SECONDS) and a fraction (F).
3086 f = modf(offset * sec_per_unit, &seconds);
3088 result->ts.tv_sec = origin - seconds;
3089 result->ts.tv_nsec = fabs(f * 1e9);
3091 /* Check for overflow. */
3092 checkval = (uintmax_t)origin - seconds;
3093 if (checkval != result->ts.tv_sec)
3095 /* an overflow has occurred. */
3096 error (1, 0, overflowmessage, str);
3098 return true;
3100 else
3102 /* Conversion from ASCII to double failed. */
3103 return false;
3106 else
3108 return false;
3112 /* Insert a time predicate based on the information in ENTRY.
3113 ARGV is a pointer to the argument array.
3114 ARG_PTR is a pointer to an index into the array, incremented if
3115 all went well.
3117 Return true if input is valid, false if not.
3119 A new predicate node is assigned, along with an argument node
3120 obtained with malloc.
3122 Used by -atime, -ctime, and -mtime parsers. */
3124 static boolean
3125 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
3127 struct predicate *our_pred;
3128 struct time_val tval;
3129 enum comparison_type comp;
3130 const char *timearg;
3131 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
3132 time_t origin;
3134 if (!collect_arg(argv, arg_ptr, &timearg))
3135 return false;
3137 /* Decide the origin by previewing the comparison type. */
3138 origin = options.cur_day_start;
3140 if (get_comp_type(&timearg, &comp))
3142 /* Remember, we invert the sense of the comparison, so this tests against COMP_LT instead of COMP_GT... */
3143 if (COMP_LT == tval.kind)
3145 uintmax_t expected = origin + (DAYSECS-1);
3146 origin += (DAYSECS-1);
3147 if (origin != expected)
3149 error(1, 0,
3150 _("arithmetic overflow when trying to calculate the end of today"));
3153 /* We discard the value of comp here, as get_relative_timestamp
3154 * will set tval.kind.
3158 if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
3159 return false;
3161 our_pred = insert_primary (entry);
3162 our_pred->args.reftime = tval;
3163 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
3165 if (options.debug_options & DebugExpressionTree)
3167 time_t t;
3169 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3170 fprintf (stderr, " type: %s %s ",
3171 (tval.kind == COMP_GT) ? "gt" :
3172 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
3173 (tval.kind == COMP_GT) ? " >" :
3174 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
3175 t = our_pred->args.reftime.ts.tv_sec;
3176 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3177 if (tval.kind == COMP_EQ)
3179 t = our_pred->args.reftime.ts.tv_sec += DAYSECS;
3180 fprintf (stderr, " < %ju %s",
3181 (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
3182 our_pred->args.reftime.ts.tv_sec -= DAYSECS;
3186 return true;
3189 /* Get the comparison type prefix (if any) from a number argument.
3190 The prefix is at *STR.
3191 Set *COMP_TYPE to the kind of comparison that is requested.
3192 Advance *STR beyond any initial comparison prefix.
3194 Return true if all okay, false if input error. */
3195 static boolean
3196 get_comp_type(const char **str, enum comparison_type *comp_type)
3198 switch (**str)
3200 case '+':
3201 *comp_type = COMP_GT;
3202 (*str)++;
3203 break;
3204 case '-':
3205 *comp_type = COMP_LT;
3206 (*str)++;
3207 break;
3208 default:
3209 *comp_type = COMP_EQ;
3210 break;
3212 return true;
3219 /* Get a number with comparison information.
3220 The sense of the comparison information is 'normal'; that is,
3221 '+' looks for a count > than the number and '-' less than.
3223 STR is the ASCII representation of the number.
3224 Set *NUM to the number.
3225 Set *COMP_TYPE to the kind of comparison that is requested.
3227 Return true if all okay, false if input error. */
3229 static boolean
3230 get_num (const char *str,
3231 uintmax_t *num,
3232 enum comparison_type *comp_type)
3234 char *pend;
3236 if (str == NULL)
3237 return false;
3239 /* Figure out the comparison type if the caller accepts one. */
3240 if (comp_type)
3242 if (!get_comp_type(&str, comp_type))
3243 return false;
3246 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
3249 /* Insert a number predicate.
3250 ARGV is a pointer to the argument array.
3251 *ARG_PTR is an index into ARGV, incremented if all went well.
3252 *PRED is the predicate processor to insert.
3254 Return true if input is valid, false if error.
3256 A new predicate node is assigned, along with an argument node
3257 obtained with malloc.
3259 Used by -inum and -links parsers. */
3261 static struct predicate *
3262 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
3264 const char *numstr;
3266 if (collect_arg(argv, arg_ptr, &numstr))
3268 uintmax_t num;
3269 enum comparison_type c_type;
3271 if (get_num (numstr, &num, &c_type))
3273 struct predicate *our_pred = insert_primary (entry);
3274 our_pred->args.numinfo.kind = c_type;
3275 our_pred->args.numinfo.l_val = num;
3277 if (options.debug_options & DebugExpressionTree)
3279 fprintf (stderr, "inserting %s\n", our_pred->p_name);
3280 fprintf (stderr, " type: %s %s ",
3281 (c_type == COMP_GT) ? "gt" :
3282 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
3283 (c_type == COMP_GT) ? " >" :
3284 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
3285 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
3287 return our_pred;
3290 return NULL;
3293 static void
3294 open_output_file (const char *path, struct format_val *p)
3296 p->segment = NULL;
3297 p->quote_opts = clone_quoting_options (NULL);
3299 if (!strcmp (path, "/dev/stderr"))
3301 p->stream = stderr;
3302 p->filename = _("standard error");
3304 else if (!strcmp (path, "/dev/stdout"))
3306 p->stream = stdout;
3307 p->filename = _("standard output");
3309 else
3311 p->stream = fopen_safer (path, "w");
3312 p->filename = path;
3314 if (p->stream == NULL)
3316 fatal_file_error(path);
3320 p->dest_is_tty = stream_is_tty(p->stream);
3323 static void
3324 open_stdout (struct format_val *p)
3326 open_output_file("/dev/stdout", p);