Added Kinyarwanda (rw) to ALL_LINGUAS.
[findutils.git] / find / parser.c
blob97d977886e7295c5574248370d486732cdb0beef
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, int kind, struct predicate *pred));
162 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
163 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
164 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
165 static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
166 static FILE *open_output_file PARAMS((char *path));
167 static boolean stream_is_tty(FILE *fp);
168 static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
170 #define PASTE(x,y) x##y
171 #define STRINGIFY(s) #s
173 #define PARSE_OPTION(what,suffix) \
174 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
176 #define PARSE_POSOPT(what,suffix) \
177 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
179 #define PARSE_TEST(what,suffix) \
180 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
182 #define PARSE_TEST_NP(what,suffix) \
183 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_ACTION(what,suffix) \
186 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
188 #define PARSE_ACTION_NP(what,suffix) \
189 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
191 #define PARSE_PUNCTUATION(what,suffix) \
192 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
195 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
196 If they are in some Unix versions of find, they are marked `Unix'. */
198 static struct parser_table const parse_table[] =
200 PARSE_PUNCTUATION("!", negate),
201 PARSE_PUNCTUATION("not", negate), /* GNU */
202 PARSE_PUNCTUATION("(", open),
203 PARSE_PUNCTUATION(")", close),
204 PARSE_PUNCTUATION(",", comma), /* GNU */
205 PARSE_PUNCTUATION("a", and),
206 PARSE_TEST ("amin", amin), /* GNU */
207 PARSE_PUNCTUATION("and", and), /* GNU */
208 PARSE_TEST ("anewer", anewer), /* GNU */
209 {ARG_TEST, "atime", parse_time, pred_atime},
210 PARSE_TEST ("cmin", cmin), /* GNU */
211 PARSE_TEST ("cnewer", cnewer), /* GNU */
212 {ARG_TEST, "ctime", parse_time, pred_ctime},
213 PARSE_POSOPT ("daystart", daystart), /* GNU */
214 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
215 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
216 PARSE_OPTION ("depth", depth),
217 PARSE_TEST ("empty", empty), /* GNU */
218 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
219 {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
220 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
221 PARSE_ACTION ("fls", fls), /* GNU */
222 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
223 PARSE_ACTION ("fprint", fprint), /* GNU */
224 PARSE_ACTION ("fprint0", fprint0), /* GNU */
225 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
226 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
227 PARSE_TEST ("gid", gid), /* GNU */
228 PARSE_TEST ("group", group),
229 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
230 PARSE_TEST ("ilname", ilname), /* GNU */
231 PARSE_TEST ("iname", iname), /* GNU */
232 PARSE_TEST ("inum", inum), /* GNU, Unix */
233 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
234 PARSE_TEST_NP ("iregex", iregex), /* GNU */
235 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
236 PARSE_TEST ("links", links),
237 PARSE_TEST ("lname", lname), /* GNU */
238 PARSE_ACTION ("ls", ls), /* GNU, Unix */
239 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
240 PARSE_OPTION ("mindepth", mindepth), /* GNU */
241 PARSE_TEST ("mmin", mmin), /* GNU */
242 PARSE_OPTION ("mount", xdev), /* Unix */
243 {ARG_TEST, "mtime", parse_time, pred_mtime},
244 PARSE_TEST ("name", name),
245 #ifdef UNIMPLEMENTED_UNIX
246 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
247 #endif
248 PARSE_TEST ("newer", newer),
249 PARSE_OPTION ("noleaf", noleaf), /* GNU */
250 PARSE_TEST ("nogroup", nogroup),
251 PARSE_TEST ("nouser", nouser),
252 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
253 PARSE_POSOPT ("nowarn", nowarn), /* GNU */
254 PARSE_PUNCTUATION("o", or),
255 PARSE_PUNCTUATION("or", or), /* GNU */
256 PARSE_ACTION ("ok", ok),
257 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
258 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
259 PARSE_TEST ("perm", perm),
260 PARSE_ACTION ("print", print),
261 PARSE_ACTION ("print0", print0), /* GNU */
262 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
263 PARSE_ACTION ("prune", prune),
264 PARSE_ACTION ("quit", quit), /* GNU */
265 {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
266 PARSE_TEST ("regex", regex), /* GNU */
267 PARSE_OPTION ("regextype", regextype), /* GNU */
268 PARSE_TEST ("samefile", samefile), /* GNU */
269 #if 0
270 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
271 #endif
272 PARSE_TEST ("size", size),
273 PARSE_TEST ("type", type),
274 PARSE_TEST ("uid", uid), /* GNU */
275 PARSE_TEST ("used", used), /* GNU */
276 PARSE_TEST ("user", user),
277 PARSE_OPTION ("warn", warn), /* GNU */
278 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
279 {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
280 PARSE_OPTION ("xdev", xdev),
281 PARSE_TEST ("xtype", xtype), /* GNU */
282 #ifdef UNIMPLEMENTED_UNIX
283 /* It's pretty ugly for find to know about archive formats.
284 Plus what it could do with cpio archives is very limited.
285 Better to leave it out. */
286 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
287 #endif
288 /* gnulib's stdbool.h might have made true and false into macros,
289 * so we can't leave named 'true' and 'false' tokens, so we have
290 * to expeant the relevant entries longhand.
292 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
293 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
294 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
296 /* Various other cases that don't fit neatly into our macro scheme. */
297 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
298 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
299 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
300 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
301 {0, 0, 0, 0}
305 static const char *first_nonoption_arg = NULL;
306 static const struct parser_table *noop = NULL;
310 static const struct parser_table*
311 get_noop(void)
313 int i;
314 if (NULL == noop)
316 for (i = 0; parse_table[i].parser_name != 0; i++)
318 if (ARG_NOOP ==parse_table[i].type)
320 noop = &(parse_table[i]);
321 break;
325 return noop;
330 void
331 set_follow_state(enum SymlinkOption opt)
333 if (options.debug_options & DebugStat)
335 /* For DebugStat, the choice is made at runtime within debug_stat()
336 * by checking the contents of the symlink_handling variable.
338 options.xstat = debug_stat;
340 else
342 switch (opt)
344 case SYMLINK_ALWAYS_DEREF: /* -L */
345 options.xstat = optionl_stat;
346 options.no_leaf_check = true;
347 break;
349 case SYMLINK_NEVER_DEREF: /* -P (default) */
350 options.xstat = optionp_stat;
351 /* Can't turn no_leaf_check off because the user might have specified
352 * -noleaf anyway
354 break;
356 case SYMLINK_DEREF_ARGSONLY: /* -H */
357 options.xstat = optionh_stat;
358 options.no_leaf_check = true;
361 options.symlink_handling = opt;
365 void
366 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
368 (void) args;
369 (void) argno;
370 (void) last;
371 (void) predicates;
372 first_nonoption_arg = NULL;
375 void
376 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
378 /* does nothing */
379 (void) args;
380 (void) argno;
381 (void) last;
382 (void) predicates;
388 /* Return a pointer to the parser function to invoke for predicate
389 SEARCH_NAME.
390 Return NULL if SEARCH_NAME is not a valid predicate name. */
392 const struct parser_table*
393 find_parser (char *search_name)
395 int i;
396 const char *original_arg = search_name;
398 if (*search_name == '-')
399 search_name++;
400 for (i = 0; parse_table[i].parser_name != 0; i++)
402 if (strcmp (parse_table[i].parser_name, search_name) == 0)
404 /* If this is an option, but we have already had a
405 * non-option argument, the user may be under the
406 * impression that the behaviour of the option
407 * argument is conditional on some preceding
408 * tests. This might typically be the case with,
409 * for example, -maxdepth.
411 * The options -daystart and -follow are exempt
412 * from this treatment, since their positioning
413 * in the command line does have an effect on
414 * subsequent tests but not previous ones. That
415 * might be intentional on the part of the user.
417 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
419 /* Something other than -follow/-daystart.
420 * If this is an option, check if it followed
421 * a non-option and if so, issue a warning.
423 if (parse_table[i].type == ARG_OPTION)
425 if ((first_nonoption_arg != NULL)
426 && options.warnings )
428 /* option which follows a non-option */
429 error (0, 0,
430 _("warning: you have specified the %s "
431 "option after a non-option argument %s, "
432 "but options are not positional (%s affects "
433 "tests specified before it as well as those "
434 "specified after it). Please specify options "
435 "before other arguments.\n"),
436 original_arg,
437 first_nonoption_arg,
438 original_arg);
441 else
443 /* Not an option or a positional option,
444 * so remember we've seen it in order to
445 * use it in a possible future warning message.
447 if (first_nonoption_arg == NULL)
449 first_nonoption_arg = original_arg;
454 return &parse_table[i];
457 return NULL;
460 static float
461 estimate_file_age_success_rate(float num_days)
463 if (num_days < 0.1)
465 /* Assume 1% of files have timestamps in the future */
466 return 0.01f;
468 else if (num_days < 1)
470 /* Assume 30% of files have timestamps today */
471 return 0.3f;
473 else if (num_days > 100)
475 /* Assume 30% of files are very old */
476 return 0.3f;
478 else
480 /* Assume 39% of files are between 1 and 100 days old. */
481 return 0.39f;
485 static float
486 estimate_timestamp_success_rate(time_t when)
488 int num_days = (when - options.cur_day_start) / 86400;
489 return estimate_file_age_success_rate(num_days);
493 /* The parsers are responsible to continue scanning ARGV for
494 their arguments. Each parser knows what is and isn't
495 allowed for itself.
497 ARGV is the argument array.
498 *ARG_PTR is the index to start at in ARGV,
499 updated to point beyond the last element consumed.
501 The predicate structure is updated with the new information. */
503 static boolean
504 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
506 struct predicate *our_pred;
507 uintmax_t num;
508 enum comparison_type c_type;
509 time_t t;
511 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
512 return false;
513 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
514 return false;
515 t = options.cur_day_start + DAYSECS - num * 60;
516 our_pred = insert_primary (entry);
517 our_pred->args.info.kind = c_type;
518 our_pred->args.info.negative = t < 0;
519 our_pred->args.info.l_val = t;
520 our_pred->est_success_rate = estimate_file_age_success_rate(num);
521 (*arg_ptr)++;
522 return true;
525 static boolean
526 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
528 struct predicate *our_pred;
530 (void) argv;
531 (void) arg_ptr;
533 our_pred = get_new_pred (entry);
534 our_pred->pred_func = pred_and;
535 our_pred->p_type = BI_OP;
536 our_pred->p_prec = AND_PREC;
537 our_pred->need_stat = our_pred->need_type = false;
538 return true;
541 static boolean
542 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
544 struct predicate *our_pred;
545 struct stat stat_newer;
547 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
548 return false;
549 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
550 error (1, errno, "%s", argv[*arg_ptr]);
551 our_pred = insert_primary (entry);
552 our_pred->args.time = stat_newer.st_mtime;
553 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
554 (*arg_ptr)++;
555 return true;
558 boolean
559 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
561 struct predicate *our_pred;
563 (void) argv;
564 (void) arg_ptr;
566 our_pred = get_new_pred (entry);
567 our_pred->pred_func = pred_close;
568 our_pred->p_type = CLOSE_PAREN;
569 our_pred->p_prec = NO_PREC;
570 our_pred->need_stat = our_pred->need_type = false;
571 return true;
574 static boolean
575 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
577 struct predicate *our_pred;
578 uintmax_t num;
579 enum comparison_type c_type;
580 time_t t;
582 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
583 return false;
584 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
585 return false;
586 t = options.cur_day_start + DAYSECS - num * 60;
587 our_pred = insert_primary (entry);
588 our_pred->args.info.kind = c_type;
589 our_pred->args.info.negative = t < 0;
590 our_pred->args.info.l_val = t;
591 our_pred->est_success_rate = estimate_file_age_success_rate(num);
592 (*arg_ptr)++;
593 return true;
596 static boolean
597 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
599 struct predicate *our_pred;
600 struct stat stat_newer;
602 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
603 return false;
604 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
605 error (1, errno, "%s", argv[*arg_ptr]);
606 our_pred = insert_primary (entry);
607 our_pred->args.time = stat_newer.st_mtime;
608 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
609 (*arg_ptr)++;
610 return true;
613 static boolean
614 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
616 struct predicate *our_pred;
618 (void) argv;
619 (void) arg_ptr;
621 our_pred = get_new_pred (entry);
622 our_pred->pred_func = pred_comma;
623 our_pred->p_type = BI_OP;
624 our_pred->p_prec = COMMA_PREC;
625 our_pred->need_stat = our_pred->need_type = false;
626 our_pred->est_success_rate = 1.0f;
627 return true;
630 static boolean
631 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
633 struct tm *local;
635 (void) entry;
636 (void) argv;
637 (void) arg_ptr;
639 if (options.full_days == false)
641 options.cur_day_start += DAYSECS;
642 local = localtime (&options.cur_day_start);
643 options.cur_day_start -= (local
644 ? (local->tm_sec + local->tm_min * 60
645 + local->tm_hour * 3600)
646 : options.cur_day_start % DAYSECS);
647 options.full_days = true;
649 return true;
652 static boolean
653 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
655 struct predicate *our_pred;
656 (void) argv;
657 (void) arg_ptr;
659 our_pred = insert_primary (entry);
660 our_pred->side_effects = our_pred->no_default_print = true;
661 /* -delete implies -depth */
662 options.do_dir_first = false;
663 our_pred->est_success_rate = 1.0f;
664 return true;
667 static boolean
668 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
670 (void) entry;
671 (void) argv;
672 (void) arg_ptr;
674 options.do_dir_first = false;
675 return parse_noop(entry, argv, arg_ptr);
678 static boolean
679 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
681 (void) argv;
682 (void) arg_ptr;
684 if (options.warnings)
686 error (0, 0,
687 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
689 return parse_depth(entry, argv, arg_ptr);
692 static boolean
693 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
695 struct predicate *our_pred;
696 (void) argv;
697 (void) arg_ptr;
699 our_pred = insert_primary (entry);
700 our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
701 return true;
704 static boolean
705 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
707 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
710 static boolean
711 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
713 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
716 static boolean
717 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
719 struct predicate *our_pred;
721 (void) argv;
722 (void) arg_ptr;
724 our_pred = insert_primary (entry);
725 our_pred->need_stat = our_pred->need_type = false;
726 our_pred->side_effects = our_pred->no_default_print = false;
727 our_pred->est_success_rate = 0.0f;
728 return true;
731 static boolean
732 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
734 struct predicate *our_pred;
736 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
737 return false;
738 our_pred = insert_primary (entry);
739 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
740 our_pred->side_effects = our_pred->no_default_print = true;
741 our_pred->est_success_rate = 1.0f;
742 (*arg_ptr)++;
743 return true;
746 static boolean
747 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
749 FILE *fp;
751 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
752 return false;
753 if (argv[*arg_ptr + 1] == NULL)
755 /* Ensure we get "missing arg" message, not "invalid arg". */
756 (*arg_ptr)++;
757 return false;
759 fp = open_output_file (argv[*arg_ptr]);
760 (*arg_ptr)++;
761 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
764 static boolean
765 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
767 (void) entry;
768 (void) argv;
769 (void) arg_ptr;
771 set_follow_state(SYMLINK_ALWAYS_DEREF);
772 return parse_noop(entry, argv, arg_ptr);
775 static boolean
776 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
778 struct predicate *our_pred;
780 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
781 return false;
782 our_pred = insert_primary (entry);
783 our_pred->args.printf_vec.segment = NULL;
784 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
785 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
786 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
787 our_pred->side_effects = our_pred->no_default_print = true;
788 our_pred->need_stat = our_pred->need_type = false;
789 our_pred->est_success_rate = 1.0f;
790 (*arg_ptr)++;
791 return true;
794 static boolean
795 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
797 struct predicate *our_pred;
799 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
800 return false;
801 our_pred = insert_primary (entry);
802 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
803 our_pred->side_effects = our_pred->no_default_print = true;
804 our_pred->need_stat = our_pred->need_type = false;
805 our_pred->est_success_rate = 1.0f;
806 (*arg_ptr)++;
807 return true;
810 static float estimate_fstype_success_rate(const char *fsname)
812 struct stat dir_stat;
813 const char *dir = "/";
814 if (0 == stat(dir, &dir_stat))
816 const char *fstype = filesystem_type(&dir_stat, dir);
817 /* Assume most files are on the same filesystem type as the root fs. */
818 if (0 == strcmp(fsname, fstype))
819 return 0.7f;
820 else
821 return 0.3f;
823 return 1.0f;
827 static boolean
828 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
830 struct predicate *our_pred;
832 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
833 return false;
834 our_pred = insert_primary (entry);
835 our_pred->args.str = argv[*arg_ptr];
837 /* This is an expensive operation, so although there are
838 * circumstances where it is selective, we ignore this fact because
839 * we probably don't want to promote this test to the front anyway.
841 our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
842 (*arg_ptr)++;
843 return true;
846 static boolean
847 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
849 struct predicate *p = insert_num (argv, arg_ptr, entry);
850 p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
851 return p;
854 static boolean
855 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
857 struct group *cur_gr;
858 struct predicate *our_pred;
859 gid_t gid;
860 int gid_len;
862 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
863 return false;
864 cur_gr = getgrnam (argv[*arg_ptr]);
865 endgrent ();
866 if (cur_gr != NULL)
867 gid = cur_gr->gr_gid;
868 else
870 gid_len = strspn (argv[*arg_ptr], "0123456789");
871 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
872 return false;
873 gid = atoi (argv[*arg_ptr]);
875 our_pred = insert_primary (entry);
876 our_pred->args.gid = gid;
877 our_pred->est_success_rate = (our_pred->args.info.l_val < 100) ? 0.99 : 0.2;
878 (*arg_ptr)++;
879 return true;
882 static boolean
883 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
885 (void) entry;
886 (void) argv;
887 (void) arg_ptr;
889 usage(stdout, 0, NULL);
890 puts (_("\n\
891 default path is the current directory; default expression is -print\n\
892 expression may consist of: operators, options, tests, and actions:\n"));
893 puts (_("\
894 operators (decreasing precedence; -and is implicit where no others are given):\n\
895 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
896 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
897 puts (_("\
898 positional options (always true): -daystart -follow -regextype\n\n\
899 normal options (always true, specified before other expressions):\n\
900 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
901 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
902 puts (_("\
903 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
904 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
905 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
906 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
907 puts (_("\
908 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
909 -readable -writable -executable\n\
910 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
911 -used N -user NAME -xtype [bcdpfls]\n"));
912 puts (_("\
913 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
914 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
915 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
916 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
917 "));
918 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
919 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
920 email to <bug-findutils@gnu.org>."));
921 exit (0);
924 static float estimate_pattern_match_rate(const char *pattern, int is_regex)
926 if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
928 /* A wildcard; assume the pattern matches most files. */
929 return 0.8f;
931 else
933 return 0.1f;
937 static boolean
938 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
940 struct predicate *our_pred;
942 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
943 return false;
944 our_pred = insert_primary (entry);
945 our_pred->args.str = argv[*arg_ptr];
946 /* Use the generic glob pattern estimator to figure out how many
947 * links will match, but bear in mind that most files won't be links.
949 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
950 (*arg_ptr)++;
951 return true;
955 /* sanity check the fnmatch() function to make sure
956 * it really is the GNU version.
958 static boolean
959 fnmatch_sanitycheck(void)
961 /* fprintf(stderr, "Performing find sanity check..."); */
962 if (0 != fnmatch("foo", "foo", 0)
963 || 0 == fnmatch("Foo", "foo", 0)
964 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
966 error (1, 0, _("sanity check of the fnmatch() library function failed."));
967 /* fprintf(stderr, "FAILED\n"); */
968 return false;
971 /* fprintf(stderr, "OK\n"); */
972 return true;
976 static boolean
977 check_name_arg(const char *pred, const char *arg)
979 if (strchr(arg, '/'))
981 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'."),
982 pred, arg, arg);
984 return true; /* allow it anyway */
989 static boolean
990 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
992 struct predicate *our_pred;
994 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
995 return false;
996 if (!check_name_arg("-iname", argv[*arg_ptr]))
997 return false;
999 fnmatch_sanitycheck();
1001 our_pred = insert_primary (entry);
1002 our_pred->need_stat = our_pred->need_type = false;
1003 our_pred->args.str = argv[*arg_ptr];
1004 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1005 (*arg_ptr)++;
1006 return true;
1009 static boolean
1010 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
1012 struct predicate *p = insert_num (argv, arg_ptr, entry);
1013 /* inode number is exact match only, so very low proportions of files match */
1014 p->est_success_rate = 1e-6;
1015 return p;
1018 /* -ipath is deprecated (at RMS's request) in favour of
1019 * -iwholename. See the node "GNU Manuals" in standards.texi
1020 * for the rationale for this (basically, GNU prefers the use
1021 * of the phrase "file name" to "path name"
1023 static boolean
1024 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
1026 error (0, 0,
1027 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1029 return parse_iwholename(entry, argv, arg_ptr);
1032 static boolean
1033 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1035 struct predicate *our_pred;
1037 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1038 return false;
1040 fnmatch_sanitycheck();
1042 our_pred = insert_primary_withpred (entry, pred_ipath);
1043 our_pred->need_stat = our_pred->need_type = false;
1044 our_pred->args.str = argv[*arg_ptr];
1045 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1046 (*arg_ptr)++;
1047 return true;
1050 static boolean
1051 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
1053 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
1056 static boolean
1057 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
1059 struct predicate *p = insert_num (argv, arg_ptr, entry);
1060 if (p->args.info.l_val == 1)
1061 p->est_success_rate = 0.99;
1062 else if (p->args.info.l_val == 2)
1063 p->est_success_rate = 0.01;
1064 else
1065 p->est_success_rate = 1e-3;
1066 return p;
1069 static boolean
1070 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
1072 struct predicate *our_pred;
1074 (void) argv;
1075 (void) arg_ptr;
1077 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1078 return false;
1080 fnmatch_sanitycheck();
1082 our_pred = insert_primary (entry);
1083 our_pred->args.str = argv[*arg_ptr];
1084 our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
1085 (*arg_ptr)++;
1086 return true;
1089 static boolean
1090 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1092 struct predicate *our_pred;
1094 (void) &argv;
1095 (void) &arg_ptr;
1097 our_pred = insert_primary (entry);
1098 our_pred->side_effects = our_pred->no_default_print = true;
1099 return true;
1102 static boolean
1103 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1105 int depth_len;
1106 (void) entry;
1108 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1109 return false;
1110 depth_len = strspn (argv[*arg_ptr], "0123456789");
1111 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1112 return false;
1113 options.maxdepth = atoi (argv[*arg_ptr]);
1114 if (options.maxdepth < 0)
1115 return false;
1116 (*arg_ptr)++;
1117 return parse_noop(entry, argv, arg_ptr);
1120 static boolean
1121 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1123 int depth_len;
1124 (void) entry;
1126 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1127 return false;
1128 depth_len = strspn (argv[*arg_ptr], "0123456789");
1129 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1130 return false;
1131 options.mindepth = atoi (argv[*arg_ptr]);
1132 if (options.mindepth < 0)
1133 return false;
1134 (*arg_ptr)++;
1135 return parse_noop(entry, argv, arg_ptr);
1138 static boolean
1139 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1141 struct predicate *our_pred;
1142 uintmax_t num;
1143 enum comparison_type c_type;
1144 time_t t;
1146 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1147 return false;
1148 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
1149 return false;
1150 t = options.cur_day_start + DAYSECS - num * 60;
1151 our_pred = insert_primary (entry);
1152 our_pred->args.info.kind = c_type;
1153 our_pred->args.info.negative = t < 0;
1154 our_pred->args.info.l_val = t;
1155 our_pred->est_success_rate = estimate_file_age_success_rate(num);
1156 (*arg_ptr)++;
1157 return true;
1160 static boolean
1161 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1163 struct predicate *our_pred;
1165 (void) argv;
1166 (void) arg_ptr;
1168 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1169 return false;
1170 if (!check_name_arg("-name", argv[*arg_ptr]))
1171 return false;
1172 fnmatch_sanitycheck();
1174 our_pred = insert_primary (entry);
1175 our_pred->need_stat = our_pred->need_type = false;
1176 our_pred->args.str = argv[*arg_ptr];
1177 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1178 (*arg_ptr)++;
1179 return true;
1182 static boolean
1183 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1185 struct predicate *our_pred;
1187 (void) &argv;
1188 (void) &arg_ptr;
1190 our_pred = get_new_pred_chk_op (entry);
1191 our_pred->pred_func = pred_negate;
1192 our_pred->p_type = UNI_OP;
1193 our_pred->p_prec = NEGATE_PREC;
1194 our_pred->need_stat = our_pred->need_type = false;
1195 return true;
1198 static boolean
1199 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1201 struct predicate *our_pred;
1202 struct stat stat_newer;
1204 (void) argv;
1205 (void) arg_ptr;
1207 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1208 return false;
1209 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1210 error (1, errno, "%s", argv[*arg_ptr]);
1211 our_pred = insert_primary (entry);
1212 our_pred->args.time = stat_newer.st_mtime;
1213 our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
1214 (*arg_ptr)++;
1215 return true;
1218 static boolean
1219 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1221 (void) &argv;
1222 (void) &arg_ptr;
1223 (void) entry;
1225 options.no_leaf_check = true;
1226 return parse_noop(entry, argv, arg_ptr);
1229 #ifdef CACHE_IDS
1230 /* Arbitrary amount by which to increase size
1231 of `uid_unused' and `gid_unused'. */
1232 #define ALLOC_STEP 2048
1234 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1235 char *uid_unused = NULL;
1237 /* Number of elements in `uid_unused'. */
1238 unsigned uid_allocated;
1240 /* Similar for GIDs and group entries. */
1241 char *gid_unused = NULL;
1242 unsigned gid_allocated;
1243 #endif
1245 static boolean
1246 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1248 struct predicate *our_pred;
1250 (void) &argv;
1251 (void) &arg_ptr;
1253 our_pred = insert_primary (entry);
1254 our_pred->est_success_rate = 1e-4;
1255 #ifdef CACHE_IDS
1256 if (gid_unused == NULL)
1258 struct group *gr;
1260 gid_allocated = ALLOC_STEP;
1261 gid_unused = xmalloc (gid_allocated);
1262 memset (gid_unused, 1, gid_allocated);
1263 setgrent ();
1264 while ((gr = getgrent ()) != NULL)
1266 if ((unsigned) gr->gr_gid >= gid_allocated)
1268 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1269 gid_unused = xrealloc (gid_unused, new_allocated);
1270 memset (gid_unused + gid_allocated, 1,
1271 new_allocated - gid_allocated);
1272 gid_allocated = new_allocated;
1274 gid_unused[(unsigned) gr->gr_gid] = 0;
1276 endgrent ();
1278 #endif
1279 return true;
1282 static boolean
1283 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1285 struct predicate *our_pred;
1286 (void) argv;
1287 (void) arg_ptr;
1290 our_pred = insert_primary (entry);
1291 our_pred->est_success_rate = 1e-3;
1292 #ifdef CACHE_IDS
1293 if (uid_unused == NULL)
1295 struct passwd *pw;
1297 uid_allocated = ALLOC_STEP;
1298 uid_unused = xmalloc (uid_allocated);
1299 memset (uid_unused, 1, uid_allocated);
1300 setpwent ();
1301 while ((pw = getpwent ()) != NULL)
1303 if ((unsigned) pw->pw_uid >= uid_allocated)
1305 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1306 uid_unused = xrealloc (uid_unused, new_allocated);
1307 memset (uid_unused + uid_allocated, 1,
1308 new_allocated - uid_allocated);
1309 uid_allocated = new_allocated;
1311 uid_unused[(unsigned) pw->pw_uid] = 0;
1313 endpwent ();
1315 #endif
1316 return true;
1319 static boolean
1320 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1322 (void) argv;
1323 (void) arg_ptr;
1324 (void) entry;
1326 options.warnings = false;
1327 return parse_noop(entry, argv, arg_ptr);
1330 static boolean
1331 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1333 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1336 static boolean
1337 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1339 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1342 boolean
1343 parse_open (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_chk_op (entry);
1351 our_pred->pred_func = pred_open;
1352 our_pred->p_type = OPEN_PAREN;
1353 our_pred->p_prec = NO_PREC;
1354 our_pred->need_stat = our_pred->need_type = false;
1355 return true;
1358 static boolean
1359 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1361 struct predicate *our_pred;
1363 (void) argv;
1364 (void) arg_ptr;
1366 our_pred = get_new_pred (entry);
1367 our_pred->pred_func = pred_or;
1368 our_pred->p_type = BI_OP;
1369 our_pred->p_prec = OR_PREC;
1370 our_pred->need_stat = our_pred->need_type = false;
1371 return true;
1374 /* -path is deprecated (at RMS's request) in favour of
1375 * -iwholename. See the node "GNU Manuals" in standards.texi
1376 * for the rationale for this (basically, GNU prefers the use
1377 * of the phrase "file name" to "path name".
1379 * We do not issue a warning that this usage is deprecated
1380 * since HPUX find supports this predicate also.
1382 static boolean
1383 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1385 return parse_wholename(entry, argv, arg_ptr);
1388 static boolean
1389 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1391 struct predicate *our_pred;
1393 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1394 return false;
1395 our_pred = insert_primary_withpred (entry, pred_path);
1396 our_pred->need_stat = our_pred->need_type = false;
1397 our_pred->args.str = argv[*arg_ptr];
1398 our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
1399 (*arg_ptr)++;
1400 return true;
1403 static boolean
1404 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1406 mode_t perm_val[2];
1407 float rate;
1408 int mode_start = 0;
1409 boolean havekind = false;
1410 enum permissions_type kind = PERM_EXACT;
1411 struct mode_change *change = NULL;
1412 struct predicate *our_pred;
1414 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1415 return false;
1417 switch (argv[*arg_ptr][0])
1419 case '-':
1420 mode_start = 1;
1421 kind = PERM_AT_LEAST;
1422 havekind = true;
1423 rate = 0.2;
1424 break;
1426 case '+':
1427 change = mode_compile (argv[*arg_ptr]);
1428 if (NULL == change)
1430 /* Most likely the caller is an old script that is still
1431 * using the obsolete GNU syntax '-perm +MODE'. This old
1432 * syntax was withdrawn in favor of '-perm /MODE' because
1433 * it is incompatible with POSIX in some cases, but we
1434 * still support uses of it that are not incompatible with
1435 * POSIX.
1437 mode_start = 1;
1438 kind = PERM_ANY;
1439 rate = 0.3;
1441 else
1443 /* This is a POSIX-compatible usage */
1444 mode_start = 0;
1445 kind = PERM_EXACT;
1446 rate = 0.1;
1448 havekind = true;
1449 break;
1451 case '/': /* GNU extension */
1452 mode_start = 1;
1453 kind = PERM_ANY;
1454 havekind = true;
1455 rate = 0.3;
1456 break;
1458 default:
1459 /* For example, '-perm 0644', which is valid and matches
1460 * only files whose mode is exactly 0644.
1462 * We do nothing here, because mode_start and kind are already
1463 * correctly set.
1465 rate = 0.01;
1466 break;
1469 if (NULL == change)
1471 change = mode_compile (argv[*arg_ptr] + mode_start);
1472 if (NULL == change)
1473 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1475 perm_val[0] = mode_adjust (0, false, 0, change, NULL);
1476 perm_val[1] = mode_adjust (0, true, 0, change, NULL);
1477 free (change);
1479 our_pred = insert_primary (entry);
1480 our_pred->est_success_rate = rate;
1481 if (havekind)
1483 our_pred->args.perm.kind = kind;
1485 else
1488 switch (argv[*arg_ptr][0])
1490 case '-':
1491 our_pred->args.perm.kind = PERM_AT_LEAST;
1492 break;
1493 case '+':
1494 our_pred->args.perm.kind = PERM_ANY;
1495 break;
1496 default:
1497 our_pred->args.perm.kind = PERM_EXACT;
1498 break;
1501 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
1503 /* The meaning of -perm /000 will change in the future.
1504 * It currently matches no files, but like -perm -000 it
1505 * should match all files.
1507 error (0, 0,
1508 _("warning: you have specified a mode pattern %s which is "
1509 "equivalent to 000. The meaning of -perm /000 will soon be "
1510 "changed to be consistent with -perm -000; that is, at the "
1511 "moment it matches no files but it will soon be changed to "
1512 "match all files."),
1513 argv[*arg_ptr]);
1516 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
1517 (*arg_ptr)++;
1518 return true;
1521 boolean
1522 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1524 struct predicate *our_pred;
1526 (void) argv;
1527 (void) arg_ptr;
1529 our_pred = insert_primary (entry);
1530 /* -print has the side effect of printing. This prevents us
1531 from doing undesired multiple printing when the user has
1532 already specified -print. */
1533 our_pred->side_effects = our_pred->no_default_print = true;
1534 our_pred->need_stat = our_pred->need_type = false;
1535 our_pred->args.printf_vec.segment = NULL;
1536 our_pred->args.printf_vec.stream = stdout;
1537 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1538 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1540 return true;
1543 static boolean
1544 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1546 struct predicate *our_pred;
1548 (void) argv;
1549 (void) arg_ptr;
1551 our_pred = insert_primary (entry);
1552 /* -print0 has the side effect of printing. This prevents us
1553 from doing undesired multiple printing when the user has
1554 already specified -print0. */
1555 our_pred->side_effects = our_pred->no_default_print = true;
1556 our_pred->need_stat = our_pred->need_type = false;
1557 return true;
1560 static boolean
1561 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1563 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1564 return false;
1565 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1568 static boolean
1569 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1571 struct predicate *our_pred;
1573 (void) argv;
1574 (void) arg_ptr;
1576 our_pred = insert_primary (entry);
1577 our_pred->need_stat = our_pred->need_type = false;
1578 /* -prune has a side effect that it does not descend into
1579 the current directory. */
1580 our_pred->side_effects = true;
1581 our_pred->no_default_print = false;
1582 return true;
1585 static boolean
1586 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1588 struct predicate *our_pred = insert_primary (entry);
1589 (void) argv;
1590 (void) arg_ptr;
1591 our_pred->need_stat = our_pred->need_type = false;
1592 our_pred->side_effects = true; /* Exiting is a side effect... */
1593 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1594 our_pred->est_success_rate = 1e-6;
1595 return true;
1599 static boolean
1600 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1602 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1603 return false;
1605 /* collect the regex type name */
1606 options.regex_options = get_regex_type(argv[*arg_ptr]);
1607 (*arg_ptr)++;
1609 return parse_noop(entry, argv, arg_ptr);
1613 static boolean
1614 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1616 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1619 static boolean
1620 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1622 struct predicate *our_pred;
1623 struct re_pattern_buffer *re;
1624 const char *error_message;
1626 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1627 return false;
1628 our_pred = insert_primary_withpred (entry, pred_regex);
1629 our_pred->need_stat = our_pred->need_type = false;
1630 re = (struct re_pattern_buffer *)
1631 xmalloc (sizeof (struct re_pattern_buffer));
1632 our_pred->args.regex = re;
1633 re->allocated = 100;
1634 re->buffer = (unsigned char *) xmalloc (re->allocated);
1635 re->fastmap = NULL;
1637 re_set_syntax(regex_options);
1638 re->syntax = regex_options;
1639 re->translate = NULL;
1641 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1642 re);
1643 if (error_message)
1644 error (1, 0, "%s", error_message);
1645 our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
1646 (*arg_ptr)++;
1647 return true;
1650 static boolean
1651 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1653 struct predicate *our_pred;
1654 uintmax_t num;
1655 enum comparison_type c_type;
1656 int blksize = 512;
1657 int len;
1658 float rate = 1.0;
1660 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1661 return false;
1662 len = strlen (argv[*arg_ptr]);
1663 if (len == 0)
1664 error (1, 0, _("invalid null argument to -size"));
1665 switch (argv[*arg_ptr][len - 1])
1667 case 'b':
1668 blksize = 512;
1669 argv[*arg_ptr][len - 1] = '\0';
1670 break;
1672 case 'c':
1673 blksize = 1;
1674 argv[*arg_ptr][len - 1] = '\0';
1675 break;
1677 case 'k':
1678 blksize = 1024;
1679 argv[*arg_ptr][len - 1] = '\0';
1680 break;
1682 case 'M': /* Megabytes */
1683 blksize = 1024*1024;
1684 argv[*arg_ptr][len - 1] = '\0';
1685 break;
1687 case 'G': /* Gigabytes */
1688 blksize = 1024*1024*1024;
1689 argv[*arg_ptr][len - 1] = '\0';
1690 break;
1692 case 'w':
1693 blksize = 2;
1694 argv[*arg_ptr][len - 1] = '\0';
1695 break;
1697 case '0':
1698 case '1':
1699 case '2':
1700 case '3':
1701 case '4':
1702 case '5':
1703 case '6':
1704 case '7':
1705 case '8':
1706 case '9':
1707 break;
1709 default:
1710 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1712 if (!get_num (argv[*arg_ptr], &num, &c_type))
1713 return false;
1714 our_pred = insert_primary (entry);
1715 our_pred->args.size.kind = c_type;
1716 our_pred->args.size.blocksize = blksize;
1717 our_pred->args.size.size = num;
1718 our_pred->need_stat = true;
1719 our_pred->need_type = false;
1721 if (COMP_GT == c_type)
1722 our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
1723 else if (COMP_LT == c_type)
1724 our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
1725 else
1726 our_pred->est_success_rate = 0.01;
1728 (*arg_ptr)++;
1729 return true;
1733 static boolean
1734 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1736 struct predicate *our_pred;
1737 struct stat st;
1739 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1740 return false;
1741 if ((*options.xstat) (argv[*arg_ptr], &st))
1742 error (1, errno, "%s", argv[*arg_ptr]);
1744 our_pred = insert_primary (entry);
1745 our_pred->args.fileid.ino = st.st_ino;
1746 our_pred->args.fileid.dev = st.st_dev;
1747 our_pred->need_type = false;
1748 our_pred->need_stat = true;
1749 our_pred->est_success_rate = 0.01f;
1750 (*arg_ptr)++;
1751 return true;
1754 #if 0
1755 static boolean
1756 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1758 const char *arg;
1759 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1760 "must be 'literal' or 'safe'");
1762 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1764 error (1, errno, "%s", errmsg);
1765 return false;
1767 else
1769 arg = argv[*arg_ptr];
1771 if (0 == strcmp("literal", arg))
1773 options.literal_control_chars = true;
1775 else if (0 == strcmp("safe", arg))
1777 options.literal_control_chars = false;
1779 else
1781 error (1, errno, "%s", errmsg);
1782 return false;
1784 (*arg_ptr)++; /* consume the argument. */
1785 return true;
1788 #endif
1791 static boolean
1792 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1794 struct predicate *our_pred;
1796 (void) argv;
1797 (void) arg_ptr;
1799 our_pred = insert_primary (entry);
1800 our_pred->need_stat = our_pred->need_type = false;
1801 our_pred->est_success_rate = 1.0f;
1802 return true;
1805 static boolean
1806 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
1808 (void) entry;
1809 return parse_true(get_noop(), argv, arg_ptr);
1812 static boolean
1813 parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1815 struct predicate *our_pred;
1816 (void) argv;
1817 (void) arg_ptr;
1818 our_pred = insert_primary (entry);
1819 our_pred->need_stat = our_pred->need_type = false;
1820 our_pred->side_effects = our_pred->no_default_print = false;
1821 if (our_pred->pred_func == pred_executable)
1822 our_pred->est_success_rate = 0.2;
1823 else
1824 our_pred->est_success_rate = 0.9;
1825 return true;
1828 static boolean
1829 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1831 return insert_type (argv, arg_ptr, entry, pred_type);
1834 static boolean
1835 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1837 struct predicate *p = insert_num (argv, arg_ptr, entry);
1838 p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
1839 return p;
1842 static boolean
1843 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1845 struct predicate *our_pred;
1846 uintmax_t num_days;
1847 enum comparison_type c_type;
1848 time_t t;
1850 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1851 return false;
1852 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1853 return false;
1854 t = num_days * DAYSECS;
1855 our_pred = insert_primary (entry);
1856 our_pred->args.info.kind = c_type;
1857 our_pred->args.info.negative = t < 0;
1858 our_pred->args.info.l_val = t;
1859 our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
1860 (*arg_ptr)++;
1861 return true;
1864 static boolean
1865 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1867 struct passwd *cur_pwd;
1868 struct predicate *our_pred;
1869 uid_t uid;
1870 int uid_len;
1872 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1873 return false;
1874 cur_pwd = getpwnam (argv[*arg_ptr]);
1875 endpwent ();
1876 if (cur_pwd != NULL)
1877 uid = cur_pwd->pw_uid;
1878 else
1880 uid_len = strspn (argv[*arg_ptr], "0123456789");
1881 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1882 return false;
1883 uid = atoi (argv[*arg_ptr]);
1885 our_pred = insert_primary (entry);
1886 our_pred->args.uid = uid;
1887 our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
1888 (*arg_ptr)++;
1889 return true;
1892 static boolean
1893 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1895 extern char *version_string;
1896 int features = 0;
1898 (void) argv;
1899 (void) arg_ptr;
1900 (void) entry;
1902 fflush (stderr);
1903 printf (_("GNU find version %s\n"), version_string);
1904 printf (_("Features enabled: "));
1906 #if CACHE_IDS
1907 printf("CACHE_IDS ");
1908 ++features;
1909 #endif
1910 #if DEBUG
1911 printf("DEBUG ");
1912 ++features;
1913 #endif
1914 #if DEBUG_STAT
1915 printf("DEBUG_STAT ");
1916 ++features;
1917 #endif
1918 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1919 printf("D_TYPE ");
1920 ++features;
1921 #endif
1922 #if defined(O_NOFOLLOW)
1923 printf("O_NOFOLLOW(%s) ",
1924 (options.open_nofollow_available ? "enabled" : "disabled"));
1925 ++features;
1926 #endif
1927 #if defined(LEAF_OPTIMISATION)
1928 printf("LEAF_OPTIMISATION ");
1929 ++features;
1930 #endif
1932 if (is_fts_enabled())
1934 printf("FTS ");
1935 ++features;
1938 printf("CBO(level=%d) ", (int)(options.optimisation_level));
1939 ++features;
1941 if (0 == features)
1943 /* For the moment, leave this as English in case someone wants
1944 to parse these strings. */
1945 printf("none");
1947 printf("\n");
1949 exit (0);
1952 static boolean
1953 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1955 (void) argv;
1956 (void) arg_ptr;
1957 (void) entry;
1958 options.stay_on_filesystem = true;
1959 return parse_noop(entry, argv, arg_ptr);
1962 static boolean
1963 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1965 (void) argv;
1966 (void) arg_ptr;
1967 (void) entry;
1968 options.ignore_readdir_race = true;
1969 return parse_noop(entry, argv, arg_ptr);
1972 static boolean
1973 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1975 (void) argv;
1976 (void) arg_ptr;
1977 (void) entry;
1978 options.ignore_readdir_race = false;
1979 return parse_noop(entry, argv, arg_ptr);
1982 static boolean
1983 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1985 (void) argv;
1986 (void) arg_ptr;
1987 (void) entry;
1988 options.warnings = true;
1989 return parse_noop(entry, argv, arg_ptr);
1992 static boolean
1993 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1995 (void) argv;
1996 (void) arg_ptr;
1997 return insert_type (argv, arg_ptr, entry, pred_xtype);
2000 static boolean
2001 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
2003 mode_t type_cell;
2004 struct predicate *our_pred;
2005 float rate = 0.5;
2007 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
2008 || (strlen (argv[*arg_ptr]) != 1))
2009 return false;
2010 switch (argv[*arg_ptr][0])
2012 case 'b': /* block special */
2013 type_cell = S_IFBLK;
2014 rate = 0.01f;
2015 break;
2016 case 'c': /* character special */
2017 type_cell = S_IFCHR;
2018 rate = 0.01f;
2019 break;
2020 case 'd': /* directory */
2021 type_cell = S_IFDIR;
2022 rate = 0.4f;
2023 break;
2024 case 'f': /* regular file */
2025 type_cell = S_IFREG;
2026 rate = 0.95f;
2027 break;
2028 #ifdef S_IFLNK
2029 case 'l': /* symbolic link */
2030 type_cell = S_IFLNK;
2031 rate = 0.1f;
2032 break;
2033 #endif
2034 #ifdef S_IFIFO
2035 case 'p': /* pipe */
2036 type_cell = S_IFIFO;
2037 rate = 0.01f;
2038 break;
2039 #endif
2040 #ifdef S_IFSOCK
2041 case 's': /* socket */
2042 type_cell = S_IFSOCK;
2043 rate = 0.01f;
2044 break;
2045 #endif
2046 #ifdef S_IFDOOR
2047 case 'D': /* Solaris door */
2048 type_cell = S_IFDOOR;
2049 rate = 0.01f;
2050 break;
2051 #endif
2052 default: /* None of the above ... nuke 'em. */
2053 return false;
2055 our_pred = insert_primary_withpred (entry, which_pred);
2056 our_pred->est_success_rate = rate;
2058 /* Figure out if we will need to stat the file, because if we don't
2059 * need to follow symlinks, we can avoid a stat call by using
2060 * struct dirent.d_type.
2062 if (which_pred == pred_xtype)
2064 our_pred->need_stat = true;
2065 our_pred->need_type = false;
2067 else
2069 our_pred->need_stat = false; /* struct dirent is enough */
2070 our_pred->need_type = true;
2072 our_pred->args.type = type_cell;
2073 (*arg_ptr)++; /* Move on to next argument. */
2074 return true;
2078 /* Return true if the file accessed via FP is a terminal.
2080 static boolean
2081 stream_is_tty(FILE *fp)
2083 int fd = fileno(fp);
2084 if (-1 == fd)
2086 return false; /* not a valid stream */
2088 else
2090 return isatty(fd) ? true : false;
2098 /* XXX: do we need to pass FUNC to this function? */
2099 static boolean
2100 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
2102 char *format; /* Beginning of unprocessed format string. */
2103 register char *scan; /* Current address in scanning `format'. */
2104 register char *scan2; /* Address inside of element being scanned. */
2105 struct segment **segmentp; /* Address of current segment. */
2106 struct predicate *our_pred;
2108 format = argv[(*arg_ptr)++];
2110 our_pred = insert_primary_withpred (entry, func);
2111 our_pred->side_effects = our_pred->no_default_print = true;
2112 our_pred->args.printf_vec.stream = fp;
2113 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
2114 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2115 our_pred->need_type = false;
2116 our_pred->need_stat = false;
2118 segmentp = &our_pred->args.printf_vec.segment;
2119 *segmentp = NULL;
2121 for (scan = format; *scan; scan++)
2123 if (*scan == '\\')
2125 scan2 = scan + 1;
2126 if (*scan2 >= '0' && *scan2 <= '7')
2128 register int n, i;
2130 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2131 i++, scan2++)
2132 n = 8 * n + *scan2 - '0';
2133 scan2--;
2134 *scan = n;
2136 else
2138 switch (*scan2)
2140 case 'a':
2141 *scan = 7;
2142 break;
2143 case 'b':
2144 *scan = '\b';
2145 break;
2146 case 'c':
2147 make_segment (segmentp, format, scan - format, KIND_STOP,
2148 our_pred);
2149 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
2150 our_pred->p_cost = NeedsStatInfo;
2151 return true;
2152 case 'f':
2153 *scan = '\f';
2154 break;
2155 case 'n':
2156 *scan = '\n';
2157 break;
2158 case 'r':
2159 *scan = '\r';
2160 break;
2161 case 't':
2162 *scan = '\t';
2163 break;
2164 case 'v':
2165 *scan = '\v';
2166 break;
2167 case '\\':
2168 /* *scan = '\\'; * it already is */
2169 break;
2170 default:
2171 error (0, 0,
2172 _("warning: unrecognized escape `\\%c'"), *scan2);
2173 scan++;
2174 continue;
2177 segmentp = make_segment (segmentp, format, scan - format + 1,
2178 KIND_PLAIN, 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, our_pred);
2193 scan++;
2194 format = scan + 1;
2195 continue;
2197 /* Scan past flags, width and precision, to verify kind. */
2198 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2199 /* Do nothing. */ ;
2200 while (ISDIGIT (*scan2))
2201 scan2++;
2202 if (*scan2 == '.')
2203 for (scan2++; ISDIGIT (*scan2); scan2++)
2204 /* Do nothing. */ ;
2205 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
2207 segmentp = make_segment (segmentp, format, scan2 - format,
2208 (int) *scan2, our_pred);
2209 scan = scan2;
2210 format = scan + 1;
2212 else if (strchr ("ACT", *scan2) && scan2[1])
2214 segmentp = make_segment (segmentp, format, scan2 - format,
2215 *scan2 | (scan2[1] << 8),
2216 our_pred);
2217 scan = scan2 + 1;
2218 format = scan + 1;
2219 continue;
2221 else
2223 /* An unrecognized % escape. Print the char after the %. */
2224 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2225 *scan2);
2226 segmentp = make_segment (segmentp, format, scan - format,
2227 KIND_PLAIN, our_pred);
2228 format = scan + 1;
2229 continue;
2234 if (scan > format)
2235 make_segment (segmentp, format, scan - format, KIND_PLAIN,
2236 our_pred);
2237 return true;
2240 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2241 from the text in FORMAT, which has length LEN.
2242 Return the address of the `next' pointer of the new segment. */
2244 static struct segment **
2245 make_segment (struct segment **segment, char *format, int len, int kind,
2246 struct predicate *pred)
2248 enum EvaluationCost mycost = NeedsNothing;
2249 char *fmt;
2251 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2253 (*segment)->kind = kind;
2254 (*segment)->next = NULL;
2255 (*segment)->text_len = len;
2257 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2258 strncpy (fmt, format, len);
2259 fmt += len;
2261 switch (kind & 0xff)
2263 case KIND_PLAIN: /* Plain text string, no % conversion. */
2264 case KIND_STOP: /* Terminate argument, no newline. */
2265 break;
2267 case 'l': /* object of symlink */
2268 pred->need_stat = true;
2269 mycost = NeedsLinkName;
2270 *fmt++ = 's';
2271 break;
2273 case 'y': /* file type */
2274 pred->need_type = true;
2275 mycost = NeedsType;
2276 *fmt++ = 's';
2277 break;
2279 case 'a': /* atime in `ctime' format */
2280 case 'A': /* atime in user-specified strftime format */
2281 case 'c': /* ctime in `ctime' format */
2282 case 'C': /* ctime in user-specified strftime format */
2283 case 'F': /* filesystem type */
2284 case 'g': /* group name */
2285 case 'i': /* inode number */
2286 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2287 case 's': /* size in bytes */
2288 case 't': /* mtime in `ctime' format */
2289 case 'T': /* mtime in user-specified strftime format */
2290 case 'u': /* user name */
2291 pred->need_stat = true;
2292 mycost = NeedsStatInfo;
2293 *fmt++ = 's';
2294 break;
2296 case 'Y': /* symlink pointed file type */
2297 pred->need_stat = true;
2298 mycost = NeedsType; /* true for amortised effect */
2299 *fmt++ = 's';
2300 break;
2302 case 'f': /* basename of path */
2303 case 'h': /* leading directories part of path */
2304 case 'H': /* ARGV element file was found under */
2305 case 'p': /* pathname */
2306 case 'P': /* pathname with ARGV element stripped */
2307 *fmt++ = 's';
2308 break;
2310 /* Numeric items that one might expect to honour
2311 * #, 0, + flags but which do not.
2313 case 'G': /* GID number */
2314 case 'U': /* UID number */
2315 case 'b': /* size in 512-byte blocks */
2316 case 'D': /* Filesystem device on which the file exits */
2317 case 'k': /* size in 1K blocks */
2318 case 'n': /* number of links */
2319 pred->need_stat = true;
2320 mycost = NeedsStatInfo;
2321 *fmt++ = 's';
2322 break;
2324 /* Numeric items that DO honour #, 0, + flags.
2326 case 'd': /* depth in search tree (0 = ARGV element) */
2327 *fmt++ = 'd';
2328 break;
2330 case 'm': /* mode as octal number (perms only) */
2331 *fmt++ = 'o';
2332 pred->need_stat = true;
2333 mycost = NeedsStatInfo;
2334 break;
2336 *fmt = '\0';
2338 if (mycost > pred->p_cost)
2339 pred->p_cost = mycost;
2340 return &(*segment)->next;
2343 static void
2344 check_path_safety(const char *action)
2346 const char *path = getenv("PATH");
2347 char *s;
2348 s = next_element(path, 1);
2349 while ((s = next_element ((char *) NULL, 1)) != NULL)
2351 if (0 == strcmp(s, "."))
2353 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)"),
2354 action);
2360 /* handles both exec and ok predicate */
2361 #if defined(NEW_EXEC)
2362 /* handles both exec and ok predicate */
2363 static boolean
2364 new_insert_exec_ok (const char *action,
2365 const struct parser_table *entry,
2366 char **argv,
2367 int *arg_ptr)
2369 int start, end; /* Indexes in ARGV of start & end of cmd. */
2370 int i; /* Index into cmd args */
2371 int saw_braces; /* True if previous arg was '{}'. */
2372 boolean allow_plus; /* True if + is a valid terminator */
2373 int brace_count; /* Number of instances of {}. */
2374 PRED_FUNC func = entry->pred_func;
2375 enum BC_INIT_STATUS bcstatus;
2377 struct predicate *our_pred;
2378 struct exec_val *execp; /* Pointer for efficiency. */
2380 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2381 return false;
2383 our_pred = insert_primary_withpred (entry, func);
2384 our_pred->side_effects = our_pred->no_default_print = true;
2385 our_pred->need_type = our_pred->need_stat = false;
2387 execp = &our_pred->args.exec_vec;
2389 if ((func != pred_okdir) && (func != pred_ok))
2391 allow_plus = true;
2392 execp->close_stdin = false;
2394 else
2396 allow_plus = false;
2397 /* If find reads stdin (i.e. for -ok and similar), close stdin
2398 * in the child to prevent some script from consiming the output
2399 * intended for find.
2401 execp->close_stdin = true;
2405 if ((func == pred_execdir) || (func == pred_okdir))
2407 options.ignore_readdir_race = false;
2408 check_path_safety(action);
2409 execp->use_current_dir = true;
2411 else
2413 execp->use_current_dir = false;
2416 our_pred->args.exec_vec.multiple = 0;
2418 /* Count the number of args with path replacements, up until the ';'.
2419 * Also figure out if the command is terminated by ";" or by "+".
2421 start = *arg_ptr;
2422 for (end = start, saw_braces=0, brace_count=0;
2423 (argv[end] != NULL)
2424 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2425 end++)
2427 /* For -exec and -execdir, "{} +" can terminate the command. */
2428 if ( allow_plus
2429 && argv[end][0] == '+' && argv[end][1] == 0
2430 && saw_braces)
2432 our_pred->args.exec_vec.multiple = 1;
2433 break;
2436 saw_braces = 0;
2437 if (strstr (argv[end], "{}"))
2439 saw_braces = 1;
2440 ++brace_count;
2442 if (0 == end && (func == pred_execdir || func == pred_okdir))
2444 /* The POSIX standard says that {} replacement should
2445 * occur even in the utility name. This is insecure
2446 * since it means we will be executing a command whose
2447 * name is chosen according to whatever find finds in
2448 * the filesystem. That can be influenced by an
2449 * attacker. Hence for -execdir and -okdir this is not
2450 * allowed. We can specify this as those options are
2451 * not defined by POSIX.
2453 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2458 /* Fail if no command given or no semicolon found. */
2459 if ((end == start) || (argv[end] == NULL))
2461 *arg_ptr = end;
2462 free(our_pred);
2463 return false;
2466 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2469 const char *suffix;
2470 if (func == pred_execdir)
2471 suffix = "dir";
2472 else
2473 suffix = "";
2475 error(1, 0,
2476 _("Only one instance of {} is supported with -exec%s ... +"),
2477 suffix);
2480 /* We use a switch statement here so that
2481 * the compiler warns us when we forget to handle a
2482 * newly invented enum value.
2484 bcstatus = bc_init_controlinfo(&execp->ctl);
2485 switch (bcstatus)
2487 case BC_INIT_ENV_TOO_BIG:
2488 error(1, 0,
2489 _("The environment is too large for exec()."));
2490 break;
2491 case BC_INIT_OK:
2492 /* Good news. Carry on. */
2493 break;
2495 bc_use_sensible_arg_max(&execp->ctl);
2498 execp->ctl.exec_callback = launch;
2500 if (our_pred->args.exec_vec.multiple)
2502 /* "+" terminator, so we can just append our arguments after the
2503 * command and initial arguments.
2505 execp->replace_vec = NULL;
2506 execp->ctl.replace_pat = NULL;
2507 execp->ctl.rplen = 0;
2508 execp->ctl.lines_per_exec = 0; /* no limit */
2509 execp->ctl.args_per_exec = 0; /* no limit */
2511 /* remember how many arguments there are */
2512 execp->ctl.initial_argc = (end-start) - 1;
2514 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2515 bc_init_state(&execp->ctl, &execp->state, execp);
2517 /* Gather the initial arguments. Skip the {}. */
2518 for (i=start; i<end-1; ++i)
2520 bc_push_arg(&execp->ctl, &execp->state,
2521 argv[i], strlen(argv[i])+1,
2522 NULL, 0,
2526 else
2528 /* Semicolon terminator - more than one {} is supported, so we
2529 * have to do brace-replacement.
2531 execp->num_args = end - start;
2533 execp->ctl.replace_pat = "{}";
2534 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2535 execp->ctl.lines_per_exec = 0; /* no limit */
2536 execp->ctl.args_per_exec = 0; /* no limit */
2537 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2540 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2541 bc_init_state(&execp->ctl, &execp->state, execp);
2543 /* Remember the (pre-replacement) arguments for later. */
2544 for (i=0; i<execp->num_args; ++i)
2546 execp->replace_vec[i] = argv[i+start];
2550 if (argv[end] == NULL)
2551 *arg_ptr = end;
2552 else
2553 *arg_ptr = end + 1;
2555 return true;
2557 #else
2558 /* handles both exec and ok predicate */
2559 static boolean
2560 old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
2562 int start, end; /* Indexes in ARGV of start & end of cmd. */
2563 int num_paths; /* Number of args with path replacements. */
2564 int path_pos; /* Index in array of path replacements. */
2565 int vec_pos; /* Index in array of args. */
2566 struct predicate *our_pred;
2567 struct exec_val *execp; /* Pointer for efficiency. */
2569 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2570 return false;
2572 /* Count the number of args with path replacements, up until the ';'. */
2573 start = *arg_ptr;
2574 for (end = start, num_paths = 0;
2575 (argv[end] != NULL)
2576 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2577 end++)
2578 if (strstr (argv[end], "{}"))
2579 num_paths++;
2580 /* Fail if no command given or no semicolon found. */
2581 if ((end == start) || (argv[end] == NULL))
2583 *arg_ptr = end;
2584 return false;
2587 our_pred = insert_primary (func);
2588 our_pred->side_effects = our_pred->no_default_print = true;
2589 execp = &our_pred->args.exec_vec;
2590 execp->usercontext = our_pred;
2591 execp->use_current_dir = false;
2592 execp->paths =
2593 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
2594 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
2595 /* Record the positions of all args, and the args with path replacements. */
2596 for (end = start, path_pos = vec_pos = 0;
2597 (argv[end] != NULL)
2598 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2599 end++)
2601 register char *p;
2603 execp->paths[path_pos].count = 0;
2604 for (p = argv[end]; *p; ++p)
2605 if (p[0] == '{' && p[1] == '}')
2607 execp->paths[path_pos].count++;
2608 ++p;
2610 if (execp->paths[path_pos].count)
2612 execp->paths[path_pos].offset = vec_pos;
2613 execp->paths[path_pos].origarg = argv[end];
2614 path_pos++;
2616 execp->vec[vec_pos++] = argv[end];
2618 execp->paths[path_pos].offset = -1;
2619 execp->vec[vec_pos] = NULL;
2621 if (argv[end] == NULL)
2622 *arg_ptr = end;
2623 else
2624 *arg_ptr = end + 1;
2625 return true;
2627 #endif
2631 static boolean
2632 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2634 #if defined(NEW_EXEC)
2635 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2636 #else
2637 return old_insert_exec_ok(func, argv, arg_ptr);
2638 #endif
2643 /* Get a number of days and comparison type.
2644 STR is the ASCII representation.
2645 Set *NUM_DAYS to the number of days, taken as being from
2646 the current moment (or possibly midnight). Thus the sense of the
2647 comparison type appears to be reversed.
2648 Set *COMP_TYPE to the kind of comparison that is requested.
2650 Return true if all okay, false if input error.
2652 Used by -atime, -ctime and -mtime (parsers) to
2653 get the appropriate information for a time predicate processor. */
2655 static boolean
2656 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2658 boolean r = get_num (str, num_days, comp_type);
2659 if (r)
2660 switch (*comp_type)
2662 case COMP_LT: *comp_type = COMP_GT; break;
2663 case COMP_GT: *comp_type = COMP_LT; break;
2664 default: break;
2666 return r;
2669 /* Insert a time predicate PRED.
2670 ARGV is a pointer to the argument array.
2671 ARG_PTR is a pointer to an index into the array, incremented if
2672 all went well.
2674 Return true if input is valid, false if not.
2676 A new predicate node is assigned, along with an argument node
2677 obtained with malloc.
2679 Used by -atime, -ctime, and -mtime parsers. */
2681 static boolean
2682 parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
2684 struct predicate *our_pred;
2685 uintmax_t num_days;
2686 enum comparison_type c_type;
2687 time_t t;
2689 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2690 return false;
2691 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2692 return false;
2694 /* Figure out the timestamp value we are looking for. */
2695 t = ( options.cur_day_start - num_days * DAYSECS
2696 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2698 if (1)
2700 /* We introduce a scope in which 'val' can be declared, for the
2701 * benefit of compilers that are really C89 compilers
2702 * which support intmax_t because config.h #defines it
2704 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2705 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2706 t = val;
2708 /* Check for possibility of an overflow */
2709 if ( (intmax_t)t != val )
2711 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2715 our_pred = insert_primary (entry);
2716 our_pred->args.info.kind = c_type;
2717 our_pred->args.info.negative = t < 0;
2718 our_pred->args.info.l_val = t;
2719 our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
2720 (*arg_ptr)++;
2722 if (options.debug_options & DebugExpressionTree)
2724 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2725 fprintf (stderr, " type: %s %s ",
2726 (c_type == COMP_GT) ? "gt" :
2727 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2728 (c_type == COMP_GT) ? " >" :
2729 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2730 t = our_pred->args.info.l_val;
2731 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2732 if (c_type == COMP_EQ)
2734 t = our_pred->args.info.l_val += DAYSECS;
2735 fprintf (stderr, " < %ju %s",
2736 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2737 our_pred->args.info.l_val -= DAYSECS;
2741 return true;
2744 /* Get a number with comparison information.
2745 The sense of the comparison information is 'normal'; that is,
2746 '+' looks for a count > than the number and '-' less than.
2748 STR is the ASCII representation of the number.
2749 Set *NUM to the number.
2750 Set *COMP_TYPE to the kind of comparison that is requested.
2752 Return true if all okay, false if input error. */
2754 static boolean
2755 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2757 if (str == NULL)
2758 return false;
2759 switch (str[0])
2761 case '+':
2762 *comp_type = COMP_GT;
2763 str++;
2764 break;
2765 case '-':
2766 *comp_type = COMP_LT;
2767 str++;
2768 break;
2769 default:
2770 *comp_type = COMP_EQ;
2771 break;
2774 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2777 /* Insert a number predicate.
2778 ARGV is a pointer to the argument array.
2779 *ARG_PTR is an index into ARGV, incremented if all went well.
2780 *PRED is the predicate processor to insert.
2782 Return true if input is valid, false if error.
2784 A new predicate node is assigned, along with an argument node
2785 obtained with malloc.
2787 Used by -inum and -links parsers. */
2789 static struct predicate *
2790 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2792 struct predicate *our_pred;
2793 uintmax_t num;
2794 enum comparison_type c_type;
2796 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2797 return NULL;
2798 if (!get_num (argv[*arg_ptr], &num, &c_type))
2799 return NULL;
2800 our_pred = insert_primary (entry);
2801 our_pred->args.info.kind = c_type;
2802 our_pred->args.info.l_val = num;
2803 (*arg_ptr)++;
2805 if (options.debug_options & DebugExpressionTree)
2807 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2808 fprintf (stderr, " type: %s %s ",
2809 (c_type == COMP_GT) ? "gt" :
2810 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2811 (c_type == COMP_GT) ? " >" :
2812 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2813 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2815 return our_pred;
2818 static FILE *
2819 open_output_file (char *path)
2821 FILE *f;
2823 if (!strcmp (path, "/dev/stderr"))
2824 return stderr;
2825 else if (!strcmp (path, "/dev/stdout"))
2826 return stdout;
2827 f = fopen_safer (path, "w");
2828 if (f == NULL)
2829 error (1, errno, "%s", path);
2830 return f;