Changed the interpretatioon of -perm /000 as described in bug #14748
[findutils.git] / find / parser.c
blob7397b0c660aba055ba5bf32a6ca08499bb010fed
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 <assert.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <fnmatch.h>
28 #include "modechange.h"
29 #include "modetype.h"
30 #include "xstrtol.h"
31 #include "xalloc.h"
32 #include "quote.h"
33 #include "quotearg.h"
34 #include "buildcmd.h"
35 #include "nextelem.h"
36 #include "stdio-safer.h"
37 #include "regextype.h"
39 #ifdef HAVE_FCNTL_H
40 #include <fcntl.h>
41 #else
42 #include <sys/file.h>
43 #endif
45 /* The presence of unistd.h is assumed by gnulib these days, so we
46 * might as well assume it too.
48 /* We need <unistd.h> for isatty(). */
49 #include <unistd.h>
51 #if ENABLE_NLS
52 # include <libintl.h>
53 # define _(Text) gettext (Text)
54 #else
55 # define _(Text) Text
56 #endif
57 #ifdef gettext_noop
58 # define N_(String) gettext_noop (String)
59 #else
60 /* See locate.c for explanation as to why not use (String) */
61 # define N_(String) String
62 #endif
64 #if !defined (isascii) || defined (STDC_HEADERS)
65 #ifdef isascii
66 #undef isascii
67 #endif
68 #define isascii(c) 1
69 #endif
71 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
72 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
74 #ifndef HAVE_ENDGRENT
75 #define endgrent()
76 #endif
77 #ifndef HAVE_ENDPWENT
78 #define endpwent()
79 #endif
81 static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
82 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
83 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
84 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
85 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
86 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
87 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 #if 0
136 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 #endif
138 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
157 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
158 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
159 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
161 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len,
162 int kind, char format_char, char aux_format_char,
163 struct predicate *pred));
164 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
165 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
166 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
167 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
168 static FILE *open_output_file PARAMS((char *path));
169 static boolean stream_is_tty(FILE *fp);
170 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
172 #define PASTE(x,y) x##y
173 #define STRINGIFY(s) #s
175 #define PARSE_OPTION(what,suffix) \
176 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
178 #define PARSE_POSOPT(what,suffix) \
179 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
181 #define PARSE_TEST(what,suffix) \
182 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
184 #define PARSE_TEST_NP(what,suffix) \
185 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
187 #define PARSE_ACTION(what,suffix) \
188 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
190 #define PARSE_ACTION_NP(what,suffix) \
191 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
193 #define PARSE_PUNCTUATION(what,suffix) \
194 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
197 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
198 If they are in some Unix versions of find, they are marked `Unix'. */
200 static struct parser_table const parse_table[] =
202 PARSE_PUNCTUATION("!", negate),
203 PARSE_PUNCTUATION("not", negate), /* GNU */
204 PARSE_PUNCTUATION("(", open),
205 PARSE_PUNCTUATION(")", close),
206 PARSE_PUNCTUATION(",", comma), /* GNU */
207 PARSE_PUNCTUATION("a", and),
208 PARSE_TEST ("amin", amin), /* GNU */
209 PARSE_PUNCTUATION("and", and), /* GNU */
210 PARSE_TEST ("anewer", anewer), /* GNU */
211 {ARG_TEST, "atime", parse_time, pred_atime},
212 PARSE_TEST ("cmin", cmin), /* GNU */
213 PARSE_TEST ("cnewer", cnewer), /* GNU */
214 {ARG_TEST, "ctime", parse_time, pred_ctime},
215 PARSE_POSOPT ("daystart", daystart), /* GNU */
216 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
217 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
218 PARSE_OPTION ("depth", depth),
219 PARSE_TEST ("empty", empty), /* GNU */
220 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
221 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
222 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
223 PARSE_ACTION ("fls", fls), /* GNU */
224 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
225 PARSE_ACTION ("fprint", fprint), /* GNU */
226 PARSE_ACTION ("fprint0", fprint0), /* GNU */
227 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
228 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
229 PARSE_TEST ("gid", gid), /* GNU */
230 PARSE_TEST ("group", group),
231 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
232 PARSE_TEST ("ilname", ilname), /* GNU */
233 PARSE_TEST ("iname", iname), /* GNU */
234 PARSE_TEST ("inum", inum), /* GNU, Unix */
235 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
236 PARSE_TEST_NP ("iregex", iregex), /* GNU */
237 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
238 PARSE_TEST ("links", links),
239 PARSE_TEST ("lname", lname), /* GNU */
240 PARSE_ACTION ("ls", ls), /* GNU, Unix */
241 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
242 PARSE_OPTION ("mindepth", mindepth), /* GNU */
243 PARSE_TEST ("mmin", mmin), /* GNU */
244 PARSE_OPTION ("mount", xdev), /* Unix */
245 {ARG_TEST, "mtime", parse_time, pred_mtime},
246 PARSE_TEST ("name", name),
247 #ifdef UNIMPLEMENTED_UNIX
248 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
249 #endif
250 PARSE_TEST ("newer", newer),
251 PARSE_OPTION ("noleaf", noleaf), /* GNU */
252 PARSE_TEST ("nogroup", nogroup),
253 PARSE_TEST ("nouser", nouser),
254 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
255 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
256 PARSE_PUNCTUATION("o", or),
257 PARSE_PUNCTUATION("or", or), /* GNU */
258 PARSE_ACTION ("ok", ok),
259 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
260 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
261 PARSE_TEST ("perm", perm),
262 PARSE_ACTION ("print", print),
263 PARSE_ACTION ("print0", print0), /* GNU */
264 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
265 PARSE_ACTION ("prune", prune),
266 PARSE_ACTION ("quit", quit), /* GNU */
267 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
268 PARSE_TEST ("regex", regex), /* GNU */
269 PARSE_OPTION ("regextype", regextype), /* GNU */
270 PARSE_TEST ("samefile", samefile), /* GNU */
271 #if 0
272 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
273 #endif
274 PARSE_TEST ("size", size),
275 PARSE_TEST ("type", type),
276 PARSE_TEST ("uid", uid), /* GNU */
277 PARSE_TEST ("used", used), /* GNU */
278 PARSE_TEST ("user", user),
279 PARSE_OPTION ("warn", warn), /* GNU */
280 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
281 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
282 PARSE_OPTION ("xdev", xdev),
283 PARSE_TEST ("xtype", xtype), /* GNU */
284 #ifdef UNIMPLEMENTED_UNIX
285 /* It's pretty ugly for find to know about archive formats.
286 Plus what it could do with cpio archives is very limited.
287 Better to leave it out. */
288 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
289 #endif
290 /* gnulib's stdbool.h might have made true and false into macros,
291 * so we can't leave named 'true' and 'false' tokens, so we have
292 * to expeant the relevant entries longhand.
294 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
295 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
296 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
298 /* Various other cases that don't fit neatly into our macro scheme. */
299 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
300 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
301 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
302 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
303 {0, 0, 0, 0}
307 static const char *first_nonoption_arg = NULL;
308 static const struct parser_table *noop = NULL;
312 static const struct parser_table*
313 get_noop(void)
315 int i;
316 if (NULL == noop)
318 for (i = 0; parse_table[i].parser_name != 0; i++)
320 if (ARG_NOOP ==parse_table[i].type)
322 noop = &(parse_table[i]);
323 break;
327 return noop;
332 void
333 set_follow_state(enum SymlinkOption opt)
335 if (options.debug_options & DebugStat)
337 /* For DebugStat, the choice is made at runtime within debug_stat()
338 * by checking the contents of the symlink_handling variable.
340 options.xstat = debug_stat;
342 else
344 switch (opt)
346 case SYMLINK_ALWAYS_DEREF: /* -L */
347 options.xstat = optionl_stat;
348 options.no_leaf_check = true;
349 break;
351 case SYMLINK_NEVER_DEREF: /* -P (default) */
352 options.xstat = optionp_stat;
353 /* Can't turn no_leaf_check off because the user might have specified
354 * -noleaf anyway
356 break;
358 case SYMLINK_DEREF_ARGSONLY: /* -H */
359 options.xstat = optionh_stat;
360 options.no_leaf_check = true;
363 options.symlink_handling = opt;
367 void
368 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
370 (void) args;
371 (void) argno;
372 (void) last;
373 (void) predicates;
374 first_nonoption_arg = NULL;
377 void
378 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
380 /* does nothing */
381 (void) args;
382 (void) argno;
383 (void) last;
384 (void) predicates;
390 /* Return a pointer to the parser function to invoke for predicate
391 SEARCH_NAME.
392 Return NULL if SEARCH_NAME is not a valid predicate name. */
394 const struct parser_table*
395 find_parser (char *search_name)
397 int i;
398 const char *original_arg = search_name;
400 if (*search_name == '-')
401 search_name++;
402 for (i = 0; parse_table[i].parser_name != 0; i++)
404 if (strcmp (parse_table[i].parser_name, search_name) == 0)
406 /* If this is an option, but we have already had a
407 * non-option argument, the user may be under the
408 * impression that the behaviour of the option
409 * argument is conditional on some preceding
410 * tests. This might typically be the case with,
411 * for example, -maxdepth.
413 * The options -daystart and -follow are exempt
414 * from this treatment, since their positioning
415 * in the command line does have an effect on
416 * subsequent tests but not previous ones. That
417 * might be intentional on the part of the user.
419 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
421 /* Something other than -follow/-daystart.
422 * If this is an option, check if it followed
423 * a non-option and if so, issue a warning.
425 if (parse_table[i].type == ARG_OPTION)
427 if ((first_nonoption_arg != NULL)
428 && options.warnings )
430 /* option which follows a non-option */
431 error (0, 0,
432 _("warning: you have specified the %s "
433 "option after a non-option argument %s, "
434 "but options are not positional (%s affects "
435 "tests specified before it as well as those "
436 "specified after it). Please specify options "
437 "before other arguments.\n"),
438 original_arg,
439 first_nonoption_arg,
440 original_arg);
443 else
445 /* Not an option or a positional option,
446 * so remember we've seen it in order to
447 * use it in a possible future warning message.
449 if (first_nonoption_arg == NULL)
451 first_nonoption_arg = original_arg;
456 return &parse_table[i];
459 return NULL;
462 static float
463 estimate_file_age_success_rate(float num_days)
465 if (num_days < 0.1)
467 /* Assume 1% of files have timestamps in the future */
468 return 0.01f;
470 else if (num_days < 1)
472 /* Assume 30% of files have timestamps today */
473 return 0.3f;
475 else if (num_days > 100)
477 /* Assume 30% of files are very old */
478 return 0.3f;
480 else
482 /* Assume 39% of files are between 1 and 100 days old. */
483 return 0.39f;
487 static float
488 estimate_timestamp_success_rate(time_t when)
490 int num_days = (when - options.cur_day_start) / 86400;
491 return estimate_file_age_success_rate(num_days);
495 /* The parsers are responsible to continue scanning ARGV for
496 their arguments. Each parser knows what is and isn't
497 allowed for itself.
499 ARGV is the argument array.
500 *ARG_PTR is the index to start at in ARGV,
501 updated to point beyond the last element consumed.
503 The predicate structure is updated with the new information. */
505 static boolean
506 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
508 struct predicate *our_pred;
509 uintmax_t num;
510 enum comparison_type c_type;
511 time_t t;
513 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
514 return false;
515 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
516 return false;
517 t = options.cur_day_start + DAYSECS - num * 60;
518 our_pred = insert_primary (entry);
519 our_pred->args.info.kind = c_type;
520 our_pred->args.info.negative = t < 0;
521 our_pred->args.info.l_val = t;
522 our_pred->est_success_rate = estimate_file_age_success_rate(num);
523 (*arg_ptr)++;
524 return true;
527 static boolean
528 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
530 struct predicate *our_pred;
532 (void) argv;
533 (void) arg_ptr;
535 our_pred = get_new_pred (entry);
536 our_pred->pred_func = pred_and;
537 our_pred->p_type = BI_OP;
538 our_pred->p_prec = AND_PREC;
539 our_pred->need_stat = our_pred->need_type = false;
540 return true;
543 static boolean
544 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
546 struct predicate *our_pred;
547 struct stat stat_newer;
549 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
550 return false;
551 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
552 error (1, errno, "%s", argv[*arg_ptr]);
553 our_pred = insert_primary (entry);
554 our_pred->args.time = stat_newer.st_mtime;
555 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
556 (*arg_ptr)++;
557 return true;
560 boolean
561 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
563 struct predicate *our_pred;
565 (void) argv;
566 (void) arg_ptr;
568 our_pred = get_new_pred (entry);
569 our_pred->pred_func = pred_close;
570 our_pred->p_type = CLOSE_PAREN;
571 our_pred->p_prec = NO_PREC;
572 our_pred->need_stat = our_pred->need_type = false;
573 return true;
576 static boolean
577 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
579 struct predicate *our_pred;
580 uintmax_t num;
581 enum comparison_type c_type;
582 time_t t;
584 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
585 return false;
586 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
587 return false;
588 t = options.cur_day_start + DAYSECS - num * 60;
589 our_pred = insert_primary (entry);
590 our_pred->args.info.kind = c_type;
591 our_pred->args.info.negative = t < 0;
592 our_pred->args.info.l_val = t;
593 our_pred->est_success_rate = estimate_file_age_success_rate(num);
594 (*arg_ptr)++;
595 return true;
598 static boolean
599 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
601 struct predicate *our_pred;
602 struct stat stat_newer;
604 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
605 return false;
606 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
607 error (1, errno, "%s", argv[*arg_ptr]);
608 our_pred = insert_primary (entry);
609 our_pred->args.time = stat_newer.st_mtime;
610 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
611 (*arg_ptr)++;
612 return true;
615 static boolean
616 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
618 struct predicate *our_pred;
620 (void) argv;
621 (void) arg_ptr;
623 our_pred = get_new_pred (entry);
624 our_pred->pred_func = pred_comma;
625 our_pred->p_type = BI_OP;
626 our_pred->p_prec = COMMA_PREC;
627 our_pred->need_stat = our_pred->need_type = false;
628 our_pred->est_success_rate = 1.0f;
629 return true;
632 static boolean
633 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
635 struct tm *local;
637 (void) entry;
638 (void) argv;
639 (void) arg_ptr;
641 if (options.full_days == false)
643 options.cur_day_start += DAYSECS;
644 local = localtime (&options.cur_day_start);
645 options.cur_day_start -= (local
646 ? (local->tm_sec + local->tm_min * 60
647 + local->tm_hour * 3600)
648 : options.cur_day_start % DAYSECS);
649 options.full_days = true;
651 return true;
654 static boolean
655 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
657 struct predicate *our_pred;
658 (void) argv;
659 (void) arg_ptr;
661 our_pred = insert_primary (entry);
662 our_pred->side_effects = our_pred->no_default_print = true;
663 /* -delete implies -depth */
664 options.do_dir_first = false;
665 our_pred->est_success_rate = 1.0f;
666 return true;
669 static boolean
670 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
672 (void) entry;
673 (void) argv;
674 (void) arg_ptr;
676 options.do_dir_first = false;
677 return parse_noop(entry, argv, arg_ptr);
680 static boolean
681 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
683 (void) argv;
684 (void) arg_ptr;
686 if (options.warnings)
688 error (0, 0,
689 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
691 return parse_depth(entry, argv, arg_ptr);
694 static boolean
695 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
697 struct predicate *our_pred;
698 (void) argv;
699 (void) arg_ptr;
701 our_pred = insert_primary (entry);
702 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
703 return true;
706 static boolean
707 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
709 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
712 static boolean
713 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
715 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
718 static boolean
719 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
721 struct predicate *our_pred;
723 (void) argv;
724 (void) arg_ptr;
726 our_pred = insert_primary (entry);
727 our_pred->need_stat = our_pred->need_type = false;
728 our_pred->side_effects = our_pred->no_default_print = false;
729 our_pred->est_success_rate = 0.0f;
730 return true;
733 static boolean
734 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
736 struct predicate *our_pred;
738 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
739 return false;
740 our_pred = insert_primary (entry);
741 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
742 our_pred->side_effects = our_pred->no_default_print = true;
743 our_pred->est_success_rate = 1.0f;
744 (*arg_ptr)++;
745 return true;
748 static boolean
749 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
751 FILE *fp;
753 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
754 return false;
755 if (argv[*arg_ptr + 1] == NULL)
757 /* Ensure we get "missing arg" message, not "invalid arg". */
758 (*arg_ptr)++;
759 return false;
761 fp = open_output_file (argv[*arg_ptr]);
762 (*arg_ptr)++;
763 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
766 static boolean
767 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
769 (void) entry;
770 (void) argv;
771 (void) arg_ptr;
773 set_follow_state(SYMLINK_ALWAYS_DEREF);
774 return parse_noop(entry, argv, arg_ptr);
777 static boolean
778 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
780 struct predicate *our_pred;
782 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
783 return false;
784 our_pred = insert_primary (entry);
785 our_pred->args.printf_vec.segment = NULL;
786 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
787 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
788 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
789 our_pred->side_effects = our_pred->no_default_print = true;
790 our_pred->need_stat = our_pred->need_type = false;
791 our_pred->est_success_rate = 1.0f;
792 (*arg_ptr)++;
793 return true;
796 static boolean
797 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
799 struct predicate *our_pred;
801 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
802 return false;
803 our_pred = insert_primary (entry);
804 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
805 our_pred->side_effects = our_pred->no_default_print = true;
806 our_pred->need_stat = our_pred->need_type = false;
807 our_pred->est_success_rate = 1.0f;
808 (*arg_ptr)++;
809 return true;
812 static float estimate_fstype_success_rate(const char *fsname)
814 struct stat dir_stat;
815 const char *dir = "/";
816 if (0 == stat(dir, &dir_stat))
818 const char *fstype = filesystem_type(&dir_stat, dir);
819 /* Assume most files are on the same filesystem type as the root fs. */
820 if (0 == strcmp(fsname, fstype))
821 return 0.7f;
822 else
823 return 0.3f;
825 return 1.0f;
829 static boolean
830 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
832 struct predicate *our_pred;
834 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
835 return false;
836 our_pred = insert_primary (entry);
837 our_pred->args.str = argv[*arg_ptr];
839 /* This is an expensive operation, so although there are
840 * circumstances where it is selective, we ignore this fact because
841 * we probably don't want to promote this test to the front anyway.
843 our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
844 (*arg_ptr)++;
845 return true;
848 static boolean
849 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
851 struct predicate *p = insert_num (argv, arg_ptr, entry);
852 p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
853 return p;
856 static boolean
857 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
859 struct group *cur_gr;
860 struct predicate *our_pred;
861 gid_t gid;
862 int gid_len;
864 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
865 return false;
866 cur_gr = getgrnam (argv[*arg_ptr]);
867 endgrent ();
868 if (cur_gr != NULL)
869 gid = cur_gr->gr_gid;
870 else
872 gid_len = strspn (argv[*arg_ptr], "0123456789");
873 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
874 return false;
875 gid = atoi (argv[*arg_ptr]);
877 our_pred = insert_primary (entry);
878 our_pred->args.gid = gid;
879 our_pred->est_success_rate = (our_pred->args.info.l_val < 100) ? 0.99 : 0.2;
880 (*arg_ptr)++;
881 return true;
884 static boolean
885 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
887 (void) entry;
888 (void) argv;
889 (void) arg_ptr;
891 usage(stdout, 0, NULL);
892 puts (_("\n\
893 default path is the current directory; default expression is -print\n\
894 expression may consist of: operators, options, tests, and actions:\n"));
895 puts (_("\
896 operators (decreasing precedence; -and is implicit where no others are given):\n\
897 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
898 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
899 puts (_("\
900 positional options (always true): -daystart -follow -regextype\n\n\
901 normal options (always true, specified before other expressions):\n\
902 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
903 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
904 puts (_("\
905 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
906 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
907 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
908 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
909 puts (_("\
910 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
911 -readable -writable -executable\n\
912 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
913 -used N -user NAME -xtype [bcdpfls]\n"));
914 puts (_("\
915 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
916 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
917 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
918 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
919 "));
920 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
921 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
922 email to <bug-findutils@gnu.org>."));
923 exit (0);
926 static float estimate_pattern_match_rate(const char *pattern, int is_regex)
928 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
930 /* A wildcard; assume the pattern matches most files. */
931 return 0.8f;
933 else
935 return 0.1f;
939 static boolean
940 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
942 struct predicate *our_pred;
944 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
945 return false;
946 our_pred = insert_primary (entry);
947 our_pred->args.str = argv[*arg_ptr];
948 /* Use the generic glob pattern estimator to figure out how many
949 * links will match, but bear in mind that most files won't be links.
951 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
952 (*arg_ptr)++;
953 return true;
957 /* sanity check the fnmatch() function to make sure
958 * it really is the GNU version.
960 static boolean
961 fnmatch_sanitycheck(void)
963 /* fprintf(stderr, "Performing find sanity check..."); */
964 if (0 != fnmatch("foo", "foo", 0)
965 || 0 == fnmatch("Foo", "foo", 0)
966 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
968 error (1, 0, _("sanity check of the fnmatch() library function failed."));
969 /* fprintf(stderr, "FAILED\n"); */
970 return false;
973 /* fprintf(stderr, "OK\n"); */
974 return true;
978 static boolean
979 check_name_arg(const char *pred, const char *arg)
981 if (strchr(arg, '/'))
983 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'."),
984 pred, arg, arg);
986 return true; /* allow it anyway */
991 static boolean
992 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
994 struct predicate *our_pred;
996 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
997 return false;
998 if (!check_name_arg("-iname", argv[*arg_ptr]))
999 return false;
1001 fnmatch_sanitycheck();
1003 our_pred = insert_primary (entry);
1004 our_pred->need_stat = our_pred->need_type = false;
1005 our_pred->args.str = argv[*arg_ptr];
1006 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1007 (*arg_ptr)++;
1008 return true;
1011 static boolean
1012 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1014 struct predicate *p = insert_num (argv, arg_ptr, entry);
1015 /* inode number is exact match only, so very low proportions of files match */
1016 p->est_success_rate = 1e-6;
1017 return p;
1020 /* -ipath is deprecated (at RMS's request) in favour of
1021 * -iwholename. See the node "GNU Manuals" in standards.texi
1022 * for the rationale for this (basically, GNU prefers the use
1023 * of the phrase "file name" to "path name"
1025 static boolean
1026 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1028 error (0, 0,
1029 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1031 return parse_iwholename(entry, argv, arg_ptr);
1034 static boolean
1035 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1037 struct predicate *our_pred;
1039 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1040 return false;
1042 fnmatch_sanitycheck();
1044 our_pred = insert_primary_withpred (entry, pred_ipath);
1045 our_pred->need_stat = our_pred->need_type = false;
1046 our_pred->args.str = argv[*arg_ptr];
1047 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1048 (*arg_ptr)++;
1049 return true;
1052 static boolean
1053 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1055 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1058 static boolean
1059 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1061 struct predicate *p = insert_num (argv, arg_ptr, entry);
1062 if (p->args.info.l_val == 1)
1063 p->est_success_rate = 0.99;
1064 else if (p->args.info.l_val == 2)
1065 p->est_success_rate = 0.01;
1066 else
1067 p->est_success_rate = 1e-3;
1068 return p;
1071 static boolean
1072 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1074 struct predicate *our_pred;
1076 (void) argv;
1077 (void) arg_ptr;
1079 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1080 return false;
1082 fnmatch_sanitycheck();
1084 our_pred = insert_primary (entry);
1085 our_pred->args.str = argv[*arg_ptr];
1086 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
1087 (*arg_ptr)++;
1088 return true;
1091 static boolean
1092 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1094 struct predicate *our_pred;
1096 (void) &argv;
1097 (void) &arg_ptr;
1099 our_pred = insert_primary (entry);
1100 our_pred->side_effects = our_pred->no_default_print = true;
1101 return true;
1104 static boolean
1105 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1107 int depth_len;
1108 (void) entry;
1110 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1111 return false;
1112 depth_len = strspn (argv[*arg_ptr], "0123456789");
1113 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1114 return false;
1115 options.maxdepth = atoi (argv[*arg_ptr]);
1116 if (options.maxdepth < 0)
1117 return false;
1118 (*arg_ptr)++;
1119 return parse_noop(entry, argv, arg_ptr);
1122 static boolean
1123 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1125 int depth_len;
1126 (void) entry;
1128 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1129 return false;
1130 depth_len = strspn (argv[*arg_ptr], "0123456789");
1131 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1132 return false;
1133 options.mindepth = atoi (argv[*arg_ptr]);
1134 if (options.mindepth < 0)
1135 return false;
1136 (*arg_ptr)++;
1137 return parse_noop(entry, argv, arg_ptr);
1140 static boolean
1141 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1143 struct predicate *our_pred;
1144 uintmax_t num;
1145 enum comparison_type c_type;
1146 time_t t;
1148 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1149 return false;
1150 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
1151 return false;
1152 t = options.cur_day_start + DAYSECS - num * 60;
1153 our_pred = insert_primary (entry);
1154 our_pred->args.info.kind = c_type;
1155 our_pred->args.info.negative = t < 0;
1156 our_pred->args.info.l_val = t;
1157 our_pred->est_success_rate = estimate_file_age_success_rate(num);
1158 (*arg_ptr)++;
1159 return true;
1162 static boolean
1163 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1165 struct predicate *our_pred;
1167 (void) argv;
1168 (void) arg_ptr;
1170 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1171 return false;
1172 if (!check_name_arg("-name", argv[*arg_ptr]))
1173 return false;
1174 fnmatch_sanitycheck();
1176 our_pred = insert_primary (entry);
1177 our_pred->need_stat = our_pred->need_type = false;
1178 our_pred->args.str = argv[*arg_ptr];
1179 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1180 (*arg_ptr)++;
1181 return true;
1184 static boolean
1185 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1187 struct predicate *our_pred;
1189 (void) &argv;
1190 (void) &arg_ptr;
1192 our_pred = get_new_pred_chk_op (entry);
1193 our_pred->pred_func = pred_negate;
1194 our_pred->p_type = UNI_OP;
1195 our_pred->p_prec = NEGATE_PREC;
1196 our_pred->need_stat = our_pred->need_type = false;
1197 return true;
1200 static boolean
1201 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1203 struct predicate *our_pred;
1204 struct stat stat_newer;
1206 (void) argv;
1207 (void) arg_ptr;
1209 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1210 return false;
1211 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1212 error (1, errno, "%s", argv[*arg_ptr]);
1213 our_pred = insert_primary (entry);
1214 our_pred->args.time = stat_newer.st_mtime;
1215 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1216 (*arg_ptr)++;
1217 return true;
1220 static boolean
1221 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1223 (void) &argv;
1224 (void) &arg_ptr;
1225 (void) entry;
1227 options.no_leaf_check = true;
1228 return parse_noop(entry, argv, arg_ptr);
1231 #ifdef CACHE_IDS
1232 /* Arbitrary amount by which to increase size
1233 of `uid_unused' and `gid_unused'. */
1234 #define ALLOC_STEP 2048
1236 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1237 char *uid_unused = NULL;
1239 /* Number of elements in `uid_unused'. */
1240 unsigned uid_allocated;
1242 /* Similar for GIDs and group entries. */
1243 char *gid_unused = NULL;
1244 unsigned gid_allocated;
1245 #endif
1247 static boolean
1248 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1250 struct predicate *our_pred;
1252 (void) &argv;
1253 (void) &arg_ptr;
1255 our_pred = insert_primary (entry);
1256 our_pred->est_success_rate = 1e-4;
1257 #ifdef CACHE_IDS
1258 if (gid_unused == NULL)
1260 struct group *gr;
1262 gid_allocated = ALLOC_STEP;
1263 gid_unused = xmalloc (gid_allocated);
1264 memset (gid_unused, 1, gid_allocated);
1265 setgrent ();
1266 while ((gr = getgrent ()) != NULL)
1268 if ((unsigned) gr->gr_gid >= gid_allocated)
1270 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1271 gid_unused = xrealloc (gid_unused, new_allocated);
1272 memset (gid_unused + gid_allocated, 1,
1273 new_allocated - gid_allocated);
1274 gid_allocated = new_allocated;
1276 gid_unused[(unsigned) gr->gr_gid] = 0;
1278 endgrent ();
1280 #endif
1281 return true;
1284 static boolean
1285 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1287 struct predicate *our_pred;
1288 (void) argv;
1289 (void) arg_ptr;
1292 our_pred = insert_primary (entry);
1293 our_pred->est_success_rate = 1e-3;
1294 #ifdef CACHE_IDS
1295 if (uid_unused == NULL)
1297 struct passwd *pw;
1299 uid_allocated = ALLOC_STEP;
1300 uid_unused = xmalloc (uid_allocated);
1301 memset (uid_unused, 1, uid_allocated);
1302 setpwent ();
1303 while ((pw = getpwent ()) != NULL)
1305 if ((unsigned) pw->pw_uid >= uid_allocated)
1307 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1308 uid_unused = xrealloc (uid_unused, new_allocated);
1309 memset (uid_unused + uid_allocated, 1,
1310 new_allocated - uid_allocated);
1311 uid_allocated = new_allocated;
1313 uid_unused[(unsigned) pw->pw_uid] = 0;
1315 endpwent ();
1317 #endif
1318 return true;
1321 static boolean
1322 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1324 (void) argv;
1325 (void) arg_ptr;
1326 (void) entry;
1328 options.warnings = false;
1329 return parse_noop(entry, argv, arg_ptr);
1332 static boolean
1333 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1335 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1338 static boolean
1339 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1341 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1344 boolean
1345 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1347 struct predicate *our_pred;
1349 (void) argv;
1350 (void) arg_ptr;
1352 our_pred = get_new_pred_chk_op (entry);
1353 our_pred->pred_func = pred_open;
1354 our_pred->p_type = OPEN_PAREN;
1355 our_pred->p_prec = NO_PREC;
1356 our_pred->need_stat = our_pred->need_type = false;
1357 return true;
1360 static boolean
1361 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1363 struct predicate *our_pred;
1365 (void) argv;
1366 (void) arg_ptr;
1368 our_pred = get_new_pred (entry);
1369 our_pred->pred_func = pred_or;
1370 our_pred->p_type = BI_OP;
1371 our_pred->p_prec = OR_PREC;
1372 our_pred->need_stat = our_pred->need_type = false;
1373 return true;
1376 /* -path is deprecated (at RMS's request) in favour of
1377 * -iwholename. See the node "GNU Manuals" in standards.texi
1378 * for the rationale for this (basically, GNU prefers the use
1379 * of the phrase "file name" to "path name".
1381 * We do not issue a warning that this usage is deprecated
1382 * since HPUX find supports this predicate also.
1384 static boolean
1385 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1387 return parse_wholename(entry, argv, arg_ptr);
1390 static boolean
1391 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1393 struct predicate *our_pred;
1395 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1396 return false;
1397 our_pred = insert_primary_withpred (entry, pred_path);
1398 our_pred->need_stat = our_pred->need_type = false;
1399 our_pred->args.str = argv[*arg_ptr];
1400 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1401 (*arg_ptr)++;
1402 return true;
1405 static boolean
1406 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1408 mode_t perm_val[2];
1409 float rate;
1410 int mode_start = 0;
1411 boolean havekind = false;
1412 enum permissions_type kind = PERM_EXACT;
1413 struct mode_change *change = NULL;
1414 struct predicate *our_pred;
1416 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1417 return false;
1419 switch (argv[*arg_ptr][0])
1421 case '-':
1422 mode_start = 1;
1423 kind = PERM_AT_LEAST;
1424 havekind = true;
1425 rate = 0.2;
1426 break;
1428 case '+':
1429 change = mode_compile (argv[*arg_ptr]);
1430 if (NULL == change)
1432 /* Most likely the caller is an old script that is still
1433 * using the obsolete GNU syntax '-perm +MODE'. This old
1434 * syntax was withdrawn in favor of '-perm /MODE' because
1435 * it is incompatible with POSIX in some cases, but we
1436 * still support uses of it that are not incompatible with
1437 * POSIX.
1439 mode_start = 1;
1440 kind = PERM_ANY;
1441 rate = 0.3;
1443 else
1445 /* This is a POSIX-compatible usage */
1446 mode_start = 0;
1447 kind = PERM_EXACT;
1448 rate = 0.1;
1450 havekind = true;
1451 break;
1453 case '/': /* GNU extension */
1454 mode_start = 1;
1455 kind = PERM_ANY;
1456 havekind = true;
1457 rate = 0.3;
1458 break;
1460 default:
1461 /* For example, '-perm 0644', which is valid and matches
1462 * only files whose mode is exactly 0644.
1464 mode_start = 0;
1465 kind = PERM_EXACT;
1466 havekind = true;
1467 rate = 0.01;
1468 break;
1471 if (NULL == change)
1473 change = mode_compile (argv[*arg_ptr] + mode_start);
1474 if (NULL == change)
1475 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1477 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1478 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1479 free (change);
1481 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1483 /* The meaning of -perm /000 will change in the future. It
1484 * currently matches no files, but like -perm -000 it should
1485 * match all files.
1487 * Starting in 2005, we used to issue a warning message
1488 * informing the user that the behaviour would change in the
1489 * future. We have now changed the behaviour and issue a
1490 * warning message that the behaviour recently changed.
1492 error (0, 0,
1493 _("warning: you have specified a mode pattern %s (which is "
1494 "equivalent to /000). The meaning of -perm /000 has now been "
1495 "changed to be consistent with -perm -000; that is, while it "
1496 "used to match no files, it now matches all files."),
1497 argv[*arg_ptr]);
1499 kind = PERM_AT_LEAST;
1500 havekind = true;
1502 /* The "magic" number below is just the fraction of files on my
1503 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1504 * Actual totals are 1472 and 1073833.
1506 rate = 0.9986; /* probably matches anything but a broken symlink */
1509 our_pred = insert_primary (entry);
1510 our_pred->est_success_rate = rate;
1511 if (havekind)
1513 our_pred->args.perm.kind = kind;
1515 else
1518 switch (argv[*arg_ptr][0])
1520 case '-':
1521 our_pred->args.perm.kind = PERM_AT_LEAST;
1522 break;
1523 case '+':
1524 our_pred->args.perm.kind = PERM_ANY;
1525 break;
1526 default:
1527 our_pred->args.perm.kind = PERM_EXACT;
1528 break;
1531 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1532 (*arg_ptr)++;
1533 return true;
1536 boolean
1537 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1539 struct predicate *our_pred;
1541 (void) argv;
1542 (void) arg_ptr;
1544 our_pred = insert_primary (entry);
1545 /* -print has the side effect of printing. This prevents us
1546 from doing undesired multiple printing when the user has
1547 already specified -print. */
1548 our_pred->side_effects = our_pred->no_default_print = true;
1549 our_pred->need_stat = our_pred->need_type = false;
1550 our_pred->args.printf_vec.segment = NULL;
1551 our_pred->args.printf_vec.stream = stdout;
1552 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1553 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1555 return true;
1558 static boolean
1559 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1561 struct predicate *our_pred;
1563 (void) argv;
1564 (void) arg_ptr;
1566 our_pred = insert_primary (entry);
1567 /* -print0 has the side effect of printing. This prevents us
1568 from doing undesired multiple printing when the user has
1569 already specified -print0. */
1570 our_pred->side_effects = our_pred->no_default_print = true;
1571 our_pred->need_stat = our_pred->need_type = false;
1572 return true;
1575 static boolean
1576 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1578 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1579 return false;
1580 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1583 static boolean
1584 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1586 struct predicate *our_pred;
1588 (void) argv;
1589 (void) arg_ptr;
1591 our_pred = insert_primary (entry);
1592 our_pred->need_stat = our_pred->need_type = false;
1593 /* -prune has a side effect that it does not descend into
1594 the current directory. */
1595 our_pred->side_effects = true;
1596 our_pred->no_default_print = false;
1597 return true;
1600 static boolean
1601 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1603 struct predicate *our_pred = insert_primary (entry);
1604 (void) argv;
1605 (void) arg_ptr;
1606 our_pred->need_stat = our_pred->need_type = false;
1607 our_pred->side_effects = true; /* Exiting is a side effect... */
1608 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1609 our_pred->est_success_rate = 1e-6;
1610 return true;
1614 static boolean
1615 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1617 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1618 return false;
1620 /* collect the regex type name */
1621 options.regex_options = get_regex_type(argv[*arg_ptr]);
1622 (*arg_ptr)++;
1624 return parse_noop(entry, argv, arg_ptr);
1628 static boolean
1629 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1631 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1634 static boolean
1635 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1637 struct predicate *our_pred;
1638 struct re_pattern_buffer *re;
1639 const char *error_message;
1641 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1642 return false;
1643 our_pred = insert_primary_withpred (entry, pred_regex);
1644 our_pred->need_stat = our_pred->need_type = false;
1645 re = (struct re_pattern_buffer *)
1646 xmalloc (sizeof (struct re_pattern_buffer));
1647 our_pred->args.regex = re;
1648 re->allocated = 100;
1649 re->buffer = (unsigned char *) xmalloc (re->allocated);
1650 re->fastmap = NULL;
1652 re_set_syntax(regex_options);
1653 re->syntax = regex_options;
1654 re->translate = NULL;
1656 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1657 re);
1658 if (error_message)
1659 error (1, 0, "%s", error_message);
1660 our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
1661 (*arg_ptr)++;
1662 return true;
1665 static boolean
1666 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1668 struct predicate *our_pred;
1669 uintmax_t num;
1670 enum comparison_type c_type;
1671 int blksize = 512;
1672 int len;
1673 float rate = 1.0;
1675 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1676 return false;
1677 len = strlen (argv[*arg_ptr]);
1678 if (len == 0)
1679 error (1, 0, _("invalid null argument to -size"));
1680 switch (argv[*arg_ptr][len - 1])
1682 case 'b':
1683 blksize = 512;
1684 argv[*arg_ptr][len - 1] = '\0';
1685 break;
1687 case 'c':
1688 blksize = 1;
1689 argv[*arg_ptr][len - 1] = '\0';
1690 break;
1692 case 'k':
1693 blksize = 1024;
1694 argv[*arg_ptr][len - 1] = '\0';
1695 break;
1697 case 'M': /* Megabytes */
1698 blksize = 1024*1024;
1699 argv[*arg_ptr][len - 1] = '\0';
1700 break;
1702 case 'G': /* Gigabytes */
1703 blksize = 1024*1024*1024;
1704 argv[*arg_ptr][len - 1] = '\0';
1705 break;
1707 case 'w':
1708 blksize = 2;
1709 argv[*arg_ptr][len - 1] = '\0';
1710 break;
1712 case '0':
1713 case '1':
1714 case '2':
1715 case '3':
1716 case '4':
1717 case '5':
1718 case '6':
1719 case '7':
1720 case '8':
1721 case '9':
1722 break;
1724 default:
1725 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1727 if (!get_num (argv[*arg_ptr], &num, &c_type))
1728 return false;
1729 our_pred = insert_primary (entry);
1730 our_pred->args.size.kind = c_type;
1731 our_pred->args.size.blocksize = blksize;
1732 our_pred->args.size.size = num;
1733 our_pred->need_stat = true;
1734 our_pred->need_type = false;
1736 if (COMP_GT == c_type)
1737 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1738 else if (COMP_LT == c_type)
1739 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1740 else
1741 our_pred->est_success_rate = 0.01;
1743 (*arg_ptr)++;
1744 return true;
1748 static boolean
1749 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1751 struct predicate *our_pred;
1752 struct stat st;
1754 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1755 return false;
1756 if ((*options.xstat) (argv[*arg_ptr], &st))
1757 error (1, errno, "%s", argv[*arg_ptr]);
1759 our_pred = insert_primary (entry);
1760 our_pred->args.fileid.ino = st.st_ino;
1761 our_pred->args.fileid.dev = st.st_dev;
1762 our_pred->need_type = false;
1763 our_pred->need_stat = true;
1764 our_pred->est_success_rate = 0.01f;
1765 (*arg_ptr)++;
1766 return true;
1769 #if 0
1770 static boolean
1771 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1773 const char *arg;
1774 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1775 "must be 'literal' or 'safe'");
1777 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1779 error (1, errno, "%s", errmsg);
1780 return false;
1782 else
1784 arg = argv[*arg_ptr];
1786 if (0 == strcmp("literal", arg))
1788 options.literal_control_chars = true;
1790 else if (0 == strcmp("safe", arg))
1792 options.literal_control_chars = false;
1794 else
1796 error (1, errno, "%s", errmsg);
1797 return false;
1799 (*arg_ptr)++; /* consume the argument. */
1800 return true;
1803 #endif
1806 static boolean
1807 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1809 struct predicate *our_pred;
1811 (void) argv;
1812 (void) arg_ptr;
1814 our_pred = insert_primary (entry);
1815 our_pred->need_stat = our_pred->need_type = false;
1816 our_pred->est_success_rate = 1.0f;
1817 return true;
1820 static boolean
1821 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
1823 (void) entry;
1824 return parse_true(get_noop(), argv, arg_ptr);
1827 static boolean
1828 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1830 struct predicate *our_pred;
1831 (void) argv;
1832 (void) arg_ptr;
1833 our_pred = insert_primary (entry);
1834 our_pred->need_stat = our_pred->need_type = false;
1835 our_pred->side_effects = our_pred->no_default_print = false;
1836 if (our_pred->pred_func == pred_executable)
1837 our_pred->est_success_rate = 0.2;
1838 else
1839 our_pred->est_success_rate = 0.9;
1840 return true;
1843 static boolean
1844 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1846 return insert_type (argv, arg_ptr, entry, pred_type);
1849 static boolean
1850 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1852 struct predicate *p = insert_num (argv, arg_ptr, entry);
1853 p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
1854 return p;
1857 static boolean
1858 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1860 struct predicate *our_pred;
1861 uintmax_t num_days;
1862 enum comparison_type c_type;
1863 time_t t;
1865 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1866 return false;
1867 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1868 return false;
1869 t = num_days * DAYSECS;
1870 our_pred = insert_primary (entry);
1871 our_pred->args.info.kind = c_type;
1872 our_pred->args.info.negative = t < 0;
1873 our_pred->args.info.l_val = t;
1874 our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
1875 (*arg_ptr)++;
1876 return true;
1879 static boolean
1880 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1882 struct passwd *cur_pwd;
1883 struct predicate *our_pred;
1884 uid_t uid;
1885 int uid_len;
1887 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1888 return false;
1889 cur_pwd = getpwnam (argv[*arg_ptr]);
1890 endpwent ();
1891 if (cur_pwd != NULL)
1892 uid = cur_pwd->pw_uid;
1893 else
1895 uid_len = strspn (argv[*arg_ptr], "0123456789");
1896 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1897 return false;
1898 uid = atoi (argv[*arg_ptr]);
1900 our_pred = insert_primary (entry);
1901 our_pred->args.uid = uid;
1902 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
1903 (*arg_ptr)++;
1904 return true;
1907 static boolean
1908 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1910 extern char *version_string;
1911 int features = 0;
1913 (void) argv;
1914 (void) arg_ptr;
1915 (void) entry;
1917 fflush (stderr);
1918 printf (_("GNU find version %s\n"), version_string);
1919 printf (_("Features enabled: "));
1921 #if CACHE_IDS
1922 printf("CACHE_IDS ");
1923 ++features;
1924 #endif
1925 #if DEBUG
1926 printf("DEBUG ");
1927 ++features;
1928 #endif
1929 #if DEBUG_STAT
1930 printf("DEBUG_STAT ");
1931 ++features;
1932 #endif
1933 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1934 printf("D_TYPE ");
1935 ++features;
1936 #endif
1937 #if defined(O_NOFOLLOW)
1938 printf("O_NOFOLLOW(%s) ",
1939 (options.open_nofollow_available ? "enabled" : "disabled"));
1940 ++features;
1941 #endif
1942 #if defined(LEAF_OPTIMISATION)
1943 printf("LEAF_OPTIMISATION ");
1944 ++features;
1945 #endif
1947 if (is_fts_enabled())
1949 printf("FTS ");
1950 ++features;
1953 printf("CBO(level=%d) ", (int)(options.optimisation_level));
1954 ++features;
1956 if (0 == features)
1958 /* For the moment, leave this as English in case someone wants
1959 to parse these strings. */
1960 printf("none");
1962 printf("\n");
1964 exit (0);
1967 static boolean
1968 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1970 (void) argv;
1971 (void) arg_ptr;
1972 (void) entry;
1973 options.stay_on_filesystem = true;
1974 return parse_noop(entry, argv, arg_ptr);
1977 static boolean
1978 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1980 (void) argv;
1981 (void) arg_ptr;
1982 (void) entry;
1983 options.ignore_readdir_race = true;
1984 return parse_noop(entry, argv, arg_ptr);
1987 static boolean
1988 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1990 (void) argv;
1991 (void) arg_ptr;
1992 (void) entry;
1993 options.ignore_readdir_race = false;
1994 return parse_noop(entry, argv, arg_ptr);
1997 static boolean
1998 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
2000 (void) argv;
2001 (void) arg_ptr;
2002 (void) entry;
2003 options.warnings = true;
2004 return parse_noop(entry, argv, arg_ptr);
2007 static boolean
2008 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
2010 (void) argv;
2011 (void) arg_ptr;
2012 return insert_type (argv, arg_ptr, entry, pred_xtype);
2015 static boolean
2016 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2018 mode_t type_cell;
2019 struct predicate *our_pred;
2020 float rate = 0.5;
2022 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
2023 || (strlen (argv[*arg_ptr]) != 1))
2024 return false;
2025 switch (argv[*arg_ptr][0])
2027 case 'b': /* block special */
2028 type_cell = S_IFBLK;
2029 rate = 0.01f;
2030 break;
2031 case 'c': /* character special */
2032 type_cell = S_IFCHR;
2033 rate = 0.01f;
2034 break;
2035 case 'd': /* directory */
2036 type_cell = S_IFDIR;
2037 rate = 0.4f;
2038 break;
2039 case 'f': /* regular file */
2040 type_cell = S_IFREG;
2041 rate = 0.95f;
2042 break;
2043 #ifdef S_IFLNK
2044 case 'l': /* symbolic link */
2045 type_cell = S_IFLNK;
2046 rate = 0.1f;
2047 break;
2048 #endif
2049 #ifdef S_IFIFO
2050 case 'p': /* pipe */
2051 type_cell = S_IFIFO;
2052 rate = 0.01f;
2053 break;
2054 #endif
2055 #ifdef S_IFSOCK
2056 case 's': /* socket */
2057 type_cell = S_IFSOCK;
2058 rate = 0.01f;
2059 break;
2060 #endif
2061 #ifdef S_IFDOOR
2062 case 'D': /* Solaris door */
2063 type_cell = S_IFDOOR;
2064 rate = 0.01f;
2065 break;
2066 #endif
2067 default: /* None of the above ... nuke 'em. */
2068 return false;
2070 our_pred = insert_primary_withpred (entry, which_pred);
2071 our_pred->est_success_rate = rate;
2073 /* Figure out if we will need to stat the file, because if we don't
2074 * need to follow symlinks, we can avoid a stat call by using
2075 * struct dirent.d_type.
2077 if (which_pred == pred_xtype)
2079 our_pred->need_stat = true;
2080 our_pred->need_type = false;
2082 else
2084 our_pred->need_stat = false; /* struct dirent is enough */
2085 our_pred->need_type = true;
2087 our_pred->args.type = type_cell;
2088 (*arg_ptr)++; /* Move on to next argument. */
2089 return true;
2093 /* Return true if the file accessed via FP is a terminal.
2095 static boolean
2096 stream_is_tty(FILE *fp)
2098 int fd = fileno(fp);
2099 if (-1 == fd)
2101 return false; /* not a valid stream */
2103 else
2105 return isatty(fd) ? true : false;
2113 /* XXX: do we need to pass FUNC to this function? */
2114 static boolean
2115 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
2117 char *format; /* Beginning of unprocessed format string. */
2118 register char *scan; /* Current address in scanning `format'. */
2119 register char *scan2; /* Address inside of element being scanned. */
2120 struct segment **segmentp; /* Address of current segment. */
2121 struct predicate *our_pred;
2123 format = argv[(*arg_ptr)++];
2125 our_pred = insert_primary_withpred (entry, func);
2126 our_pred->side_effects = our_pred->no_default_print = true;
2127 our_pred->args.printf_vec.stream = fp;
2128 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
2129 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2130 our_pred->need_type = false;
2131 our_pred->need_stat = false;
2133 segmentp = &our_pred->args.printf_vec.segment;
2134 *segmentp = NULL;
2136 for (scan = format; *scan; scan++)
2138 if (*scan == '\\')
2140 scan2 = scan + 1;
2141 if (*scan2 >= '0' && *scan2 <= '7')
2143 register int n, i;
2145 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2146 i++, scan2++)
2147 n = 8 * n + *scan2 - '0';
2148 scan2--;
2149 *scan = n;
2151 else
2153 switch (*scan2)
2155 case 'a':
2156 *scan = 7;
2157 break;
2158 case 'b':
2159 *scan = '\b';
2160 break;
2161 case 'c':
2162 make_segment (segmentp, format, scan - format,
2163 KIND_STOP, 0, 0,
2164 our_pred);
2165 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2166 our_pred->p_cost = NeedsStatInfo;
2167 return true;
2168 case 'f':
2169 *scan = '\f';
2170 break;
2171 case 'n':
2172 *scan = '\n';
2173 break;
2174 case 'r':
2175 *scan = '\r';
2176 break;
2177 case 't':
2178 *scan = '\t';
2179 break;
2180 case 'v':
2181 *scan = '\v';
2182 break;
2183 case '\\':
2184 /* *scan = '\\'; * it already is */
2185 break;
2186 default:
2187 error (0, 0,
2188 _("warning: unrecognized escape `\\%c'"), *scan2);
2189 scan++;
2190 continue;
2193 segmentp = make_segment (segmentp, format, scan - format + 1,
2194 KIND_PLAIN, 0, 0,
2195 our_pred);
2196 format = scan2 + 1; /* Move past the escape. */
2197 scan = scan2; /* Incremented immediately by `for'. */
2199 else if (*scan == '%')
2201 if (scan[1] == 0)
2203 /* Trailing %. We don't like those. */
2204 error (1, 0, _("error: %s at end of format string"), scan);
2206 else if (scan[1] == '%')
2208 segmentp = make_segment (segmentp, format, scan - format + 1,
2209 KIND_PLAIN, 0, 0,
2210 our_pred);
2211 scan++;
2212 format = scan + 1;
2213 continue;
2215 /* Scan past flags, width and precision, to verify kind. */
2216 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2217 /* Do nothing. */ ;
2218 while (ISDIGIT (*scan2))
2219 scan2++;
2220 if (*scan2 == '.')
2221 for (scan2++; ISDIGIT (*scan2); scan2++)
2222 /* Do nothing. */ ;
2223 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
2225 segmentp = make_segment (segmentp, format, scan2 - format,
2226 KIND_FORMAT, *scan2, 0,
2227 our_pred);
2228 scan = scan2;
2229 format = scan + 1;
2231 else if (strchr ("ACT", *scan2) && scan2[1])
2233 segmentp = make_segment (segmentp, format, scan2 - format,
2234 KIND_FORMAT, scan2[0], scan2[1],
2235 our_pred);
2236 scan = scan2 + 1;
2237 format = scan + 1;
2238 continue;
2240 else
2242 /* An unrecognized % escape. Print the char after the %. */
2243 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2244 *scan2);
2245 segmentp = make_segment (segmentp, format, scan - format,
2246 KIND_PLAIN, 0, 0,
2247 our_pred);
2248 format = scan + 1;
2249 continue;
2254 if (scan > format)
2255 make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
2256 our_pred);
2257 return true;
2260 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2261 from the text in FORMAT, which has length LEN.
2262 Return the address of the `next' pointer of the new segment. */
2264 static struct segment **
2265 make_segment (struct segment **segment,
2266 char *format,
2267 int len,
2268 int kind,
2269 char format_char,
2270 char aux_format_char,
2271 struct predicate *pred)
2273 enum EvaluationCost mycost = NeedsNothing;
2274 char *fmt;
2276 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2278 (*segment)->segkind = kind;
2279 (*segment)->format_char[0] = format_char;
2280 (*segment)->format_char[1] = aux_format_char;
2281 (*segment)->next = NULL;
2282 (*segment)->text_len = len;
2284 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2285 strncpy (fmt, format, len);
2286 fmt += len;
2288 switch (kind)
2290 case KIND_PLAIN: /* Plain text string, no % conversion. */
2291 case KIND_STOP: /* Terminate argument, no newline. */
2292 assert(0 == format_char);
2293 assert(0 == aux_format_char);
2294 *fmt = '\0';
2295 if (mycost > pred->p_cost)
2296 pred->p_cost = NeedsNothing;
2297 return &(*segment)->next;
2298 break;
2301 assert(kind == KIND_FORMAT);
2302 switch (format_char)
2304 case 'l': /* object of symlink */
2305 pred->need_stat = true;
2306 mycost = NeedsLinkName;
2307 *fmt++ = 's';
2308 break;
2310 case 'y': /* file type */
2311 pred->need_type = true;
2312 mycost = NeedsType;
2313 *fmt++ = 's';
2314 break;
2316 case 'a': /* atime in `ctime' format */
2317 case 'A': /* atime in user-specified strftime format */
2318 case 'c': /* ctime in `ctime' format */
2319 case 'C': /* ctime in user-specified strftime format */
2320 case 'F': /* filesystem type */
2321 case 'g': /* group name */
2322 case 'i': /* inode number */
2323 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2324 case 's': /* size in bytes */
2325 case 't': /* mtime in `ctime' format */
2326 case 'T': /* mtime in user-specified strftime format */
2327 case 'u': /* user name */
2328 pred->need_stat = true;
2329 mycost = NeedsStatInfo;
2330 *fmt++ = 's';
2331 break;
2333 case 'S': /* sparseness */
2334 pred->need_stat = true;
2335 mycost = NeedsStatInfo;
2336 *fmt++ = 'g';
2337 break;
2339 case 'Y': /* symlink pointed file type */
2340 pred->need_stat = true;
2341 mycost = NeedsType; /* true for amortised effect */
2342 *fmt++ = 's';
2343 break;
2345 case 'f': /* basename of path */
2346 case 'h': /* leading directories part of path */
2347 case 'p': /* pathname */
2348 case 'P': /* pathname with ARGV element stripped */
2349 *fmt++ = 's';
2350 break;
2352 case 'H': /* ARGV element file was found under */
2353 *fmt++ = 's';
2354 break;
2356 /* Numeric items that one might expect to honour
2357 * #, 0, + flags but which do not.
2359 case 'G': /* GID number */
2360 case 'U': /* UID number */
2361 case 'b': /* size in 512-byte blocks */
2362 case 'D': /* Filesystem device on which the file exits */
2363 case 'k': /* size in 1K blocks */
2364 case 'n': /* number of links */
2365 pred->need_stat = true;
2366 mycost = NeedsStatInfo;
2367 *fmt++ = 's';
2368 break;
2370 /* Numeric items that DO honour #, 0, + flags.
2372 case 'd': /* depth in search tree (0 = ARGV element) */
2373 *fmt++ = 'd';
2374 break;
2376 case 'm': /* mode as octal number (perms only) */
2377 *fmt++ = 'o';
2378 pred->need_stat = true;
2379 mycost = NeedsStatInfo;
2380 break;
2382 case '{':
2383 case '[':
2384 case '(':
2385 error (1, 0,
2386 _("error: the format directive `%%%c' is reserved for future use"),
2387 (int)kind);
2388 /*NOTREACHED*/
2389 break;
2391 *fmt = '\0';
2393 if (mycost > pred->p_cost)
2394 pred->p_cost = mycost;
2395 return &(*segment)->next;
2398 static void
2399 check_path_safety(const char *action, char **argv)
2401 const char *path = getenv("PATH");
2403 (void)argv;
2405 char *s;
2406 s = next_element(path, 1);
2407 while ((s = next_element ((char *) NULL, 1)) != NULL)
2409 if (0 == strcmp(s, "."))
2411 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)"),
2412 action);
2414 else if ('/' != s[0])
2416 /* Relative paths are also dangerous in $PATH. */
2417 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"),
2418 s, action);
2424 /* handles both exec and ok predicate */
2425 static boolean
2426 new_insert_exec_ok (const char *action,
2427 const struct parser_table *entry,
2428 char **argv,
2429 int *arg_ptr)
2431 int start, end; /* Indexes in ARGV of start & end of cmd. */
2432 int i; /* Index into cmd args */
2433 int saw_braces; /* True if previous arg was '{}'. */
2434 boolean allow_plus; /* True if + is a valid terminator */
2435 int brace_count; /* Number of instances of {}. */
2436 PRED_FUNC func = entry->pred_func;
2437 enum BC_INIT_STATUS bcstatus;
2439 struct predicate *our_pred;
2440 struct exec_val *execp; /* Pointer for efficiency. */
2442 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2443 return false;
2445 our_pred = insert_primary_withpred (entry, func);
2446 our_pred->side_effects = our_pred->no_default_print = true;
2447 our_pred->need_type = our_pred->need_stat = false;
2449 execp = &our_pred->args.exec_vec;
2451 if ((func != pred_okdir) && (func != pred_ok))
2453 allow_plus = true;
2454 execp->close_stdin = false;
2456 else
2458 allow_plus = false;
2459 /* If find reads stdin (i.e. for -ok and similar), close stdin
2460 * in the child to prevent some script from consiming the output
2461 * intended for find.
2463 execp->close_stdin = true;
2467 if ((func == pred_execdir) || (func == pred_okdir))
2469 options.ignore_readdir_race = false;
2470 check_path_safety(action, argv);
2471 execp->use_current_dir = true;
2473 else
2475 execp->use_current_dir = false;
2478 our_pred->args.exec_vec.multiple = 0;
2480 /* Count the number of args with path replacements, up until the ';'.
2481 * Also figure out if the command is terminated by ";" or by "+".
2483 start = *arg_ptr;
2484 for (end = start, saw_braces=0, brace_count=0;
2485 (argv[end] != NULL)
2486 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2487 end++)
2489 /* For -exec and -execdir, "{} +" can terminate the command. */
2490 if ( allow_plus
2491 && argv[end][0] == '+' && argv[end][1] == 0
2492 && saw_braces)
2494 our_pred->args.exec_vec.multiple = 1;
2495 break;
2498 saw_braces = 0;
2499 if (strstr (argv[end], "{}"))
2501 saw_braces = 1;
2502 ++brace_count;
2504 if (0 == end && (func == pred_execdir || func == pred_okdir))
2506 /* The POSIX standard says that {} replacement should
2507 * occur even in the utility name. This is insecure
2508 * since it means we will be executing a command whose
2509 * name is chosen according to whatever find finds in
2510 * the filesystem. That can be influenced by an
2511 * attacker. Hence for -execdir and -okdir this is not
2512 * allowed. We can specify this as those options are
2513 * not defined by POSIX.
2515 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2520 /* Fail if no command given or no semicolon found. */
2521 if ((end == start) || (argv[end] == NULL))
2523 *arg_ptr = end;
2524 free(our_pred);
2525 return false;
2528 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2531 const char *suffix;
2532 if (func == pred_execdir)
2533 suffix = "dir";
2534 else
2535 suffix = "";
2537 error(1, 0,
2538 _("Only one instance of {} is supported with -exec%s ... +"),
2539 suffix);
2542 /* We use a switch statement here so that
2543 * the compiler warns us when we forget to handle a
2544 * newly invented enum value.
2546 bcstatus = bc_init_controlinfo(&execp->ctl);
2547 switch (bcstatus)
2549 case BC_INIT_ENV_TOO_BIG:
2550 error(1, 0,
2551 _("The environment is too large for exec()."));
2552 break;
2553 case BC_INIT_OK:
2554 /* Good news. Carry on. */
2555 break;
2557 bc_use_sensible_arg_max(&execp->ctl);
2560 execp->ctl.exec_callback = launch;
2562 if (our_pred->args.exec_vec.multiple)
2564 /* "+" terminator, so we can just append our arguments after the
2565 * command and initial arguments.
2567 execp->replace_vec = NULL;
2568 execp->ctl.replace_pat = NULL;
2569 execp->ctl.rplen = 0;
2570 execp->ctl.lines_per_exec = 0; /* no limit */
2571 execp->ctl.args_per_exec = 0; /* no limit */
2573 /* remember how many arguments there are */
2574 execp->ctl.initial_argc = (end-start) - 1;
2576 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2577 bc_init_state(&execp->ctl, &execp->state, execp);
2579 /* Gather the initial arguments. Skip the {}. */
2580 for (i=start; i<end-1; ++i)
2582 bc_push_arg(&execp->ctl, &execp->state,
2583 argv[i], strlen(argv[i])+1,
2584 NULL, 0,
2588 else
2590 /* Semicolon terminator - more than one {} is supported, so we
2591 * have to do brace-replacement.
2593 execp->num_args = end - start;
2595 execp->ctl.replace_pat = "{}";
2596 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2597 execp->ctl.lines_per_exec = 0; /* no limit */
2598 execp->ctl.args_per_exec = 0; /* no limit */
2599 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2602 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2603 bc_init_state(&execp->ctl, &execp->state, execp);
2605 /* Remember the (pre-replacement) arguments for later. */
2606 for (i=0; i<execp->num_args; ++i)
2608 execp->replace_vec[i] = argv[i+start];
2612 if (argv[end] == NULL)
2613 *arg_ptr = end;
2614 else
2615 *arg_ptr = end + 1;
2617 return true;
2622 static boolean
2623 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2625 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2630 /* Get a number of days and comparison type.
2631 STR is the ASCII representation.
2632 Set *NUM_DAYS to the number of days, taken as being from
2633 the current moment (or possibly midnight). Thus the sense of the
2634 comparison type appears to be reversed.
2635 Set *COMP_TYPE to the kind of comparison that is requested.
2637 Return true if all okay, false if input error.
2639 Used by -atime, -ctime and -mtime (parsers) to
2640 get the appropriate information for a time predicate processor. */
2642 static boolean
2643 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2645 boolean r = get_num (str, num_days, comp_type);
2646 if (r)
2647 switch (*comp_type)
2649 case COMP_LT: *comp_type = COMP_GT; break;
2650 case COMP_GT: *comp_type = COMP_LT; break;
2651 default: break;
2653 return r;
2656 /* Insert a time predicate PRED.
2657 ARGV is a pointer to the argument array.
2658 ARG_PTR is a pointer to an index into the array, incremented if
2659 all went well.
2661 Return true if input is valid, false if not.
2663 A new predicate node is assigned, along with an argument node
2664 obtained with malloc.
2666 Used by -atime, -ctime, and -mtime parsers. */
2668 static boolean
2669 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
2671 struct predicate *our_pred;
2672 uintmax_t num_days;
2673 enum comparison_type c_type;
2674 time_t t;
2676 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2677 return false;
2678 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2679 return false;
2681 /* Figure out the timestamp value we are looking for. */
2682 t = ( options.cur_day_start - num_days * DAYSECS
2683 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2685 if (1)
2687 /* We introduce a scope in which 'val' can be declared, for the
2688 * benefit of compilers that are really C89 compilers
2689 * which support intmax_t because config.h #defines it
2691 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2692 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2693 t = val;
2695 /* Check for possibility of an overflow */
2696 if ( (intmax_t)t != val )
2698 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2702 our_pred = insert_primary (entry);
2703 our_pred->args.info.kind = c_type;
2704 our_pred->args.info.negative = t < 0;
2705 our_pred->args.info.l_val = t;
2706 our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
2707 (*arg_ptr)++;
2709 if (options.debug_options & DebugExpressionTree)
2711 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2712 fprintf (stderr, " type: %s %s ",
2713 (c_type == COMP_GT) ? "gt" :
2714 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2715 (c_type == COMP_GT) ? " >" :
2716 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2717 t = our_pred->args.info.l_val;
2718 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2719 if (c_type == COMP_EQ)
2721 t = our_pred->args.info.l_val += DAYSECS;
2722 fprintf (stderr, " < %ju %s",
2723 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2724 our_pred->args.info.l_val -= DAYSECS;
2728 return true;
2731 /* Get a number with comparison information.
2732 The sense of the comparison information is 'normal'; that is,
2733 '+' looks for a count > than the number and '-' less than.
2735 STR is the ASCII representation of the number.
2736 Set *NUM to the number.
2737 Set *COMP_TYPE to the kind of comparison that is requested.
2739 Return true if all okay, false if input error. */
2741 static boolean
2742 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2744 if (str == NULL)
2745 return false;
2746 switch (str[0])
2748 case '+':
2749 *comp_type = COMP_GT;
2750 str++;
2751 break;
2752 case '-':
2753 *comp_type = COMP_LT;
2754 str++;
2755 break;
2756 default:
2757 *comp_type = COMP_EQ;
2758 break;
2761 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2764 /* Insert a number predicate.
2765 ARGV is a pointer to the argument array.
2766 *ARG_PTR is an index into ARGV, incremented if all went well.
2767 *PRED is the predicate processor to insert.
2769 Return true if input is valid, false if error.
2771 A new predicate node is assigned, along with an argument node
2772 obtained with malloc.
2774 Used by -inum and -links parsers. */
2776 static struct predicate *
2777 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2779 struct predicate *our_pred;
2780 uintmax_t num;
2781 enum comparison_type c_type;
2783 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2784 return NULL;
2785 if (!get_num (argv[*arg_ptr], &num, &c_type))
2786 return NULL;
2787 our_pred = insert_primary (entry);
2788 our_pred->args.info.kind = c_type;
2789 our_pred->args.info.l_val = num;
2790 (*arg_ptr)++;
2792 if (options.debug_options & DebugExpressionTree)
2794 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2795 fprintf (stderr, " type: %s %s ",
2796 (c_type == COMP_GT) ? "gt" :
2797 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2798 (c_type == COMP_GT) ? " >" :
2799 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2800 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2802 return our_pred;
2805 static FILE *
2806 open_output_file (char *path)
2808 FILE *f;
2810 if (!strcmp (path, "/dev/stderr"))
2811 return stderr;
2812 else if (!strcmp (path, "/dev/stdout"))
2813 return stdout;
2814 f = fopen_safer (path, "w");
2815 if (f == NULL)
2816 error (1, errno, "%s", path);
2817 return f;