Updated Romanian, Slovak and Estonian translations from Translation Project
[findutils.git] / find / parser.c
blobd8962d5ed591789cf03e267e670aa3665f5a0a51
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_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_mtime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
154 boolean parse_open PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
155 boolean parse_close PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
159 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
160 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
161 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
163 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
164 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
165 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
166 static boolean insert_time PARAMS((char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred));
167 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
168 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
169 static FILE *open_output_file PARAMS((char *path));
170 static boolean stream_is_tty(FILE *fp);
172 #ifdef DEBUG
173 char *find_pred_name PARAMS((PRED_FUNC pred_func));
174 #endif /* DEBUG */
177 #define PASTE(x,y) x##y
178 #define STRINGIFY(s) #s
180 #define PARSE_OPTION(what,suffix) \
181 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
183 #define PARSE_POSOPT(what,suffix) \
184 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
186 #define PARSE_TEST(what,suffix) \
187 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
189 #define PARSE_TEST_NP(what,suffix) \
190 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
192 #define PARSE_ACTION(what,suffix) \
193 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
195 #define PARSE_ACTION_NP(what,suffix) \
196 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
198 #define PARSE_PUNCTUATION(what,suffix) \
199 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
202 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
203 If they are in some Unix versions of find, they are marked `Unix'. */
205 static struct parser_table const parse_table[] =
207 PARSE_PUNCTUATION("!", negate),
208 PARSE_PUNCTUATION("not", negate), /* GNU */
209 PARSE_PUNCTUATION("(", open),
210 PARSE_PUNCTUATION(")", close),
211 PARSE_PUNCTUATION(",", comma), /* GNU */
212 PARSE_PUNCTUATION("a", and),
213 PARSE_TEST ("amin", amin), /* GNU */
214 PARSE_PUNCTUATION("and", and), /* GNU */
215 PARSE_TEST ("anewer", anewer), /* GNU */
216 PARSE_TEST ("atime", atime),
217 PARSE_TEST ("cmin", cmin), /* GNU */
218 PARSE_TEST ("cnewer", cnewer), /* GNU */
219 PARSE_TEST ("ctime", ctime),
220 PARSE_POSOPT ("daystart", daystart), /* GNU */
221 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
222 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
223 PARSE_OPTION ("depth", depth),
224 PARSE_TEST ("empty", empty), /* GNU */
225 PARSE_ACTION ("exec", exec),
226 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
227 PARSE_ACTION ("fls", fls), /* GNU */
228 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
229 PARSE_ACTION ("fprint", fprint), /* GNU */
230 PARSE_ACTION ("fprint0", fprint0), /* GNU */
231 PARSE_ACTION ("fprintf", fprintf), /* GNU */
232 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
233 PARSE_TEST ("gid", gid), /* GNU */
234 PARSE_TEST ("group", group),
235 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
236 PARSE_TEST ("ilname", ilname), /* GNU */
237 PARSE_TEST ("iname", iname), /* GNU */
238 PARSE_TEST ("inum", inum), /* GNU, Unix */
239 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
240 PARSE_TEST_NP ("iregex", iregex), /* GNU */
241 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
242 PARSE_TEST ("links", links),
243 PARSE_TEST ("lname", lname), /* GNU */
244 PARSE_ACTION ("ls", ls), /* GNU, Unix */
245 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
246 PARSE_OPTION ("mindepth", mindepth), /* GNU */
247 PARSE_TEST ("mmin", mmin), /* GNU */
248 PARSE_OPTION ("mount", xdev), /* Unix */
249 PARSE_TEST ("mtime", mtime),
250 PARSE_TEST ("name", name),
251 #ifdef UNIMPLEMENTED_UNIX
252 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
253 #endif
254 PARSE_TEST ("newer", newer),
255 PARSE_OPTION ("noleaf", noleaf), /* GNU */
256 PARSE_TEST ("nogroup", nogroup),
257 PARSE_TEST ("nouser", nouser),
258 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
259 PARSE_OPTION ("nowarn", nowarn), /* GNU */
260 PARSE_PUNCTUATION("o", or),
261 PARSE_PUNCTUATION("or", or), /* GNU */
262 PARSE_ACTION ("ok", ok),
263 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
264 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
265 PARSE_TEST ("perm", perm),
266 PARSE_ACTION ("print", print),
267 PARSE_ACTION ("print0", print0), /* GNU */
268 PARSE_ACTION_NP ("printf", printf), /* GNU */
269 PARSE_ACTION ("prune", prune),
270 PARSE_ACTION ("quit", quit), /* GNU */
271 PARSE_TEST ("regex", regex), /* GNU */
272 PARSE_OPTION ("regextype", regextype), /* GNU */
273 PARSE_TEST ("samefile", samefile), /* GNU */
274 PARSE_TEST ("size", size),
275 PARSE_TEST ("type", type),
276 PARSE_TEST ("uid", uid), /* GNU */
277 PARSE_TEST ("used", used), /* GNU */
278 PARSE_TEST ("user", user),
279 PARSE_OPTION ("warn", warn), /* GNU */
280 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
281 PARSE_OPTION ("xdev", xdev),
282 PARSE_TEST ("xtype", xtype), /* GNU */
283 #ifdef UNIMPLEMENTED_UNIX
284 /* It's pretty ugly for find to know about archive formats.
285 Plus what it could do with cpio archives is very limited.
286 Better to leave it out. */
287 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
288 #endif
289 /* gnulib's stdbool.h might have made true and false into macros,
290 * so we can't leave named 'true' and 'false' tokens, so we have
291 * to expeant the relevant entries longhand.
293 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
294 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
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;
309 void
310 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
312 (void) args;
313 (void) argno;
314 (void) last;
315 (void) predicates;
316 first_nonoption_arg = NULL;
319 void
320 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
322 /* does nothing */
323 (void) args;
324 (void) argno;
325 (void) last;
326 (void) predicates;
332 /* Return a pointer to the parser function to invoke for predicate
333 SEARCH_NAME.
334 Return NULL if SEARCH_NAME is not a valid predicate name. */
336 const struct parser_table*
337 find_parser (char *search_name)
339 int i;
340 const char *original_arg = search_name;
342 if (*search_name == '-')
343 search_name++;
344 for (i = 0; parse_table[i].parser_name != 0; i++)
346 if (strcmp (parse_table[i].parser_name, search_name) == 0)
348 /* If this is an option, but we have already had a
349 * non-option argument, the user may be under the
350 * impression that the behaviour of the option
351 * argument is conditional on some preceding
352 * tests. This might typically be the case with,
353 * for example, -maxdepth.
355 * The options -daystart and -follow are exempt
356 * from this treatment, since their positioning
357 * in the command line does have an effect on
358 * subsequent tests but not previous ones. That
359 * might be intentional on the part of the user.
361 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
363 /* Something other than -follow/-daystart.
364 * If this is an option, check if it followed
365 * a non-option and if so, issue a warning.
367 if (parse_table[i].type == ARG_OPTION)
369 if ((first_nonoption_arg != NULL)
370 && options.warnings )
372 /* option which follows a non-option */
373 error (0, 0,
374 _("warning: you have specified the %s "
375 "option after a non-option argument %s, "
376 "but options are not positional (%s affects "
377 "tests specified before it as well as those "
378 "specified after it). Please specify options "
379 "before other arguments.\n"),
380 original_arg,
381 first_nonoption_arg,
382 original_arg);
385 else
387 /* Not an option or a positional option,
388 * so remember we've seen it in order to
389 * use it in a possible future warning message.
391 if (first_nonoption_arg == NULL)
393 first_nonoption_arg = original_arg;
398 return &parse_table[i];
401 return NULL;
404 /* The parsers are responsible to continue scanning ARGV for
405 their arguments. Each parser knows what is and isn't
406 allowed for itself.
408 ARGV is the argument array.
409 *ARG_PTR is the index to start at in ARGV,
410 updated to point beyond the last element consumed.
412 The predicate structure is updated with the new information. */
414 static boolean
415 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
417 struct predicate *our_pred;
418 uintmax_t num;
419 enum comparison_type c_type;
420 time_t t;
422 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
423 return false;
424 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
425 return false;
426 t = options.cur_day_start + DAYSECS - num * 60;
427 our_pred = insert_primary (entry);
428 our_pred->args.info.kind = c_type;
429 our_pred->args.info.negative = t < 0;
430 our_pred->args.info.l_val = t;
431 (*arg_ptr)++;
432 return true;
435 static boolean
436 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
438 struct predicate *our_pred;
440 (void) argv;
441 (void) arg_ptr;
443 our_pred = get_new_pred (entry);
444 our_pred->pred_func = pred_and;
445 #ifdef DEBUG
446 our_pred->p_name = find_pred_name (pred_and);
447 #endif /* DEBUG */
448 our_pred->p_type = BI_OP;
449 our_pred->p_prec = AND_PREC;
450 our_pred->need_stat = our_pred->need_type = false;
451 return true;
454 static boolean
455 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
457 struct predicate *our_pred;
458 struct stat stat_newer;
460 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
461 return false;
462 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
463 error (1, errno, "%s", argv[*arg_ptr]);
464 our_pred = insert_primary (entry);
465 our_pred->args.time = stat_newer.st_mtime;
466 (*arg_ptr)++;
467 return true;
470 static boolean
471 parse_atime (const struct parser_table* entry, char **argv, int *arg_ptr)
473 return insert_time (argv, arg_ptr, entry, pred_atime);
476 boolean
477 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
479 struct predicate *our_pred;
481 (void) argv;
482 (void) arg_ptr;
484 our_pred = get_new_pred (entry);
485 our_pred->pred_func = pred_close;
486 #ifdef DEBUG
487 our_pred->p_name = find_pred_name (pred_close);
488 #endif /* DEBUG */
489 our_pred->p_type = CLOSE_PAREN;
490 our_pred->p_prec = NO_PREC;
491 our_pred->need_stat = our_pred->need_type = false;
492 return true;
495 static boolean
496 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
498 struct predicate *our_pred;
499 uintmax_t num;
500 enum comparison_type c_type;
501 time_t t;
503 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
504 return false;
505 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
506 return false;
507 t = options.cur_day_start + DAYSECS - num * 60;
508 our_pred = insert_primary (entry);
509 our_pred->args.info.kind = c_type;
510 our_pred->args.info.negative = t < 0;
511 our_pred->args.info.l_val = t;
512 (*arg_ptr)++;
513 return true;
516 static boolean
517 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
519 struct predicate *our_pred;
520 struct stat stat_newer;
522 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
523 return false;
524 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
525 error (1, errno, "%s", argv[*arg_ptr]);
526 our_pred = insert_primary (entry);
527 our_pred->args.time = stat_newer.st_mtime;
528 (*arg_ptr)++;
529 return true;
532 static boolean
533 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
535 struct predicate *our_pred;
537 (void) argv;
538 (void) arg_ptr;
540 our_pred = get_new_pred (entry);
541 our_pred->pred_func = pred_comma;
542 #ifdef DEBUG
543 our_pred->p_name = find_pred_name (pred_comma);
544 #endif /* DEBUG */
545 our_pred->p_type = BI_OP;
546 our_pred->p_prec = COMMA_PREC;
547 our_pred->need_stat = our_pred->need_type = false;
548 return true;
551 static boolean
552 parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr)
554 return insert_time (argv, arg_ptr, entry, pred_ctime);
557 static boolean
558 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
560 struct tm *local;
562 (void) entry;
563 (void) argv;
564 (void) arg_ptr;
566 if (options.full_days == false)
568 options.cur_day_start += DAYSECS;
569 local = localtime (&options.cur_day_start);
570 options.cur_day_start -= (local
571 ? (local->tm_sec + local->tm_min * 60
572 + local->tm_hour * 3600)
573 : options.cur_day_start % DAYSECS);
574 options.full_days = true;
576 return true;
579 static boolean
580 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
582 struct predicate *our_pred;
583 (void) argv;
584 (void) arg_ptr;
586 our_pred = insert_primary (entry);
587 our_pred->side_effects = our_pred->no_default_print = true;
588 /* -delete implies -depth */
589 options.do_dir_first = false;
590 return true;
593 static boolean
594 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
596 (void) entry;
597 (void) argv;
598 (void) arg_ptr;
600 options.do_dir_first = false;
601 return true;
604 static boolean
605 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
607 (void) argv;
608 (void) arg_ptr;
610 if (options.warnings)
612 error (0, 0,
613 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
615 return parse_depth(entry, argv, arg_ptr);
618 static boolean
619 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
621 (void) argv;
622 (void) arg_ptr;
624 insert_primary (entry);
625 return true;
628 static boolean
629 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
631 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
634 static boolean
635 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
637 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
640 static boolean
641 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
643 struct predicate *our_pred;
645 (void) argv;
646 (void) arg_ptr;
648 our_pred = insert_primary (entry);
649 our_pred->need_stat = our_pred->need_type = false;
650 our_pred->side_effects = our_pred->no_default_print = false;
651 return true;
654 static boolean
655 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
657 struct predicate *our_pred;
659 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
660 return false;
661 our_pred = insert_primary (entry);
662 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
663 our_pred->side_effects = our_pred->no_default_print = true;
664 (*arg_ptr)++;
665 return true;
668 static boolean
669 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
671 FILE *fp;
673 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
674 return false;
675 if (argv[*arg_ptr + 1] == NULL)
677 /* Ensure we get "missing arg" message, not "invalid arg". */
678 (*arg_ptr)++;
679 return false;
681 fp = open_output_file (argv[*arg_ptr]);
682 (*arg_ptr)++;
683 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
686 static boolean
687 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
689 (void) entry;
690 (void) argv;
691 (void) arg_ptr;
693 set_follow_state(SYMLINK_ALWAYS_DEREF);
694 return true;
697 static boolean
698 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
700 struct predicate *our_pred;
702 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
703 return false;
704 our_pred = insert_primary (entry);
705 our_pred->args.printf_vec.segment = NULL;
706 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
707 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
708 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
709 our_pred->side_effects = our_pred->no_default_print = true;
710 our_pred->need_stat = our_pred->need_type = false;
711 (*arg_ptr)++;
712 return true;
715 static boolean
716 parse_fprint0 (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 our_pred->need_stat = our_pred->need_type = false;
726 (*arg_ptr)++;
727 return true;
730 static boolean
731 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
733 struct predicate *our_pred;
735 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
736 return false;
737 our_pred = insert_primary (entry);
738 our_pred->args.str = argv[*arg_ptr];
739 (*arg_ptr)++;
740 return true;
743 static boolean
744 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
746 return insert_num (argv, arg_ptr, entry);
749 static boolean
750 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
752 struct group *cur_gr;
753 struct predicate *our_pred;
754 gid_t gid;
755 int gid_len;
757 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
758 return false;
759 cur_gr = getgrnam (argv[*arg_ptr]);
760 endgrent ();
761 if (cur_gr != NULL)
762 gid = cur_gr->gr_gid;
763 else
765 gid_len = strspn (argv[*arg_ptr], "0123456789");
766 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
767 return false;
768 gid = atoi (argv[*arg_ptr]);
770 our_pred = insert_primary (entry);
771 our_pred->args.gid = gid;
772 (*arg_ptr)++;
773 return true;
776 static boolean
777 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
779 (void) entry;
780 (void) argv;
781 (void) arg_ptr;
783 printf (_("\
784 Usage: %s [path...] [expression]\n"), program_name);
785 puts (_("\n\
786 default path is the current directory; default expression is -print\n\
787 expression may consist of: operators, options, tests, and actions:\n"));
788 puts (_("\
789 operators (decreasing precedence; -and is implicit where no others are given):\n\
790 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
791 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
792 puts (_("\
793 positional options (always true): -daystart -follow -regextype\n\n\
794 normal options (always true, specified before other expressions):\n\
795 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
796 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
797 puts (_("\
798 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
799 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
800 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
801 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
802 puts (_("\
803 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
804 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
805 -used N -user NAME -xtype [bcdpfls]\n"));
806 puts (_("\
807 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
808 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
809 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
810 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
811 "));
812 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
813 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
814 email to <bug-findutils@gnu.org>."));
815 exit (0);
818 static boolean
819 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
821 struct predicate *our_pred;
823 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
824 return false;
825 our_pred = insert_primary (entry);
826 our_pred->args.str = argv[*arg_ptr];
827 (*arg_ptr)++;
828 return true;
832 /* sanity check the fnmatch() function to make sure
833 * it really is the GNU version.
835 static boolean
836 fnmatch_sanitycheck(void)
838 /* fprintf(stderr, "Performing find sanity check..."); */
839 if (0 != fnmatch("foo", "foo", 0)
840 || 0 == fnmatch("Foo", "foo", 0)
841 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
843 error (1, 0, _("sanity check of the fnmatch() library function failed."));
844 /* fprintf(stderr, "FAILED\n"); */
845 return false;
848 /* fprintf(stderr, "OK\n"); */
849 return true;
853 static boolean
854 check_name_arg(const char *pred, const char *arg)
856 if (strchr(arg, '/'))
858 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'."),
859 pred, arg, arg);
861 return true; /* allow it anyway */
866 static boolean
867 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
869 struct predicate *our_pred;
871 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
872 return false;
873 if (!check_name_arg("-iname", argv[*arg_ptr]))
874 return false;
876 fnmatch_sanitycheck();
878 our_pred = insert_primary (entry);
879 our_pred->need_stat = our_pred->need_type = false;
880 our_pred->args.str = argv[*arg_ptr];
881 (*arg_ptr)++;
882 return true;
885 static boolean
886 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
888 return insert_num (argv, arg_ptr, entry);
891 /* -ipath is deprecated (at RMS's request) in favour of
892 * -iwholename. See the node "GNU Manuals" in standards.texi
893 * for the rationale for this (basically, GNU prefers the use
894 * of the phrase "file name" to "path name"
896 static boolean
897 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
899 error (0, 0,
900 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
902 return parse_iwholename(entry, argv, arg_ptr);
905 static boolean
906 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
908 struct predicate *our_pred;
910 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
911 return false;
913 fnmatch_sanitycheck();
915 our_pred = insert_primary_withpred (entry, pred_ipath);
916 our_pred->need_stat = our_pred->need_type = false;
917 our_pred->args.str = argv[*arg_ptr];
918 (*arg_ptr)++;
919 return true;
922 static boolean
923 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
925 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
928 static boolean
929 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
931 return insert_num (argv, arg_ptr, entry);
934 static boolean
935 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
937 struct predicate *our_pred;
939 (void) argv;
940 (void) arg_ptr;
942 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
943 return false;
945 fnmatch_sanitycheck();
947 our_pred = insert_primary (entry);
948 our_pred->args.str = argv[*arg_ptr];
949 (*arg_ptr)++;
950 return true;
953 static boolean
954 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
956 struct predicate *our_pred;
958 (void) &argv;
959 (void) &arg_ptr;
961 our_pred = insert_primary (entry);
962 our_pred->side_effects = our_pred->no_default_print = true;
963 return true;
966 static boolean
967 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
969 int depth_len;
970 (void) entry;
972 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
973 return false;
974 depth_len = strspn (argv[*arg_ptr], "0123456789");
975 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
976 return false;
977 options.maxdepth = atoi (argv[*arg_ptr]);
978 if (options.maxdepth < 0)
979 return false;
980 (*arg_ptr)++;
981 return true;
984 static boolean
985 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
987 int depth_len;
988 (void) entry;
990 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
991 return false;
992 depth_len = strspn (argv[*arg_ptr], "0123456789");
993 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
994 return false;
995 options.mindepth = atoi (argv[*arg_ptr]);
996 if (options.mindepth < 0)
997 return false;
998 (*arg_ptr)++;
999 return true;
1002 static boolean
1003 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1005 struct predicate *our_pred;
1006 uintmax_t num;
1007 enum comparison_type c_type;
1008 time_t t;
1010 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1011 return false;
1012 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
1013 return false;
1014 t = options.cur_day_start + DAYSECS - num * 60;
1015 our_pred = insert_primary (entry);
1016 our_pred->args.info.kind = c_type;
1017 our_pred->args.info.negative = t < 0;
1018 our_pred->args.info.l_val = t;
1019 (*arg_ptr)++;
1020 return true;
1023 static boolean
1024 parse_mtime (const struct parser_table* entry, char **argv, int *arg_ptr)
1026 return insert_time (argv, arg_ptr, entry, pred_mtime);
1029 static boolean
1030 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1032 struct predicate *our_pred;
1034 (void) argv;
1035 (void) arg_ptr;
1037 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1038 return false;
1039 if (!check_name_arg("-name", argv[*arg_ptr]))
1040 return false;
1041 fnmatch_sanitycheck();
1043 our_pred = insert_primary (entry);
1044 our_pred->need_stat = our_pred->need_type = false;
1045 our_pred->args.str = argv[*arg_ptr];
1046 (*arg_ptr)++;
1047 return true;
1050 static boolean
1051 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1053 struct predicate *our_pred;
1055 (void) &argv;
1056 (void) &arg_ptr;
1058 our_pred = get_new_pred_chk_op (entry);
1059 our_pred->pred_func = pred_negate;
1060 #ifdef DEBUG
1061 our_pred->p_name = find_pred_name (pred_negate);
1062 #endif /* DEBUG */
1063 our_pred->p_type = UNI_OP;
1064 our_pred->p_prec = NEGATE_PREC;
1065 our_pred->need_stat = our_pred->need_type = false;
1066 return true;
1069 static boolean
1070 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1072 struct predicate *our_pred;
1073 struct stat stat_newer;
1075 (void) argv;
1076 (void) arg_ptr;
1078 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1079 return false;
1080 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1081 error (1, errno, "%s", argv[*arg_ptr]);
1082 our_pred = insert_primary (entry);
1083 our_pred->args.time = stat_newer.st_mtime;
1084 (*arg_ptr)++;
1085 return true;
1088 static boolean
1089 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1091 (void) &argv;
1092 (void) &arg_ptr;
1093 (void) entry;
1095 options.no_leaf_check = true;
1096 return true;
1099 #ifdef CACHE_IDS
1100 /* Arbitrary amount by which to increase size
1101 of `uid_unused' and `gid_unused'. */
1102 #define ALLOC_STEP 2048
1104 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1105 char *uid_unused = NULL;
1107 /* Number of elements in `uid_unused'. */
1108 unsigned uid_allocated;
1110 /* Similar for GIDs and group entries. */
1111 char *gid_unused = NULL;
1112 unsigned gid_allocated;
1113 #endif
1115 static boolean
1116 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1118 struct predicate *our_pred;
1120 (void) &argv;
1121 (void) &arg_ptr;
1123 our_pred = insert_primary (entry);
1124 #ifdef CACHE_IDS
1125 if (gid_unused == NULL)
1127 struct group *gr;
1129 gid_allocated = ALLOC_STEP;
1130 gid_unused = xmalloc (gid_allocated);
1131 memset (gid_unused, 1, gid_allocated);
1132 setgrent ();
1133 while ((gr = getgrent ()) != NULL)
1135 if ((unsigned) gr->gr_gid >= gid_allocated)
1137 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1138 gid_unused = xrealloc (gid_unused, new_allocated);
1139 memset (gid_unused + gid_allocated, 1,
1140 new_allocated - gid_allocated);
1141 gid_allocated = new_allocated;
1143 gid_unused[(unsigned) gr->gr_gid] = 0;
1145 endgrent ();
1147 #endif
1148 return true;
1151 static boolean
1152 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1154 struct predicate *our_pred;
1155 (void) argv;
1156 (void) arg_ptr;
1159 our_pred = insert_primary (entry);
1160 #ifdef CACHE_IDS
1161 if (uid_unused == NULL)
1163 struct passwd *pw;
1165 uid_allocated = ALLOC_STEP;
1166 uid_unused = xmalloc (uid_allocated);
1167 memset (uid_unused, 1, uid_allocated);
1168 setpwent ();
1169 while ((pw = getpwent ()) != NULL)
1171 if ((unsigned) pw->pw_uid >= uid_allocated)
1173 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1174 uid_unused = xrealloc (uid_unused, new_allocated);
1175 memset (uid_unused + uid_allocated, 1,
1176 new_allocated - uid_allocated);
1177 uid_allocated = new_allocated;
1179 uid_unused[(unsigned) pw->pw_uid] = 0;
1181 endpwent ();
1183 #endif
1184 return true;
1187 static boolean
1188 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1190 (void) argv;
1191 (void) arg_ptr;
1192 (void) entry;
1194 options.warnings = false;
1195 return true;;
1198 static boolean
1199 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1201 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1204 static boolean
1205 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1207 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1210 boolean
1211 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1213 struct predicate *our_pred;
1215 (void) argv;
1216 (void) arg_ptr;
1218 our_pred = get_new_pred_chk_op (entry);
1219 our_pred->pred_func = pred_open;
1220 #ifdef DEBUG
1221 our_pred->p_name = find_pred_name (pred_open);
1222 #endif /* DEBUG */
1223 our_pred->p_type = OPEN_PAREN;
1224 our_pred->p_prec = NO_PREC;
1225 our_pred->need_stat = our_pred->need_type = false;
1226 return true;
1229 static boolean
1230 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1232 struct predicate *our_pred;
1234 (void) argv;
1235 (void) arg_ptr;
1237 our_pred = get_new_pred (entry);
1238 our_pred->pred_func = pred_or;
1239 #ifdef DEBUG
1240 our_pred->p_name = find_pred_name (pred_or);
1241 #endif /* DEBUG */
1242 our_pred->p_type = BI_OP;
1243 our_pred->p_prec = OR_PREC;
1244 our_pred->need_stat = our_pred->need_type = false;
1245 return true;
1248 /* -path is deprecated (at RMS's request) in favour of
1249 * -iwholename. See the node "GNU Manuals" in standards.texi
1250 * for the rationale for this (basically, GNU prefers the use
1251 * of the phrase "file name" to "path name".
1253 * We do not issue a warning that this usage is deprecated
1254 * since HPUX find supports this predicate also.
1256 static boolean
1257 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1259 return parse_wholename(entry, argv, arg_ptr);
1262 static boolean
1263 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1265 struct predicate *our_pred;
1267 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1268 return false;
1269 our_pred = insert_primary_withpred (entry, pred_path);
1270 our_pred->need_stat = our_pred->need_type = false;
1271 our_pred->args.str = argv[*arg_ptr];
1272 (*arg_ptr)++;
1273 return true;
1276 static boolean
1277 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1279 mode_t perm_val;
1280 int mode_start = 0;
1281 boolean havekind = false;
1282 enum permissions_type kind = PERM_EXACT;
1283 struct mode_change *change = NULL;
1284 struct predicate *our_pred;
1286 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1287 return false;
1289 switch (argv[*arg_ptr][0])
1291 case '-':
1292 mode_start = 1;
1293 kind = PERM_AT_LEAST;
1294 havekind = true;
1295 break;
1297 case '+':
1298 change = mode_compile (argv[*arg_ptr]);
1299 if (NULL == change)
1301 /* Most likely the caller is an old script that is still
1302 * using the obsolete GNU syntax '-perm +MODE'. This old
1303 * syntax was withdrawn in favor of '-perm /MODE' because
1304 * it is incompatible with POSIX in some cases, but we
1305 * still support uses of it that are not incompatible with
1306 * POSIX.
1308 mode_start = 1;
1309 kind = PERM_ANY;
1311 else
1313 /* This is a POSIX-compatible usage */
1314 mode_start = 0;
1315 kind = PERM_EXACT;
1317 havekind = true;
1318 break;
1320 case '/': /* GNU extension */
1321 mode_start = 1;
1322 kind = PERM_ANY;
1323 havekind = true;
1324 break;
1326 default:
1327 /* For example, '-perm 0644', which is valid and matches
1328 * only files whose mode is exactly 0644.
1330 * We do nothing here, because mode_start and kind are already
1331 * correctly set.
1333 break;
1336 if (NULL == change)
1338 change = mode_compile (argv[*arg_ptr] + mode_start);
1339 if (NULL == change)
1340 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1342 perm_val = mode_adjust (0, change, 0);
1343 free (change);
1345 our_pred = insert_primary (entry);
1347 if (havekind)
1349 our_pred->args.perm.kind = kind;
1351 else
1354 switch (argv[*arg_ptr][0])
1356 case '-':
1357 our_pred->args.perm.kind = PERM_AT_LEAST;
1358 break;
1359 case '+':
1360 our_pred->args.perm.kind = PERM_ANY;
1361 break;
1362 default:
1363 our_pred->args.perm.kind = PERM_EXACT;
1364 break;
1367 our_pred->args.perm.val = perm_val & MODE_ALL;
1368 (*arg_ptr)++;
1369 return true;
1372 boolean
1373 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1375 struct predicate *our_pred;
1377 (void) argv;
1378 (void) arg_ptr;
1380 our_pred = insert_primary (entry);
1381 /* -print has the side effect of printing. This prevents us
1382 from doing undesired multiple printing when the user has
1383 already specified -print. */
1384 our_pred->side_effects = our_pred->no_default_print = true;
1385 our_pred->need_stat = our_pred->need_type = false;
1386 our_pred->args.printf_vec.segment = NULL;
1387 our_pred->args.printf_vec.stream = stdout;
1388 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1389 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1391 return true;
1394 static boolean
1395 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1397 struct predicate *our_pred;
1399 (void) argv;
1400 (void) arg_ptr;
1402 our_pred = insert_primary (entry);
1403 /* -print0 has the side effect of printing. This prevents us
1404 from doing undesired multiple printing when the user has
1405 already specified -print0. */
1406 our_pred->side_effects = our_pred->no_default_print = true;
1407 our_pred->need_stat = our_pred->need_type = false;
1408 return true;
1411 static boolean
1412 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1414 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1415 return false;
1416 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1419 static boolean
1420 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1422 struct predicate *our_pred;
1424 (void) argv;
1425 (void) arg_ptr;
1427 our_pred = insert_primary (entry);
1428 our_pred->need_stat = our_pred->need_type = false;
1429 /* -prune has a side effect that it does not descend into
1430 the current directory. */
1431 our_pred->side_effects = true;
1432 our_pred->no_default_print = false;
1433 return true;
1436 static boolean
1437 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1439 struct predicate *our_pred = insert_primary (entry);
1440 (void) argv;
1441 (void) arg_ptr;
1442 our_pred->need_stat = our_pred->need_type = false;
1443 our_pred->side_effects = true; /* Exiting is a side effect... */
1444 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1445 return true;
1449 static boolean
1450 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1452 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1453 return false;
1455 /* collect the regex type name */
1456 options.regex_options = get_regex_type(argv[*arg_ptr]);
1457 (*arg_ptr)++;
1459 return true;
1463 static boolean
1464 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1466 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1469 static boolean
1470 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1472 struct predicate *our_pred;
1473 struct re_pattern_buffer *re;
1474 const char *error_message;
1476 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1477 return false;
1478 our_pred = insert_primary_withpred (entry, pred_regex);
1479 our_pred->need_stat = our_pred->need_type = false;
1480 re = (struct re_pattern_buffer *)
1481 xmalloc (sizeof (struct re_pattern_buffer));
1482 our_pred->args.regex = re;
1483 re->allocated = 100;
1484 re->buffer = (unsigned char *) xmalloc (re->allocated);
1485 re->fastmap = NULL;
1487 re_set_syntax(regex_options);
1488 re->syntax = regex_options;
1489 re->translate = NULL;
1491 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1492 re);
1493 if (error_message)
1494 error (1, 0, "%s", error_message);
1495 (*arg_ptr)++;
1496 return true;
1499 static boolean
1500 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1502 struct predicate *our_pred;
1503 uintmax_t num;
1504 enum comparison_type c_type;
1505 int blksize = 512;
1506 int len;
1508 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1509 return false;
1510 len = strlen (argv[*arg_ptr]);
1511 if (len == 0)
1512 error (1, 0, _("invalid null argument to -size"));
1513 switch (argv[*arg_ptr][len - 1])
1515 case 'b':
1516 blksize = 512;
1517 argv[*arg_ptr][len - 1] = '\0';
1518 break;
1520 case 'c':
1521 blksize = 1;
1522 argv[*arg_ptr][len - 1] = '\0';
1523 break;
1525 case 'k':
1526 blksize = 1024;
1527 argv[*arg_ptr][len - 1] = '\0';
1528 break;
1530 case 'M': /* Megabytes */
1531 blksize = 1024*1024;
1532 argv[*arg_ptr][len - 1] = '\0';
1533 break;
1535 case 'G': /* Gigabytes */
1536 blksize = 1024*1024*1024;
1537 argv[*arg_ptr][len - 1] = '\0';
1538 break;
1540 case 'w':
1541 blksize = 2;
1542 argv[*arg_ptr][len - 1] = '\0';
1543 break;
1545 case '0':
1546 case '1':
1547 case '2':
1548 case '3':
1549 case '4':
1550 case '5':
1551 case '6':
1552 case '7':
1553 case '8':
1554 case '9':
1555 break;
1557 default:
1558 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1560 if (!get_num (argv[*arg_ptr], &num, &c_type))
1561 return false;
1562 our_pred = insert_primary (entry);
1563 our_pred->args.size.kind = c_type;
1564 our_pred->args.size.blocksize = blksize;
1565 our_pred->args.size.size = num;
1566 (*arg_ptr)++;
1567 return true;
1571 static boolean
1572 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1574 struct predicate *our_pred;
1575 struct stat st;
1577 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1578 return false;
1579 if ((*options.xstat) (argv[*arg_ptr], &st))
1580 error (1, errno, "%s", argv[*arg_ptr]);
1582 our_pred = insert_primary (entry);
1583 our_pred->args.fileid.ino = st.st_ino;
1584 our_pred->args.fileid.dev = st.st_dev;
1585 our_pred->need_type = false;
1586 our_pred->need_stat = true;
1587 (*arg_ptr)++;
1588 return true;
1592 static boolean
1593 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1595 struct predicate *our_pred;
1597 (void) argv;
1598 (void) arg_ptr;
1600 our_pred = insert_primary (entry);
1601 our_pred->need_stat = our_pred->need_type = false;
1602 return true;
1605 static boolean
1606 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1608 return insert_type (argv, arg_ptr, entry, pred_type);
1611 static boolean
1612 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1614 return insert_num (argv, arg_ptr, entry);
1617 static boolean
1618 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1620 struct predicate *our_pred;
1621 uintmax_t num_days;
1622 enum comparison_type c_type;
1623 time_t t;
1625 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1626 return false;
1627 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1628 return false;
1629 t = num_days * DAYSECS;
1630 our_pred = insert_primary (entry);
1631 our_pred->args.info.kind = c_type;
1632 our_pred->args.info.negative = t < 0;
1633 our_pred->args.info.l_val = t;
1634 (*arg_ptr)++;
1635 return true;
1638 static boolean
1639 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1641 struct passwd *cur_pwd;
1642 struct predicate *our_pred;
1643 uid_t uid;
1644 int uid_len;
1646 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1647 return false;
1648 cur_pwd = getpwnam (argv[*arg_ptr]);
1649 endpwent ();
1650 if (cur_pwd != NULL)
1651 uid = cur_pwd->pw_uid;
1652 else
1654 uid_len = strspn (argv[*arg_ptr], "0123456789");
1655 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1656 return false;
1657 uid = atoi (argv[*arg_ptr]);
1659 our_pred = insert_primary (entry);
1660 our_pred->args.uid = uid;
1661 (*arg_ptr)++;
1662 return true;
1665 static boolean
1666 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1668 extern char *version_string;
1669 int features = 0;
1671 (void) argv;
1672 (void) arg_ptr;
1673 (void) entry;
1675 fflush (stderr);
1676 printf (_("GNU find version %s\n"), version_string);
1677 printf (_("Features enabled: "));
1679 #if CACHE_IDS
1680 printf("CACHE_IDS ");
1681 ++features;
1682 #endif
1683 #if DEBUG
1684 printf("DEBUG ");
1685 ++features;
1686 #endif
1687 #if DEBUG_STAT
1688 printf("DEBUG_STAT ");
1689 ++features;
1690 #endif
1691 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1692 printf("D_TYPE ");
1693 ++features;
1694 #endif
1695 #if defined(O_NOFOLLOW)
1696 printf("O_NOFOLLOW(%s) ",
1697 (options.open_nofollow_available ? "enabled" : "disabled"));
1698 ++features;
1699 #endif
1700 #if defined(LEAF_OPTIMISATION)
1701 printf("LEAF_OPTIMISATION ");
1702 ++features;
1703 #endif
1704 if (0 == features)
1706 /* For the moment, leave this as English in case someone wants
1707 to parse these strings. */
1708 printf("none");
1710 printf("\n");
1712 exit (0);
1715 static boolean
1716 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1718 (void) argv;
1719 (void) arg_ptr;
1720 (void) entry;
1721 options.stay_on_filesystem = true;
1722 return true;
1725 static boolean
1726 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1728 (void) argv;
1729 (void) arg_ptr;
1730 (void) entry;
1731 options.ignore_readdir_race = true;
1732 return true;
1735 static boolean
1736 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1738 (void) argv;
1739 (void) arg_ptr;
1740 (void) entry;
1741 options.ignore_readdir_race = false;
1742 return true;
1745 static boolean
1746 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1748 (void) argv;
1749 (void) arg_ptr;
1750 (void) entry;
1751 options.warnings = true;
1752 return true;
1755 static boolean
1756 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1758 (void) argv;
1759 (void) arg_ptr;
1760 return insert_type (argv, arg_ptr, entry, pred_xtype);
1763 static boolean
1764 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
1766 mode_t type_cell;
1767 struct predicate *our_pred;
1769 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1770 || (strlen (argv[*arg_ptr]) != 1))
1771 return false;
1772 switch (argv[*arg_ptr][0])
1774 case 'b': /* block special */
1775 type_cell = S_IFBLK;
1776 break;
1777 case 'c': /* character special */
1778 type_cell = S_IFCHR;
1779 break;
1780 case 'd': /* directory */
1781 type_cell = S_IFDIR;
1782 break;
1783 case 'f': /* regular file */
1784 type_cell = S_IFREG;
1785 break;
1786 #ifdef S_IFLNK
1787 case 'l': /* symbolic link */
1788 type_cell = S_IFLNK;
1789 break;
1790 #endif
1791 #ifdef S_IFIFO
1792 case 'p': /* pipe */
1793 type_cell = S_IFIFO;
1794 break;
1795 #endif
1796 #ifdef S_IFSOCK
1797 case 's': /* socket */
1798 type_cell = S_IFSOCK;
1799 break;
1800 #endif
1801 #ifdef S_IFDOOR
1802 case 'D': /* Solaris door */
1803 type_cell = S_IFDOOR;
1804 break;
1805 #endif
1806 default: /* None of the above ... nuke 'em. */
1807 return false;
1809 our_pred = insert_primary_withpred (entry, which_pred);
1811 /* Figure out if we will need to stat the file, because if we don't
1812 * need to follow symlinks, we can avoid a stat call by using
1813 * struct dirent.d_type.
1815 if (which_pred == pred_xtype)
1817 our_pred->need_stat = true;
1818 our_pred->need_type = false;
1820 else
1822 our_pred->need_stat = false; /* struct dirent is enough */
1823 our_pred->need_type = true;
1825 our_pred->args.type = type_cell;
1826 (*arg_ptr)++; /* Move on to next argument. */
1827 return true;
1831 /* Return true if the file accessed via FP is a terminal.
1833 static boolean
1834 stream_is_tty(FILE *fp)
1836 int fd = fileno(fp);
1837 if (-1 == fd)
1839 return false; /* not a valid stream */
1841 else
1843 return isatty(fd) ? true : false;
1850 /* If true, we've determined that the current fprintf predicate
1851 uses stat information. */
1852 static boolean fprintf_stat_needed;
1854 /* XXX: do we need to pass FUNC to this function? */
1855 static boolean
1856 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
1858 char *format; /* Beginning of unprocessed format string. */
1859 register char *scan; /* Current address in scanning `format'. */
1860 register char *scan2; /* Address inside of element being scanned. */
1861 struct segment **segmentp; /* Address of current segment. */
1862 struct predicate *our_pred;
1864 format = argv[(*arg_ptr)++];
1866 fprintf_stat_needed = false; /* Might be overridden later. */
1867 our_pred = insert_primary_withpred (entry, func);
1868 our_pred->side_effects = our_pred->no_default_print = true;
1869 our_pred->args.printf_vec.stream = fp;
1870 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
1871 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1872 segmentp = &our_pred->args.printf_vec.segment;
1873 *segmentp = NULL;
1875 for (scan = format; *scan; scan++)
1877 if (*scan == '\\')
1879 scan2 = scan + 1;
1880 if (*scan2 >= '0' && *scan2 <= '7')
1882 register int n, i;
1884 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1885 i++, scan2++)
1886 n = 8 * n + *scan2 - '0';
1887 scan2--;
1888 *scan = n;
1890 else
1892 switch (*scan2)
1894 case 'a':
1895 *scan = 7;
1896 break;
1897 case 'b':
1898 *scan = '\b';
1899 break;
1900 case 'c':
1901 make_segment (segmentp, format, scan - format, KIND_STOP);
1902 our_pred->need_stat = fprintf_stat_needed;
1903 return true;
1904 case 'f':
1905 *scan = '\f';
1906 break;
1907 case 'n':
1908 *scan = '\n';
1909 break;
1910 case 'r':
1911 *scan = '\r';
1912 break;
1913 case 't':
1914 *scan = '\t';
1915 break;
1916 case 'v':
1917 *scan = '\v';
1918 break;
1919 case '\\':
1920 /* *scan = '\\'; * it already is */
1921 break;
1922 default:
1923 error (0, 0,
1924 _("warning: unrecognized escape `\\%c'"), *scan2);
1925 scan++;
1926 continue;
1929 segmentp = make_segment (segmentp, format, scan - format + 1,
1930 KIND_PLAIN);
1931 format = scan2 + 1; /* Move past the escape. */
1932 scan = scan2; /* Incremented immediately by `for'. */
1934 else if (*scan == '%')
1936 if (scan[1] == '%')
1938 segmentp = make_segment (segmentp, format, scan - format + 1,
1939 KIND_PLAIN);
1940 scan++;
1941 format = scan + 1;
1942 continue;
1944 /* Scan past flags, width and precision, to verify kind. */
1945 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1946 /* Do nothing. */ ;
1947 while (ISDIGIT (*scan2))
1948 scan2++;
1949 if (*scan2 == '.')
1950 for (scan2++; ISDIGIT (*scan2); scan2++)
1951 /* Do nothing. */ ;
1952 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1954 segmentp = make_segment (segmentp, format, scan2 - format,
1955 (int) *scan2);
1956 scan = scan2;
1957 format = scan + 1;
1959 else if (strchr ("ACT", *scan2) && scan2[1])
1961 segmentp = make_segment (segmentp, format, scan2 - format,
1962 *scan2 | (scan2[1] << 8));
1963 scan = scan2 + 1;
1964 format = scan + 1;
1965 continue;
1967 else
1969 /* An unrecognized % escape. Print the char after the %. */
1970 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1971 *scan2);
1972 segmentp = make_segment (segmentp, format, scan - format,
1973 KIND_PLAIN);
1974 format = scan + 1;
1975 continue;
1980 if (scan > format)
1981 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1982 our_pred->need_type = false;
1983 our_pred->need_stat = fprintf_stat_needed;
1984 return true;
1987 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1988 from the text in FORMAT, which has length LEN.
1989 Return the address of the `next' pointer of the new segment. */
1991 static struct segment **
1992 make_segment (struct segment **segment, char *format, int len, int kind)
1994 char *fmt;
1996 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1998 (*segment)->kind = kind;
1999 (*segment)->next = NULL;
2000 (*segment)->text_len = len;
2002 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2003 strncpy (fmt, format, len);
2004 fmt += len;
2006 switch (kind & 0xff)
2008 case KIND_PLAIN: /* Plain text string, no % conversion. */
2009 case KIND_STOP: /* Terminate argument, no newline. */
2010 break;
2012 case 'a': /* atime in `ctime' format */
2013 case 'A': /* atime in user-specified strftime format */
2014 case 'c': /* ctime in `ctime' format */
2015 case 'C': /* ctime in user-specified strftime format */
2016 case 'F': /* filesystem type */
2017 case 'g': /* group name */
2018 case 'i': /* inode number */
2019 case 'l': /* object of symlink */
2020 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2021 case 's': /* size in bytes */
2022 case 't': /* mtime in `ctime' format */
2023 case 'T': /* mtime in user-specified strftime format */
2024 case 'u': /* user name */
2025 case 'y': /* file type */
2026 case 'Y': /* symlink pointed file type */
2027 fprintf_stat_needed = true;
2028 /* FALLTHROUGH */
2029 case 'f': /* basename of path */
2030 case 'h': /* leading directories part of path */
2031 case 'H': /* ARGV element file was found under */
2032 case 'p': /* pathname */
2033 case 'P': /* pathname with ARGV element stripped */
2034 *fmt++ = 's';
2035 break;
2037 /* Numeric items that one might expect to honour
2038 * #, 0, + flags but which do not.
2040 case 'G': /* GID number */
2041 case 'U': /* UID number */
2042 case 'b': /* size in 512-byte blocks */
2043 case 'D': /* Filesystem device on which the file exits */
2044 case 'k': /* size in 1K blocks */
2045 case 'n': /* number of links */
2046 fprintf_stat_needed = true;
2047 *fmt++ = 's';
2048 break;
2050 /* Numeric items that DO honour #, 0, + flags.
2052 case 'd': /* depth in search tree (0 = ARGV element) */
2053 *fmt++ = 'd';
2054 break;
2056 case 'm': /* mode as octal number (perms only) */
2057 *fmt++ = 'o';
2058 fprintf_stat_needed = true;
2059 break;
2061 *fmt = '\0';
2063 return &(*segment)->next;
2066 static void
2067 check_path_safety(const char *action)
2069 const char *path = getenv("PATH");
2070 char *s;
2071 s = next_element(path, 1);
2072 while ((s = next_element ((char *) NULL, 1)) != NULL)
2074 if (0 == strcmp(s, "."))
2076 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)"),
2077 action);
2083 /* handles both exec and ok predicate */
2084 #if defined(NEW_EXEC)
2085 /* handles both exec and ok predicate */
2086 static boolean
2087 new_insert_exec_ok (const char *action,
2088 const struct parser_table *entry,
2089 char **argv,
2090 int *arg_ptr)
2092 int start, end; /* Indexes in ARGV of start & end of cmd. */
2093 int i; /* Index into cmd args */
2094 int saw_braces; /* True if previous arg was '{}'. */
2095 boolean allow_plus; /* True if + is a valid terminator */
2096 int brace_count; /* Number of instances of {}. */
2097 PRED_FUNC func = entry->pred_func;
2099 struct predicate *our_pred;
2100 struct exec_val *execp; /* Pointer for efficiency. */
2102 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2103 return false;
2105 our_pred = insert_primary_withpred (entry, func);
2106 our_pred->side_effects = our_pred->no_default_print = true;
2107 execp = &our_pred->args.exec_vec;
2109 if ((func != pred_okdir) && (func != pred_ok))
2111 allow_plus = true;
2112 execp->close_stdin = false;
2114 else
2116 allow_plus = false;
2117 /* If find reads stdin (i.e. for -ok and similar), close stdin
2118 * in the child to prevent some script from consiming the output
2119 * intended for find.
2121 execp->close_stdin = true;
2125 if ((func == pred_execdir) || (func == pred_okdir))
2127 options.ignore_readdir_race = false;
2128 check_path_safety(action);
2129 execp->use_current_dir = true;
2131 else
2133 execp->use_current_dir = false;
2136 our_pred->args.exec_vec.multiple = 0;
2138 /* Count the number of args with path replacements, up until the ';'.
2139 * Also figure out if the command is terminated by ";" or by "+".
2141 start = *arg_ptr;
2142 for (end = start, saw_braces=0, brace_count=0;
2143 (argv[end] != NULL)
2144 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2145 end++)
2147 /* For -exec and -execdir, "{} +" can terminate the command. */
2148 if ( allow_plus
2149 && argv[end][0] == '+' && argv[end][1] == 0
2150 && saw_braces)
2152 our_pred->args.exec_vec.multiple = 1;
2153 break;
2156 saw_braces = 0;
2157 if (strstr (argv[end], "{}"))
2159 saw_braces = 1;
2160 ++brace_count;
2162 if (0 == end && (func == pred_execdir || func == pred_okdir))
2164 /* The POSIX standard says that {} replacement should
2165 * occur even in the utility name. This is insecure
2166 * since it means we will be executing a command whose
2167 * name is chosen according to whatever find finds in
2168 * the filesystem. That can be influenced by an
2169 * attacker. Hence for -execdir and -okdir this is not
2170 * allowed. We can specify this as those options are
2171 * not defined by POSIX.
2173 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2178 /* Fail if no command given or no semicolon found. */
2179 if ((end == start) || (argv[end] == NULL))
2181 *arg_ptr = end;
2182 free(our_pred);
2183 return false;
2186 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2189 const char *suffix;
2190 if (func == pred_execdir)
2191 suffix = "dir";
2192 else
2193 suffix = "";
2195 error(1, 0,
2196 _("Only one instance of {} is supported with -exec%s ... +"),
2197 suffix);
2200 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2201 bc_init_controlinfo(&execp->ctl);
2202 execp->ctl.exec_callback = launch;
2204 if (our_pred->args.exec_vec.multiple)
2206 /* "+" terminator, so we can just append our arguments after the
2207 * command and initial arguments.
2209 execp->replace_vec = NULL;
2210 execp->ctl.replace_pat = NULL;
2211 execp->ctl.rplen = 0;
2212 execp->ctl.lines_per_exec = 0; /* no limit */
2213 execp->ctl.args_per_exec = 0; /* no limit */
2215 /* remember how many arguments there are */
2216 execp->ctl.initial_argc = (end-start) - 1;
2218 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2219 bc_init_state(&execp->ctl, &execp->state, execp);
2221 /* Gather the initial arguments. Skip the {}. */
2222 for (i=start; i<end-1; ++i)
2224 bc_push_arg(&execp->ctl, &execp->state,
2225 argv[i], strlen(argv[i])+1,
2226 NULL, 0,
2230 else
2232 /* Semicolon terminator - more than one {} is supported, so we
2233 * have to do brace-replacement.
2235 execp->num_args = end - start;
2237 execp->ctl.replace_pat = "{}";
2238 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2239 execp->ctl.lines_per_exec = 0; /* no limit */
2240 execp->ctl.args_per_exec = 0; /* no limit */
2241 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2244 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2245 bc_init_state(&execp->ctl, &execp->state, execp);
2247 /* Remember the (pre-replacement) arguments for later. */
2248 for (i=0; i<execp->num_args; ++i)
2250 execp->replace_vec[i] = argv[i+start];
2254 if (argv[end] == NULL)
2255 *arg_ptr = end;
2256 else
2257 *arg_ptr = end + 1;
2259 return true;
2261 #else
2262 /* handles both exec and ok predicate */
2263 static boolean
2264 old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
2266 int start, end; /* Indexes in ARGV of start & end of cmd. */
2267 int num_paths; /* Number of args with path replacements. */
2268 int path_pos; /* Index in array of path replacements. */
2269 int vec_pos; /* Index in array of args. */
2270 struct predicate *our_pred;
2271 struct exec_val *execp; /* Pointer for efficiency. */
2273 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2274 return false;
2276 /* Count the number of args with path replacements, up until the ';'. */
2277 start = *arg_ptr;
2278 for (end = start, num_paths = 0;
2279 (argv[end] != NULL)
2280 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2281 end++)
2282 if (strstr (argv[end], "{}"))
2283 num_paths++;
2284 /* Fail if no command given or no semicolon found. */
2285 if ((end == start) || (argv[end] == NULL))
2287 *arg_ptr = end;
2288 return false;
2291 our_pred = insert_primary (func);
2292 our_pred->side_effects = our_pred->no_default_print = true;
2293 execp = &our_pred->args.exec_vec;
2294 execp->usercontext = our_pred;
2295 execp->use_current_dir = false;
2296 execp->paths =
2297 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
2298 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
2299 /* Record the positions of all args, and the args with path replacements. */
2300 for (end = start, path_pos = vec_pos = 0;
2301 (argv[end] != NULL)
2302 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2303 end++)
2305 register char *p;
2307 execp->paths[path_pos].count = 0;
2308 for (p = argv[end]; *p; ++p)
2309 if (p[0] == '{' && p[1] == '}')
2311 execp->paths[path_pos].count++;
2312 ++p;
2314 if (execp->paths[path_pos].count)
2316 execp->paths[path_pos].offset = vec_pos;
2317 execp->paths[path_pos].origarg = argv[end];
2318 path_pos++;
2320 execp->vec[vec_pos++] = argv[end];
2322 execp->paths[path_pos].offset = -1;
2323 execp->vec[vec_pos] = NULL;
2325 if (argv[end] == NULL)
2326 *arg_ptr = end;
2327 else
2328 *arg_ptr = end + 1;
2329 return true;
2331 #endif
2335 static boolean
2336 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2338 #if defined(NEW_EXEC)
2339 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2340 #else
2341 return old_insert_exec_ok(func, argv, arg_ptr);
2342 #endif
2347 /* Get a number of days and comparison type.
2348 STR is the ASCII representation.
2349 Set *NUM_DAYS to the number of days, taken as being from
2350 the current moment (or possibly midnight). Thus the sense of the
2351 comparison type appears to be reversed.
2352 Set *COMP_TYPE to the kind of comparison that is requested.
2354 Return true if all okay, false if input error.
2356 Used by -atime, -ctime and -mtime (parsers) to
2357 get the appropriate information for a time predicate processor. */
2359 static boolean
2360 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2362 boolean r = get_num (str, num_days, comp_type);
2363 if (r)
2364 switch (*comp_type)
2366 case COMP_LT: *comp_type = COMP_GT; break;
2367 case COMP_GT: *comp_type = COMP_LT; break;
2368 default: break;
2370 return r;
2373 /* Insert a time predicate PRED.
2374 ARGV is a pointer to the argument array.
2375 ARG_PTR is a pointer to an index into the array, incremented if
2376 all went well.
2378 Return true if input is valid, false if not.
2380 A new predicate node is assigned, along with an argument node
2381 obtained with malloc.
2383 Used by -atime, -ctime, and -mtime parsers. */
2385 static boolean
2386 insert_time (char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred)
2388 struct predicate *our_pred;
2389 uintmax_t num_days;
2390 enum comparison_type c_type;
2391 time_t t;
2393 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2394 return false;
2395 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2396 return false;
2398 /* Figure out the timestamp value we are looking for. */
2399 t = ( options.cur_day_start - num_days * DAYSECS
2400 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2402 if (1)
2404 /* We introduce a scope in which 'val' can be declared, for the
2405 * benefit of compilers that are really C89 compilers
2406 * which support intmax_t because config.h #defines it
2408 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2409 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2410 t = val;
2412 /* Check for possibility of an overflow */
2413 if ( (intmax_t)t != val )
2415 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2419 our_pred = insert_primary_withpred (entry, pred);
2420 our_pred->args.info.kind = c_type;
2421 our_pred->args.info.negative = t < 0;
2422 our_pred->args.info.l_val = t;
2423 (*arg_ptr)++;
2424 #ifdef DEBUG
2425 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2426 fprintf (stderr, " type: %s %s ",
2427 (c_type == COMP_GT) ? "gt" :
2428 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2429 (c_type == COMP_GT) ? " >" :
2430 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2431 t = our_pred->args.info.l_val;
2432 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2433 if (c_type == COMP_EQ)
2435 t = our_pred->args.info.l_val += DAYSECS;
2436 fprintf (stderr, " < %ju %s",
2437 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2438 our_pred->args.info.l_val -= DAYSECS;
2440 #endif /* DEBUG */
2441 return true;
2444 /* Get a number with comparison information.
2445 The sense of the comparison information is 'normal'; that is,
2446 '+' looks for a count > than the number and '-' less than.
2448 STR is the ASCII representation of the number.
2449 Set *NUM to the number.
2450 Set *COMP_TYPE to the kind of comparison that is requested.
2452 Return true if all okay, false if input error. */
2454 static boolean
2455 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2457 if (str == NULL)
2458 return false;
2459 switch (str[0])
2461 case '+':
2462 *comp_type = COMP_GT;
2463 str++;
2464 break;
2465 case '-':
2466 *comp_type = COMP_LT;
2467 str++;
2468 break;
2469 default:
2470 *comp_type = COMP_EQ;
2471 break;
2474 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2477 /* Insert a number predicate.
2478 ARGV is a pointer to the argument array.
2479 *ARG_PTR is an index into ARGV, incremented if all went well.
2480 *PRED is the predicate processor to insert.
2482 Return true if input is valid, false if error.
2484 A new predicate node is assigned, along with an argument node
2485 obtained with malloc.
2487 Used by -inum and -links parsers. */
2489 static boolean
2490 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2492 struct predicate *our_pred;
2493 uintmax_t num;
2494 enum comparison_type c_type;
2496 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2497 return false;
2498 if (!get_num (argv[*arg_ptr], &num, &c_type))
2499 return false;
2500 our_pred = insert_primary (entry);
2501 our_pred->args.info.kind = c_type;
2502 our_pred->args.info.l_val = num;
2503 (*arg_ptr)++;
2504 #ifdef DEBUG
2505 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2506 fprintf (stderr, " type: %s %s ",
2507 (c_type == COMP_GT) ? "gt" :
2508 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2509 (c_type == COMP_GT) ? " >" :
2510 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2511 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2512 #endif /* DEBUG */
2513 return true;
2516 static FILE *
2517 open_output_file (char *path)
2519 FILE *f;
2521 if (!strcmp (path, "/dev/stderr"))
2522 return stderr;
2523 else if (!strcmp (path, "/dev/stdout"))
2524 return stdout;
2525 f = fopen_safer (path, "w");
2526 if (f == NULL)
2527 error (1, errno, "%s", path);
2528 return f;