Assume unistd.h is present - avoid using HAVE_UNISTD_H
[findutils.git] / find / parser.c
blobbc33587904bf8f82ef074411bfcfc5461c52ef16
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"
37 #ifdef HAVE_FCNTL_H
38 #include <fcntl.h>
39 #else
40 #include <sys/file.h>
41 #endif
43 /* The presence of unistd.h is assumed by gnulib these days, so we
44 * might as well assume it too.
46 /* We need <unistd.h> for isatty(). */
47 #include <unistd.h>
49 #if ENABLE_NLS
50 # include <libintl.h>
51 # define _(Text) gettext (Text)
52 #else
53 # define _(Text) Text
54 #endif
55 #ifdef gettext_noop
56 # define N_(String) gettext_noop (String)
57 #else
58 /* See locate.c for explanation as to why not use (String) */
59 # define N_(String) String
60 #endif
62 #if !defined (isascii) || defined (STDC_HEADERS)
63 #ifdef isascii
64 #undef isascii
65 #endif
66 #define isascii(c) 1
67 #endif
69 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
70 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
72 #ifndef HAVE_ENDGRENT
73 #define endgrent()
74 #endif
75 #ifndef HAVE_ENDPWENT
76 #define endpwent()
77 #endif
79 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
80 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
81 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
82 static boolean parse_atime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
83 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
84 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
85 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
86 static boolean parse_ctime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
87 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_mtime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 boolean parse_open PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
153 boolean parse_close PARAMS((const struct parser_table* entry, char *argv[], int *arg_ptr));
157 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
158 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
159 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
160 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
161 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
162 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
163 static boolean insert_time PARAMS((char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred));
164 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
165 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
166 static FILE *open_output_file PARAMS((char *path));
167 static boolean stream_is_tty(FILE *fp);
169 #ifdef DEBUG
170 char *find_pred_name PARAMS((PRED_FUNC pred_func));
171 #endif /* DEBUG */
174 #define PASTE(x,y) x##y
175 #define STRINGIFY(s) #s
177 #define PARSE_OPTION(what,suffix) \
178 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
180 #define PARSE_POSOPT(what,suffix) \
181 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
183 #define PARSE_TEST(what,suffix) \
184 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
186 #define PARSE_TEST_NP(what,suffix) \
187 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
189 #define PARSE_ACTION(what,suffix) \
190 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
192 #define PARSE_ACTION_NP(what,suffix) \
193 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
195 #define PARSE_PUNCTUATION(what,suffix) \
196 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
199 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
200 If they are in some Unix versions of find, they are marked `Unix'. */
202 static struct parser_table const parse_table[] =
204 PARSE_PUNCTUATION("!", negate),
205 PARSE_PUNCTUATION("not", negate), /* GNU */
206 PARSE_PUNCTUATION("(", open),
207 PARSE_PUNCTUATION(")", close),
208 PARSE_PUNCTUATION(",", comma), /* GNU */
209 PARSE_PUNCTUATION("a", and),
210 PARSE_TEST ("amin", amin), /* GNU */
211 PARSE_PUNCTUATION("and", and), /* GNU */
212 PARSE_TEST ("anewer", anewer), /* GNU */
213 PARSE_TEST ("atime", atime),
214 PARSE_TEST ("cmin", cmin), /* GNU */
215 PARSE_TEST ("cnewer", cnewer), /* GNU */
216 PARSE_TEST ("ctime", ctime),
217 PARSE_POSOPT ("daystart", daystart), /* GNU */
218 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
219 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
220 PARSE_OPTION ("depth", depth),
221 PARSE_TEST ("empty", empty), /* GNU */
222 PARSE_ACTION ("exec", exec),
223 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
224 PARSE_ACTION ("fls", fls), /* GNU */
225 PARSE_POSOPT ("follow", follow), /* GNU, Unix */
226 PARSE_ACTION ("fprint", fprint), /* GNU */
227 PARSE_ACTION ("fprint0", fprint0), /* GNU */
228 PARSE_ACTION ("fprintf", fprintf), /* GNU */
229 PARSE_TEST ("fstype", fstype), /* GNU, Unix */
230 PARSE_TEST ("gid", gid), /* GNU */
231 PARSE_TEST ("group", group),
232 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
233 PARSE_TEST ("ilname", ilname), /* GNU */
234 PARSE_TEST ("iname", iname), /* GNU */
235 PARSE_TEST ("inum", inum), /* GNU, Unix */
236 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
237 PARSE_TEST_NP ("iregex", iregex), /* GNU */
238 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
239 PARSE_TEST ("links", links),
240 PARSE_TEST ("lname", lname), /* GNU */
241 PARSE_ACTION ("ls", ls), /* GNU, Unix */
242 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
243 PARSE_OPTION ("mindepth", mindepth), /* GNU */
244 PARSE_TEST ("mmin", mmin), /* GNU */
245 PARSE_OPTION ("mount", xdev), /* Unix */
246 PARSE_TEST ("mtime", mtime),
247 PARSE_TEST ("name", name),
248 #ifdef UNIMPLEMENTED_UNIX
249 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
250 #endif
251 PARSE_TEST ("newer", newer),
252 PARSE_OPTION ("noleaf", noleaf), /* GNU */
253 PARSE_TEST ("nogroup", nogroup),
254 PARSE_TEST ("nouser", nouser),
255 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
256 PARSE_OPTION ("nowarn", nowarn), /* GNU */
257 PARSE_PUNCTUATION("o", or),
258 PARSE_PUNCTUATION("or", or), /* GNU */
259 PARSE_ACTION ("ok", ok),
260 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
261 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
262 PARSE_TEST ("perm", perm),
263 PARSE_ACTION ("print", print),
264 PARSE_ACTION ("print0", print0), /* GNU */
265 PARSE_ACTION_NP ("printf", printf), /* GNU */
266 PARSE_ACTION ("prune", prune),
267 PARSE_ACTION ("quit", quit), /* GNU */
268 PARSE_TEST ("regex", regex), /* GNU */
269 PARSE_TEST ("samefile", samefile), /* GNU */
270 PARSE_TEST ("size", size),
271 PARSE_TEST ("type", type),
272 PARSE_TEST ("uid", uid), /* GNU */
273 PARSE_TEST ("used", used), /* GNU */
274 PARSE_TEST ("user", user),
275 PARSE_OPTION ("warn", warn), /* GNU */
276 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
277 PARSE_OPTION ("xdev", xdev),
278 PARSE_TEST ("xtype", xtype), /* GNU */
279 #ifdef UNIMPLEMENTED_UNIX
280 /* It's pretty ugly for find to know about archive formats.
281 Plus what it could do with cpio archives is very limited.
282 Better to leave it out. */
283 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
284 #endif
285 /* gnulib's stdbool.h might have made true and false into macros,
286 * so we can't leave named 'true' and 'false' tokens, so we have
287 * to expeant the relevant entries longhand.
289 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
290 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
292 /* Various other cases that don't fit neatly into our macro scheme. */
293 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
294 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
295 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
296 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
297 {0, 0, 0, 0}
301 static const char *first_nonoption_arg = NULL;
303 /* Return a pointer to the parser function to invoke for predicate
304 SEARCH_NAME.
305 Return NULL if SEARCH_NAME is not a valid predicate name. */
307 const struct parser_table*
308 find_parser (char *search_name)
310 int i;
311 const char *original_arg = search_name;
313 if (*search_name == '-')
314 search_name++;
315 for (i = 0; parse_table[i].parser_name != 0; i++)
317 if (strcmp (parse_table[i].parser_name, search_name) == 0)
319 /* If this is an option, but we have already had a
320 * non-option argument, the user may be under the
321 * impression that the behaviour of the option
322 * argument is conditional on some preceding
323 * tests. This might typically be the case with,
324 * for example, -maxdepth.
326 * The options -daystart and -follow are exempt
327 * from this treatment, since their positioning
328 * in the command line does have an effect on
329 * subsequent tests but not previous ones. That
330 * might be intentional on the part of the user.
332 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
334 /* Something other than -follow/-daystart.
335 * If this is an option, check if it followed
336 * a non-option and if so, issue a warning.
338 if (parse_table[i].type == ARG_OPTION)
340 if ((first_nonoption_arg != NULL)
341 && options.warnings )
343 /* option which follows a non-option */
344 error (0, 0,
345 _("warning: you have specified the %s "
346 "option after a non-option argument %s, "
347 "but options are not positional (%s affects "
348 "tests specified before it as well as those "
349 "specified after it). Please specify options "
350 "before other arguments.\n"),
351 original_arg,
352 first_nonoption_arg,
353 original_arg);
356 else
358 /* Not an option or a positional option,
359 * so remember we've seen it in order to
360 * use it in a possible future warning message.
362 if (first_nonoption_arg == NULL)
364 first_nonoption_arg = original_arg;
369 return &parse_table[i];
372 return NULL;
375 /* The parsers are responsible to continue scanning ARGV for
376 their arguments. Each parser knows what is and isn't
377 allowed for itself.
379 ARGV is the argument array.
380 *ARG_PTR is the index to start at in ARGV,
381 updated to point beyond the last element consumed.
383 The predicate structure is updated with the new information. */
385 static boolean
386 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
388 struct predicate *our_pred;
389 uintmax_t num;
390 enum comparison_type c_type;
391 time_t t;
393 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
394 return false;
395 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
396 return false;
397 t = options.cur_day_start + DAYSECS - num * 60;
398 our_pred = insert_primary (entry);
399 our_pred->args.info.kind = c_type;
400 our_pred->args.info.negative = t < 0;
401 our_pred->args.info.l_val = t;
402 (*arg_ptr)++;
403 return true;
406 static boolean
407 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
409 struct predicate *our_pred;
411 (void) argv;
412 (void) arg_ptr;
414 our_pred = get_new_pred (entry);
415 our_pred->pred_func = pred_and;
416 #ifdef DEBUG
417 our_pred->p_name = find_pred_name (pred_and);
418 #endif /* DEBUG */
419 our_pred->p_type = BI_OP;
420 our_pred->p_prec = AND_PREC;
421 our_pred->need_stat = our_pred->need_type = false;
422 return true;
425 static boolean
426 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
428 struct predicate *our_pred;
429 struct stat stat_newer;
431 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
432 return false;
433 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
434 error (1, errno, "%s", argv[*arg_ptr]);
435 our_pred = insert_primary (entry);
436 our_pred->args.time = stat_newer.st_mtime;
437 (*arg_ptr)++;
438 return true;
441 static boolean
442 parse_atime (const struct parser_table* entry, char **argv, int *arg_ptr)
444 return insert_time (argv, arg_ptr, entry, pred_atime);
447 boolean
448 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
450 struct predicate *our_pred;
452 (void) argv;
453 (void) arg_ptr;
455 our_pred = get_new_pred (entry);
456 our_pred->pred_func = pred_close;
457 #ifdef DEBUG
458 our_pred->p_name = find_pred_name (pred_close);
459 #endif /* DEBUG */
460 our_pred->p_type = CLOSE_PAREN;
461 our_pred->p_prec = NO_PREC;
462 our_pred->need_stat = our_pred->need_type = false;
463 return true;
466 static boolean
467 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
469 struct predicate *our_pred;
470 uintmax_t num;
471 enum comparison_type c_type;
472 time_t t;
474 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
475 return false;
476 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
477 return false;
478 t = options.cur_day_start + DAYSECS - num * 60;
479 our_pred = insert_primary (entry);
480 our_pred->args.info.kind = c_type;
481 our_pred->args.info.negative = t < 0;
482 our_pred->args.info.l_val = t;
483 (*arg_ptr)++;
484 return true;
487 static boolean
488 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
490 struct predicate *our_pred;
491 struct stat stat_newer;
493 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
494 return false;
495 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
496 error (1, errno, "%s", argv[*arg_ptr]);
497 our_pred = insert_primary (entry);
498 our_pred->args.time = stat_newer.st_mtime;
499 (*arg_ptr)++;
500 return true;
503 static boolean
504 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
506 struct predicate *our_pred;
508 (void) argv;
509 (void) arg_ptr;
511 our_pred = get_new_pred (entry);
512 our_pred->pred_func = pred_comma;
513 #ifdef DEBUG
514 our_pred->p_name = find_pred_name (pred_comma);
515 #endif /* DEBUG */
516 our_pred->p_type = BI_OP;
517 our_pred->p_prec = COMMA_PREC;
518 our_pred->need_stat = our_pred->need_type = false;
519 return true;
522 static boolean
523 parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr)
525 return insert_time (argv, arg_ptr, entry, pred_ctime);
528 static boolean
529 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
531 struct tm *local;
533 (void) entry;
534 (void) argv;
535 (void) arg_ptr;
537 if (options.full_days == false)
539 options.cur_day_start += DAYSECS;
540 local = localtime (&options.cur_day_start);
541 options.cur_day_start -= (local
542 ? (local->tm_sec + local->tm_min * 60
543 + local->tm_hour * 3600)
544 : options.cur_day_start % DAYSECS);
545 options.full_days = true;
547 return true;
550 static boolean
551 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
553 struct predicate *our_pred;
554 (void) argv;
555 (void) arg_ptr;
557 our_pred = insert_primary (entry);
558 our_pred->side_effects = our_pred->no_default_print = true;
559 /* -delete implies -depth */
560 options.do_dir_first = false;
561 return true;
564 static boolean
565 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
567 (void) entry;
568 (void) argv;
569 (void) arg_ptr;
571 options.do_dir_first = false;
572 return true;
575 static boolean
576 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
578 (void) argv;
579 (void) arg_ptr;
581 if (options.warnings)
583 error (0, 0,
584 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
586 return parse_depth(entry, argv, arg_ptr);
589 static boolean
590 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
592 (void) argv;
593 (void) arg_ptr;
595 insert_primary (entry);
596 return true;
599 static boolean
600 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
602 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
605 static boolean
606 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
608 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
611 static boolean
612 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
614 struct predicate *our_pred;
616 (void) argv;
617 (void) arg_ptr;
619 our_pred = insert_primary (entry);
620 our_pred->need_stat = our_pred->need_type = false;
621 our_pred->side_effects = our_pred->no_default_print = false;
622 return true;
625 static boolean
626 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
628 struct predicate *our_pred;
630 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
631 return false;
632 our_pred = insert_primary (entry);
633 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
634 our_pred->side_effects = our_pred->no_default_print = true;
635 (*arg_ptr)++;
636 return true;
639 static boolean
640 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
642 FILE *fp;
644 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
645 return false;
646 if (argv[*arg_ptr + 1] == NULL)
648 /* Ensure we get "missing arg" message, not "invalid arg". */
649 (*arg_ptr)++;
650 return false;
652 fp = open_output_file (argv[*arg_ptr]);
653 (*arg_ptr)++;
654 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
657 static boolean
658 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
660 (void) entry;
661 (void) argv;
662 (void) arg_ptr;
664 set_follow_state(SYMLINK_ALWAYS_DEREF);
665 return true;
668 static boolean
669 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
671 struct predicate *our_pred;
673 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
674 return false;
675 our_pred = insert_primary (entry);
676 our_pred->args.printf_vec.segment = NULL;
677 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
678 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
679 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
680 our_pred->side_effects = our_pred->no_default_print = true;
681 our_pred->need_stat = our_pred->need_type = false;
682 (*arg_ptr)++;
683 return true;
686 static boolean
687 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
689 struct predicate *our_pred;
691 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
692 return false;
693 our_pred = insert_primary (entry);
694 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
695 our_pred->side_effects = our_pred->no_default_print = true;
696 our_pred->need_stat = our_pred->need_type = false;
697 (*arg_ptr)++;
698 return true;
701 static boolean
702 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
704 struct predicate *our_pred;
706 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
707 return false;
708 our_pred = insert_primary (entry);
709 our_pred->args.str = argv[*arg_ptr];
710 (*arg_ptr)++;
711 return true;
714 static boolean
715 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
717 return insert_num (argv, arg_ptr, entry);
720 static boolean
721 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
723 struct group *cur_gr;
724 struct predicate *our_pred;
725 gid_t gid;
726 int gid_len;
728 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
729 return false;
730 cur_gr = getgrnam (argv[*arg_ptr]);
731 endgrent ();
732 if (cur_gr != NULL)
733 gid = cur_gr->gr_gid;
734 else
736 gid_len = strspn (argv[*arg_ptr], "0123456789");
737 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
738 return false;
739 gid = atoi (argv[*arg_ptr]);
741 our_pred = insert_primary (entry);
742 our_pred->args.gid = gid;
743 (*arg_ptr)++;
744 return true;
747 static boolean
748 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
750 (void) entry;
751 (void) argv;
752 (void) arg_ptr;
754 printf (_("\
755 Usage: %s [path...] [expression]\n"), program_name);
756 puts (_("\n\
757 default path is the current directory; default expression is -print\n\
758 expression may consist of: operators, options, tests, and actions:\n"));
759 puts (_("\
760 operators (decreasing precedence; -and is implicit where no others are given):\n\
761 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
762 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
763 puts (_("\
764 positional options (always true): -daystart -follow\n\
765 normal options (always true, specified before other expressions):\n\
766 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
767 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
768 puts (_("\
769 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
770 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
771 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
772 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
773 puts (_("\
774 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
775 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
776 -used N -user NAME -xtype [bcdpfls]\n"));
777 puts (_("\
778 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
779 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
780 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
781 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
782 "));
783 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
784 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
785 email to <bug-findutils@gnu.org>."));
786 exit (0);
789 static boolean
790 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
792 struct predicate *our_pred;
794 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
795 return false;
796 our_pred = insert_primary (entry);
797 our_pred->args.str = argv[*arg_ptr];
798 (*arg_ptr)++;
799 return true;
803 /* sanity check the fnmatch() function to make sure
804 * it really is the GNU version.
806 static boolean
807 fnmatch_sanitycheck(void)
809 /* fprintf(stderr, "Performing find sanity check..."); */
810 if (0 != fnmatch("foo", "foo", 0)
811 || 0 == fnmatch("Foo", "foo", 0)
812 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
814 error (1, 0, _("sanity check of the fnmatch() library function failed."));
815 /* fprintf(stderr, "FAILED\n"); */
816 return false;
819 /* fprintf(stderr, "OK\n"); */
820 return true;
824 static boolean
825 check_name_arg(const char *pred, const char *arg)
827 if (strchr(arg, '/'))
829 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'."),
830 pred, arg, arg);
832 return true; /* allow it anyway */
837 static boolean
838 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
840 struct predicate *our_pred;
842 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
843 return false;
844 if (!check_name_arg("-iname", argv[*arg_ptr]))
845 return false;
847 fnmatch_sanitycheck();
849 our_pred = insert_primary (entry);
850 our_pred->need_stat = our_pred->need_type = false;
851 our_pred->args.str = argv[*arg_ptr];
852 (*arg_ptr)++;
853 return true;
856 static boolean
857 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
859 return insert_num (argv, arg_ptr, entry);
862 /* -ipath is deprecated (at RMS's request) in favour of
863 * -iwholename. See the node "GNU Manuals" in standards.texi
864 * for the rationale for this (basically, GNU prefers the use
865 * of the phrase "file name" to "path name"
867 static boolean
868 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
870 error (0, 0,
871 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
873 return parse_iwholename(entry, argv, arg_ptr);
876 static boolean
877 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
879 struct predicate *our_pred;
881 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
882 return false;
884 fnmatch_sanitycheck();
886 our_pred = insert_primary_withpred (entry, pred_ipath);
887 our_pred->need_stat = our_pred->need_type = false;
888 our_pred->args.str = argv[*arg_ptr];
889 (*arg_ptr)++;
890 return true;
893 static boolean
894 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
896 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
899 static boolean
900 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
902 return insert_num (argv, arg_ptr, entry);
905 static boolean
906 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
908 struct predicate *our_pred;
910 (void) argv;
911 (void) arg_ptr;
913 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
914 return false;
916 fnmatch_sanitycheck();
918 our_pred = insert_primary (entry);
919 our_pred->args.str = argv[*arg_ptr];
920 (*arg_ptr)++;
921 return true;
924 static boolean
925 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
927 struct predicate *our_pred;
929 (void) &argv;
930 (void) &arg_ptr;
932 our_pred = insert_primary (entry);
933 our_pred->side_effects = our_pred->no_default_print = true;
934 return true;
937 static boolean
938 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
940 int depth_len;
941 (void) entry;
943 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
944 return false;
945 depth_len = strspn (argv[*arg_ptr], "0123456789");
946 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
947 return false;
948 options.maxdepth = atoi (argv[*arg_ptr]);
949 if (options.maxdepth < 0)
950 return false;
951 (*arg_ptr)++;
952 return true;
955 static boolean
956 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
958 int depth_len;
959 (void) entry;
961 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
962 return false;
963 depth_len = strspn (argv[*arg_ptr], "0123456789");
964 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
965 return false;
966 options.mindepth = atoi (argv[*arg_ptr]);
967 if (options.mindepth < 0)
968 return false;
969 (*arg_ptr)++;
970 return true;
973 static boolean
974 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
976 struct predicate *our_pred;
977 uintmax_t num;
978 enum comparison_type c_type;
979 time_t t;
981 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
982 return false;
983 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
984 return false;
985 t = options.cur_day_start + DAYSECS - num * 60;
986 our_pred = insert_primary (entry);
987 our_pred->args.info.kind = c_type;
988 our_pred->args.info.negative = t < 0;
989 our_pred->args.info.l_val = t;
990 (*arg_ptr)++;
991 return true;
994 static boolean
995 parse_mtime (const struct parser_table* entry, char **argv, int *arg_ptr)
997 return insert_time (argv, arg_ptr, entry, pred_mtime);
1000 static boolean
1001 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1003 struct predicate *our_pred;
1005 (void) argv;
1006 (void) arg_ptr;
1008 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1009 return false;
1010 if (!check_name_arg("-name", argv[*arg_ptr]))
1011 return false;
1012 fnmatch_sanitycheck();
1014 our_pred = insert_primary (entry);
1015 our_pred->need_stat = our_pred->need_type = false;
1016 our_pred->args.str = argv[*arg_ptr];
1017 (*arg_ptr)++;
1018 return true;
1021 static boolean
1022 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1024 struct predicate *our_pred;
1026 (void) &argv;
1027 (void) &arg_ptr;
1029 our_pred = get_new_pred_chk_op (entry);
1030 our_pred->pred_func = pred_negate;
1031 #ifdef DEBUG
1032 our_pred->p_name = find_pred_name (pred_negate);
1033 #endif /* DEBUG */
1034 our_pred->p_type = UNI_OP;
1035 our_pred->p_prec = NEGATE_PREC;
1036 our_pred->need_stat = our_pred->need_type = false;
1037 return true;
1040 static boolean
1041 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1043 struct predicate *our_pred;
1044 struct stat stat_newer;
1046 (void) argv;
1047 (void) arg_ptr;
1049 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1050 return false;
1051 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1052 error (1, errno, "%s", argv[*arg_ptr]);
1053 our_pred = insert_primary (entry);
1054 our_pred->args.time = stat_newer.st_mtime;
1055 (*arg_ptr)++;
1056 return true;
1059 static boolean
1060 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1062 (void) &argv;
1063 (void) &arg_ptr;
1064 (void) entry;
1066 options.no_leaf_check = true;
1067 return true;
1070 #ifdef CACHE_IDS
1071 /* Arbitrary amount by which to increase size
1072 of `uid_unused' and `gid_unused'. */
1073 #define ALLOC_STEP 2048
1075 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1076 char *uid_unused = NULL;
1078 /* Number of elements in `uid_unused'. */
1079 unsigned uid_allocated;
1081 /* Similar for GIDs and group entries. */
1082 char *gid_unused = NULL;
1083 unsigned gid_allocated;
1084 #endif
1086 static boolean
1087 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1089 struct predicate *our_pred;
1091 (void) &argv;
1092 (void) &arg_ptr;
1094 our_pred = insert_primary (entry);
1095 #ifdef CACHE_IDS
1096 if (gid_unused == NULL)
1098 struct group *gr;
1100 gid_allocated = ALLOC_STEP;
1101 gid_unused = xmalloc (gid_allocated);
1102 memset (gid_unused, 1, gid_allocated);
1103 setgrent ();
1104 while ((gr = getgrent ()) != NULL)
1106 if ((unsigned) gr->gr_gid >= gid_allocated)
1108 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1109 gid_unused = xrealloc (gid_unused, new_allocated);
1110 memset (gid_unused + gid_allocated, 1,
1111 new_allocated - gid_allocated);
1112 gid_allocated = new_allocated;
1114 gid_unused[(unsigned) gr->gr_gid] = 0;
1116 endgrent ();
1118 #endif
1119 return true;
1122 static boolean
1123 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1125 struct predicate *our_pred;
1126 (void) argv;
1127 (void) arg_ptr;
1130 our_pred = insert_primary (entry);
1131 #ifdef CACHE_IDS
1132 if (uid_unused == NULL)
1134 struct passwd *pw;
1136 uid_allocated = ALLOC_STEP;
1137 uid_unused = xmalloc (uid_allocated);
1138 memset (uid_unused, 1, uid_allocated);
1139 setpwent ();
1140 while ((pw = getpwent ()) != NULL)
1142 if ((unsigned) pw->pw_uid >= uid_allocated)
1144 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1145 uid_unused = xrealloc (uid_unused, new_allocated);
1146 memset (uid_unused + uid_allocated, 1,
1147 new_allocated - uid_allocated);
1148 uid_allocated = new_allocated;
1150 uid_unused[(unsigned) pw->pw_uid] = 0;
1152 endpwent ();
1154 #endif
1155 return true;
1158 static boolean
1159 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1161 (void) argv;
1162 (void) arg_ptr;
1163 (void) entry;
1165 options.warnings = false;
1166 return true;;
1169 static boolean
1170 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1172 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1175 static boolean
1176 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1178 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1181 boolean
1182 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1184 struct predicate *our_pred;
1186 (void) argv;
1187 (void) arg_ptr;
1189 our_pred = get_new_pred_chk_op (entry);
1190 our_pred->pred_func = pred_open;
1191 #ifdef DEBUG
1192 our_pred->p_name = find_pred_name (pred_open);
1193 #endif /* DEBUG */
1194 our_pred->p_type = OPEN_PAREN;
1195 our_pred->p_prec = NO_PREC;
1196 our_pred->need_stat = our_pred->need_type = false;
1197 return true;
1200 static boolean
1201 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1203 struct predicate *our_pred;
1205 (void) argv;
1206 (void) arg_ptr;
1208 our_pred = get_new_pred (entry);
1209 our_pred->pred_func = pred_or;
1210 #ifdef DEBUG
1211 our_pred->p_name = find_pred_name (pred_or);
1212 #endif /* DEBUG */
1213 our_pred->p_type = BI_OP;
1214 our_pred->p_prec = OR_PREC;
1215 our_pred->need_stat = our_pred->need_type = false;
1216 return true;
1219 /* -path is deprecated (at RMS's request) in favour of
1220 * -iwholename. See the node "GNU Manuals" in standards.texi
1221 * for the rationale for this (basically, GNU prefers the use
1222 * of the phrase "file name" to "path name".
1224 * We do not issue a warning that this usage is deprecated
1225 * since HPUX find supports this predicate also.
1227 static boolean
1228 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1230 return parse_wholename(entry, argv, arg_ptr);
1233 static boolean
1234 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1236 struct predicate *our_pred;
1238 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1239 return false;
1240 our_pred = insert_primary_withpred (entry, pred_path);
1241 our_pred->need_stat = our_pred->need_type = false;
1242 our_pred->args.str = argv[*arg_ptr];
1243 (*arg_ptr)++;
1244 return true;
1247 static boolean
1248 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1250 mode_t perm_val;
1251 int mode_start = 0;
1252 enum permissions_type kind = PERM_EXACT;
1253 struct mode_change *change = NULL;
1254 struct predicate *our_pred;
1256 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1257 return false;
1259 switch (argv[*arg_ptr][0])
1261 case '-':
1262 mode_start = 1;
1263 kind = PERM_AT_LEAST;
1264 break;
1266 case '+':
1267 change = mode_compile (argv[*arg_ptr]);
1268 if (NULL == change)
1270 /* Most likely the caller is an old script that is still
1271 * using the obsolete GNU syntax '-perm +MODE'. This old
1272 * syntax was withdrawn in favor of '-perm /MODE' because
1273 * it is incompatible with POSIX in some cases, but we
1274 * still support uses of it that are not incompatible with
1275 * POSIX.
1277 mode_start = 1;
1278 kind = PERM_ANY;
1280 else
1282 /* This is a POSIX-compatible usage */
1283 mode_start = 0;
1284 kind = PERM_EXACT;
1286 break;
1288 case '/': /* GNU extension */
1289 mode_start = 1;
1290 kind = PERM_ANY;
1291 break;
1293 default:
1294 /* For example, '-perm 0644', which is valid and matches
1295 * only files whose mode is exactly 0644.
1297 * We do nothing here, because mode_start and kind are already
1298 * correctly set.
1300 break;
1303 if (NULL == change)
1305 change = mode_compile (argv[*arg_ptr] + mode_start);
1306 if (NULL == change)
1307 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1309 perm_val = mode_adjust (0, change, 0);
1310 free (change);
1312 our_pred = insert_primary (entry);
1314 switch (argv[*arg_ptr][0])
1316 case '-':
1317 our_pred->args.perm.kind = PERM_AT_LEAST;
1318 break;
1319 case '+':
1320 our_pred->args.perm.kind = PERM_ANY;
1321 break;
1322 default:
1323 our_pred->args.perm.kind = PERM_EXACT;
1324 break;
1326 our_pred->args.perm.val = perm_val & MODE_ALL;
1327 (*arg_ptr)++;
1328 return true;
1331 boolean
1332 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1334 struct predicate *our_pred;
1336 (void) argv;
1337 (void) arg_ptr;
1339 our_pred = insert_primary (entry);
1340 /* -print has the side effect of printing. This prevents us
1341 from doing undesired multiple printing when the user has
1342 already specified -print. */
1343 our_pred->side_effects = our_pred->no_default_print = true;
1344 our_pred->need_stat = our_pred->need_type = false;
1345 our_pred->args.printf_vec.segment = NULL;
1346 our_pred->args.printf_vec.stream = stdout;
1347 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1348 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1350 return true;
1353 static boolean
1354 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1356 struct predicate *our_pred;
1358 (void) argv;
1359 (void) arg_ptr;
1361 our_pred = insert_primary (entry);
1362 /* -print0 has the side effect of printing. This prevents us
1363 from doing undesired multiple printing when the user has
1364 already specified -print0. */
1365 our_pred->side_effects = our_pred->no_default_print = true;
1366 our_pred->need_stat = our_pred->need_type = false;
1367 return true;
1370 static boolean
1371 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1373 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1374 return false;
1375 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1378 static boolean
1379 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1381 struct predicate *our_pred;
1383 (void) argv;
1384 (void) arg_ptr;
1386 our_pred = insert_primary (entry);
1387 our_pred->need_stat = our_pred->need_type = false;
1388 /* -prune has a side effect that it does not descend into
1389 the current directory. */
1390 our_pred->side_effects = true;
1391 our_pred->no_default_print = false;
1392 return true;
1395 static boolean
1396 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1398 struct predicate *our_pred = insert_primary (entry);
1399 (void) argv;
1400 (void) arg_ptr;
1401 our_pred->need_stat = our_pred->need_type = false;
1402 our_pred->side_effects = true; /* Exiting is a side effect... */
1403 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1404 return true;
1408 static boolean
1409 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1411 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1414 static boolean
1415 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1417 struct predicate *our_pred;
1418 struct re_pattern_buffer *re;
1419 const char *error_message;
1421 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1422 return false;
1423 our_pred = insert_primary_withpred (entry, pred_regex);
1424 our_pred->need_stat = our_pred->need_type = false;
1425 re = (struct re_pattern_buffer *)
1426 xmalloc (sizeof (struct re_pattern_buffer));
1427 our_pred->args.regex = re;
1428 re->allocated = 100;
1429 re->buffer = (unsigned char *) xmalloc (re->allocated);
1430 re->fastmap = NULL;
1432 re_set_syntax(regex_options);
1433 re->syntax = regex_options;
1434 re->translate = NULL;
1436 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1437 re);
1438 if (error_message)
1439 error (1, 0, "%s", error_message);
1440 (*arg_ptr)++;
1441 return true;
1444 static boolean
1445 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1447 struct predicate *our_pred;
1448 uintmax_t num;
1449 enum comparison_type c_type;
1450 int blksize = 512;
1451 int len;
1453 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1454 return false;
1455 len = strlen (argv[*arg_ptr]);
1456 if (len == 0)
1457 error (1, 0, _("invalid null argument to -size"));
1458 switch (argv[*arg_ptr][len - 1])
1460 case 'b':
1461 blksize = 512;
1462 argv[*arg_ptr][len - 1] = '\0';
1463 break;
1465 case 'c':
1466 blksize = 1;
1467 argv[*arg_ptr][len - 1] = '\0';
1468 break;
1470 case 'k':
1471 blksize = 1024;
1472 argv[*arg_ptr][len - 1] = '\0';
1473 break;
1475 case 'M': /* Megabytes */
1476 blksize = 1024*1024;
1477 argv[*arg_ptr][len - 1] = '\0';
1478 break;
1480 case 'G': /* Gigabytes */
1481 blksize = 1024*1024*1024;
1482 argv[*arg_ptr][len - 1] = '\0';
1483 break;
1485 case 'w':
1486 blksize = 2;
1487 argv[*arg_ptr][len - 1] = '\0';
1488 break;
1490 case '0':
1491 case '1':
1492 case '2':
1493 case '3':
1494 case '4':
1495 case '5':
1496 case '6':
1497 case '7':
1498 case '8':
1499 case '9':
1500 break;
1502 default:
1503 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1505 if (!get_num (argv[*arg_ptr], &num, &c_type))
1506 return false;
1507 our_pred = insert_primary (entry);
1508 our_pred->args.size.kind = c_type;
1509 our_pred->args.size.blocksize = blksize;
1510 our_pred->args.size.size = num;
1511 (*arg_ptr)++;
1512 return true;
1516 static boolean
1517 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1519 struct predicate *our_pred;
1520 struct stat st;
1522 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1523 return false;
1524 if ((*options.xstat) (argv[*arg_ptr], &st))
1525 error (1, errno, "%s", argv[*arg_ptr]);
1527 our_pred = insert_primary (entry);
1528 our_pred->args.fileid.ino = st.st_ino;
1529 our_pred->args.fileid.dev = st.st_dev;
1530 our_pred->need_type = false;
1531 our_pred->need_stat = true;
1532 (*arg_ptr)++;
1533 return true;
1537 static boolean
1538 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1540 struct predicate *our_pred;
1542 (void) argv;
1543 (void) arg_ptr;
1545 our_pred = insert_primary (entry);
1546 our_pred->need_stat = our_pred->need_type = false;
1547 return true;
1550 static boolean
1551 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1553 return insert_type (argv, arg_ptr, entry, pred_type);
1556 static boolean
1557 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1559 return insert_num (argv, arg_ptr, entry);
1562 static boolean
1563 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1565 struct predicate *our_pred;
1566 uintmax_t num_days;
1567 enum comparison_type c_type;
1568 time_t t;
1570 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1571 return false;
1572 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1573 return false;
1574 t = num_days * DAYSECS;
1575 our_pred = insert_primary (entry);
1576 our_pred->args.info.kind = c_type;
1577 our_pred->args.info.negative = t < 0;
1578 our_pred->args.info.l_val = t;
1579 (*arg_ptr)++;
1580 return true;
1583 static boolean
1584 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1586 struct passwd *cur_pwd;
1587 struct predicate *our_pred;
1588 uid_t uid;
1589 int uid_len;
1591 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1592 return false;
1593 cur_pwd = getpwnam (argv[*arg_ptr]);
1594 endpwent ();
1595 if (cur_pwd != NULL)
1596 uid = cur_pwd->pw_uid;
1597 else
1599 uid_len = strspn (argv[*arg_ptr], "0123456789");
1600 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1601 return false;
1602 uid = atoi (argv[*arg_ptr]);
1604 our_pred = insert_primary (entry);
1605 our_pred->args.uid = uid;
1606 (*arg_ptr)++;
1607 return true;
1610 static boolean
1611 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1613 extern char *version_string;
1614 int features = 0;
1616 (void) argv;
1617 (void) arg_ptr;
1618 (void) entry;
1620 fflush (stderr);
1621 printf (_("GNU find version %s\n"), version_string);
1622 printf (_("Features enabled: "));
1624 #if CACHE_IDS
1625 printf("CACHE_IDS ");
1626 ++features;
1627 #endif
1628 #if DEBUG
1629 printf("DEBUG ");
1630 ++features;
1631 #endif
1632 #if DEBUG_STAT
1633 printf("DEBUG_STAT ");
1634 ++features;
1635 #endif
1636 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1637 printf("D_TYPE ");
1638 ++features;
1639 #endif
1640 #if defined(O_NOFOLLOW)
1641 printf("O_NOFOLLOW(%s) ",
1642 (options.open_nofollow_available ? "enabled" : "disabled"));
1643 ++features;
1644 #endif
1646 if (0 == features)
1648 /* For the moment, leave this as English in case someone wants
1649 to parse these strings. */
1650 printf("none");
1652 printf("\n");
1654 exit (0);
1657 static boolean
1658 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1660 (void) argv;
1661 (void) arg_ptr;
1662 (void) entry;
1663 options.stay_on_filesystem = true;
1664 return true;
1667 static boolean
1668 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1670 (void) argv;
1671 (void) arg_ptr;
1672 (void) entry;
1673 options.ignore_readdir_race = true;
1674 return true;
1677 static boolean
1678 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1680 (void) argv;
1681 (void) arg_ptr;
1682 (void) entry;
1683 options.ignore_readdir_race = false;
1684 return true;
1687 static boolean
1688 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1690 (void) argv;
1691 (void) arg_ptr;
1692 (void) entry;
1693 options.warnings = true;
1694 return true;
1697 static boolean
1698 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1700 (void) argv;
1701 (void) arg_ptr;
1702 return insert_type (argv, arg_ptr, entry, pred_xtype);
1705 static boolean
1706 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
1708 mode_t type_cell;
1709 struct predicate *our_pred;
1711 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1712 || (strlen (argv[*arg_ptr]) != 1))
1713 return false;
1714 switch (argv[*arg_ptr][0])
1716 case 'b': /* block special */
1717 type_cell = S_IFBLK;
1718 break;
1719 case 'c': /* character special */
1720 type_cell = S_IFCHR;
1721 break;
1722 case 'd': /* directory */
1723 type_cell = S_IFDIR;
1724 break;
1725 case 'f': /* regular file */
1726 type_cell = S_IFREG;
1727 break;
1728 #ifdef S_IFLNK
1729 case 'l': /* symbolic link */
1730 type_cell = S_IFLNK;
1731 break;
1732 #endif
1733 #ifdef S_IFIFO
1734 case 'p': /* pipe */
1735 type_cell = S_IFIFO;
1736 break;
1737 #endif
1738 #ifdef S_IFSOCK
1739 case 's': /* socket */
1740 type_cell = S_IFSOCK;
1741 break;
1742 #endif
1743 #ifdef S_IFDOOR
1744 case 'D': /* Solaris door */
1745 type_cell = S_IFDOOR;
1746 break;
1747 #endif
1748 default: /* None of the above ... nuke 'em. */
1749 return false;
1751 our_pred = insert_primary_withpred (entry, which_pred);
1753 /* Figure out if we will need to stat the file, because if we don't
1754 * need to follow symlinks, we can avoid a stat call by using
1755 * struct dirent.d_type.
1757 if (which_pred == pred_xtype)
1759 our_pred->need_stat = true;
1760 our_pred->need_type = false;
1762 else
1764 our_pred->need_stat = false; /* struct dirent is enough */
1765 our_pred->need_type = true;
1767 our_pred->args.type = type_cell;
1768 (*arg_ptr)++; /* Move on to next argument. */
1769 return true;
1773 /* Return true if the file accessed via FP is a terminal.
1775 static boolean
1776 stream_is_tty(FILE *fp)
1778 int fd = fileno(fp);
1779 if (-1 == fd)
1781 return false; /* not a valid stream */
1783 else
1785 return isatty(fd) ? true : false;
1792 /* If true, we've determined that the current fprintf predicate
1793 uses stat information. */
1794 static boolean fprintf_stat_needed;
1796 /* XXX: do we need to pass FUNC to this function? */
1797 static boolean
1798 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
1800 char *format; /* Beginning of unprocessed format string. */
1801 register char *scan; /* Current address in scanning `format'. */
1802 register char *scan2; /* Address inside of element being scanned. */
1803 struct segment **segmentp; /* Address of current segment. */
1804 struct predicate *our_pred;
1806 format = argv[(*arg_ptr)++];
1808 fprintf_stat_needed = false; /* Might be overridden later. */
1809 our_pred = insert_primary_withpred (entry, func);
1810 our_pred->side_effects = our_pred->no_default_print = true;
1811 our_pred->args.printf_vec.stream = fp;
1812 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
1813 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1814 segmentp = &our_pred->args.printf_vec.segment;
1815 *segmentp = NULL;
1817 for (scan = format; *scan; scan++)
1819 if (*scan == '\\')
1821 scan2 = scan + 1;
1822 if (*scan2 >= '0' && *scan2 <= '7')
1824 register int n, i;
1826 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1827 i++, scan2++)
1828 n = 8 * n + *scan2 - '0';
1829 scan2--;
1830 *scan = n;
1832 else
1834 switch (*scan2)
1836 case 'a':
1837 *scan = 7;
1838 break;
1839 case 'b':
1840 *scan = '\b';
1841 break;
1842 case 'c':
1843 make_segment (segmentp, format, scan - format, KIND_STOP);
1844 our_pred->need_stat = fprintf_stat_needed;
1845 return true;
1846 case 'f':
1847 *scan = '\f';
1848 break;
1849 case 'n':
1850 *scan = '\n';
1851 break;
1852 case 'r':
1853 *scan = '\r';
1854 break;
1855 case 't':
1856 *scan = '\t';
1857 break;
1858 case 'v':
1859 *scan = '\v';
1860 break;
1861 case '\\':
1862 /* *scan = '\\'; * it already is */
1863 break;
1864 default:
1865 error (0, 0,
1866 _("warning: unrecognized escape `\\%c'"), *scan2);
1867 scan++;
1868 continue;
1871 segmentp = make_segment (segmentp, format, scan - format + 1,
1872 KIND_PLAIN);
1873 format = scan2 + 1; /* Move past the escape. */
1874 scan = scan2; /* Incremented immediately by `for'. */
1876 else if (*scan == '%')
1878 if (scan[1] == '%')
1880 segmentp = make_segment (segmentp, format, scan - format + 1,
1881 KIND_PLAIN);
1882 scan++;
1883 format = scan + 1;
1884 continue;
1886 /* Scan past flags, width and precision, to verify kind. */
1887 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1888 /* Do nothing. */ ;
1889 while (ISDIGIT (*scan2))
1890 scan2++;
1891 if (*scan2 == '.')
1892 for (scan2++; ISDIGIT (*scan2); scan2++)
1893 /* Do nothing. */ ;
1894 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1896 segmentp = make_segment (segmentp, format, scan2 - format,
1897 (int) *scan2);
1898 scan = scan2;
1899 format = scan + 1;
1901 else if (strchr ("ACT", *scan2) && scan2[1])
1903 segmentp = make_segment (segmentp, format, scan2 - format,
1904 *scan2 | (scan2[1] << 8));
1905 scan = scan2 + 1;
1906 format = scan + 1;
1907 continue;
1909 else
1911 /* An unrecognized % escape. Print the char after the %. */
1912 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1913 *scan2);
1914 segmentp = make_segment (segmentp, format, scan - format,
1915 KIND_PLAIN);
1916 format = scan + 1;
1917 continue;
1922 if (scan > format)
1923 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1924 our_pred->need_type = false;
1925 our_pred->need_stat = fprintf_stat_needed;
1926 return true;
1929 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1930 from the text in FORMAT, which has length LEN.
1931 Return the address of the `next' pointer of the new segment. */
1933 static struct segment **
1934 make_segment (struct segment **segment, char *format, int len, int kind)
1936 char *fmt;
1938 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1940 (*segment)->kind = kind;
1941 (*segment)->next = NULL;
1942 (*segment)->text_len = len;
1944 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1945 strncpy (fmt, format, len);
1946 fmt += len;
1948 switch (kind & 0xff)
1950 case KIND_PLAIN: /* Plain text string, no % conversion. */
1951 case KIND_STOP: /* Terminate argument, no newline. */
1952 break;
1954 case 'a': /* atime in `ctime' format */
1955 case 'A': /* atime in user-specified strftime format */
1956 case 'c': /* ctime in `ctime' format */
1957 case 'C': /* ctime in user-specified strftime format */
1958 case 'F': /* filesystem type */
1959 case 'g': /* group name */
1960 case 'i': /* inode number */
1961 case 'l': /* object of symlink */
1962 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1963 case 's': /* size in bytes */
1964 case 't': /* mtime in `ctime' format */
1965 case 'T': /* mtime in user-specified strftime format */
1966 case 'u': /* user name */
1967 case 'y': /* file type */
1968 case 'Y': /* symlink pointed file type */
1969 fprintf_stat_needed = true;
1970 /* FALLTHROUGH */
1971 case 'f': /* basename of path */
1972 case 'h': /* leading directories part of path */
1973 case 'H': /* ARGV element file was found under */
1974 case 'p': /* pathname */
1975 case 'P': /* pathname with ARGV element stripped */
1976 *fmt++ = 's';
1977 break;
1979 /* Numeric items that one might expect to honour
1980 * #, 0, + flags but which do not.
1982 case 'G': /* GID number */
1983 case 'U': /* UID number */
1984 case 'b': /* size in 512-byte blocks */
1985 case 'D': /* Filesystem device on which the file exits */
1986 case 'k': /* size in 1K blocks */
1987 case 'n': /* number of links */
1988 fprintf_stat_needed = true;
1989 *fmt++ = 's';
1990 break;
1992 /* Numeric items that DO honour #, 0, + flags.
1994 case 'd': /* depth in search tree (0 = ARGV element) */
1995 *fmt++ = 'd';
1996 break;
1998 case 'm': /* mode as octal number (perms only) */
1999 *fmt++ = 'o';
2000 fprintf_stat_needed = true;
2001 break;
2003 *fmt = '\0';
2005 return &(*segment)->next;
2008 static void
2009 check_path_safety(const char *action)
2011 const char *path = getenv("PATH");
2012 char *s;
2013 s = next_element(path, 1);
2014 while ((s = next_element ((char *) NULL, 1)) != NULL)
2016 if (0 == strcmp(s, "."))
2018 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)"),
2019 action);
2025 /* handles both exec and ok predicate */
2026 #if defined(NEW_EXEC)
2027 /* handles both exec and ok predicate */
2028 static boolean
2029 new_insert_exec_ok (const char *action,
2030 const struct parser_table *entry,
2031 char **argv,
2032 int *arg_ptr)
2034 int start, end; /* Indexes in ARGV of start & end of cmd. */
2035 int i; /* Index into cmd args */
2036 int saw_braces; /* True if previous arg was '{}'. */
2037 boolean allow_plus; /* True if + is a valid terminator */
2038 int brace_count; /* Number of instances of {}. */
2039 PRED_FUNC func = entry->pred_func;
2041 struct predicate *our_pred;
2042 struct exec_val *execp; /* Pointer for efficiency. */
2044 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2045 return false;
2047 our_pred = insert_primary_withpred (entry, func);
2048 our_pred->side_effects = our_pred->no_default_print = true;
2049 execp = &our_pred->args.exec_vec;
2051 if ((func != pred_okdir) && (func != pred_ok))
2052 allow_plus = true;
2053 else
2054 allow_plus = false;
2056 if ((func == pred_execdir) || (func == pred_okdir))
2058 options.ignore_readdir_race = false;
2059 check_path_safety(action);
2060 execp->use_current_dir = true;
2062 else
2064 execp->use_current_dir = false;
2067 our_pred->args.exec_vec.multiple = 0;
2069 /* Count the number of args with path replacements, up until the ';'.
2070 * Also figure out if the command is terminated by ";" or by "+".
2072 start = *arg_ptr;
2073 for (end = start, saw_braces=0, brace_count=0;
2074 (argv[end] != NULL)
2075 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2076 end++)
2078 /* For -exec and -execdir, "{} +" can terminate the command. */
2079 if ( allow_plus
2080 && argv[end][0] == '+' && argv[end][1] == 0
2081 && saw_braces)
2083 our_pred->args.exec_vec.multiple = 1;
2084 break;
2087 saw_braces = 0;
2088 if (strstr (argv[end], "{}"))
2090 saw_braces = 1;
2091 ++brace_count;
2093 if (0 == end && (func == pred_execdir || func == pred_okdir))
2095 /* The POSIX standard says that {} replacement should
2096 * occur even in the utility name. This is insecure
2097 * since it means we will be executing a command whose
2098 * name is chosen according to whatever find finds in
2099 * the filesystem. That can be influenced by an
2100 * attacker. Hence for -execdir and -okdir this is not
2101 * allowed. We can specify this as those options are
2102 * not defined by POSIX.
2104 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2109 /* Fail if no command given or no semicolon found. */
2110 if ((end == start) || (argv[end] == NULL))
2112 *arg_ptr = end;
2113 free(our_pred);
2114 return false;
2117 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2120 const char *suffix;
2121 if (func == pred_execdir)
2122 suffix = "dir";
2123 else
2124 suffix = "";
2126 error(1, 0,
2127 _("Only one instance of {} is supported with -exec%s ... +"),
2128 suffix);
2131 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2132 bc_init_controlinfo(&execp->ctl);
2133 execp->ctl.exec_callback = launch;
2135 if (our_pred->args.exec_vec.multiple)
2137 /* "+" terminator, so we can just append our arguments after the
2138 * command and initial arguments.
2140 execp->replace_vec = NULL;
2141 execp->ctl.replace_pat = NULL;
2142 execp->ctl.rplen = 0;
2143 execp->ctl.lines_per_exec = 0; /* no limit */
2144 execp->ctl.args_per_exec = 0; /* no limit */
2146 /* remember how many arguments there are */
2147 execp->ctl.initial_argc = (end-start) - 1;
2149 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2150 bc_init_state(&execp->ctl, &execp->state, execp);
2152 /* Gather the initial arguments. Skip the {}. */
2153 for (i=start; i<end-1; ++i)
2155 bc_push_arg(&execp->ctl, &execp->state,
2156 argv[i], strlen(argv[i])+1,
2157 NULL, 0,
2161 else
2163 /* Semicolon terminator - more than one {} is supported, so we
2164 * have to do brace-replacement.
2166 execp->num_args = end - start;
2168 execp->ctl.replace_pat = "{}";
2169 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2170 execp->ctl.lines_per_exec = 0; /* no limit */
2171 execp->ctl.args_per_exec = 0; /* no limit */
2172 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2175 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2176 bc_init_state(&execp->ctl, &execp->state, execp);
2178 /* Remember the (pre-replacement) arguments for later. */
2179 for (i=0; i<execp->num_args; ++i)
2181 execp->replace_vec[i] = argv[i+start];
2185 if (argv[end] == NULL)
2186 *arg_ptr = end;
2187 else
2188 *arg_ptr = end + 1;
2190 return true;
2192 #else
2193 /* handles both exec and ok predicate */
2194 static boolean
2195 old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
2197 int start, end; /* Indexes in ARGV of start & end of cmd. */
2198 int num_paths; /* Number of args with path replacements. */
2199 int path_pos; /* Index in array of path replacements. */
2200 int vec_pos; /* Index in array of args. */
2201 struct predicate *our_pred;
2202 struct exec_val *execp; /* Pointer for efficiency. */
2204 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2205 return false;
2207 /* Count the number of args with path replacements, up until the ';'. */
2208 start = *arg_ptr;
2209 for (end = start, num_paths = 0;
2210 (argv[end] != NULL)
2211 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2212 end++)
2213 if (strstr (argv[end], "{}"))
2214 num_paths++;
2215 /* Fail if no command given or no semicolon found. */
2216 if ((end == start) || (argv[end] == NULL))
2218 *arg_ptr = end;
2219 return false;
2222 our_pred = insert_primary (func);
2223 our_pred->side_effects = our_pred->no_default_print = true;
2224 execp = &our_pred->args.exec_vec;
2225 execp->usercontext = our_pred;
2226 execp->use_current_dir = false;
2227 execp->paths =
2228 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
2229 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
2230 /* Record the positions of all args, and the args with path replacements. */
2231 for (end = start, path_pos = vec_pos = 0;
2232 (argv[end] != NULL)
2233 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2234 end++)
2236 register char *p;
2238 execp->paths[path_pos].count = 0;
2239 for (p = argv[end]; *p; ++p)
2240 if (p[0] == '{' && p[1] == '}')
2242 execp->paths[path_pos].count++;
2243 ++p;
2245 if (execp->paths[path_pos].count)
2247 execp->paths[path_pos].offset = vec_pos;
2248 execp->paths[path_pos].origarg = argv[end];
2249 path_pos++;
2251 execp->vec[vec_pos++] = argv[end];
2253 execp->paths[path_pos].offset = -1;
2254 execp->vec[vec_pos] = NULL;
2256 if (argv[end] == NULL)
2257 *arg_ptr = end;
2258 else
2259 *arg_ptr = end + 1;
2260 return true;
2262 #endif
2266 static boolean
2267 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2269 #if defined(NEW_EXEC)
2270 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2271 #else
2272 return old_insert_exec_ok(func, argv, arg_ptr);
2273 #endif
2278 /* Get a number of days and comparison type.
2279 STR is the ASCII representation.
2280 Set *NUM_DAYS to the number of days, taken as being from
2281 the current moment (or possibly midnight). Thus the sense of the
2282 comparison type appears to be reversed.
2283 Set *COMP_TYPE to the kind of comparison that is requested.
2285 Return true if all okay, false if input error.
2287 Used by -atime, -ctime and -mtime (parsers) to
2288 get the appropriate information for a time predicate processor. */
2290 static boolean
2291 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2293 boolean r = get_num (str, num_days, comp_type);
2294 if (r)
2295 switch (*comp_type)
2297 case COMP_LT: *comp_type = COMP_GT; break;
2298 case COMP_GT: *comp_type = COMP_LT; break;
2299 default: break;
2301 return r;
2304 /* Insert a time predicate PRED.
2305 ARGV is a pointer to the argument array.
2306 ARG_PTR is a pointer to an index into the array, incremented if
2307 all went well.
2309 Return true if input is valid, false if not.
2311 A new predicate node is assigned, along with an argument node
2312 obtained with malloc.
2314 Used by -atime, -ctime, and -mtime parsers. */
2316 static boolean
2317 insert_time (char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred)
2319 struct predicate *our_pred;
2320 uintmax_t num_days;
2321 enum comparison_type c_type;
2322 time_t t;
2324 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2325 return false;
2326 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2327 return false;
2329 /* Figure out the timestamp value we are looking for. */
2330 t = ( options.cur_day_start - num_days * DAYSECS
2331 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2333 if (1)
2335 /* We introduce a scope in which 'val' can be declared, for the
2336 * benefit of compilers that are really C89 compilers
2337 * which support intmax_t because config.h #defines it
2339 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2340 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2341 t = val;
2343 /* Check for possibility of an overflow */
2344 if ( (intmax_t)t != val )
2346 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2350 our_pred = insert_primary_withpred (entry, pred);
2351 our_pred->args.info.kind = c_type;
2352 our_pred->args.info.negative = t < 0;
2353 our_pred->args.info.l_val = t;
2354 (*arg_ptr)++;
2355 #ifdef DEBUG
2356 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2357 fprintf (stderr, " type: %s %s ",
2358 (c_type == COMP_GT) ? "gt" :
2359 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2360 (c_type == COMP_GT) ? " >" :
2361 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2362 t = our_pred->args.info.l_val;
2363 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2364 if (c_type == COMP_EQ)
2366 t = our_pred->args.info.l_val += DAYSECS;
2367 fprintf (stderr, " < %ju %s",
2368 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2369 our_pred->args.info.l_val -= DAYSECS;
2371 #endif /* DEBUG */
2372 return true;
2375 /* Get a number with comparison information.
2376 The sense of the comparison information is 'normal'; that is,
2377 '+' looks for a count > than the number and '-' less than.
2379 STR is the ASCII representation of the number.
2380 Set *NUM to the number.
2381 Set *COMP_TYPE to the kind of comparison that is requested.
2383 Return true if all okay, false if input error. */
2385 static boolean
2386 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2388 if (str == NULL)
2389 return false;
2390 switch (str[0])
2392 case '+':
2393 *comp_type = COMP_GT;
2394 str++;
2395 break;
2396 case '-':
2397 *comp_type = COMP_LT;
2398 str++;
2399 break;
2400 default:
2401 *comp_type = COMP_EQ;
2402 break;
2405 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2408 /* Insert a number predicate.
2409 ARGV is a pointer to the argument array.
2410 *ARG_PTR is an index into ARGV, incremented if all went well.
2411 *PRED is the predicate processor to insert.
2413 Return true if input is valid, false if error.
2415 A new predicate node is assigned, along with an argument node
2416 obtained with malloc.
2418 Used by -inum and -links parsers. */
2420 static boolean
2421 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2423 struct predicate *our_pred;
2424 uintmax_t num;
2425 enum comparison_type c_type;
2427 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2428 return false;
2429 if (!get_num (argv[*arg_ptr], &num, &c_type))
2430 return false;
2431 our_pred = insert_primary (entry);
2432 our_pred->args.info.kind = c_type;
2433 our_pred->args.info.l_val = num;
2434 (*arg_ptr)++;
2435 #ifdef DEBUG
2436 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2437 fprintf (stderr, " type: %s %s ",
2438 (c_type == COMP_GT) ? "gt" :
2439 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2440 (c_type == COMP_GT) ? " >" :
2441 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2442 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2443 #endif /* DEBUG */
2444 return true;
2447 static FILE *
2448 open_output_file (char *path)
2450 FILE *f;
2452 if (!strcmp (path, "/dev/stderr"))
2453 return stderr;
2454 else if (!strcmp (path, "/dev/stdout"))
2455 return stdout;
2456 f = fopen_safer (path, "w");
2457 if (f == NULL)
2458 error (1, errno, "%s", path);
2459 return f;