Added entries for recent changes.
[findutils.git] / find / parser.c
blob4bd25e7cbc3afdd8fcea2414a1b0a7ad69b22b3d
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 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 <pwd.h>
25 #include <grp.h>
26 #include <fnmatch.h>
27 #include "modechange.h"
28 #include "modetype.h"
29 #include "xstrtol.h"
30 #include "xalloc.h"
31 #include "quote.h"
32 #include "quotearg.h"
33 #include "buildcmd.h"
34 #include "nextelem.h"
35 #include "stdio-safer.h"
36 #include "regextype.h"
38 #ifdef HAVE_FCNTL_H
39 #include <fcntl.h>
40 #else
41 #include <sys/file.h>
42 #endif
44 /* The presence of unistd.h is assumed by gnulib these days, so we
45 * might as well assume it too.
47 /* We need <unistd.h> for isatty(). */
48 #include <unistd.h>
50 #if ENABLE_NLS
51 # include <libintl.h>
52 # define _(Text) gettext (Text)
53 #else
54 # define _(Text) Text
55 #endif
56 #ifdef gettext_noop
57 # define N_(String) gettext_noop (String)
58 #else
59 /* See locate.c for explanation as to why not use (String) */
60 # define N_(String) String
61 #endif
63 #if !defined (isascii) || defined (STDC_HEADERS)
64 #ifdef isascii
65 #undef isascii
66 #endif
67 #define isascii(c) 1
68 #endif
70 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
71 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
73 #ifndef HAVE_ENDGRENT
74 #define endgrent()
75 #endif
76 #ifndef HAVE_ENDPWENT
77 #define endpwent()
78 #endif
80 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
81 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
82 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
83 static boolean parse_atime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
84 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
85 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
86 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
87 static boolean parse_ctime 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_executable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_mtime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_readable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_size 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_writable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
159 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
160 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
162 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
163 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
164 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
165 static boolean insert_time PARAMS((char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred));
166 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
167 static boolean 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));
173 #ifdef DEBUG
174 char *find_pred_name PARAMS((PRED_FUNC pred_func));
175 #endif /* DEBUG */
178 #define PASTE(x,y) x##y
179 #define STRINGIFY(s) #s
181 #define PARSE_OPTION(what,suffix) \
182 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
184 #define PARSE_POSOPT(what,suffix) \
185 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
187 #define PARSE_TEST(what,suffix) \
188 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
190 #define PARSE_TEST_NP(what,suffix) \
191 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
193 #define PARSE_ACTION(what,suffix) \
194 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
196 #define PARSE_ACTION_NP(what,suffix) \
197 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
199 #define PARSE_PUNCTUATION(what,suffix) \
200 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
203 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
204 If they are in some Unix versions of find, they are marked `Unix'. */
206 static struct parser_table const parse_table[] =
208 PARSE_PUNCTUATION("!", negate),
209 PARSE_PUNCTUATION("not", negate), /* GNU */
210 PARSE_PUNCTUATION("(", open),
211 PARSE_PUNCTUATION(")", close),
212 PARSE_PUNCTUATION(",", comma), /* GNU */
213 PARSE_PUNCTUATION("a", and),
214 PARSE_TEST ("amin", amin), /* GNU */
215 PARSE_PUNCTUATION("and", and), /* GNU */
216 PARSE_TEST ("anewer", anewer), /* GNU */
217 PARSE_TEST ("atime", atime),
218 PARSE_TEST ("cmin", cmin), /* GNU */
219 PARSE_TEST ("cnewer", cnewer), /* GNU */
220 PARSE_TEST ("ctime", ctime),
221 PARSE_POSOPT ("daystart", daystart), /* GNU */
222 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
223 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
224 PARSE_OPTION ("depth", depth),
225 PARSE_TEST ("empty", empty), /* GNU */
226 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
227 PARSE_TEST ("executable", executable), /* GNU, 4.3.0+ */
228 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
229 PARSE_ACTION ("fls", fls), /* GNU */
230 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
231 PARSE_ACTION ("fprint", fprint), /* GNU */
232 PARSE_ACTION ("fprint0", fprint0), /* GNU */
233 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
234 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
235 PARSE_TEST ("gid", gid), /* GNU */
236 PARSE_TEST ("group", group),
237 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
238 PARSE_TEST ("ilname", ilname), /* GNU */
239 PARSE_TEST ("iname", iname), /* GNU */
240 PARSE_TEST ("inum", inum), /* GNU, Unix */
241 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
242 PARSE_TEST_NP ("iregex", iregex), /* GNU */
243 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
244 PARSE_TEST ("links", links),
245 PARSE_TEST ("lname", lname), /* GNU */
246 PARSE_ACTION ("ls", ls), /* GNU, Unix */
247 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
248 PARSE_OPTION ("mindepth", mindepth), /* GNU */
249 PARSE_TEST ("mmin", mmin), /* GNU */
250 PARSE_OPTION ("mount", xdev), /* Unix */
251 PARSE_TEST ("mtime", mtime),
252 PARSE_TEST ("name", name),
253 #ifdef UNIMPLEMENTED_UNIX
254 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
255 #endif
256 PARSE_TEST ("newer", newer),
257 PARSE_OPTION ("noleaf", noleaf), /* GNU */
258 PARSE_TEST ("nogroup", nogroup),
259 PARSE_TEST ("nouser", nouser),
260 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
261 PARSE_OPTION ("nowarn", nowarn), /* GNU */
262 PARSE_PUNCTUATION("o", or),
263 PARSE_PUNCTUATION("or", or), /* GNU */
264 PARSE_ACTION ("ok", ok),
265 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
266 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
267 PARSE_TEST ("perm", perm),
268 PARSE_ACTION ("print", print),
269 PARSE_ACTION ("print0", print0), /* GNU */
270 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
271 PARSE_ACTION ("prune", prune),
272 PARSE_ACTION ("quit", quit), /* GNU */
273 PARSE_TEST ("readable", readable), /* GNU, 4.3.0+ */
274 PARSE_TEST ("regex", regex), /* GNU */
275 PARSE_OPTION ("regextype", regextype), /* GNU */
276 PARSE_TEST ("samefile", samefile), /* GNU */
277 #if 0
278 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
279 #endif
280 PARSE_TEST ("size", size),
281 PARSE_TEST ("type", type),
282 PARSE_TEST ("uid", uid), /* GNU */
283 PARSE_TEST ("used", used), /* GNU */
284 PARSE_TEST ("user", user),
285 PARSE_OPTION ("warn", warn), /* GNU */
286 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
287 PARSE_TEST ("writable", writable), /* GNU, 4.3.0+ */
288 PARSE_OPTION ("xdev", xdev),
289 PARSE_TEST ("xtype", xtype), /* GNU */
290 #ifdef UNIMPLEMENTED_UNIX
291 /* It's pretty ugly for find to know about archive formats.
292 Plus what it could do with cpio archives is very limited.
293 Better to leave it out. */
294 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
295 #endif
296 /* gnulib's stdbool.h might have made true and false into macros,
297 * so we can't leave named 'true' and 'false' tokens, so we have
298 * to expeant the relevant entries longhand.
300 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
301 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
302 {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
304 /* Various other cases that don't fit neatly into our macro scheme. */
305 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
306 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
307 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
308 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
309 {0, 0, 0, 0}
313 static const char *first_nonoption_arg = NULL;
314 static const struct parser_table *noop = NULL;
317 static const struct parser_table*
318 get_noop(void)
320 int i;
321 if (NULL == noop)
323 for (i = 0; parse_table[i].parser_name != 0; i++)
325 if (ARG_NOOP ==parse_table[i].type)
327 noop = &(parse_table[i]);
328 break;
332 return noop;
337 void
338 set_follow_state(enum SymlinkOption opt)
340 switch (opt)
342 case SYMLINK_ALWAYS_DEREF: /* -L */
343 options.xstat = optionl_stat;
344 options.no_leaf_check = true;
345 break;
347 case SYMLINK_NEVER_DEREF: /* -P (default) */
348 options.xstat = optionp_stat;
349 /* Can't turn no_leaf_check off because the user might have specified
350 * -noleaf anyway
352 break;
354 case SYMLINK_DEREF_ARGSONLY: /* -H */
355 options.xstat = optionh_stat;
356 options.no_leaf_check = true;
359 options.symlink_handling = opt;
361 /* For DEBUG_STAT, the choice is made at runtime within debug_stat()
362 * by checking the contents of the symlink_handling variable.
364 #if defined(DEBUG_STAT)
365 options.xstat = debug_stat;
366 #endif /* !DEBUG_STAT */
370 void
371 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
373 (void) args;
374 (void) argno;
375 (void) last;
376 (void) predicates;
377 first_nonoption_arg = NULL;
380 void
381 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
383 /* does nothing */
384 (void) args;
385 (void) argno;
386 (void) last;
387 (void) predicates;
393 /* Return a pointer to the parser function to invoke for predicate
394 SEARCH_NAME.
395 Return NULL if SEARCH_NAME is not a valid predicate name. */
397 const struct parser_table*
398 find_parser (char *search_name)
400 int i;
401 const char *original_arg = search_name;
403 if (*search_name == '-')
404 search_name++;
405 for (i = 0; parse_table[i].parser_name != 0; i++)
407 if (strcmp (parse_table[i].parser_name, search_name) == 0)
409 /* If this is an option, but we have already had a
410 * non-option argument, the user may be under the
411 * impression that the behaviour of the option
412 * argument is conditional on some preceding
413 * tests. This might typically be the case with,
414 * for example, -maxdepth.
416 * The options -daystart and -follow are exempt
417 * from this treatment, since their positioning
418 * in the command line does have an effect on
419 * subsequent tests but not previous ones. That
420 * might be intentional on the part of the user.
422 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
424 /* Something other than -follow/-daystart.
425 * If this is an option, check if it followed
426 * a non-option and if so, issue a warning.
428 if (parse_table[i].type == ARG_OPTION)
430 if ((first_nonoption_arg != NULL)
431 && options.warnings )
433 /* option which follows a non-option */
434 error (0, 0,
435 _("warning: you have specified the %s "
436 "option after a non-option argument %s, "
437 "but options are not positional (%s affects "
438 "tests specified before it as well as those "
439 "specified after it). Please specify options "
440 "before other arguments.\n"),
441 original_arg,
442 first_nonoption_arg,
443 original_arg);
446 else
448 /* Not an option or a positional option,
449 * so remember we've seen it in order to
450 * use it in a possible future warning message.
452 if (first_nonoption_arg == NULL)
454 first_nonoption_arg = original_arg;
459 return &parse_table[i];
462 return NULL;
465 /* The parsers are responsible to continue scanning ARGV for
466 their arguments. Each parser knows what is and isn't
467 allowed for itself.
469 ARGV is the argument array.
470 *ARG_PTR is the index to start at in ARGV,
471 updated to point beyond the last element consumed.
473 The predicate structure is updated with the new information. */
475 static boolean
476 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
478 struct predicate *our_pred;
479 uintmax_t num;
480 enum comparison_type c_type;
481 time_t t;
483 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
484 return false;
485 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
486 return false;
487 t = options.cur_day_start + DAYSECS - num * 60;
488 our_pred = insert_primary (entry);
489 our_pred->args.info.kind = c_type;
490 our_pred->args.info.negative = t < 0;
491 our_pred->args.info.l_val = t;
492 (*arg_ptr)++;
493 return true;
496 static boolean
497 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
499 struct predicate *our_pred;
501 (void) argv;
502 (void) arg_ptr;
504 our_pred = get_new_pred (entry);
505 our_pred->pred_func = pred_and;
506 #ifdef DEBUG
507 our_pred->p_name = find_pred_name (pred_and);
508 #endif /* DEBUG */
509 our_pred->p_type = BI_OP;
510 our_pred->p_prec = AND_PREC;
511 our_pred->need_stat = our_pred->need_type = false;
512 return true;
515 static boolean
516 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
518 struct predicate *our_pred;
519 struct stat stat_newer;
521 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
522 return false;
523 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
524 error (1, errno, "%s", argv[*arg_ptr]);
525 our_pred = insert_primary (entry);
526 our_pred->args.time = stat_newer.st_mtime;
527 (*arg_ptr)++;
528 return true;
531 static boolean
532 parse_atime (const struct parser_table* entry, char **argv, int *arg_ptr)
534 return insert_time (argv, arg_ptr, entry, pred_atime);
537 boolean
538 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
540 struct predicate *our_pred;
542 (void) argv;
543 (void) arg_ptr;
545 our_pred = get_new_pred (entry);
546 our_pred->pred_func = pred_close;
547 #ifdef DEBUG
548 our_pred->p_name = find_pred_name (pred_close);
549 #endif /* DEBUG */
550 our_pred->p_type = CLOSE_PAREN;
551 our_pred->p_prec = NO_PREC;
552 our_pred->need_stat = our_pred->need_type = false;
553 return true;
556 static boolean
557 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
559 struct predicate *our_pred;
560 uintmax_t num;
561 enum comparison_type c_type;
562 time_t t;
564 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
565 return false;
566 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
567 return false;
568 t = options.cur_day_start + DAYSECS - num * 60;
569 our_pred = insert_primary (entry);
570 our_pred->args.info.kind = c_type;
571 our_pred->args.info.negative = t < 0;
572 our_pred->args.info.l_val = t;
573 (*arg_ptr)++;
574 return true;
577 static boolean
578 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
580 struct predicate *our_pred;
581 struct stat stat_newer;
583 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
584 return false;
585 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
586 error (1, errno, "%s", argv[*arg_ptr]);
587 our_pred = insert_primary (entry);
588 our_pred->args.time = stat_newer.st_mtime;
589 (*arg_ptr)++;
590 return true;
593 static boolean
594 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
596 struct predicate *our_pred;
598 (void) argv;
599 (void) arg_ptr;
601 our_pred = get_new_pred (entry);
602 our_pred->pred_func = pred_comma;
603 #ifdef DEBUG
604 our_pred->p_name = find_pred_name (pred_comma);
605 #endif /* DEBUG */
606 our_pred->p_type = BI_OP;
607 our_pred->p_prec = COMMA_PREC;
608 our_pred->need_stat = our_pred->need_type = false;
609 return true;
612 static boolean
613 parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr)
615 return insert_time (argv, arg_ptr, entry, pred_ctime);
618 static boolean
619 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
621 struct tm *local;
623 (void) entry;
624 (void) argv;
625 (void) arg_ptr;
627 if (options.full_days == false)
629 options.cur_day_start += DAYSECS;
630 local = localtime (&options.cur_day_start);
631 options.cur_day_start -= (local
632 ? (local->tm_sec + local->tm_min * 60
633 + local->tm_hour * 3600)
634 : options.cur_day_start % DAYSECS);
635 options.full_days = true;
637 return true;
640 static boolean
641 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
643 struct predicate *our_pred;
644 (void) argv;
645 (void) arg_ptr;
647 our_pred = insert_primary (entry);
648 our_pred->side_effects = our_pred->no_default_print = true;
649 /* -delete implies -depth */
650 options.do_dir_first = false;
651 return true;
654 static boolean
655 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
657 (void) entry;
658 (void) argv;
659 (void) arg_ptr;
661 options.do_dir_first = false;
662 return parse_noop(entry, argv, arg_ptr);
665 static boolean
666 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
668 (void) argv;
669 (void) arg_ptr;
671 if (options.warnings)
673 error (0, 0,
674 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
676 return parse_depth(entry, argv, arg_ptr);
679 static boolean
680 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
682 (void) argv;
683 (void) arg_ptr;
685 insert_primary (entry);
686 return true;
689 static boolean
690 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
692 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
695 static boolean
696 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
698 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
701 static boolean
702 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
704 struct predicate *our_pred;
706 (void) argv;
707 (void) arg_ptr;
709 our_pred = insert_primary (entry);
710 our_pred->need_stat = our_pred->need_type = false;
711 our_pred->side_effects = our_pred->no_default_print = false;
712 return true;
715 static boolean
716 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
718 struct predicate *our_pred;
720 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
721 return false;
722 our_pred = insert_primary (entry);
723 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
724 our_pred->side_effects = our_pred->no_default_print = true;
725 (*arg_ptr)++;
726 return true;
729 static boolean
730 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
732 FILE *fp;
734 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
735 return false;
736 if (argv[*arg_ptr + 1] == NULL)
738 /* Ensure we get "missing arg" message, not "invalid arg". */
739 (*arg_ptr)++;
740 return false;
742 fp = open_output_file (argv[*arg_ptr]);
743 (*arg_ptr)++;
744 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
747 static boolean
748 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
750 (void) entry;
751 (void) argv;
752 (void) arg_ptr;
754 set_follow_state(SYMLINK_ALWAYS_DEREF);
755 return parse_noop(entry, argv, arg_ptr);
758 static boolean
759 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
761 struct predicate *our_pred;
763 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
764 return false;
765 our_pred = insert_primary (entry);
766 our_pred->args.printf_vec.segment = NULL;
767 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
768 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
769 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
770 our_pred->side_effects = our_pred->no_default_print = true;
771 our_pred->need_stat = our_pred->need_type = false;
772 (*arg_ptr)++;
773 return true;
776 static boolean
777 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
779 struct predicate *our_pred;
781 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
782 return false;
783 our_pred = insert_primary (entry);
784 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
785 our_pred->side_effects = our_pred->no_default_print = true;
786 our_pred->need_stat = our_pred->need_type = false;
787 (*arg_ptr)++;
788 return true;
791 static boolean
792 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
794 struct predicate *our_pred;
796 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
797 return false;
798 our_pred = insert_primary (entry);
799 our_pred->args.str = argv[*arg_ptr];
800 (*arg_ptr)++;
801 return true;
804 static boolean
805 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
807 return insert_num (argv, arg_ptr, entry);
810 static boolean
811 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
813 struct group *cur_gr;
814 struct predicate *our_pred;
815 gid_t gid;
816 int gid_len;
818 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
819 return false;
820 cur_gr = getgrnam (argv[*arg_ptr]);
821 endgrent ();
822 if (cur_gr != NULL)
823 gid = cur_gr->gr_gid;
824 else
826 gid_len = strspn (argv[*arg_ptr], "0123456789");
827 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
828 return false;
829 gid = atoi (argv[*arg_ptr]);
831 our_pred = insert_primary (entry);
832 our_pred->args.gid = gid;
833 (*arg_ptr)++;
834 return true;
837 static boolean
838 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
840 (void) entry;
841 (void) argv;
842 (void) arg_ptr;
844 printf (_("\
845 Usage: %s [path...] [expression]\n"), program_name);
846 puts (_("\n\
847 default path is the current directory; default expression is -print\n\
848 expression may consist of: operators, options, tests, and actions:\n"));
849 puts (_("\
850 operators (decreasing precedence; -and is implicit where no others are given):\n\
851 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
852 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
853 puts (_("\
854 positional options (always true): -daystart -follow -regextype\n\n\
855 normal options (always true, specified before other expressions):\n\
856 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
857 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
858 puts (_("\
859 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
860 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
861 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
862 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
863 puts (_("\
864 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
865 -readable -writable -executable\n\
866 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
867 -used N -user NAME -xtype [bcdpfls]\n"));
868 puts (_("\
869 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
870 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
871 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
872 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
873 "));
874 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
875 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
876 email to <bug-findutils@gnu.org>."));
877 exit (0);
880 static boolean
881 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
883 struct predicate *our_pred;
885 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
886 return false;
887 our_pred = insert_primary (entry);
888 our_pred->args.str = argv[*arg_ptr];
889 (*arg_ptr)++;
890 return true;
894 /* sanity check the fnmatch() function to make sure
895 * it really is the GNU version.
897 static boolean
898 fnmatch_sanitycheck(void)
900 /* fprintf(stderr, "Performing find sanity check..."); */
901 if (0 != fnmatch("foo", "foo", 0)
902 || 0 == fnmatch("Foo", "foo", 0)
903 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
905 error (1, 0, _("sanity check of the fnmatch() library function failed."));
906 /* fprintf(stderr, "FAILED\n"); */
907 return false;
910 /* fprintf(stderr, "OK\n"); */
911 return true;
915 static boolean
916 check_name_arg(const char *pred, const char *arg)
918 if (strchr(arg, '/'))
920 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'."),
921 pred, arg, arg);
923 return true; /* allow it anyway */
928 static boolean
929 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
931 struct predicate *our_pred;
933 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
934 return false;
935 if (!check_name_arg("-iname", argv[*arg_ptr]))
936 return false;
938 fnmatch_sanitycheck();
940 our_pred = insert_primary (entry);
941 our_pred->need_stat = our_pred->need_type = false;
942 our_pred->args.str = argv[*arg_ptr];
943 (*arg_ptr)++;
944 return true;
947 static boolean
948 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
950 return insert_num (argv, arg_ptr, entry);
953 /* -ipath is deprecated (at RMS's request) in favour of
954 * -iwholename. See the node "GNU Manuals" in standards.texi
955 * for the rationale for this (basically, GNU prefers the use
956 * of the phrase "file name" to "path name"
958 static boolean
959 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
961 error (0, 0,
962 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
964 return parse_iwholename(entry, argv, arg_ptr);
967 static boolean
968 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
970 struct predicate *our_pred;
972 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
973 return false;
975 fnmatch_sanitycheck();
977 our_pred = insert_primary_withpred (entry, pred_ipath);
978 our_pred->need_stat = our_pred->need_type = false;
979 our_pred->args.str = argv[*arg_ptr];
980 (*arg_ptr)++;
981 return true;
984 static boolean
985 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
987 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
990 static boolean
991 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
993 return insert_num (argv, arg_ptr, entry);
996 static boolean
997 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
999 struct predicate *our_pred;
1001 (void) argv;
1002 (void) arg_ptr;
1004 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1005 return false;
1007 fnmatch_sanitycheck();
1009 our_pred = insert_primary (entry);
1010 our_pred->args.str = argv[*arg_ptr];
1011 (*arg_ptr)++;
1012 return true;
1015 static boolean
1016 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
1018 struct predicate *our_pred;
1020 (void) &argv;
1021 (void) &arg_ptr;
1023 our_pred = insert_primary (entry);
1024 our_pred->side_effects = our_pred->no_default_print = true;
1025 return true;
1028 static boolean
1029 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1031 int depth_len;
1032 (void) entry;
1034 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1035 return false;
1036 depth_len = strspn (argv[*arg_ptr], "0123456789");
1037 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1038 return false;
1039 options.maxdepth = atoi (argv[*arg_ptr]);
1040 if (options.maxdepth < 0)
1041 return false;
1042 (*arg_ptr)++;
1043 return parse_noop(entry, argv, arg_ptr);
1046 static boolean
1047 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1049 int depth_len;
1050 (void) entry;
1052 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1053 return false;
1054 depth_len = strspn (argv[*arg_ptr], "0123456789");
1055 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1056 return false;
1057 options.mindepth = atoi (argv[*arg_ptr]);
1058 if (options.mindepth < 0)
1059 return false;
1060 (*arg_ptr)++;
1061 return parse_noop(entry, argv, arg_ptr);
1064 static boolean
1065 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1067 struct predicate *our_pred;
1068 uintmax_t num;
1069 enum comparison_type c_type;
1070 time_t t;
1072 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1073 return false;
1074 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
1075 return false;
1076 t = options.cur_day_start + DAYSECS - num * 60;
1077 our_pred = insert_primary (entry);
1078 our_pred->args.info.kind = c_type;
1079 our_pred->args.info.negative = t < 0;
1080 our_pred->args.info.l_val = t;
1081 (*arg_ptr)++;
1082 return true;
1085 static boolean
1086 parse_mtime (const struct parser_table* entry, char **argv, int *arg_ptr)
1088 return insert_time (argv, arg_ptr, entry, pred_mtime);
1091 static boolean
1092 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1094 struct predicate *our_pred;
1096 (void) argv;
1097 (void) arg_ptr;
1099 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1100 return false;
1101 if (!check_name_arg("-name", argv[*arg_ptr]))
1102 return false;
1103 fnmatch_sanitycheck();
1105 our_pred = insert_primary (entry);
1106 our_pred->need_stat = our_pred->need_type = false;
1107 our_pred->args.str = argv[*arg_ptr];
1108 (*arg_ptr)++;
1109 return true;
1112 static boolean
1113 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1115 struct predicate *our_pred;
1117 (void) &argv;
1118 (void) &arg_ptr;
1120 our_pred = get_new_pred_chk_op (entry);
1121 our_pred->pred_func = pred_negate;
1122 #ifdef DEBUG
1123 our_pred->p_name = find_pred_name (pred_negate);
1124 #endif /* DEBUG */
1125 our_pred->p_type = UNI_OP;
1126 our_pred->p_prec = NEGATE_PREC;
1127 our_pred->need_stat = our_pred->need_type = false;
1128 return true;
1131 static boolean
1132 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1134 struct predicate *our_pred;
1135 struct stat stat_newer;
1137 (void) argv;
1138 (void) arg_ptr;
1140 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1141 return false;
1142 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1143 error (1, errno, "%s", argv[*arg_ptr]);
1144 our_pred = insert_primary (entry);
1145 our_pred->args.time = stat_newer.st_mtime;
1146 (*arg_ptr)++;
1147 return true;
1150 static boolean
1151 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1153 (void) &argv;
1154 (void) &arg_ptr;
1155 (void) entry;
1157 options.no_leaf_check = true;
1158 return parse_noop(entry, argv, arg_ptr);
1161 #ifdef CACHE_IDS
1162 /* Arbitrary amount by which to increase size
1163 of `uid_unused' and `gid_unused'. */
1164 #define ALLOC_STEP 2048
1166 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1167 char *uid_unused = NULL;
1169 /* Number of elements in `uid_unused'. */
1170 unsigned uid_allocated;
1172 /* Similar for GIDs and group entries. */
1173 char *gid_unused = NULL;
1174 unsigned gid_allocated;
1175 #endif
1177 static boolean
1178 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1180 struct predicate *our_pred;
1182 (void) &argv;
1183 (void) &arg_ptr;
1185 our_pred = insert_primary (entry);
1186 #ifdef CACHE_IDS
1187 if (gid_unused == NULL)
1189 struct group *gr;
1191 gid_allocated = ALLOC_STEP;
1192 gid_unused = xmalloc (gid_allocated);
1193 memset (gid_unused, 1, gid_allocated);
1194 setgrent ();
1195 while ((gr = getgrent ()) != NULL)
1197 if ((unsigned) gr->gr_gid >= gid_allocated)
1199 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1200 gid_unused = xrealloc (gid_unused, new_allocated);
1201 memset (gid_unused + gid_allocated, 1,
1202 new_allocated - gid_allocated);
1203 gid_allocated = new_allocated;
1205 gid_unused[(unsigned) gr->gr_gid] = 0;
1207 endgrent ();
1209 #endif
1210 return true;
1213 static boolean
1214 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1216 struct predicate *our_pred;
1217 (void) argv;
1218 (void) arg_ptr;
1221 our_pred = insert_primary (entry);
1222 #ifdef CACHE_IDS
1223 if (uid_unused == NULL)
1225 struct passwd *pw;
1227 uid_allocated = ALLOC_STEP;
1228 uid_unused = xmalloc (uid_allocated);
1229 memset (uid_unused, 1, uid_allocated);
1230 setpwent ();
1231 while ((pw = getpwent ()) != NULL)
1233 if ((unsigned) pw->pw_uid >= uid_allocated)
1235 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1236 uid_unused = xrealloc (uid_unused, new_allocated);
1237 memset (uid_unused + uid_allocated, 1,
1238 new_allocated - uid_allocated);
1239 uid_allocated = new_allocated;
1241 uid_unused[(unsigned) pw->pw_uid] = 0;
1243 endpwent ();
1245 #endif
1246 return true;
1249 static boolean
1250 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1252 (void) argv;
1253 (void) arg_ptr;
1254 (void) entry;
1256 options.warnings = false;
1257 return parse_noop(entry, argv, arg_ptr);
1260 static boolean
1261 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1263 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1266 static boolean
1267 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1269 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1272 boolean
1273 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1275 struct predicate *our_pred;
1277 (void) argv;
1278 (void) arg_ptr;
1280 our_pred = get_new_pred_chk_op (entry);
1281 our_pred->pred_func = pred_open;
1282 #ifdef DEBUG
1283 our_pred->p_name = find_pred_name (pred_open);
1284 #endif /* DEBUG */
1285 our_pred->p_type = OPEN_PAREN;
1286 our_pred->p_prec = NO_PREC;
1287 our_pred->need_stat = our_pred->need_type = false;
1288 return true;
1291 static boolean
1292 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1294 struct predicate *our_pred;
1296 (void) argv;
1297 (void) arg_ptr;
1299 our_pred = get_new_pred (entry);
1300 our_pred->pred_func = pred_or;
1301 #ifdef DEBUG
1302 our_pred->p_name = find_pred_name (pred_or);
1303 #endif /* DEBUG */
1304 our_pred->p_type = BI_OP;
1305 our_pred->p_prec = OR_PREC;
1306 our_pred->need_stat = our_pred->need_type = false;
1307 return true;
1310 /* -path is deprecated (at RMS's request) in favour of
1311 * -iwholename. See the node "GNU Manuals" in standards.texi
1312 * for the rationale for this (basically, GNU prefers the use
1313 * of the phrase "file name" to "path name".
1315 * We do not issue a warning that this usage is deprecated
1316 * since HPUX find supports this predicate also.
1318 static boolean
1319 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1321 return parse_wholename(entry, argv, arg_ptr);
1324 static boolean
1325 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1327 struct predicate *our_pred;
1329 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1330 return false;
1331 our_pred = insert_primary_withpred (entry, pred_path);
1332 our_pred->need_stat = our_pred->need_type = false;
1333 our_pred->args.str = argv[*arg_ptr];
1334 (*arg_ptr)++;
1335 return true;
1338 static boolean
1339 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1341 mode_t perm_val;
1342 int mode_start = 0;
1343 boolean havekind = false;
1344 enum permissions_type kind = PERM_EXACT;
1345 struct mode_change *change = NULL;
1346 struct predicate *our_pred;
1348 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1349 return false;
1351 switch (argv[*arg_ptr][0])
1353 case '-':
1354 mode_start = 1;
1355 kind = PERM_AT_LEAST;
1356 havekind = true;
1357 break;
1359 case '+':
1360 change = mode_compile (argv[*arg_ptr]);
1361 if (NULL == change)
1363 /* Most likely the caller is an old script that is still
1364 * using the obsolete GNU syntax '-perm +MODE'. This old
1365 * syntax was withdrawn in favor of '-perm /MODE' because
1366 * it is incompatible with POSIX in some cases, but we
1367 * still support uses of it that are not incompatible with
1368 * POSIX.
1370 mode_start = 1;
1371 kind = PERM_ANY;
1373 else
1375 /* This is a POSIX-compatible usage */
1376 mode_start = 0;
1377 kind = PERM_EXACT;
1379 havekind = true;
1380 break;
1382 case '/': /* GNU extension */
1383 mode_start = 1;
1384 kind = PERM_ANY;
1385 havekind = true;
1386 break;
1388 default:
1389 /* For example, '-perm 0644', which is valid and matches
1390 * only files whose mode is exactly 0644.
1392 * We do nothing here, because mode_start and kind are already
1393 * correctly set.
1395 break;
1398 if (NULL == change)
1400 change = mode_compile (argv[*arg_ptr] + mode_start);
1401 if (NULL == change)
1402 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1404 perm_val = mode_adjust (0, change, 0);
1405 free (change);
1407 our_pred = insert_primary (entry);
1409 if (havekind)
1411 our_pred->args.perm.kind = kind;
1413 else
1416 switch (argv[*arg_ptr][0])
1418 case '-':
1419 our_pred->args.perm.kind = PERM_AT_LEAST;
1420 break;
1421 case '+':
1422 our_pred->args.perm.kind = PERM_ANY;
1423 break;
1424 default:
1425 our_pred->args.perm.kind = PERM_EXACT;
1426 break;
1429 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val))
1431 /* The meaning of -perm /000 will change in the future.
1432 * It currently matches no files, but like -perm -000 it
1433 * should match all files.
1435 error (0, 0,
1436 _("warning: you have specified a mode pattern %s which is "
1437 "equivalent to 000. The meaning of -perm /000 will soon be "
1438 "changed to be consistent with -perm -000; that is, at the "
1439 "moment it matches no files but it will soon be changed to "
1440 "match all files."),
1441 argv[*arg_ptr]);
1444 our_pred->args.perm.val = perm_val & MODE_ALL;
1445 (*arg_ptr)++;
1446 return true;
1449 boolean
1450 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1452 struct predicate *our_pred;
1454 (void) argv;
1455 (void) arg_ptr;
1457 our_pred = insert_primary (entry);
1458 /* -print has the side effect of printing. This prevents us
1459 from doing undesired multiple printing when the user has
1460 already specified -print. */
1461 our_pred->side_effects = our_pred->no_default_print = true;
1462 our_pred->need_stat = our_pred->need_type = false;
1463 our_pred->args.printf_vec.segment = NULL;
1464 our_pred->args.printf_vec.stream = stdout;
1465 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1466 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1468 return true;
1471 static boolean
1472 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1474 struct predicate *our_pred;
1476 (void) argv;
1477 (void) arg_ptr;
1479 our_pred = insert_primary (entry);
1480 /* -print0 has the side effect of printing. This prevents us
1481 from doing undesired multiple printing when the user has
1482 already specified -print0. */
1483 our_pred->side_effects = our_pred->no_default_print = true;
1484 our_pred->need_stat = our_pred->need_type = false;
1485 return true;
1488 static boolean
1489 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1491 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1492 return false;
1493 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1496 static boolean
1497 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1499 struct predicate *our_pred;
1501 (void) argv;
1502 (void) arg_ptr;
1504 our_pred = insert_primary (entry);
1505 our_pred->need_stat = our_pred->need_type = false;
1506 /* -prune has a side effect that it does not descend into
1507 the current directory. */
1508 our_pred->side_effects = true;
1509 our_pred->no_default_print = false;
1510 return true;
1513 static boolean
1514 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1516 struct predicate *our_pred = insert_primary (entry);
1517 (void) argv;
1518 (void) arg_ptr;
1519 our_pred->need_stat = our_pred->need_type = false;
1520 our_pred->side_effects = true; /* Exiting is a side effect... */
1521 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1522 return true;
1526 static boolean
1527 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1529 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1530 return false;
1532 /* collect the regex type name */
1533 options.regex_options = get_regex_type(argv[*arg_ptr]);
1534 (*arg_ptr)++;
1536 return parse_noop(entry, argv, arg_ptr);
1540 static boolean
1541 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1543 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1546 static boolean
1547 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1549 struct predicate *our_pred;
1550 struct re_pattern_buffer *re;
1551 const char *error_message;
1553 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1554 return false;
1555 our_pred = insert_primary_withpred (entry, pred_regex);
1556 our_pred->need_stat = our_pred->need_type = false;
1557 re = (struct re_pattern_buffer *)
1558 xmalloc (sizeof (struct re_pattern_buffer));
1559 our_pred->args.regex = re;
1560 re->allocated = 100;
1561 re->buffer = (unsigned char *) xmalloc (re->allocated);
1562 re->fastmap = NULL;
1564 re_set_syntax(regex_options);
1565 re->syntax = regex_options;
1566 re->translate = NULL;
1568 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1569 re);
1570 if (error_message)
1571 error (1, 0, "%s", error_message);
1572 (*arg_ptr)++;
1573 return true;
1576 static boolean
1577 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1579 struct predicate *our_pred;
1580 uintmax_t num;
1581 enum comparison_type c_type;
1582 int blksize = 512;
1583 int len;
1585 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1586 return false;
1587 len = strlen (argv[*arg_ptr]);
1588 if (len == 0)
1589 error (1, 0, _("invalid null argument to -size"));
1590 switch (argv[*arg_ptr][len - 1])
1592 case 'b':
1593 blksize = 512;
1594 argv[*arg_ptr][len - 1] = '\0';
1595 break;
1597 case 'c':
1598 blksize = 1;
1599 argv[*arg_ptr][len - 1] = '\0';
1600 break;
1602 case 'k':
1603 blksize = 1024;
1604 argv[*arg_ptr][len - 1] = '\0';
1605 break;
1607 case 'M': /* Megabytes */
1608 blksize = 1024*1024;
1609 argv[*arg_ptr][len - 1] = '\0';
1610 break;
1612 case 'G': /* Gigabytes */
1613 blksize = 1024*1024*1024;
1614 argv[*arg_ptr][len - 1] = '\0';
1615 break;
1617 case 'w':
1618 blksize = 2;
1619 argv[*arg_ptr][len - 1] = '\0';
1620 break;
1622 case '0':
1623 case '1':
1624 case '2':
1625 case '3':
1626 case '4':
1627 case '5':
1628 case '6':
1629 case '7':
1630 case '8':
1631 case '9':
1632 break;
1634 default:
1635 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1637 if (!get_num (argv[*arg_ptr], &num, &c_type))
1638 return false;
1639 our_pred = insert_primary (entry);
1640 our_pred->args.size.kind = c_type;
1641 our_pred->args.size.blocksize = blksize;
1642 our_pred->args.size.size = num;
1643 (*arg_ptr)++;
1644 return true;
1648 static boolean
1649 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1651 struct predicate *our_pred;
1652 struct stat st;
1654 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1655 return false;
1656 if ((*options.xstat) (argv[*arg_ptr], &st))
1657 error (1, errno, "%s", argv[*arg_ptr]);
1659 our_pred = insert_primary (entry);
1660 our_pred->args.fileid.ino = st.st_ino;
1661 our_pred->args.fileid.dev = st.st_dev;
1662 our_pred->need_type = false;
1663 our_pred->need_stat = true;
1664 (*arg_ptr)++;
1665 return true;
1668 #if 0
1669 static boolean
1670 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1672 const char *arg;
1673 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1674 "must be 'literal' or 'safe'");
1676 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1678 error (1, errno, "%s", errmsg);
1679 return false;
1681 else
1683 arg = argv[*arg_ptr];
1685 if (0 == strcmp("literal", arg))
1687 options.literal_control_chars = true;
1689 else if (0 == strcmp("safe", arg))
1691 options.literal_control_chars = false;
1693 else
1695 error (1, errno, "%s", errmsg);
1696 return false;
1698 (*arg_ptr)++; /* consume the argument. */
1699 return true;
1702 #endif
1705 static boolean
1706 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1708 struct predicate *our_pred;
1710 (void) argv;
1711 (void) arg_ptr;
1713 our_pred = insert_primary (entry);
1714 our_pred->need_stat = our_pred->need_type = false;
1715 return true;
1718 static boolean
1719 parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
1721 (void) entry;
1722 return parse_true(get_noop(), argv, arg_ptr);
1725 static boolean
1726 insert_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1728 struct predicate *our_pred;
1729 (void) argv;
1730 (void) arg_ptr;
1731 our_pred = insert_primary (entry);
1732 our_pred->need_stat = our_pred->need_type = false;
1733 our_pred->side_effects = our_pred->no_default_print = false;
1734 return true;
1737 static boolean
1738 parse_executable (const struct parser_table* entry, char **argv, int *arg_ptr)
1740 return insert_accesscheck(entry, argv, arg_ptr);
1743 static boolean
1744 parse_readable (const struct parser_table* entry, char **argv, int *arg_ptr)
1746 return insert_accesscheck(entry, argv, arg_ptr);
1749 static boolean
1750 parse_writable (const struct parser_table* entry, char **argv, int *arg_ptr)
1752 return insert_accesscheck(entry, argv, arg_ptr);
1755 static boolean
1756 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1758 return insert_type (argv, arg_ptr, entry, pred_type);
1761 static boolean
1762 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1764 return insert_num (argv, arg_ptr, entry);
1767 static boolean
1768 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1770 struct predicate *our_pred;
1771 uintmax_t num_days;
1772 enum comparison_type c_type;
1773 time_t t;
1775 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1776 return false;
1777 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1778 return false;
1779 t = num_days * DAYSECS;
1780 our_pred = insert_primary (entry);
1781 our_pred->args.info.kind = c_type;
1782 our_pred->args.info.negative = t < 0;
1783 our_pred->args.info.l_val = t;
1784 (*arg_ptr)++;
1785 return true;
1788 static boolean
1789 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1791 struct passwd *cur_pwd;
1792 struct predicate *our_pred;
1793 uid_t uid;
1794 int uid_len;
1796 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1797 return false;
1798 cur_pwd = getpwnam (argv[*arg_ptr]);
1799 endpwent ();
1800 if (cur_pwd != NULL)
1801 uid = cur_pwd->pw_uid;
1802 else
1804 uid_len = strspn (argv[*arg_ptr], "0123456789");
1805 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1806 return false;
1807 uid = atoi (argv[*arg_ptr]);
1809 our_pred = insert_primary (entry);
1810 our_pred->args.uid = uid;
1811 (*arg_ptr)++;
1812 return true;
1815 static boolean
1816 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1818 extern char *version_string;
1819 int features = 0;
1821 (void) argv;
1822 (void) arg_ptr;
1823 (void) entry;
1825 fflush (stderr);
1826 printf (_("GNU find version %s\n"), version_string);
1827 printf (_("Features enabled: "));
1829 #if CACHE_IDS
1830 printf("CACHE_IDS ");
1831 ++features;
1832 #endif
1833 #if DEBUG
1834 printf("DEBUG ");
1835 ++features;
1836 #endif
1837 #if DEBUG_STAT
1838 printf("DEBUG_STAT ");
1839 ++features;
1840 #endif
1841 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1842 printf("D_TYPE ");
1843 ++features;
1844 #endif
1845 #if defined(O_NOFOLLOW)
1846 printf("O_NOFOLLOW(%s) ",
1847 (options.open_nofollow_available ? "enabled" : "disabled"));
1848 ++features;
1849 #endif
1850 #if defined(LEAF_OPTIMISATION)
1851 printf("LEAF_OPTIMISATION ");
1852 ++features;
1853 #endif
1855 if (is_fts_enabled())
1857 printf("FTS ");
1858 ++features;
1861 if (0 == features)
1863 /* For the moment, leave this as English in case someone wants
1864 to parse these strings. */
1865 printf("none");
1867 printf("\n");
1869 exit (0);
1872 static boolean
1873 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1875 (void) argv;
1876 (void) arg_ptr;
1877 (void) entry;
1878 options.stay_on_filesystem = true;
1879 return parse_noop(entry, argv, arg_ptr);
1882 static boolean
1883 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1885 (void) argv;
1886 (void) arg_ptr;
1887 (void) entry;
1888 options.ignore_readdir_race = true;
1889 return parse_noop(entry, argv, arg_ptr);
1892 static boolean
1893 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1895 (void) argv;
1896 (void) arg_ptr;
1897 (void) entry;
1898 options.ignore_readdir_race = false;
1899 return parse_noop(entry, argv, arg_ptr);
1902 static boolean
1903 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1905 (void) argv;
1906 (void) arg_ptr;
1907 (void) entry;
1908 options.warnings = true;
1909 return parse_noop(entry, argv, arg_ptr);
1912 static boolean
1913 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1915 (void) argv;
1916 (void) arg_ptr;
1917 return insert_type (argv, arg_ptr, entry, pred_xtype);
1920 static boolean
1921 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
1923 mode_t type_cell;
1924 struct predicate *our_pred;
1926 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1927 || (strlen (argv[*arg_ptr]) != 1))
1928 return false;
1929 switch (argv[*arg_ptr][0])
1931 case 'b': /* block special */
1932 type_cell = S_IFBLK;
1933 break;
1934 case 'c': /* character special */
1935 type_cell = S_IFCHR;
1936 break;
1937 case 'd': /* directory */
1938 type_cell = S_IFDIR;
1939 break;
1940 case 'f': /* regular file */
1941 type_cell = S_IFREG;
1942 break;
1943 #ifdef S_IFLNK
1944 case 'l': /* symbolic link */
1945 type_cell = S_IFLNK;
1946 break;
1947 #endif
1948 #ifdef S_IFIFO
1949 case 'p': /* pipe */
1950 type_cell = S_IFIFO;
1951 break;
1952 #endif
1953 #ifdef S_IFSOCK
1954 case 's': /* socket */
1955 type_cell = S_IFSOCK;
1956 break;
1957 #endif
1958 #ifdef S_IFDOOR
1959 case 'D': /* Solaris door */
1960 type_cell = S_IFDOOR;
1961 break;
1962 #endif
1963 default: /* None of the above ... nuke 'em. */
1964 return false;
1966 our_pred = insert_primary_withpred (entry, which_pred);
1968 /* Figure out if we will need to stat the file, because if we don't
1969 * need to follow symlinks, we can avoid a stat call by using
1970 * struct dirent.d_type.
1972 if (which_pred == pred_xtype)
1974 our_pred->need_stat = true;
1975 our_pred->need_type = false;
1977 else
1979 our_pred->need_stat = false; /* struct dirent is enough */
1980 our_pred->need_type = true;
1982 our_pred->args.type = type_cell;
1983 (*arg_ptr)++; /* Move on to next argument. */
1984 return true;
1988 /* Return true if the file accessed via FP is a terminal.
1990 static boolean
1991 stream_is_tty(FILE *fp)
1993 int fd = fileno(fp);
1994 if (-1 == fd)
1996 return false; /* not a valid stream */
1998 else
2000 return isatty(fd) ? true : false;
2007 /* If true, we've determined that the current fprintf predicate
2008 uses stat information. */
2009 static boolean fprintf_stat_needed;
2011 /* XXX: do we need to pass FUNC to this function? */
2012 static boolean
2013 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
2015 char *format; /* Beginning of unprocessed format string. */
2016 register char *scan; /* Current address in scanning `format'. */
2017 register char *scan2; /* Address inside of element being scanned. */
2018 struct segment **segmentp; /* Address of current segment. */
2019 struct predicate *our_pred;
2021 format = argv[(*arg_ptr)++];
2023 fprintf_stat_needed = false; /* Might be overridden later. */
2024 our_pred = insert_primary_withpred (entry, func);
2025 our_pred->side_effects = our_pred->no_default_print = true;
2026 our_pred->args.printf_vec.stream = fp;
2027 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
2028 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2029 segmentp = &our_pred->args.printf_vec.segment;
2030 *segmentp = NULL;
2032 for (scan = format; *scan; scan++)
2034 if (*scan == '\\')
2036 scan2 = scan + 1;
2037 if (*scan2 >= '0' && *scan2 <= '7')
2039 register int n, i;
2041 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2042 i++, scan2++)
2043 n = 8 * n + *scan2 - '0';
2044 scan2--;
2045 *scan = n;
2047 else
2049 switch (*scan2)
2051 case 'a':
2052 *scan = 7;
2053 break;
2054 case 'b':
2055 *scan = '\b';
2056 break;
2057 case 'c':
2058 make_segment (segmentp, format, scan - format, KIND_STOP);
2059 our_pred->need_stat = fprintf_stat_needed;
2060 return true;
2061 case 'f':
2062 *scan = '\f';
2063 break;
2064 case 'n':
2065 *scan = '\n';
2066 break;
2067 case 'r':
2068 *scan = '\r';
2069 break;
2070 case 't':
2071 *scan = '\t';
2072 break;
2073 case 'v':
2074 *scan = '\v';
2075 break;
2076 case '\\':
2077 /* *scan = '\\'; * it already is */
2078 break;
2079 default:
2080 error (0, 0,
2081 _("warning: unrecognized escape `\\%c'"), *scan2);
2082 scan++;
2083 continue;
2086 segmentp = make_segment (segmentp, format, scan - format + 1,
2087 KIND_PLAIN);
2088 format = scan2 + 1; /* Move past the escape. */
2089 scan = scan2; /* Incremented immediately by `for'. */
2091 else if (*scan == '%')
2093 if (scan[1] == '%')
2095 segmentp = make_segment (segmentp, format, scan - format + 1,
2096 KIND_PLAIN);
2097 scan++;
2098 format = scan + 1;
2099 continue;
2101 /* Scan past flags, width and precision, to verify kind. */
2102 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2103 /* Do nothing. */ ;
2104 while (ISDIGIT (*scan2))
2105 scan2++;
2106 if (*scan2 == '.')
2107 for (scan2++; ISDIGIT (*scan2); scan2++)
2108 /* Do nothing. */ ;
2109 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
2111 segmentp = make_segment (segmentp, format, scan2 - format,
2112 (int) *scan2);
2113 scan = scan2;
2114 format = scan + 1;
2116 else if (strchr ("ACT", *scan2) && scan2[1])
2118 segmentp = make_segment (segmentp, format, scan2 - format,
2119 *scan2 | (scan2[1] << 8));
2120 scan = scan2 + 1;
2121 format = scan + 1;
2122 continue;
2124 else
2126 /* An unrecognized % escape. Print the char after the %. */
2127 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2128 *scan2);
2129 segmentp = make_segment (segmentp, format, scan - format,
2130 KIND_PLAIN);
2131 format = scan + 1;
2132 continue;
2137 if (scan > format)
2138 make_segment (segmentp, format, scan - format, KIND_PLAIN);
2139 our_pred->need_type = false;
2140 our_pred->need_stat = fprintf_stat_needed;
2141 return true;
2144 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2145 from the text in FORMAT, which has length LEN.
2146 Return the address of the `next' pointer of the new segment. */
2148 static struct segment **
2149 make_segment (struct segment **segment, char *format, int len, int kind)
2151 char *fmt;
2153 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2155 (*segment)->kind = kind;
2156 (*segment)->next = NULL;
2157 (*segment)->text_len = len;
2159 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2160 strncpy (fmt, format, len);
2161 fmt += len;
2163 switch (kind & 0xff)
2165 case KIND_PLAIN: /* Plain text string, no % conversion. */
2166 case KIND_STOP: /* Terminate argument, no newline. */
2167 break;
2169 case 'a': /* atime in `ctime' format */
2170 case 'A': /* atime in user-specified strftime format */
2171 case 'c': /* ctime in `ctime' format */
2172 case 'C': /* ctime in user-specified strftime format */
2173 case 'F': /* filesystem type */
2174 case 'g': /* group name */
2175 case 'i': /* inode number */
2176 case 'l': /* object of symlink */
2177 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2178 case 's': /* size in bytes */
2179 case 't': /* mtime in `ctime' format */
2180 case 'T': /* mtime in user-specified strftime format */
2181 case 'u': /* user name */
2182 case 'y': /* file type */
2183 case 'Y': /* symlink pointed file type */
2184 fprintf_stat_needed = true;
2185 /* FALLTHROUGH */
2186 case 'f': /* basename of path */
2187 case 'h': /* leading directories part of path */
2188 case 'H': /* ARGV element file was found under */
2189 case 'p': /* pathname */
2190 case 'P': /* pathname with ARGV element stripped */
2191 *fmt++ = 's';
2192 break;
2194 /* Numeric items that one might expect to honour
2195 * #, 0, + flags but which do not.
2197 case 'G': /* GID number */
2198 case 'U': /* UID number */
2199 case 'b': /* size in 512-byte blocks */
2200 case 'D': /* Filesystem device on which the file exits */
2201 case 'k': /* size in 1K blocks */
2202 case 'n': /* number of links */
2203 fprintf_stat_needed = true;
2204 *fmt++ = 's';
2205 break;
2207 /* Numeric items that DO honour #, 0, + flags.
2209 case 'd': /* depth in search tree (0 = ARGV element) */
2210 *fmt++ = 'd';
2211 break;
2213 case 'm': /* mode as octal number (perms only) */
2214 *fmt++ = 'o';
2215 fprintf_stat_needed = true;
2216 break;
2218 *fmt = '\0';
2220 return &(*segment)->next;
2223 static void
2224 check_path_safety(const char *action)
2226 const char *path = getenv("PATH");
2227 char *s;
2228 s = next_element(path, 1);
2229 while ((s = next_element ((char *) NULL, 1)) != NULL)
2231 if (0 == strcmp(s, "."))
2233 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)"),
2234 action);
2240 /* handles both exec and ok predicate */
2241 #if defined(NEW_EXEC)
2242 /* handles both exec and ok predicate */
2243 static boolean
2244 new_insert_exec_ok (const char *action,
2245 const struct parser_table *entry,
2246 char **argv,
2247 int *arg_ptr)
2249 int start, end; /* Indexes in ARGV of start & end of cmd. */
2250 int i; /* Index into cmd args */
2251 int saw_braces; /* True if previous arg was '{}'. */
2252 boolean allow_plus; /* True if + is a valid terminator */
2253 int brace_count; /* Number of instances of {}. */
2254 PRED_FUNC func = entry->pred_func;
2256 struct predicate *our_pred;
2257 struct exec_val *execp; /* Pointer for efficiency. */
2259 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2260 return false;
2262 our_pred = insert_primary_withpred (entry, func);
2263 our_pred->side_effects = our_pred->no_default_print = true;
2264 execp = &our_pred->args.exec_vec;
2266 if ((func != pred_okdir) && (func != pred_ok))
2268 allow_plus = true;
2269 execp->close_stdin = false;
2271 else
2273 allow_plus = false;
2274 /* If find reads stdin (i.e. for -ok and similar), close stdin
2275 * in the child to prevent some script from consiming the output
2276 * intended for find.
2278 execp->close_stdin = true;
2282 if ((func == pred_execdir) || (func == pred_okdir))
2284 options.ignore_readdir_race = false;
2285 check_path_safety(action);
2286 execp->use_current_dir = true;
2288 else
2290 execp->use_current_dir = false;
2293 our_pred->args.exec_vec.multiple = 0;
2295 /* Count the number of args with path replacements, up until the ';'.
2296 * Also figure out if the command is terminated by ";" or by "+".
2298 start = *arg_ptr;
2299 for (end = start, saw_braces=0, brace_count=0;
2300 (argv[end] != NULL)
2301 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2302 end++)
2304 /* For -exec and -execdir, "{} +" can terminate the command. */
2305 if ( allow_plus
2306 && argv[end][0] == '+' && argv[end][1] == 0
2307 && saw_braces)
2309 our_pred->args.exec_vec.multiple = 1;
2310 break;
2313 saw_braces = 0;
2314 if (strstr (argv[end], "{}"))
2316 saw_braces = 1;
2317 ++brace_count;
2319 if (0 == end && (func == pred_execdir || func == pred_okdir))
2321 /* The POSIX standard says that {} replacement should
2322 * occur even in the utility name. This is insecure
2323 * since it means we will be executing a command whose
2324 * name is chosen according to whatever find finds in
2325 * the filesystem. That can be influenced by an
2326 * attacker. Hence for -execdir and -okdir this is not
2327 * allowed. We can specify this as those options are
2328 * not defined by POSIX.
2330 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2335 /* Fail if no command given or no semicolon found. */
2336 if ((end == start) || (argv[end] == NULL))
2338 *arg_ptr = end;
2339 free(our_pred);
2340 return false;
2343 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2346 const char *suffix;
2347 if (func == pred_execdir)
2348 suffix = "dir";
2349 else
2350 suffix = "";
2352 error(1, 0,
2353 _("Only one instance of {} is supported with -exec%s ... +"),
2354 suffix);
2357 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2358 bc_init_controlinfo(&execp->ctl);
2359 execp->ctl.exec_callback = launch;
2361 if (our_pred->args.exec_vec.multiple)
2363 /* "+" terminator, so we can just append our arguments after the
2364 * command and initial arguments.
2366 execp->replace_vec = NULL;
2367 execp->ctl.replace_pat = NULL;
2368 execp->ctl.rplen = 0;
2369 execp->ctl.lines_per_exec = 0; /* no limit */
2370 execp->ctl.args_per_exec = 0; /* no limit */
2372 /* remember how many arguments there are */
2373 execp->ctl.initial_argc = (end-start) - 1;
2375 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2376 bc_init_state(&execp->ctl, &execp->state, execp);
2378 /* Gather the initial arguments. Skip the {}. */
2379 for (i=start; i<end-1; ++i)
2381 bc_push_arg(&execp->ctl, &execp->state,
2382 argv[i], strlen(argv[i])+1,
2383 NULL, 0,
2387 else
2389 /* Semicolon terminator - more than one {} is supported, so we
2390 * have to do brace-replacement.
2392 execp->num_args = end - start;
2394 execp->ctl.replace_pat = "{}";
2395 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2396 execp->ctl.lines_per_exec = 0; /* no limit */
2397 execp->ctl.args_per_exec = 0; /* no limit */
2398 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2401 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2402 bc_init_state(&execp->ctl, &execp->state, execp);
2404 /* Remember the (pre-replacement) arguments for later. */
2405 for (i=0; i<execp->num_args; ++i)
2407 execp->replace_vec[i] = argv[i+start];
2411 if (argv[end] == NULL)
2412 *arg_ptr = end;
2413 else
2414 *arg_ptr = end + 1;
2416 return true;
2418 #else
2419 /* handles both exec and ok predicate */
2420 static boolean
2421 old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
2423 int start, end; /* Indexes in ARGV of start & end of cmd. */
2424 int num_paths; /* Number of args with path replacements. */
2425 int path_pos; /* Index in array of path replacements. */
2426 int vec_pos; /* Index in array of args. */
2427 struct predicate *our_pred;
2428 struct exec_val *execp; /* Pointer for efficiency. */
2430 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2431 return false;
2433 /* Count the number of args with path replacements, up until the ';'. */
2434 start = *arg_ptr;
2435 for (end = start, num_paths = 0;
2436 (argv[end] != NULL)
2437 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2438 end++)
2439 if (strstr (argv[end], "{}"))
2440 num_paths++;
2441 /* Fail if no command given or no semicolon found. */
2442 if ((end == start) || (argv[end] == NULL))
2444 *arg_ptr = end;
2445 return false;
2448 our_pred = insert_primary (func);
2449 our_pred->side_effects = our_pred->no_default_print = true;
2450 execp = &our_pred->args.exec_vec;
2451 execp->usercontext = our_pred;
2452 execp->use_current_dir = false;
2453 execp->paths =
2454 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
2455 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
2456 /* Record the positions of all args, and the args with path replacements. */
2457 for (end = start, path_pos = vec_pos = 0;
2458 (argv[end] != NULL)
2459 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2460 end++)
2462 register char *p;
2464 execp->paths[path_pos].count = 0;
2465 for (p = argv[end]; *p; ++p)
2466 if (p[0] == '{' && p[1] == '}')
2468 execp->paths[path_pos].count++;
2469 ++p;
2471 if (execp->paths[path_pos].count)
2473 execp->paths[path_pos].offset = vec_pos;
2474 execp->paths[path_pos].origarg = argv[end];
2475 path_pos++;
2477 execp->vec[vec_pos++] = argv[end];
2479 execp->paths[path_pos].offset = -1;
2480 execp->vec[vec_pos] = NULL;
2482 if (argv[end] == NULL)
2483 *arg_ptr = end;
2484 else
2485 *arg_ptr = end + 1;
2486 return true;
2488 #endif
2492 static boolean
2493 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2495 #if defined(NEW_EXEC)
2496 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2497 #else
2498 return old_insert_exec_ok(func, argv, arg_ptr);
2499 #endif
2504 /* Get a number of days and comparison type.
2505 STR is the ASCII representation.
2506 Set *NUM_DAYS to the number of days, taken as being from
2507 the current moment (or possibly midnight). Thus the sense of the
2508 comparison type appears to be reversed.
2509 Set *COMP_TYPE to the kind of comparison that is requested.
2511 Return true if all okay, false if input error.
2513 Used by -atime, -ctime and -mtime (parsers) to
2514 get the appropriate information for a time predicate processor. */
2516 static boolean
2517 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2519 boolean r = get_num (str, num_days, comp_type);
2520 if (r)
2521 switch (*comp_type)
2523 case COMP_LT: *comp_type = COMP_GT; break;
2524 case COMP_GT: *comp_type = COMP_LT; break;
2525 default: break;
2527 return r;
2530 /* Insert a time predicate PRED.
2531 ARGV is a pointer to the argument array.
2532 ARG_PTR is a pointer to an index into the array, incremented if
2533 all went well.
2535 Return true if input is valid, false if not.
2537 A new predicate node is assigned, along with an argument node
2538 obtained with malloc.
2540 Used by -atime, -ctime, and -mtime parsers. */
2542 static boolean
2543 insert_time (char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred)
2545 struct predicate *our_pred;
2546 uintmax_t num_days;
2547 enum comparison_type c_type;
2548 time_t t;
2550 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2551 return false;
2552 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2553 return false;
2555 /* Figure out the timestamp value we are looking for. */
2556 t = ( options.cur_day_start - num_days * DAYSECS
2557 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2559 if (1)
2561 /* We introduce a scope in which 'val' can be declared, for the
2562 * benefit of compilers that are really C89 compilers
2563 * which support intmax_t because config.h #defines it
2565 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2566 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2567 t = val;
2569 /* Check for possibility of an overflow */
2570 if ( (intmax_t)t != val )
2572 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2576 our_pred = insert_primary_withpred (entry, pred);
2577 our_pred->args.info.kind = c_type;
2578 our_pred->args.info.negative = t < 0;
2579 our_pred->args.info.l_val = t;
2580 (*arg_ptr)++;
2581 #ifdef DEBUG
2582 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2583 fprintf (stderr, " type: %s %s ",
2584 (c_type == COMP_GT) ? "gt" :
2585 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2586 (c_type == COMP_GT) ? " >" :
2587 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2588 t = our_pred->args.info.l_val;
2589 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2590 if (c_type == COMP_EQ)
2592 t = our_pred->args.info.l_val += DAYSECS;
2593 fprintf (stderr, " < %ju %s",
2594 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2595 our_pred->args.info.l_val -= DAYSECS;
2597 #endif /* DEBUG */
2598 return true;
2601 /* Get a number with comparison information.
2602 The sense of the comparison information is 'normal'; that is,
2603 '+' looks for a count > than the number and '-' less than.
2605 STR is the ASCII representation of the number.
2606 Set *NUM to the number.
2607 Set *COMP_TYPE to the kind of comparison that is requested.
2609 Return true if all okay, false if input error. */
2611 static boolean
2612 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2614 if (str == NULL)
2615 return false;
2616 switch (str[0])
2618 case '+':
2619 *comp_type = COMP_GT;
2620 str++;
2621 break;
2622 case '-':
2623 *comp_type = COMP_LT;
2624 str++;
2625 break;
2626 default:
2627 *comp_type = COMP_EQ;
2628 break;
2631 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2634 /* Insert a number predicate.
2635 ARGV is a pointer to the argument array.
2636 *ARG_PTR is an index into ARGV, incremented if all went well.
2637 *PRED is the predicate processor to insert.
2639 Return true if input is valid, false if error.
2641 A new predicate node is assigned, along with an argument node
2642 obtained with malloc.
2644 Used by -inum and -links parsers. */
2646 static boolean
2647 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2649 struct predicate *our_pred;
2650 uintmax_t num;
2651 enum comparison_type c_type;
2653 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2654 return false;
2655 if (!get_num (argv[*arg_ptr], &num, &c_type))
2656 return false;
2657 our_pred = insert_primary (entry);
2658 our_pred->args.info.kind = c_type;
2659 our_pred->args.info.l_val = num;
2660 (*arg_ptr)++;
2661 #ifdef DEBUG
2662 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2663 fprintf (stderr, " type: %s %s ",
2664 (c_type == COMP_GT) ? "gt" :
2665 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2666 (c_type == COMP_GT) ? " >" :
2667 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2668 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2669 #endif /* DEBUG */
2670 return true;
2673 static FILE *
2674 open_output_file (char *path)
2676 FILE *f;
2678 if (!strcmp (path, "/dev/stderr"))
2679 return stderr;
2680 else if (!strcmp (path, "/dev/stdout"))
2681 return stdout;
2682 f = fopen_safer (path, "w");
2683 if (f == NULL)
2684 error (1, errno, "%s", path);
2685 return f;