New method of checking out and configuring gnulib - define which version we need...
[findutils.git] / find / parser.c
blob129a799d96767ea107500f96b6c2e8e7888010a2
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005, 2006 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA.
22 #include "defs.h"
23 #include <ctype.h>
24 #include <math.h>
25 #include <assert.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <fnmatch.h>
29 #include "modechange.h"
30 #include "modetype.h"
31 #include "xstrtol.h"
32 #include "xalloc.h"
33 #include "quote.h"
34 #include "quotearg.h"
35 #include "buildcmd.h"
36 #include "nextelem.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
40 #include "xstrtod.h"
41 #include "gnulib-version.h"
43 #ifdef HAVE_FCNTL_H
44 #include <fcntl.h>
45 #else
46 #include <sys/file.h>
47 #endif
49 /* The presence of unistd.h is assumed by gnulib these days, so we
50 * might as well assume it too.
52 /* We need <unistd.h> for isatty(). */
53 #include <unistd.h>
55 #if ENABLE_NLS
56 # include <libintl.h>
57 # define _(Text) gettext (Text)
58 #else
59 # define _(Text) Text
60 #endif
61 #ifdef gettext_noop
62 # define N_(String) gettext_noop (String)
63 #else
64 /* See locate.c for explanation as to why not use (String) */
65 # define N_(String) String
66 #endif
68 #if !defined (isascii) || defined (STDC_HEADERS)
69 #ifdef isascii
70 #undef isascii
71 #endif
72 #define isascii(c) 1
73 #endif
75 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
76 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
78 #ifndef HAVE_ENDGRENT
79 #define endgrent()
80 #endif
81 #ifndef HAVE_ENDPWENT
82 #define endpwent()
83 #endif
85 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
86 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
87 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 #if 0
140 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 #endif
142 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
156 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
161 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
162 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
163 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
165 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
166 int kind, char format_char, char aux_format_char,
167 struct predicate *pred));
168 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
169 static boolean get_comp_type PARAMS((char **str, enum comparison_type *comp_type));
170 static boolean get_relative_timestamp PARAMS((char *str, struct time_val *tval, time_t origin, double sec_per_unit, const char *overflowmessage));
171 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
172 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
173 static FILE *open_output_file PARAMS((char *path));
174 static boolean stream_is_tty(FILE *fp);
175 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
177 #define PASTE(x,y) x##y
178 #define STRINGIFY(s) #s
180 #define PARSE_OPTION(what,suffix) \
181 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
183 #define PARSE_POSOPT(what,suffix) \
184 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
186 #define PARSE_TEST(what,suffix) \
187 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
189 #define PARSE_TEST_NP(what,suffix) \
190 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
192 #define PARSE_ACTION(what,suffix) \
193 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
195 #define PARSE_ACTION_NP(what,suffix) \
196 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
198 #define PARSE_PUNCTUATION(what,suffix) \
199 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
202 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
203 If they are in some Unix versions of find, they are marked `Unix'. */
205 static struct parser_table const parse_table[] =
207 PARSE_PUNCTUATION("!", negate),
208 PARSE_PUNCTUATION("not", negate), /* GNU */
209 PARSE_PUNCTUATION("(", open),
210 PARSE_PUNCTUATION(")", close),
211 PARSE_PUNCTUATION(",", comma), /* GNU */
212 PARSE_PUNCTUATION("a", and),
213 PARSE_TEST ("amin", amin), /* GNU */
214 PARSE_PUNCTUATION("and", and), /* GNU */
215 PARSE_TEST ("anewer", anewer), /* GNU */
216 {ARG_TEST, "atime", parse_time, pred_atime},
217 PARSE_TEST ("cmin", cmin), /* GNU */
218 PARSE_TEST ("cnewer", cnewer), /* GNU */
219 {ARG_TEST, "ctime", parse_time, pred_ctime},
220 PARSE_POSOPT ("daystart", daystart), /* GNU */
221 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
222 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
223 PARSE_OPTION ("depth", depth),
224 PARSE_TEST ("empty", empty), /* GNU */
225 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
226 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
227 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
228 PARSE_ACTION ("fls", fls), /* GNU */
229 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
230 PARSE_ACTION ("fprint", fprint), /* GNU */
231 PARSE_ACTION ("fprint0", fprint0), /* GNU */
232 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
233 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
234 PARSE_TEST ("gid", gid), /* GNU */
235 PARSE_TEST ("group", group),
236 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
237 PARSE_TEST ("ilname", ilname), /* GNU */
238 PARSE_TEST ("iname", iname), /* GNU */
239 PARSE_TEST ("inum", inum), /* GNU, Unix */
240 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
241 PARSE_TEST_NP ("iregex", iregex), /* GNU */
242 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
243 PARSE_TEST ("links", links),
244 PARSE_TEST ("lname", lname), /* GNU */
245 PARSE_ACTION ("ls", ls), /* GNU, Unix */
246 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
247 PARSE_OPTION ("mindepth", mindepth), /* GNU */
248 PARSE_TEST ("mmin", mmin), /* GNU */
249 PARSE_OPTION ("mount", xdev), /* Unix */
250 {ARG_TEST, "mtime", parse_time, pred_mtime},
251 PARSE_TEST ("name", name),
252 #ifdef UNIMPLEMENTED_UNIX
253 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
254 #endif
255 PARSE_TEST ("newer", newer),
256 PARSE_OPTION ("noleaf", noleaf), /* GNU */
257 PARSE_TEST ("nogroup", nogroup),
258 PARSE_TEST ("nouser", nouser),
259 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
260 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
261 PARSE_PUNCTUATION("o", or),
262 PARSE_PUNCTUATION("or", or), /* GNU */
263 PARSE_ACTION ("ok", ok),
264 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
265 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
266 PARSE_TEST ("perm", perm),
267 PARSE_ACTION ("print", print),
268 PARSE_ACTION ("print0", print0), /* GNU */
269 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
270 PARSE_ACTION ("prune", prune),
271 PARSE_ACTION ("quit", quit), /* GNU */
272 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
273 PARSE_TEST ("regex", regex), /* GNU */
274 PARSE_OPTION ("regextype", regextype), /* GNU */
275 PARSE_TEST ("samefile", samefile), /* GNU */
276 #if 0
277 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
278 #endif
279 PARSE_TEST ("size", size),
280 PARSE_TEST ("type", type),
281 PARSE_TEST ("uid", uid), /* GNU */
282 PARSE_TEST ("used", used), /* GNU */
283 PARSE_TEST ("user", user),
284 PARSE_OPTION ("warn", warn), /* GNU */
285 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
286 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
287 PARSE_OPTION ("xdev", xdev),
288 PARSE_TEST ("xtype", xtype), /* GNU */
289 #ifdef UNIMPLEMENTED_UNIX
290 /* It's pretty ugly for find to know about archive formats.
291 Plus what it could do with cpio archives is very limited.
292 Better to leave it out. */
293 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
294 #endif
295 /* gnulib's stdbool.h might have made true and false into macros,
296 * so we can't leave named 'true' and 'false' tokens, so we have
297 * to expeant the relevant entries longhand.
299 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
300 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
301 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
303 /* Various other cases that don't fit neatly into our macro scheme. */
304 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
305 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
306 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
307 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
308 {0, 0, 0, 0}
312 static const char *first_nonoption_arg = NULL;
313 static const struct parser_table *noop = NULL;
317 static const struct parser_table*
318 get_noop(void)
320 int i;
321 if (NULL == noop)
323 for (i = 0; parse_table[i].parser_name != 0; i++)
325 if (ARG_NOOP ==parse_table[i].type)
327 noop = &(parse_table[i]);
328 break;
332 return noop;
337 void
338 set_follow_state(enum SymlinkOption opt)
340 if (options.debug_options & DebugStat)
342 /* For DebugStat, the choice is made at runtime within debug_stat()
343 * by checking the contents of the symlink_handling variable.
345 options.xstat = debug_stat;
347 else
349 switch (opt)
351 case SYMLINK_ALWAYS_DEREF: /* -L */
352 options.xstat = optionl_stat;
353 options.no_leaf_check = true;
354 break;
356 case SYMLINK_NEVER_DEREF: /* -P (default) */
357 options.xstat = optionp_stat;
358 /* Can't turn no_leaf_check off because the user might have specified
359 * -noleaf anyway
361 break;
363 case SYMLINK_DEREF_ARGSONLY: /* -H */
364 options.xstat = optionh_stat;
365 options.no_leaf_check = true;
368 options.symlink_handling = opt;
372 void
373 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
375 (void) args;
376 (void) argno;
377 (void) last;
378 (void) predicates;
379 first_nonoption_arg = NULL;
382 void
383 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
385 /* does nothing */
386 (void) args;
387 (void) argno;
388 (void) last;
389 (void) predicates;
395 /* Return a pointer to the parser function to invoke for predicate
396 SEARCH_NAME.
397 Return NULL if SEARCH_NAME is not a valid predicate name. */
399 const struct parser_table*
400 find_parser (char *search_name)
402 int i;
403 const char *original_arg = search_name;
405 if (*search_name == '-')
406 search_name++;
407 for (i = 0; parse_table[i].parser_name != 0; i++)
409 if (strcmp (parse_table[i].parser_name, search_name) == 0)
411 /* If this is an option, but we have already had a
412 * non-option argument, the user may be under the
413 * impression that the behaviour of the option
414 * argument is conditional on some preceding
415 * tests. This might typically be the case with,
416 * for example, -maxdepth.
418 * The options -daystart and -follow are exempt
419 * from this treatment, since their positioning
420 * in the command line does have an effect on
421 * subsequent tests but not previous ones. That
422 * might be intentional on the part of the user.
424 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
426 /* Something other than -follow/-daystart.
427 * If this is an option, check if it followed
428 * a non-option and if so, issue a warning.
430 if (parse_table[i].type == ARG_OPTION)
432 if ((first_nonoption_arg != NULL)
433 && options.warnings )
435 /* option which follows a non-option */
436 error (0, 0,
437 _("warning: you have specified the %s "
438 "option after a non-option argument %s, "
439 "but options are not positional (%s affects "
440 "tests specified before it as well as those "
441 "specified after it). Please specify options "
442 "before other arguments.\n"),
443 original_arg,
444 first_nonoption_arg,
445 original_arg);
448 else
450 /* Not an option or a positional option,
451 * so remember we've seen it in order to
452 * use it in a possible future warning message.
454 if (first_nonoption_arg == NULL)
456 first_nonoption_arg = original_arg;
461 return &parse_table[i];
464 return NULL;
467 static float
468 estimate_file_age_success_rate(float num_days)
470 if (num_days < 0.1)
472 /* Assume 1% of files have timestamps in the future */
473 return 0.01f;
475 else if (num_days < 1)
477 /* Assume 30% of files have timestamps today */
478 return 0.3f;
480 else if (num_days > 100)
482 /* Assume 30% of files are very old */
483 return 0.3f;
485 else
487 /* Assume 39% of files are between 1 and 100 days old. */
488 return 0.39f;
492 static float
493 estimate_timestamp_success_rate(time_t when)
495 int num_days = (options.cur_day_start - when) / 86400;
496 return estimate_file_age_success_rate(num_days);
499 /* The parsers are responsible to continue scanning ARGV for
500 their arguments. Each parser knows what is and isn't
501 allowed for itself.
503 ARGV is the argument array.
504 *ARG_PTR is the index to start at in ARGV,
505 updated to point beyond the last element consumed.
507 The predicate structure is updated with the new information. */
510 static boolean
511 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
513 struct predicate *our_pred;
515 (void) argv;
516 (void) arg_ptr;
518 our_pred = get_new_pred (entry);
519 our_pred->pred_func = pred_and;
520 our_pred->p_type = BI_OP;
521 our_pred->p_prec = AND_PREC;
522 our_pred->need_stat = our_pred->need_type = false;
523 return true;
526 static boolean
527 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
529 struct predicate *our_pred;
530 struct stat stat_newer;
532 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
533 return false;
534 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
535 error (1, errno, "%s", argv[*arg_ptr]);
536 our_pred = insert_primary (entry);
537 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
538 our_pred->args.reftime.kind = COMP_GT;
539 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
540 (*arg_ptr)++;
541 return true;
544 boolean
545 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
547 struct predicate *our_pred;
549 (void) argv;
550 (void) arg_ptr;
552 our_pred = get_new_pred (entry);
553 our_pred->pred_func = pred_close;
554 our_pred->p_type = CLOSE_PAREN;
555 our_pred->p_prec = NO_PREC;
556 our_pred->need_stat = our_pred->need_type = false;
557 return true;
560 static boolean
561 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
563 struct predicate *our_pred;
564 struct stat stat_newer;
566 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
567 return false;
568 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
569 error (1, errno, "%s", argv[*arg_ptr]);
570 our_pred = insert_primary (entry);
571 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
572 our_pred->args.reftime.kind = COMP_GT;
573 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
574 (*arg_ptr)++;
575 return true;
578 static boolean
579 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
581 struct predicate *our_pred;
583 (void) argv;
584 (void) arg_ptr;
586 our_pred = get_new_pred (entry);
587 our_pred->pred_func = pred_comma;
588 our_pred->p_type = BI_OP;
589 our_pred->p_prec = COMMA_PREC;
590 our_pred->need_stat = our_pred->need_type = false;
591 our_pred->est_success_rate = 1.0f;
592 return true;
595 static boolean
596 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
598 struct tm *local;
600 (void) entry;
601 (void) argv;
602 (void) arg_ptr;
604 if (options.full_days == false)
606 options.cur_day_start += DAYSECS;
607 local = localtime (&options.cur_day_start);
608 options.cur_day_start -= (local
609 ? (local->tm_sec + local->tm_min * 60
610 + local->tm_hour * 3600)
611 : options.cur_day_start % DAYSECS);
612 options.full_days = true;
614 return true;
617 static boolean
618 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
620 struct predicate *our_pred;
621 (void) argv;
622 (void) arg_ptr;
624 our_pred = insert_primary (entry);
625 our_pred->side_effects = our_pred->no_default_print = true;
626 /* -delete implies -depth */
627 options.do_dir_first = false;
628 our_pred->est_success_rate = 1.0f;
629 return true;
632 static boolean
633 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
635 (void) entry;
636 (void) argv;
637 (void) arg_ptr;
639 options.do_dir_first = false;
640 return parse_noop(entry, argv, arg_ptr);
643 static boolean
644 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
646 (void) argv;
647 (void) arg_ptr;
649 if (options.warnings)
651 error (0, 0,
652 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
654 return parse_depth(entry, argv, arg_ptr);
657 static boolean
658 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
660 struct predicate *our_pred;
661 (void) argv;
662 (void) arg_ptr;
664 our_pred = insert_primary (entry);
665 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
666 return true;
669 static boolean
670 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
672 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
675 static boolean
676 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
678 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
681 static boolean
682 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
684 struct predicate *our_pred;
686 (void) argv;
687 (void) arg_ptr;
689 our_pred = insert_primary (entry);
690 our_pred->need_stat = our_pred->need_type = false;
691 our_pred->side_effects = our_pred->no_default_print = false;
692 our_pred->est_success_rate = 0.0f;
693 return true;
696 static boolean
697 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
699 struct predicate *our_pred;
701 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
702 return false;
703 our_pred = insert_primary (entry);
704 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
705 our_pred->side_effects = our_pred->no_default_print = true;
706 our_pred->est_success_rate = 1.0f;
707 (*arg_ptr)++;
708 return true;
711 static boolean
712 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
714 FILE *fp;
716 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
717 return false;
718 if (argv[*arg_ptr + 1] == NULL)
720 /* Ensure we get "missing arg" message, not "invalid arg". */
721 (*arg_ptr)++;
722 return false;
724 fp = open_output_file (argv[*arg_ptr]);
725 (*arg_ptr)++;
726 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
729 static boolean
730 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
732 (void) entry;
733 (void) argv;
734 (void) arg_ptr;
736 set_follow_state(SYMLINK_ALWAYS_DEREF);
737 return parse_noop(entry, argv, arg_ptr);
740 static boolean
741 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
743 struct predicate *our_pred;
745 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
746 return false;
747 our_pred = insert_primary (entry);
748 our_pred->args.printf_vec.segment = NULL;
749 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
750 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
751 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
752 our_pred->side_effects = our_pred->no_default_print = true;
753 our_pred->need_stat = our_pred->need_type = false;
754 our_pred->est_success_rate = 1.0f;
755 (*arg_ptr)++;
756 return true;
759 static boolean
760 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
762 struct predicate *our_pred;
764 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
765 return false;
766 our_pred = insert_primary (entry);
767 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
768 our_pred->side_effects = our_pred->no_default_print = true;
769 our_pred->need_stat = our_pred->need_type = false;
770 our_pred->est_success_rate = 1.0f;
771 (*arg_ptr)++;
772 return true;
775 static float estimate_fstype_success_rate(const char *fsname)
777 struct stat dir_stat;
778 const char *dir = "/";
779 if (0 == stat(dir, &dir_stat))
781 const char *fstype = filesystem_type(&dir_stat, dir);
782 /* Assume most files are on the same filesystem type as the root fs. */
783 if (0 == strcmp(fsname, fstype))
784 return 0.7f;
785 else
786 return 0.3f;
788 return 1.0f;
792 static boolean
793 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
795 struct predicate *our_pred;
797 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
798 return false;
799 our_pred = insert_primary (entry);
800 our_pred->args.str = argv[*arg_ptr];
802 /* This is an expensive operation, so although there are
803 * circumstances where it is selective, we ignore this fact because
804 * we probably don't want to promote this test to the front anyway.
806 our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
807 (*arg_ptr)++;
808 return true;
811 static boolean
812 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
814 struct predicate *p = insert_num (argv, arg_ptr, entry);
815 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
816 return p;
819 static boolean
820 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
822 struct group *cur_gr;
823 struct predicate *our_pred;
824 gid_t gid;
825 int gid_len;
827 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
828 return false;
829 cur_gr = getgrnam (argv[*arg_ptr]);
830 endgrent ();
831 if (cur_gr != NULL)
832 gid = cur_gr->gr_gid;
833 else
835 gid_len = strspn (argv[*arg_ptr], "0123456789");
836 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
837 return false;
838 gid = atoi (argv[*arg_ptr]);
840 our_pred = insert_primary (entry);
841 our_pred->args.gid = gid;
842 our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
843 (*arg_ptr)++;
844 return true;
847 static boolean
848 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
850 (void) entry;
851 (void) argv;
852 (void) arg_ptr;
854 usage(stdout, 0, NULL);
855 puts (_("\n\
856 default path is the current directory; default expression is -print\n\
857 expression may consist of: operators, options, tests, and actions:\n"));
858 puts (_("\
859 operators (decreasing precedence; -and is implicit where no others are given):\n\
860 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
861 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
862 puts (_("\
863 positional options (always true): -daystart -follow -regextype\n\n\
864 normal options (always true, specified before other expressions):\n\
865 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
866 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
867 puts (_("\
868 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
869 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
870 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
871 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
872 puts (_("\
873 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
874 -readable -writable -executable\n\
875 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
876 -used N -user NAME -xtype [bcdpfls]\n"));
877 puts (_("\
878 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
879 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
880 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
881 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
882 "));
883 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
884 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
885 email to <bug-findutils@gnu.org>."));
886 exit (0);
889 static float estimate_pattern_match_rate(const char *pattern, int is_regex)
891 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
893 /* A wildcard; assume the pattern matches most files. */
894 return 0.8f;
896 else
898 return 0.1f;
902 static boolean
903 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
905 struct predicate *our_pred;
907 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
908 return false;
909 our_pred = insert_primary (entry);
910 our_pred->args.str = argv[*arg_ptr];
911 /* Use the generic glob pattern estimator to figure out how many
912 * links will match, but bear in mind that most files won't be links.
914 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
915 (*arg_ptr)++;
916 return true;
920 /* sanity check the fnmatch() function to make sure
921 * it really is the GNU version.
923 static boolean
924 fnmatch_sanitycheck(void)
926 /* fprintf(stderr, "Performing find sanity check..."); */
927 if (0 != fnmatch("foo", "foo", 0)
928 || 0 == fnmatch("Foo", "foo", 0)
929 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
931 error (1, 0, _("sanity check of the fnmatch() library function failed."));
932 /* fprintf(stderr, "FAILED\n"); */
933 return false;
936 /* fprintf(stderr, "OK\n"); */
937 return true;
941 static boolean
942 check_name_arg(const char *pred, const char *arg)
944 if (strchr(arg, '/'))
946 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'."),
947 pred, arg, arg);
949 return true; /* allow it anyway */
954 static boolean
955 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
957 struct predicate *our_pred;
959 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
960 return false;
961 if (!check_name_arg("-iname", argv[*arg_ptr]))
962 return false;
964 fnmatch_sanitycheck();
966 our_pred = insert_primary (entry);
967 our_pred->need_stat = our_pred->need_type = false;
968 our_pred->args.str = argv[*arg_ptr];
969 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
970 (*arg_ptr)++;
971 return true;
974 static boolean
975 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
977 struct predicate *p = insert_num (argv, arg_ptr, entry);
978 /* inode number is exact match only, so very low proportions of files match */
979 p->est_success_rate = 1e-6;
980 return p;
983 /* -ipath is deprecated (at RMS's request) in favour of
984 * -iwholename. See the node "GNU Manuals" in standards.texi
985 * for the rationale for this (basically, GNU prefers the use
986 * of the phrase "file name" to "path name"
988 static boolean
989 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
991 error (0, 0,
992 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
994 return parse_iwholename(entry, argv, arg_ptr);
997 static boolean
998 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1000 struct predicate *our_pred;
1002 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1003 return false;
1005 fnmatch_sanitycheck();
1007 our_pred = insert_primary_withpred (entry, pred_ipath);
1008 our_pred->need_stat = our_pred->need_type = false;
1009 our_pred->args.str = argv[*arg_ptr];
1010 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1011 (*arg_ptr)++;
1012 return true;
1015 static boolean
1016 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1018 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1021 static boolean
1022 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1024 struct predicate *p = insert_num (argv, arg_ptr, entry);
1025 if (p->args.numinfo.l_val == 1)
1026 p->est_success_rate = 0.99;
1027 else if (p->args.numinfo.l_val == 2)
1028 p->est_success_rate = 0.01;
1029 else
1030 p->est_success_rate = 1e-3;
1031 return p;
1034 static boolean
1035 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1037 struct predicate *our_pred;
1039 (void) argv;
1040 (void) arg_ptr;
1042 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1043 return false;
1045 fnmatch_sanitycheck();
1047 our_pred = insert_primary (entry);
1048 our_pred->args.str = argv[*arg_ptr];
1049 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
1050 (*arg_ptr)++;
1051 return true;
1054 static boolean
1055 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1057 struct predicate *our_pred;
1059 (void) &argv;
1060 (void) &arg_ptr;
1062 our_pred = insert_primary (entry);
1063 our_pred->side_effects = our_pred->no_default_print = true;
1064 return true;
1067 static boolean
1068 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1070 int depth_len;
1071 (void) entry;
1073 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1074 return false;
1075 depth_len = strspn (argv[*arg_ptr], "0123456789");
1076 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1077 return false;
1078 options.maxdepth = atoi (argv[*arg_ptr]);
1079 if (options.maxdepth < 0)
1080 return false;
1081 (*arg_ptr)++;
1082 return parse_noop(entry, argv, arg_ptr);
1085 static boolean
1086 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1088 int depth_len;
1089 (void) entry;
1091 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1092 return false;
1093 depth_len = strspn (argv[*arg_ptr], "0123456789");
1094 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1095 return false;
1096 options.mindepth = atoi (argv[*arg_ptr]);
1097 if (options.mindepth < 0)
1098 return false;
1099 (*arg_ptr)++;
1100 return parse_noop(entry, argv, arg_ptr);
1104 static boolean
1105 do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1107 struct predicate *our_pred;
1108 struct time_val tval;
1110 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1111 return false;
1113 if (!get_relative_timestamp(argv[*arg_ptr], &tval,
1114 options.cur_day_start + DAYSECS, 60,
1115 "arithmetic overflow while converting %s minutes to a number of seconds"))
1116 return false;
1118 our_pred = insert_primary (entry);
1119 our_pred->args.reftime = tval;
1120 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
1121 (*arg_ptr)++;
1122 return true;
1124 static boolean
1125 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
1127 return do_parse_xmin(entry, argv, arg_ptr);
1130 static boolean
1131 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1133 return do_parse_xmin(entry, argv, arg_ptr);
1137 static boolean
1138 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1140 return do_parse_xmin(entry, argv, arg_ptr);
1143 static boolean
1144 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1146 struct predicate *our_pred;
1148 (void) argv;
1149 (void) arg_ptr;
1151 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1152 return false;
1153 if (!check_name_arg("-name", argv[*arg_ptr]))
1154 return false;
1155 fnmatch_sanitycheck();
1157 our_pred = insert_primary (entry);
1158 our_pred->need_stat = our_pred->need_type = false;
1159 our_pred->args.str = argv[*arg_ptr];
1160 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1161 (*arg_ptr)++;
1162 return true;
1165 static boolean
1166 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1168 struct predicate *our_pred;
1170 (void) &argv;
1171 (void) &arg_ptr;
1173 our_pred = get_new_pred_chk_op (entry);
1174 our_pred->pred_func = pred_negate;
1175 our_pred->p_type = UNI_OP;
1176 our_pred->p_prec = NEGATE_PREC;
1177 our_pred->need_stat = our_pred->need_type = false;
1178 return true;
1181 static boolean
1182 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1184 struct predicate *our_pred;
1185 struct stat stat_newer;
1187 (void) argv;
1188 (void) arg_ptr;
1190 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1191 return false;
1192 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1193 error (1, errno, "%s", argv[*arg_ptr]);
1194 our_pred = insert_primary (entry);
1195 our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
1196 our_pred->args.reftime.kind = COMP_GT;
1197 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1198 (*arg_ptr)++;
1199 return true;
1202 static boolean
1203 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1205 (void) &argv;
1206 (void) &arg_ptr;
1207 (void) entry;
1209 options.no_leaf_check = true;
1210 return parse_noop(entry, argv, arg_ptr);
1213 #ifdef CACHE_IDS
1214 /* Arbitrary amount by which to increase size
1215 of `uid_unused' and `gid_unused'. */
1216 #define ALLOC_STEP 2048
1218 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1219 char *uid_unused = NULL;
1221 /* Number of elements in `uid_unused'. */
1222 unsigned uid_allocated;
1224 /* Similar for GIDs and group entries. */
1225 char *gid_unused = NULL;
1226 unsigned gid_allocated;
1227 #endif
1229 static boolean
1230 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1232 struct predicate *our_pred;
1234 (void) &argv;
1235 (void) &arg_ptr;
1237 our_pred = insert_primary (entry);
1238 our_pred->est_success_rate = 1e-4;
1239 #ifdef CACHE_IDS
1240 if (gid_unused == NULL)
1242 struct group *gr;
1244 gid_allocated = ALLOC_STEP;
1245 gid_unused = xmalloc (gid_allocated);
1246 memset (gid_unused, 1, gid_allocated);
1247 setgrent ();
1248 while ((gr = getgrent ()) != NULL)
1250 if ((unsigned) gr->gr_gid >= gid_allocated)
1252 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1253 gid_unused = xrealloc (gid_unused, new_allocated);
1254 memset (gid_unused + gid_allocated, 1,
1255 new_allocated - gid_allocated);
1256 gid_allocated = new_allocated;
1258 gid_unused[(unsigned) gr->gr_gid] = 0;
1260 endgrent ();
1262 #endif
1263 return true;
1266 static boolean
1267 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1269 struct predicate *our_pred;
1270 (void) argv;
1271 (void) arg_ptr;
1274 our_pred = insert_primary (entry);
1275 our_pred->est_success_rate = 1e-3;
1276 #ifdef CACHE_IDS
1277 if (uid_unused == NULL)
1279 struct passwd *pw;
1281 uid_allocated = ALLOC_STEP;
1282 uid_unused = xmalloc (uid_allocated);
1283 memset (uid_unused, 1, uid_allocated);
1284 setpwent ();
1285 while ((pw = getpwent ()) != NULL)
1287 if ((unsigned) pw->pw_uid >= uid_allocated)
1289 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1290 uid_unused = xrealloc (uid_unused, new_allocated);
1291 memset (uid_unused + uid_allocated, 1,
1292 new_allocated - uid_allocated);
1293 uid_allocated = new_allocated;
1295 uid_unused[(unsigned) pw->pw_uid] = 0;
1297 endpwent ();
1299 #endif
1300 return true;
1303 static boolean
1304 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1306 (void) argv;
1307 (void) arg_ptr;
1308 (void) entry;
1310 options.warnings = false;
1311 return parse_noop(entry, argv, arg_ptr);
1314 static boolean
1315 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1317 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1320 static boolean
1321 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1323 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1326 boolean
1327 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1329 struct predicate *our_pred;
1331 (void) argv;
1332 (void) arg_ptr;
1334 our_pred = get_new_pred_chk_op (entry);
1335 our_pred->pred_func = pred_open;
1336 our_pred->p_type = OPEN_PAREN;
1337 our_pred->p_prec = NO_PREC;
1338 our_pred->need_stat = our_pred->need_type = false;
1339 return true;
1342 static boolean
1343 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1345 struct predicate *our_pred;
1347 (void) argv;
1348 (void) arg_ptr;
1350 our_pred = get_new_pred (entry);
1351 our_pred->pred_func = pred_or;
1352 our_pred->p_type = BI_OP;
1353 our_pred->p_prec = OR_PREC;
1354 our_pred->need_stat = our_pred->need_type = false;
1355 return true;
1358 /* -path is deprecated (at RMS's request) in favour of
1359 * -iwholename. See the node "GNU Manuals" in standards.texi
1360 * for the rationale for this (basically, GNU prefers the use
1361 * of the phrase "file name" to "path name".
1363 * We do not issue a warning that this usage is deprecated
1364 * since HPUX find supports this predicate also.
1366 static boolean
1367 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1369 return parse_wholename(entry, argv, arg_ptr);
1372 static boolean
1373 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1375 struct predicate *our_pred;
1377 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1378 return false;
1379 our_pred = insert_primary_withpred (entry, pred_path);
1380 our_pred->need_stat = our_pred->need_type = false;
1381 our_pred->args.str = argv[*arg_ptr];
1382 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1383 (*arg_ptr)++;
1384 return true;
1387 static boolean
1388 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1390 mode_t perm_val[2];
1391 float rate;
1392 int mode_start = 0;
1393 boolean havekind = false;
1394 enum permissions_type kind = PERM_EXACT;
1395 struct mode_change *change = NULL;
1396 struct predicate *our_pred;
1398 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1399 return false;
1401 switch (argv[*arg_ptr][0])
1403 case '-':
1404 mode_start = 1;
1405 kind = PERM_AT_LEAST;
1406 havekind = true;
1407 rate = 0.2;
1408 break;
1410 case '+':
1411 change = mode_compile (argv[*arg_ptr]);
1412 if (NULL == change)
1414 /* Most likely the caller is an old script that is still
1415 * using the obsolete GNU syntax '-perm +MODE'. This old
1416 * syntax was withdrawn in favor of '-perm /MODE' because
1417 * it is incompatible with POSIX in some cases, but we
1418 * still support uses of it that are not incompatible with
1419 * POSIX.
1421 mode_start = 1;
1422 kind = PERM_ANY;
1423 rate = 0.3;
1425 else
1427 /* This is a POSIX-compatible usage */
1428 mode_start = 0;
1429 kind = PERM_EXACT;
1430 rate = 0.1;
1432 havekind = true;
1433 break;
1435 case '/': /* GNU extension */
1436 mode_start = 1;
1437 kind = PERM_ANY;
1438 havekind = true;
1439 rate = 0.3;
1440 break;
1442 default:
1443 /* For example, '-perm 0644', which is valid and matches
1444 * only files whose mode is exactly 0644.
1446 mode_start = 0;
1447 kind = PERM_EXACT;
1448 havekind = true;
1449 rate = 0.01;
1450 break;
1453 if (NULL == change)
1455 change = mode_compile (argv[*arg_ptr] + mode_start);
1456 if (NULL == change)
1457 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1459 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1460 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1461 free (change);
1463 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1465 /* The meaning of -perm /000 will change in the future. It
1466 * currently matches no files, but like -perm -000 it should
1467 * match all files.
1469 * Starting in 2005, we used to issue a warning message
1470 * informing the user that the behaviour would change in the
1471 * future. We have now changed the behaviour and issue a
1472 * warning message that the behaviour recently changed.
1474 error (0, 0,
1475 _("warning: you have specified a mode pattern %s (which is "
1476 "equivalent to /000). The meaning of -perm /000 has now been "
1477 "changed to be consistent with -perm -000; that is, while it "
1478 "used to match no files, it now matches all files."),
1479 argv[*arg_ptr]);
1481 kind = PERM_AT_LEAST;
1482 havekind = true;
1484 /* The "magic" number below is just the fraction of files on my
1485 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1486 * Actual totals are 1472 and 1073833.
1488 rate = 0.9986; /* probably matches anything but a broken symlink */
1491 our_pred = insert_primary (entry);
1492 our_pred->est_success_rate = rate;
1493 if (havekind)
1495 our_pred->args.perm.kind = kind;
1497 else
1500 switch (argv[*arg_ptr][0])
1502 case '-':
1503 our_pred->args.perm.kind = PERM_AT_LEAST;
1504 break;
1505 case '+':
1506 our_pred->args.perm.kind = PERM_ANY;
1507 break;
1508 default:
1509 our_pred->args.perm.kind = PERM_EXACT;
1510 break;
1513 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1514 (*arg_ptr)++;
1515 return true;
1518 boolean
1519 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1521 struct predicate *our_pred;
1523 (void) argv;
1524 (void) arg_ptr;
1526 our_pred = insert_primary (entry);
1527 /* -print has the side effect of printing. This prevents us
1528 from doing undesired multiple printing when the user has
1529 already specified -print. */
1530 our_pred->side_effects = our_pred->no_default_print = true;
1531 our_pred->need_stat = our_pred->need_type = false;
1532 our_pred->args.printf_vec.segment = NULL;
1533 our_pred->args.printf_vec.stream = stdout;
1534 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1535 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1537 return true;
1540 static boolean
1541 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1543 struct predicate *our_pred;
1545 (void) argv;
1546 (void) arg_ptr;
1548 our_pred = insert_primary (entry);
1549 /* -print0 has the side effect of printing. This prevents us
1550 from doing undesired multiple printing when the user has
1551 already specified -print0. */
1552 our_pred->side_effects = our_pred->no_default_print = true;
1553 our_pred->need_stat = our_pred->need_type = false;
1554 return true;
1557 static boolean
1558 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1560 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1561 return false;
1562 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1565 static boolean
1566 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1568 struct predicate *our_pred;
1570 (void) argv;
1571 (void) arg_ptr;
1573 our_pred = insert_primary (entry);
1574 our_pred->need_stat = our_pred->need_type = false;
1575 /* -prune has a side effect that it does not descend into
1576 the current directory. */
1577 our_pred->side_effects = true;
1578 our_pred->no_default_print = false;
1579 return true;
1582 static boolean
1583 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1585 struct predicate *our_pred = insert_primary (entry);
1586 (void) argv;
1587 (void) arg_ptr;
1588 our_pred->need_stat = our_pred->need_type = false;
1589 our_pred->side_effects = true; /* Exiting is a side effect... */
1590 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1591 our_pred->est_success_rate = 1e-6;
1592 return true;
1596 static boolean
1597 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1599 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1600 return false;
1602 /* collect the regex type name */
1603 options.regex_options = get_regex_type(argv[*arg_ptr]);
1604 (*arg_ptr)++;
1606 return parse_noop(entry, argv, arg_ptr);
1610 static boolean
1611 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1613 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1616 static boolean
1617 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1619 struct predicate *our_pred;
1620 struct re_pattern_buffer *re;
1621 const char *error_message;
1623 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1624 return false;
1625 our_pred = insert_primary_withpred (entry, pred_regex);
1626 our_pred->need_stat = our_pred->need_type = false;
1627 re = (struct re_pattern_buffer *)
1628 xmalloc (sizeof (struct re_pattern_buffer));
1629 our_pred->args.regex = re;
1630 re->allocated = 100;
1631 re->buffer = (unsigned char *) xmalloc (re->allocated);
1632 re->fastmap = NULL;
1634 re_set_syntax(regex_options);
1635 re->syntax = regex_options;
1636 re->translate = NULL;
1638 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1639 re);
1640 if (error_message)
1641 error (1, 0, "%s", error_message);
1642 our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
1643 (*arg_ptr)++;
1644 return true;
1647 static boolean
1648 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1650 struct predicate *our_pred;
1651 uintmax_t num;
1652 enum comparison_type c_type;
1653 int blksize = 512;
1654 int len;
1656 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1657 return false;
1658 len = strlen (argv[*arg_ptr]);
1659 if (len == 0)
1660 error (1, 0, _("invalid null argument to -size"));
1661 switch (argv[*arg_ptr][len - 1])
1663 case 'b':
1664 blksize = 512;
1665 argv[*arg_ptr][len - 1] = '\0';
1666 break;
1668 case 'c':
1669 blksize = 1;
1670 argv[*arg_ptr][len - 1] = '\0';
1671 break;
1673 case 'k':
1674 blksize = 1024;
1675 argv[*arg_ptr][len - 1] = '\0';
1676 break;
1678 case 'M': /* Megabytes */
1679 blksize = 1024*1024;
1680 argv[*arg_ptr][len - 1] = '\0';
1681 break;
1683 case 'G': /* Gigabytes */
1684 blksize = 1024*1024*1024;
1685 argv[*arg_ptr][len - 1] = '\0';
1686 break;
1688 case 'w':
1689 blksize = 2;
1690 argv[*arg_ptr][len - 1] = '\0';
1691 break;
1693 case '0':
1694 case '1':
1695 case '2':
1696 case '3':
1697 case '4':
1698 case '5':
1699 case '6':
1700 case '7':
1701 case '8':
1702 case '9':
1703 break;
1705 default:
1706 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1708 /* TODO: accept fractional megabytes etc. ? */
1709 if (!get_num (argv[*arg_ptr], &num, &c_type))
1710 return false;
1711 our_pred = insert_primary (entry);
1712 our_pred->args.size.kind = c_type;
1713 our_pred->args.size.blocksize = blksize;
1714 our_pred->args.size.size = num;
1715 our_pred->need_stat = true;
1716 our_pred->need_type = false;
1718 if (COMP_GT == c_type)
1719 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1720 else if (COMP_LT == c_type)
1721 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1722 else
1723 our_pred->est_success_rate = 0.01;
1725 (*arg_ptr)++;
1726 return true;
1730 static boolean
1731 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1733 struct predicate *our_pred;
1734 struct stat st;
1736 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1737 return false;
1738 if ((*options.xstat) (argv[*arg_ptr], &st))
1739 error (1, errno, "%s", argv[*arg_ptr]);
1741 our_pred = insert_primary (entry);
1742 our_pred->args.fileid.ino = st.st_ino;
1743 our_pred->args.fileid.dev = st.st_dev;
1744 our_pred->need_type = false;
1745 our_pred->need_stat = true;
1746 our_pred->est_success_rate = 0.01f;
1747 (*arg_ptr)++;
1748 return true;
1751 #if 0
1752 static boolean
1753 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1755 const char *arg;
1756 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1757 "must be 'literal' or 'safe'");
1759 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1761 error (1, errno, "%s", errmsg);
1762 return false;
1764 else
1766 arg = argv[*arg_ptr];
1768 if (0 == strcmp("literal", arg))
1770 options.literal_control_chars = true;
1772 else if (0 == strcmp("safe", arg))
1774 options.literal_control_chars = false;
1776 else
1778 error (1, errno, "%s", errmsg);
1779 return false;
1781 (*arg_ptr)++; /* consume the argument. */
1782 return true;
1785 #endif
1788 static boolean
1789 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1791 struct predicate *our_pred;
1793 (void) argv;
1794 (void) arg_ptr;
1796 our_pred = insert_primary (entry);
1797 our_pred->need_stat = our_pred->need_type = false;
1798 our_pred->est_success_rate = 1.0f;
1799 return true;
1802 static boolean
1803 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
1805 (void) entry;
1806 return parse_true(get_noop(), argv, arg_ptr);
1809 static boolean
1810 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1812 struct predicate *our_pred;
1813 (void) argv;
1814 (void) arg_ptr;
1815 our_pred = insert_primary (entry);
1816 our_pred->need_stat = our_pred->need_type = false;
1817 our_pred->side_effects = our_pred->no_default_print = false;
1818 if (our_pred->pred_func == pred_executable)
1819 our_pred->est_success_rate = 0.2;
1820 else
1821 our_pred->est_success_rate = 0.9;
1822 return true;
1825 static boolean
1826 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1828 return insert_type (argv, arg_ptr, entry, pred_type);
1831 static boolean
1832 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1834 struct predicate *p = insert_num (argv, arg_ptr, entry);
1835 p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
1836 return p;
1839 static boolean
1840 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1842 struct predicate *our_pred;
1843 struct time_val tval;
1844 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
1846 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1847 return false;
1849 /* The timespec is actually a delta value, so we use an origin of 0. */
1850 if (!get_relative_timestamp(argv[*arg_ptr], &tval, 0, DAYSECS, errmsg))
1851 return false;
1853 our_pred = insert_primary (entry);
1854 our_pred->args.reftime = tval;
1855 our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
1856 (*arg_ptr)++;
1857 return true;
1860 static boolean
1861 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1863 struct passwd *cur_pwd;
1864 struct predicate *our_pred;
1865 uid_t uid;
1866 int uid_len;
1868 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1869 return false;
1870 cur_pwd = getpwnam (argv[*arg_ptr]);
1871 endpwent ();
1872 if (cur_pwd != NULL)
1873 uid = cur_pwd->pw_uid;
1874 else
1876 uid_len = strspn (argv[*arg_ptr], "0123456789");
1877 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1878 return false;
1879 uid = atoi (argv[*arg_ptr]);
1881 our_pred = insert_primary (entry);
1882 our_pred->args.uid = uid;
1883 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
1884 (*arg_ptr)++;
1885 return true;
1888 static boolean
1889 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1891 extern char *version_string;
1892 int features = 0;
1894 (void) argv;
1895 (void) arg_ptr;
1896 (void) entry;
1898 fflush (stderr);
1899 printf (_("GNU find version %s\n"), version_string);
1900 printf (_("Built using GNU gnulib version %s\n"), gnulib_version);
1901 printf (_("Features enabled: "));
1903 #if CACHE_IDS
1904 printf("CACHE_IDS ");
1905 ++features;
1906 #endif
1907 #if DEBUG
1908 printf("DEBUG ");
1909 ++features;
1910 #endif
1911 #if DEBUG_STAT
1912 printf("DEBUG_STAT ");
1913 ++features;
1914 #endif
1915 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1916 printf("D_TYPE ");
1917 ++features;
1918 #endif
1919 #if defined(O_NOFOLLOW)
1920 printf("O_NOFOLLOW(%s) ",
1921 (options.open_nofollow_available ? "enabled" : "disabled"));
1922 ++features;
1923 #endif
1924 #if defined(LEAF_OPTIMISATION)
1925 printf("LEAF_OPTIMISATION ");
1926 ++features;
1927 #endif
1929 if (is_fts_enabled())
1931 printf("FTS ");
1932 ++features;
1935 printf("CBO(level=%d) ", (int)(options.optimisation_level));
1936 ++features;
1938 if (0 == features)
1940 /* For the moment, leave this as English in case someone wants
1941 to parse these strings. */
1942 printf("none");
1944 printf("\n");
1946 exit (0);
1949 static boolean
1950 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1952 (void) argv;
1953 (void) arg_ptr;
1954 (void) entry;
1955 options.stay_on_filesystem = true;
1956 return parse_noop(entry, argv, arg_ptr);
1959 static boolean
1960 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1962 (void) argv;
1963 (void) arg_ptr;
1964 (void) entry;
1965 options.ignore_readdir_race = true;
1966 return parse_noop(entry, argv, arg_ptr);
1969 static boolean
1970 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1972 (void) argv;
1973 (void) arg_ptr;
1974 (void) entry;
1975 options.ignore_readdir_race = false;
1976 return parse_noop(entry, argv, arg_ptr);
1979 static boolean
1980 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1982 (void) argv;
1983 (void) arg_ptr;
1984 (void) entry;
1985 options.warnings = true;
1986 return parse_noop(entry, argv, arg_ptr);
1989 static boolean
1990 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1992 (void) argv;
1993 (void) arg_ptr;
1994 return insert_type (argv, arg_ptr, entry, pred_xtype);
1997 static boolean
1998 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2000 mode_t type_cell;
2001 struct predicate *our_pred;
2002 float rate = 0.5;
2004 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
2005 || (strlen (argv[*arg_ptr]) != 1))
2006 return false;
2007 switch (argv[*arg_ptr][0])
2009 case 'b': /* block special */
2010 type_cell = S_IFBLK;
2011 rate = 0.01f;
2012 break;
2013 case 'c': /* character special */
2014 type_cell = S_IFCHR;
2015 rate = 0.01f;
2016 break;
2017 case 'd': /* directory */
2018 type_cell = S_IFDIR;
2019 rate = 0.4f;
2020 break;
2021 case 'f': /* regular file */
2022 type_cell = S_IFREG;
2023 rate = 0.95f;
2024 break;
2025 #ifdef S_IFLNK
2026 case 'l': /* symbolic link */
2027 type_cell = S_IFLNK;
2028 rate = 0.1f;
2029 break;
2030 #endif
2031 #ifdef S_IFIFO
2032 case 'p': /* pipe */
2033 type_cell = S_IFIFO;
2034 rate = 0.01f;
2035 break;
2036 #endif
2037 #ifdef S_IFSOCK
2038 case 's': /* socket */
2039 type_cell = S_IFSOCK;
2040 rate = 0.01f;
2041 break;
2042 #endif
2043 #ifdef S_IFDOOR
2044 case 'D': /* Solaris door */
2045 type_cell = S_IFDOOR;
2046 rate = 0.01f;
2047 break;
2048 #endif
2049 default: /* None of the above ... nuke 'em. */
2050 return false;
2052 our_pred = insert_primary_withpred (entry, which_pred);
2053 our_pred->est_success_rate = rate;
2055 /* Figure out if we will need to stat the file, because if we don't
2056 * need to follow symlinks, we can avoid a stat call by using
2057 * struct dirent.d_type.
2059 if (which_pred == pred_xtype)
2061 our_pred->need_stat = true;
2062 our_pred->need_type = false;
2064 else
2066 our_pred->need_stat = false; /* struct dirent is enough */
2067 our_pred->need_type = true;
2069 our_pred->args.type = type_cell;
2070 (*arg_ptr)++; /* Move on to next argument. */
2071 return true;
2075 /* Return true if the file accessed via FP is a terminal.
2077 static boolean
2078 stream_is_tty(FILE *fp)
2080 int fd = fileno(fp);
2081 if (-1 == fd)
2083 return false; /* not a valid stream */
2085 else
2087 return isatty(fd) ? true : false;
2095 /* XXX: do we need to pass FUNC to this function? */
2096 static boolean
2097 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
2099 char *format; /* Beginning of unprocessed format string. */
2100 register char *scan; /* Current address in scanning `format'. */
2101 register char *scan2; /* Address inside of element being scanned. */
2102 struct segment **segmentp; /* Address of current segment. */
2103 struct predicate *our_pred;
2105 format = argv[(*arg_ptr)++];
2107 our_pred = insert_primary_withpred (entry, func);
2108 our_pred->side_effects = our_pred->no_default_print = true;
2109 our_pred->args.printf_vec.stream = fp;
2110 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
2111 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2112 our_pred->need_type = false;
2113 our_pred->need_stat = false;
2114 our_pred->p_cost = NeedsNothing;
2116 segmentp = &our_pred->args.printf_vec.segment;
2117 *segmentp = NULL;
2119 for (scan = format; *scan; scan++)
2121 if (*scan == '\\')
2123 scan2 = scan + 1;
2124 if (*scan2 >= '0' && *scan2 <= '7')
2126 register int n, i;
2128 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2129 i++, scan2++)
2130 n = 8 * n + *scan2 - '0';
2131 scan2--;
2132 *scan = n;
2134 else
2136 switch (*scan2)
2138 case 'a':
2139 *scan = 7;
2140 break;
2141 case 'b':
2142 *scan = '\b';
2143 break;
2144 case 'c':
2145 make_segment (segmentp, format, scan - format,
2146 KIND_STOP, 0, 0,
2147 our_pred);
2148 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2149 our_pred->p_cost = NeedsStatInfo;
2150 return true;
2151 case 'f':
2152 *scan = '\f';
2153 break;
2154 case 'n':
2155 *scan = '\n';
2156 break;
2157 case 'r':
2158 *scan = '\r';
2159 break;
2160 case 't':
2161 *scan = '\t';
2162 break;
2163 case 'v':
2164 *scan = '\v';
2165 break;
2166 case '\\':
2167 /* *scan = '\\'; * it already is */
2168 break;
2169 default:
2170 error (0, 0,
2171 _("warning: unrecognized escape `\\%c'"), *scan2);
2172 scan++;
2173 continue;
2176 segmentp = make_segment (segmentp, format, scan - format + 1,
2177 KIND_PLAIN, 0, 0,
2178 our_pred);
2179 format = scan2 + 1; /* Move past the escape. */
2180 scan = scan2; /* Incremented immediately by `for'. */
2182 else if (*scan == '%')
2184 if (scan[1] == 0)
2186 /* Trailing %. We don't like those. */
2187 error (1, 0, _("error: %s at end of format string"), scan);
2189 else if (scan[1] == '%')
2191 segmentp = make_segment (segmentp, format, scan - format + 1,
2192 KIND_PLAIN, 0, 0,
2193 our_pred);
2194 scan++;
2195 format = scan + 1;
2196 continue;
2198 /* Scan past flags, width and precision, to verify kind. */
2199 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2200 /* Do nothing. */ ;
2201 while (ISDIGIT (*scan2))
2202 scan2++;
2203 if (*scan2 == '.')
2204 for (scan2++; ISDIGIT (*scan2); scan2++)
2205 /* Do nothing. */ ;
2206 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2208 segmentp = make_segment (segmentp, format, scan2 - format,
2209 KIND_FORMAT, *scan2, 0,
2210 our_pred);
2211 scan = scan2;
2212 format = scan + 1;
2214 else if (strchr ("ACT", *scan2) && scan2[1])
2216 segmentp = make_segment (segmentp, format, scan2 - format,
2217 KIND_FORMAT, scan2[0], scan2[1],
2218 our_pred);
2219 scan = scan2 + 1;
2220 format = scan + 1;
2221 continue;
2223 else
2225 /* An unrecognized % escape. Print the char after the %. */
2226 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2227 *scan2);
2228 segmentp = make_segment (segmentp, format, scan - format,
2229 KIND_PLAIN, 0, 0,
2230 our_pred);
2231 format = scan + 1;
2232 continue;
2237 if (scan > format)
2238 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2239 our_pred);
2240 return true;
2243 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2244 from the text in FORMAT, which has length LEN.
2245 Return the address of the `next' pointer of the new segment. */
2247 static struct segment **
2248 make_segment (struct segment **segment,
2249 char *format,
2250 int len,
2251 int kind,
2252 char format_char,
2253 char aux_format_char,
2254 struct predicate *pred)
2256 enum EvaluationCost mycost = NeedsNothing;
2257 char *fmt;
2259 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2261 (*segment)->segkind = kind;
2262 (*segment)->format_char[0] = format_char;
2263 (*segment)->format_char[1] = aux_format_char;
2264 (*segment)->next = NULL;
2265 (*segment)->text_len = len;
2267 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2268 strncpy (fmt, format, len);
2269 fmt += len;
2271 switch (kind)
2273 case KIND_PLAIN: /* Plain text string, no % conversion. */
2274 case KIND_STOP: /* Terminate argument, no newline. */
2275 assert(0 == format_char);
2276 assert(0 == aux_format_char);
2277 *fmt = '\0';
2278 if (mycost > pred->p_cost)
2279 pred->p_cost = NeedsNothing;
2280 return &(*segment)->next;
2281 break;
2284 assert(kind == KIND_FORMAT);
2285 switch (format_char)
2287 case 'l': /* object of symlink */
2288 pred->need_stat = true;
2289 mycost = NeedsLinkName;
2290 *fmt++ = 's';
2291 break;
2293 case 'y': /* file type */
2294 pred->need_type = true;
2295 mycost = NeedsType;
2296 *fmt++ = 's';
2297 break;
2299 case 'a': /* atime in `ctime' format */
2300 case 'A': /* atime in user-specified strftime format */
2301 case 'c': /* ctime in `ctime' format */
2302 case 'C': /* ctime in user-specified strftime format */
2303 case 'F': /* filesystem type */
2304 case 'g': /* group name */
2305 case 'i': /* inode number */
2306 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2307 case 's': /* size in bytes */
2308 case 't': /* mtime in `ctime' format */
2309 case 'T': /* mtime in user-specified strftime format */
2310 case 'u': /* user name */
2311 pred->need_stat = true;
2312 mycost = NeedsStatInfo;
2313 *fmt++ = 's';
2314 break;
2316 case 'S': /* sparseness */
2317 pred->need_stat = true;
2318 mycost = NeedsStatInfo;
2319 *fmt++ = 'g';
2320 break;
2322 case 'Y': /* symlink pointed file type */
2323 pred->need_stat = true;
2324 mycost = NeedsType; /* true for amortised effect */
2325 *fmt++ = 's';
2326 break;
2328 case 'f': /* basename of path */
2329 case 'h': /* leading directories part of path */
2330 case 'p': /* pathname */
2331 case 'P': /* pathname with ARGV element stripped */
2332 *fmt++ = 's';
2333 break;
2335 case 'H': /* ARGV element file was found under */
2336 *fmt++ = 's';
2337 break;
2339 /* Numeric items that one might expect to honour
2340 * #, 0, + flags but which do not.
2342 case 'G': /* GID number */
2343 case 'U': /* UID number */
2344 case 'b': /* size in 512-byte blocks */
2345 case 'D': /* Filesystem device on which the file exits */
2346 case 'k': /* size in 1K blocks */
2347 case 'n': /* number of links */
2348 pred->need_stat = true;
2349 mycost = NeedsStatInfo;
2350 *fmt++ = 's';
2351 break;
2353 /* Numeric items that DO honour #, 0, + flags.
2355 case 'd': /* depth in search tree (0 = ARGV element) */
2356 *fmt++ = 'd';
2357 break;
2359 case 'm': /* mode as octal number (perms only) */
2360 *fmt++ = 'o';
2361 pred->need_stat = true;
2362 mycost = NeedsStatInfo;
2363 break;
2365 case '{':
2366 case '[':
2367 case '(':
2368 error (1, 0,
2369 _("error: the format directive `%%%c' is reserved for future use"),
2370 (int)kind);
2371 /*NOTREACHED*/
2372 break;
2374 *fmt = '\0';
2376 if (mycost > pred->p_cost)
2377 pred->p_cost = mycost;
2378 return &(*segment)->next;
2381 static void
2382 check_path_safety(const char *action, char **argv)
2384 const char *path = getenv("PATH");
2386 (void)argv;
2388 char *s;
2389 s = next_element(path, 1);
2390 while ((s = next_element ((char *) NULL, 1)) != NULL)
2392 if (0 == strcmp(s, "."))
2394 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)"),
2395 action);
2397 else if ('/' != s[0])
2399 /* Relative paths are also dangerous in $PATH. */
2400 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"),
2401 s, action);
2407 /* handles both exec and ok predicate */
2408 static boolean
2409 new_insert_exec_ok (const char *action,
2410 const struct parser_table *entry,
2411 char **argv,
2412 int *arg_ptr)
2414 int start, end; /* Indexes in ARGV of start & end of cmd. */
2415 int i; /* Index into cmd args */
2416 int saw_braces; /* True if previous arg was '{}'. */
2417 boolean allow_plus; /* True if + is a valid terminator */
2418 int brace_count; /* Number of instances of {}. */
2419 PRED_FUNC func = entry->pred_func;
2420 enum BC_INIT_STATUS bcstatus;
2422 struct predicate *our_pred;
2423 struct exec_val *execp; /* Pointer for efficiency. */
2425 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2426 return false;
2428 our_pred = insert_primary_withpred (entry, func);
2429 our_pred->side_effects = our_pred->no_default_print = true;
2430 our_pred->need_type = our_pred->need_stat = false;
2432 execp = &our_pred->args.exec_vec;
2434 if ((func != pred_okdir) && (func != pred_ok))
2436 allow_plus = true;
2437 execp->close_stdin = false;
2439 else
2441 allow_plus = false;
2442 /* If find reads stdin (i.e. for -ok and similar), close stdin
2443 * in the child to prevent some script from consiming the output
2444 * intended for find.
2446 execp->close_stdin = true;
2450 if ((func == pred_execdir) || (func == pred_okdir))
2452 options.ignore_readdir_race = false;
2453 check_path_safety(action, argv);
2454 execp->use_current_dir = true;
2456 else
2458 execp->use_current_dir = false;
2461 our_pred->args.exec_vec.multiple = 0;
2463 /* Count the number of args with path replacements, up until the ';'.
2464 * Also figure out if the command is terminated by ";" or by "+".
2466 start = *arg_ptr;
2467 for (end = start, saw_braces=0, brace_count=0;
2468 (argv[end] != NULL)
2469 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2470 end++)
2472 /* For -exec and -execdir, "{} +" can terminate the command. */
2473 if ( allow_plus
2474 && argv[end][0] == '+' && argv[end][1] == 0
2475 && saw_braces)
2477 our_pred->args.exec_vec.multiple = 1;
2478 break;
2481 saw_braces = 0;
2482 if (strstr (argv[end], "{}"))
2484 saw_braces = 1;
2485 ++brace_count;
2487 if (0 == end && (func == pred_execdir || func == pred_okdir))
2489 /* The POSIX standard says that {} replacement should
2490 * occur even in the utility name. This is insecure
2491 * since it means we will be executing a command whose
2492 * name is chosen according to whatever find finds in
2493 * the filesystem. That can be influenced by an
2494 * attacker. Hence for -execdir and -okdir this is not
2495 * allowed. We can specify this as those options are
2496 * not defined by POSIX.
2498 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2503 /* Fail if no command given or no semicolon found. */
2504 if ((end == start) || (argv[end] == NULL))
2506 *arg_ptr = end;
2507 free(our_pred);
2508 return false;
2511 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2514 const char *suffix;
2515 if (func == pred_execdir)
2516 suffix = "dir";
2517 else
2518 suffix = "";
2520 error(1, 0,
2521 _("Only one instance of {} is supported with -exec%s ... +"),
2522 suffix);
2525 /* We use a switch statement here so that
2526 * the compiler warns us when we forget to handle a
2527 * newly invented enum value.
2529 bcstatus = bc_init_controlinfo(&execp->ctl);
2530 switch (bcstatus)
2532 case BC_INIT_ENV_TOO_BIG:
2533 error(1, 0,
2534 _("The environment is too large for exec()."));
2535 break;
2536 case BC_INIT_OK:
2537 /* Good news. Carry on. */
2538 break;
2540 bc_use_sensible_arg_max(&execp->ctl);
2543 execp->ctl.exec_callback = launch;
2545 if (our_pred->args.exec_vec.multiple)
2547 /* "+" terminator, so we can just append our arguments after the
2548 * command and initial arguments.
2550 execp->replace_vec = NULL;
2551 execp->ctl.replace_pat = NULL;
2552 execp->ctl.rplen = 0;
2553 execp->ctl.lines_per_exec = 0; /* no limit */
2554 execp->ctl.args_per_exec = 0; /* no limit */
2556 /* remember how many arguments there are */
2557 execp->ctl.initial_argc = (end-start) - 1;
2559 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2560 bc_init_state(&execp->ctl, &execp->state, execp);
2562 /* Gather the initial arguments. Skip the {}. */
2563 for (i=start; i<end-1; ++i)
2565 bc_push_arg(&execp->ctl, &execp->state,
2566 argv[i], strlen(argv[i])+1,
2567 NULL, 0,
2571 else
2573 /* Semicolon terminator - more than one {} is supported, so we
2574 * have to do brace-replacement.
2576 execp->num_args = end - start;
2578 execp->ctl.replace_pat = "{}";
2579 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2580 execp->ctl.lines_per_exec = 0; /* no limit */
2581 execp->ctl.args_per_exec = 0; /* no limit */
2582 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2585 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2586 bc_init_state(&execp->ctl, &execp->state, execp);
2588 /* Remember the (pre-replacement) arguments for later. */
2589 for (i=0; i<execp->num_args; ++i)
2591 execp->replace_vec[i] = argv[i+start];
2595 if (argv[end] == NULL)
2596 *arg_ptr = end;
2597 else
2598 *arg_ptr = end + 1;
2600 return true;
2605 static boolean
2606 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2608 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2613 /* Get a timestamp and comparison type.
2615 STR is the ASCII representation.
2616 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
2617 relative to ORIGIN (usually the current moment or midnight).
2618 Thus the sense of the comparison type appears to be reversed.
2619 Set *COMP_TYPE to the kind of comparison that is requested.
2620 Issue OVERFLOWMESSAGE if overflow occurs.
2621 Return true if all okay, false if input error.
2623 Used by -atime, -ctime and -mtime (parsers) to
2624 get the appropriate information for a time predicate processor. */
2626 static boolean
2627 get_relative_timestamp (char *str,
2628 struct time_val *result,
2629 time_t origin,
2630 double sec_per_unit,
2631 const char *overflowmessage)
2633 uintmax_t checkval;
2634 double offset, seconds, f;
2636 if (get_comp_type(&str, &result->kind))
2638 /* Invert the sense of the comparison */
2639 switch (result->kind)
2641 case COMP_LT: result->kind = COMP_GT; break;
2642 case COMP_GT: result->kind = COMP_LT; break;
2643 default: break;
2646 /* Convert the ASCII number into floating-point. */
2647 if (xstrtod(str, NULL, &offset, strtod))
2649 /* Separate the floating point number the user specified
2650 * (which is a number of days, or minutes, etc) into an
2651 * integral number of seconds (SECONDS) and a fraction (F).
2653 f = modf(offset * sec_per_unit, &seconds);
2655 result->ts.tv_sec = origin - seconds;
2656 result->ts.tv_nsec = fabs(f * 1e9);
2658 /* Check for overflow. */
2659 checkval = (uintmax_t)origin - seconds;
2660 if (checkval != result->ts.tv_sec)
2662 /* an overflow has occurred. */
2663 error (1, 0, overflowmessage, str);
2665 return true;
2667 else
2669 /* Conversion from ASCII to double failed. */
2670 return false;
2673 else
2675 return false;
2679 /* Insert a time predicate based on the information in ENTRY.
2680 ARGV is a pointer to the argument array.
2681 ARG_PTR is a pointer to an index into the array, incremented if
2682 all went well.
2684 Return true if input is valid, false if not.
2686 A new predicate node is assigned, along with an argument node
2687 obtained with malloc.
2689 Used by -atime, -ctime, and -mtime parsers. */
2691 static boolean
2692 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
2694 struct predicate *our_pred;
2695 struct time_val tval;
2696 enum comparison_type comp;
2697 char *s;
2698 const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
2699 time_t origin;
2701 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2702 return false;
2704 /* Decide the origin by previewing the comparison type. */
2705 origin = options.cur_day_start;
2706 s = argv[*arg_ptr];
2707 if (get_comp_type(&s, &comp))
2709 /* Remember, we invert the sense of the comparison, so this tests against COMP_LT instead of COMP_GT... */
2710 if (COMP_LT == tval.kind)
2712 uintmax_t expected = origin + (DAYSECS-1);
2713 origin += (DAYSECS-1);
2714 if (origin != expected)
2716 error(1, 0,
2717 _("arithmetic overflow when trying to calculate the end of today"));
2720 /* We discard the value of comp here, as get_relative_timestamp
2721 * will set tval.kind.
2725 if (!get_relative_timestamp(argv[*arg_ptr], &tval, origin, DAYSECS, errmsg))
2726 return false;
2728 our_pred = insert_primary (entry);
2729 our_pred->args.reftime = tval;
2730 our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
2731 (*arg_ptr)++;
2733 if (options.debug_options & DebugExpressionTree)
2735 time_t t;
2737 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2738 fprintf (stderr, " type: %s %s ",
2739 (tval.kind == COMP_GT) ? "gt" :
2740 ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
2741 (tval.kind == COMP_GT) ? " >" :
2742 ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
2743 t = our_pred->args.reftime.ts.tv_sec;
2744 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
2745 if (tval.kind == COMP_EQ)
2747 t = our_pred->args.reftime.ts.tv_sec += DAYSECS;
2748 fprintf (stderr, " < %ju %s",
2749 (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
2750 our_pred->args.reftime.ts.tv_sec -= DAYSECS;
2754 return true;
2757 /* Get the comparison type prefix (if any) from a number argument.
2758 The prefix is at *STR.
2759 Set *COMP_TYPE to the kind of comparison that is requested.
2760 Advance *STR beyond any initial comparison prefix.
2762 Return true if all okay, false if input error. */
2763 static boolean
2764 get_comp_type(char **str, enum comparison_type *comp_type)
2766 switch (**str)
2768 case '+':
2769 *comp_type = COMP_GT;
2770 (*str)++;
2771 break;
2772 case '-':
2773 *comp_type = COMP_LT;
2774 (*str)++;
2775 break;
2776 default:
2777 *comp_type = COMP_EQ;
2778 break;
2780 return true;
2787 /* Get a number with comparison information.
2788 The sense of the comparison information is 'normal'; that is,
2789 '+' looks for a count > than the number and '-' less than.
2791 STR is the ASCII representation of the number.
2792 Set *NUM to the number.
2793 Set *COMP_TYPE to the kind of comparison that is requested.
2795 Return true if all okay, false if input error. */
2797 static boolean
2798 get_num (char *str,
2799 uintmax_t *num,
2800 enum comparison_type *comp_type)
2802 char *pend;
2804 if (str == NULL)
2805 return false;
2807 /* Figure out the comparison type if the caller accepts one. */
2808 if (comp_type)
2810 if (!get_comp_type(&str, comp_type))
2811 return false;
2814 return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
2817 /* Insert a number predicate.
2818 ARGV is a pointer to the argument array.
2819 *ARG_PTR is an index into ARGV, incremented if all went well.
2820 *PRED is the predicate processor to insert.
2822 Return true if input is valid, false if error.
2824 A new predicate node is assigned, along with an argument node
2825 obtained with malloc.
2827 Used by -inum and -links parsers. */
2829 static struct predicate *
2830 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2832 struct predicate *our_pred;
2833 uintmax_t num;
2834 enum comparison_type c_type;
2836 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2837 return NULL;
2838 if (!get_num (argv[*arg_ptr], &num, &c_type))
2839 return NULL;
2840 our_pred = insert_primary (entry);
2841 our_pred->args.numinfo.kind = c_type;
2842 our_pred->args.numinfo.l_val = num;
2843 (*arg_ptr)++;
2845 if (options.debug_options & DebugExpressionTree)
2847 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2848 fprintf (stderr, " type: %s %s ",
2849 (c_type == COMP_GT) ? "gt" :
2850 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2851 (c_type == COMP_GT) ? " >" :
2852 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2853 fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
2855 return our_pred;
2858 static FILE *
2859 open_output_file (char *path)
2861 FILE *f;
2863 if (!strcmp (path, "/dev/stderr"))
2864 return stderr;
2865 else if (!strcmp (path, "/dev/stdout"))
2866 return stdout;
2867 f = fopen_safer (path, "w");
2868 if (f == NULL)
2869 error (1, errno, "%s", path);
2870 return f;