Use the new find program, and the new way of locating it (/ instead of )
[findutils.git] / find / parser.c
blob608aeee1779b926b100fb39279f6835a7a17ad03
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA.
22 #include "defs.h"
23 #include <ctype.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <fnmatch.h>
27 #include "modechange.h"
28 #include "modetype.h"
29 #include "xstrtol.h"
30 #include "xalloc.h"
31 #include "quote.h"
32 #include "quotearg.h"
33 #include "buildcmd.h"
34 #include "nextelem.h"
35 #include "stdio-safer.h"
36 #include "regextype.h"
38 #ifdef HAVE_FCNTL_H
39 #include <fcntl.h>
40 #else
41 #include <sys/file.h>
42 #endif
44 /* The presence of unistd.h is assumed by gnulib these days, so we
45 * might as well assume it too.
47 /* We need <unistd.h> for isatty(). */
48 #include <unistd.h>
50 #if ENABLE_NLS
51 # include <libintl.h>
52 # define _(Text) gettext (Text)
53 #else
54 # define _(Text) Text
55 #endif
56 #ifdef gettext_noop
57 # define N_(String) gettext_noop (String)
58 #else
59 /* See locate.c for explanation as to why not use (String) */
60 # define N_(String) String
61 #endif
63 #if !defined (isascii) || defined (STDC_HEADERS)
64 #ifdef isascii
65 #undef isascii
66 #endif
67 #define isascii(c) 1
68 #endif
70 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
71 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
73 #ifndef HAVE_ENDGRENT
74 #define endgrent()
75 #endif
76 #ifndef HAVE_ENDPWENT
77 #define endpwent()
78 #endif
80 static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
81 static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
82 static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
83 static boolean parse_atime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
84 static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
85 static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
86 static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
87 static boolean parse_ctime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
88 static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
89 static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
90 static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
91 static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
92 static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
93 static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
94 static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
95 static boolean parse_executable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
96 static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
97 static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
98 static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
99 static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
100 static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
101 static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
102 static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
103 static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
104 static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
105 static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
106 static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
107 static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
108 static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
109 static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
110 static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
111 static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
112 static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
113 static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
114 static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
115 static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
116 static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
117 static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
118 static boolean parse_mtime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
119 static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
120 static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
121 static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
122 static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
123 static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
124 static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
125 static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
126 static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
127 static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
128 static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
129 static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
130 static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
131 static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
132 static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
133 static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
134 static boolean parse_readable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
135 static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
136 static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
137 static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
138 static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
139 static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
140 static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
141 static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
142 static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
143 static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
144 static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
145 static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
146 static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
147 static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
148 static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
149 static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
150 static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
151 static boolean parse_writable PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
152 static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
153 static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
155 boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
158 static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
159 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
160 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
162 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
163 static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
164 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
165 static boolean insert_time PARAMS((char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred));
166 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
167 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
168 static FILE *open_output_file PARAMS((char *path));
169 static boolean stream_is_tty(FILE *fp);
171 #ifdef DEBUG
172 char *find_pred_name PARAMS((PRED_FUNC pred_func));
173 #endif /* DEBUG */
176 #define PASTE(x,y) x##y
177 #define STRINGIFY(s) #s
179 #define PARSE_OPTION(what,suffix) \
180 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
182 #define PARSE_POSOPT(what,suffix) \
183 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_TEST(what,suffix) \
186 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
188 #define PARSE_TEST_NP(what,suffix) \
189 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
191 #define PARSE_ACTION(what,suffix) \
192 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
194 #define PARSE_ACTION_NP(what,suffix) \
195 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
197 #define PARSE_PUNCTUATION(what,suffix) \
198 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
201 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
202 If they are in some Unix versions of find, they are marked `Unix'. */
204 static struct parser_table const parse_table[] =
206 PARSE_PUNCTUATION("!", negate),
207 PARSE_PUNCTUATION("not", negate), /* GNU */
208 PARSE_PUNCTUATION("(", open),
209 PARSE_PUNCTUATION(")", close),
210 PARSE_PUNCTUATION(",", comma), /* GNU */
211 PARSE_PUNCTUATION("a", and),
212 PARSE_TEST ("amin", amin), /* GNU */
213 PARSE_PUNCTUATION("and", and), /* GNU */
214 PARSE_TEST ("anewer", anewer), /* GNU */
215 PARSE_TEST ("atime", atime),
216 PARSE_TEST ("cmin", cmin), /* GNU */
217 PARSE_TEST ("cnewer", cnewer), /* GNU */
218 PARSE_TEST ("ctime", ctime),
219 PARSE_POSOPT ("daystart", daystart), /* GNU */
220 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
221 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
222 PARSE_OPTION ("depth", depth),
223 PARSE_TEST ("empty", empty), /* GNU */
224 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
225 PARSE_TEST ("executable", executable), /* GNU, 4.3.0+ */
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 {ARG_ACTION, "fprintf", parse_fprintf, pred_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 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
269 PARSE_ACTION ("prune", prune),
270 PARSE_ACTION ("quit", quit), /* GNU */
271 PARSE_TEST ("readable", readable), /* GNU, 4.3.0+ */
272 PARSE_TEST ("regex", regex), /* GNU */
273 PARSE_OPTION ("regextype", regextype), /* GNU */
274 PARSE_TEST ("samefile", samefile), /* GNU */
275 #if 0
276 PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
277 #endif
278 PARSE_TEST ("size", size),
279 PARSE_TEST ("type", type),
280 PARSE_TEST ("uid", uid), /* GNU */
281 PARSE_TEST ("used", used), /* GNU */
282 PARSE_TEST ("user", user),
283 PARSE_OPTION ("warn", warn), /* GNU */
284 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
285 PARSE_TEST ("writable", writable), /* GNU, 4.3.0+ */
286 PARSE_OPTION ("xdev", xdev),
287 PARSE_TEST ("xtype", xtype), /* GNU */
288 #ifdef UNIMPLEMENTED_UNIX
289 /* It's pretty ugly for find to know about archive formats.
290 Plus what it could do with cpio archives is very limited.
291 Better to leave it out. */
292 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
293 #endif
294 /* gnulib's stdbool.h might have made true and false into macros,
295 * so we can't leave named 'true' and 'false' tokens, so we have
296 * to expeant the relevant entries longhand.
298 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
299 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
301 /* Various other cases that don't fit neatly into our macro scheme. */
302 {ARG_TEST, "help", parse_help, NULL}, /* GNU */
303 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
304 {ARG_TEST, "version", parse_version, NULL}, /* GNU */
305 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
306 {0, 0, 0, 0}
310 static const char *first_nonoption_arg = NULL;
315 void
316 set_follow_state(enum SymlinkOption opt)
318 switch (opt)
320 case SYMLINK_ALWAYS_DEREF: /* -L */
321 options.xstat = optionl_stat;
322 options.no_leaf_check = true;
323 break;
325 case SYMLINK_NEVER_DEREF: /* -P (default) */
326 options.xstat = optionp_stat;
327 /* Can't turn no_leaf_check off because the user might have specified
328 * -noleaf anyway
330 break;
332 case SYMLINK_DEREF_ARGSONLY: /* -H */
333 options.xstat = optionh_stat;
334 options.no_leaf_check = true;
337 options.symlink_handling = opt;
339 /* For DEBUG_STAT, the choice is made at runtime within debug_stat()
340 * by checking the contents of the symlink_handling variable.
342 #if defined(DEBUG_STAT)
343 options.xstat = debug_stat;
344 #endif /* !DEBUG_STAT */
348 void
349 parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
351 (void) args;
352 (void) argno;
353 (void) last;
354 (void) predicates;
355 first_nonoption_arg = NULL;
358 void
359 parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
361 /* does nothing */
362 (void) args;
363 (void) argno;
364 (void) last;
365 (void) predicates;
371 /* Return a pointer to the parser function to invoke for predicate
372 SEARCH_NAME.
373 Return NULL if SEARCH_NAME is not a valid predicate name. */
375 const struct parser_table*
376 find_parser (char *search_name)
378 int i;
379 const char *original_arg = search_name;
381 if (*search_name == '-')
382 search_name++;
383 for (i = 0; parse_table[i].parser_name != 0; i++)
385 if (strcmp (parse_table[i].parser_name, search_name) == 0)
387 /* If this is an option, but we have already had a
388 * non-option argument, the user may be under the
389 * impression that the behaviour of the option
390 * argument is conditional on some preceding
391 * tests. This might typically be the case with,
392 * for example, -maxdepth.
394 * The options -daystart and -follow are exempt
395 * from this treatment, since their positioning
396 * in the command line does have an effect on
397 * subsequent tests but not previous ones. That
398 * might be intentional on the part of the user.
400 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
402 /* Something other than -follow/-daystart.
403 * If this is an option, check if it followed
404 * a non-option and if so, issue a warning.
406 if (parse_table[i].type == ARG_OPTION)
408 if ((first_nonoption_arg != NULL)
409 && options.warnings )
411 /* option which follows a non-option */
412 error (0, 0,
413 _("warning: you have specified the %s "
414 "option after a non-option argument %s, "
415 "but options are not positional (%s affects "
416 "tests specified before it as well as those "
417 "specified after it). Please specify options "
418 "before other arguments.\n"),
419 original_arg,
420 first_nonoption_arg,
421 original_arg);
424 else
426 /* Not an option or a positional option,
427 * so remember we've seen it in order to
428 * use it in a possible future warning message.
430 if (first_nonoption_arg == NULL)
432 first_nonoption_arg = original_arg;
437 return &parse_table[i];
440 return NULL;
443 /* The parsers are responsible to continue scanning ARGV for
444 their arguments. Each parser knows what is and isn't
445 allowed for itself.
447 ARGV is the argument array.
448 *ARG_PTR is the index to start at in ARGV,
449 updated to point beyond the last element consumed.
451 The predicate structure is updated with the new information. */
453 static boolean
454 parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
456 struct predicate *our_pred;
457 uintmax_t num;
458 enum comparison_type c_type;
459 time_t t;
461 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
462 return false;
463 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
464 return false;
465 t = options.cur_day_start + DAYSECS - num * 60;
466 our_pred = insert_primary (entry);
467 our_pred->args.info.kind = c_type;
468 our_pred->args.info.negative = t < 0;
469 our_pred->args.info.l_val = t;
470 (*arg_ptr)++;
471 return true;
474 static boolean
475 parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
477 struct predicate *our_pred;
479 (void) argv;
480 (void) arg_ptr;
482 our_pred = get_new_pred (entry);
483 our_pred->pred_func = pred_and;
484 #ifdef DEBUG
485 our_pred->p_name = find_pred_name (pred_and);
486 #endif /* DEBUG */
487 our_pred->p_type = BI_OP;
488 our_pred->p_prec = AND_PREC;
489 our_pred->need_stat = our_pred->need_type = false;
490 return true;
493 static boolean
494 parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
496 struct predicate *our_pred;
497 struct stat stat_newer;
499 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
500 return false;
501 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
502 error (1, errno, "%s", argv[*arg_ptr]);
503 our_pred = insert_primary (entry);
504 our_pred->args.time = stat_newer.st_mtime;
505 (*arg_ptr)++;
506 return true;
509 static boolean
510 parse_atime (const struct parser_table* entry, char **argv, int *arg_ptr)
512 return insert_time (argv, arg_ptr, entry, pred_atime);
515 boolean
516 parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
518 struct predicate *our_pred;
520 (void) argv;
521 (void) arg_ptr;
523 our_pred = get_new_pred (entry);
524 our_pred->pred_func = pred_close;
525 #ifdef DEBUG
526 our_pred->p_name = find_pred_name (pred_close);
527 #endif /* DEBUG */
528 our_pred->p_type = CLOSE_PAREN;
529 our_pred->p_prec = NO_PREC;
530 our_pred->need_stat = our_pred->need_type = false;
531 return true;
534 static boolean
535 parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
537 struct predicate *our_pred;
538 uintmax_t num;
539 enum comparison_type c_type;
540 time_t t;
542 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
543 return false;
544 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
545 return false;
546 t = options.cur_day_start + DAYSECS - num * 60;
547 our_pred = insert_primary (entry);
548 our_pred->args.info.kind = c_type;
549 our_pred->args.info.negative = t < 0;
550 our_pred->args.info.l_val = t;
551 (*arg_ptr)++;
552 return true;
555 static boolean
556 parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
558 struct predicate *our_pred;
559 struct stat stat_newer;
561 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
562 return false;
563 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
564 error (1, errno, "%s", argv[*arg_ptr]);
565 our_pred = insert_primary (entry);
566 our_pred->args.time = stat_newer.st_mtime;
567 (*arg_ptr)++;
568 return true;
571 static boolean
572 parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
574 struct predicate *our_pred;
576 (void) argv;
577 (void) arg_ptr;
579 our_pred = get_new_pred (entry);
580 our_pred->pred_func = pred_comma;
581 #ifdef DEBUG
582 our_pred->p_name = find_pred_name (pred_comma);
583 #endif /* DEBUG */
584 our_pred->p_type = BI_OP;
585 our_pred->p_prec = COMMA_PREC;
586 our_pred->need_stat = our_pred->need_type = false;
587 return true;
590 static boolean
591 parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr)
593 return insert_time (argv, arg_ptr, entry, pred_ctime);
596 static boolean
597 parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
599 struct tm *local;
601 (void) entry;
602 (void) argv;
603 (void) arg_ptr;
605 if (options.full_days == false)
607 options.cur_day_start += DAYSECS;
608 local = localtime (&options.cur_day_start);
609 options.cur_day_start -= (local
610 ? (local->tm_sec + local->tm_min * 60
611 + local->tm_hour * 3600)
612 : options.cur_day_start % DAYSECS);
613 options.full_days = true;
615 return true;
618 static boolean
619 parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
621 struct predicate *our_pred;
622 (void) argv;
623 (void) arg_ptr;
625 our_pred = insert_primary (entry);
626 our_pred->side_effects = our_pred->no_default_print = true;
627 /* -delete implies -depth */
628 options.do_dir_first = false;
629 return true;
632 static boolean
633 parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
635 (void) entry;
636 (void) argv;
637 (void) arg_ptr;
639 options.do_dir_first = false;
640 return true;
643 static boolean
644 parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
646 (void) argv;
647 (void) arg_ptr;
649 if (options.warnings)
651 error (0, 0,
652 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
654 return parse_depth(entry, argv, arg_ptr);
657 static boolean
658 parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
660 (void) argv;
661 (void) arg_ptr;
663 insert_primary (entry);
664 return true;
667 static boolean
668 parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
670 return insert_exec_ok ("-exec", entry, argv, arg_ptr);
673 static boolean
674 parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
676 return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
679 static boolean
680 parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
682 struct predicate *our_pred;
684 (void) argv;
685 (void) arg_ptr;
687 our_pred = insert_primary (entry);
688 our_pred->need_stat = our_pred->need_type = false;
689 our_pred->side_effects = our_pred->no_default_print = false;
690 return true;
693 static boolean
694 parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
696 struct predicate *our_pred;
698 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
699 return false;
700 our_pred = insert_primary (entry);
701 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
702 our_pred->side_effects = our_pred->no_default_print = true;
703 (*arg_ptr)++;
704 return true;
707 static boolean
708 parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
710 FILE *fp;
712 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
713 return false;
714 if (argv[*arg_ptr + 1] == NULL)
716 /* Ensure we get "missing arg" message, not "invalid arg". */
717 (*arg_ptr)++;
718 return false;
720 fp = open_output_file (argv[*arg_ptr]);
721 (*arg_ptr)++;
722 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
725 static boolean
726 parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
728 (void) entry;
729 (void) argv;
730 (void) arg_ptr;
732 set_follow_state(SYMLINK_ALWAYS_DEREF);
733 return true;
736 static boolean
737 parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
739 struct predicate *our_pred;
741 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
742 return false;
743 our_pred = insert_primary (entry);
744 our_pred->args.printf_vec.segment = NULL;
745 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
746 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
747 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
748 our_pred->side_effects = our_pred->no_default_print = true;
749 our_pred->need_stat = our_pred->need_type = false;
750 (*arg_ptr)++;
751 return true;
754 static boolean
755 parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
757 struct predicate *our_pred;
759 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
760 return false;
761 our_pred = insert_primary (entry);
762 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
763 our_pred->side_effects = our_pred->no_default_print = true;
764 our_pred->need_stat = our_pred->need_type = false;
765 (*arg_ptr)++;
766 return true;
769 static boolean
770 parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
772 struct predicate *our_pred;
774 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
775 return false;
776 our_pred = insert_primary (entry);
777 our_pred->args.str = argv[*arg_ptr];
778 (*arg_ptr)++;
779 return true;
782 static boolean
783 parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
785 return insert_num (argv, arg_ptr, entry);
788 static boolean
789 parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
791 struct group *cur_gr;
792 struct predicate *our_pred;
793 gid_t gid;
794 int gid_len;
796 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
797 return false;
798 cur_gr = getgrnam (argv[*arg_ptr]);
799 endgrent ();
800 if (cur_gr != NULL)
801 gid = cur_gr->gr_gid;
802 else
804 gid_len = strspn (argv[*arg_ptr], "0123456789");
805 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
806 return false;
807 gid = atoi (argv[*arg_ptr]);
809 our_pred = insert_primary (entry);
810 our_pred->args.gid = gid;
811 (*arg_ptr)++;
812 return true;
815 static boolean
816 parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
818 (void) entry;
819 (void) argv;
820 (void) arg_ptr;
822 printf (_("\
823 Usage: %s [path...] [expression]\n"), program_name);
824 puts (_("\n\
825 default path is the current directory; default expression is -print\n\
826 expression may consist of: operators, options, tests, and actions:\n"));
827 puts (_("\
828 operators (decreasing precedence; -and is implicit where no others are given):\n\
829 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
830 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
831 puts (_("\
832 positional options (always true): -daystart -follow -regextype\n\n\
833 normal options (always true, specified before other expressions):\n\
834 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
835 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
836 puts (_("\
837 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
838 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
839 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
840 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
841 puts (_("\
842 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
843 -readable -writable -executable\n\
844 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
845 -used N -user NAME -xtype [bcdpfls]\n"));
846 puts (_("\
847 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
848 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
849 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
850 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
851 "));
852 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
853 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
854 email to <bug-findutils@gnu.org>."));
855 exit (0);
858 static boolean
859 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
861 struct predicate *our_pred;
863 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
864 return false;
865 our_pred = insert_primary (entry);
866 our_pred->args.str = argv[*arg_ptr];
867 (*arg_ptr)++;
868 return true;
872 /* sanity check the fnmatch() function to make sure
873 * it really is the GNU version.
875 static boolean
876 fnmatch_sanitycheck(void)
878 /* fprintf(stderr, "Performing find sanity check..."); */
879 if (0 != fnmatch("foo", "foo", 0)
880 || 0 == fnmatch("Foo", "foo", 0)
881 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
883 error (1, 0, _("sanity check of the fnmatch() library function failed."));
884 /* fprintf(stderr, "FAILED\n"); */
885 return false;
888 /* fprintf(stderr, "OK\n"); */
889 return true;
893 static boolean
894 check_name_arg(const char *pred, const char *arg)
896 if (strchr(arg, '/'))
898 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'."),
899 pred, arg, arg);
901 return true; /* allow it anyway */
906 static boolean
907 parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
909 struct predicate *our_pred;
911 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
912 return false;
913 if (!check_name_arg("-iname", argv[*arg_ptr]))
914 return false;
916 fnmatch_sanitycheck();
918 our_pred = insert_primary (entry);
919 our_pred->need_stat = our_pred->need_type = false;
920 our_pred->args.str = argv[*arg_ptr];
921 (*arg_ptr)++;
922 return true;
925 static boolean
926 parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
928 return insert_num (argv, arg_ptr, entry);
931 /* -ipath is deprecated (at RMS's request) in favour of
932 * -iwholename. See the node "GNU Manuals" in standards.texi
933 * for the rationale for this (basically, GNU prefers the use
934 * of the phrase "file name" to "path name"
936 static boolean
937 parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
939 error (0, 0,
940 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
942 return parse_iwholename(entry, argv, arg_ptr);
945 static boolean
946 parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
948 struct predicate *our_pred;
950 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
951 return false;
953 fnmatch_sanitycheck();
955 our_pred = insert_primary_withpred (entry, pred_ipath);
956 our_pred->need_stat = our_pred->need_type = false;
957 our_pred->args.str = argv[*arg_ptr];
958 (*arg_ptr)++;
959 return true;
962 static boolean
963 parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
965 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
968 static boolean
969 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
971 return insert_num (argv, arg_ptr, entry);
974 static boolean
975 parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
977 struct predicate *our_pred;
979 (void) argv;
980 (void) arg_ptr;
982 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
983 return false;
985 fnmatch_sanitycheck();
987 our_pred = insert_primary (entry);
988 our_pred->args.str = argv[*arg_ptr];
989 (*arg_ptr)++;
990 return true;
993 static boolean
994 parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
996 struct predicate *our_pred;
998 (void) &argv;
999 (void) &arg_ptr;
1001 our_pred = insert_primary (entry);
1002 our_pred->side_effects = our_pred->no_default_print = true;
1003 return true;
1006 static boolean
1007 parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1009 int depth_len;
1010 (void) entry;
1012 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1013 return false;
1014 depth_len = strspn (argv[*arg_ptr], "0123456789");
1015 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1016 return false;
1017 options.maxdepth = atoi (argv[*arg_ptr]);
1018 if (options.maxdepth < 0)
1019 return false;
1020 (*arg_ptr)++;
1021 return true;
1024 static boolean
1025 parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
1027 int depth_len;
1028 (void) entry;
1030 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1031 return false;
1032 depth_len = strspn (argv[*arg_ptr], "0123456789");
1033 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
1034 return false;
1035 options.mindepth = atoi (argv[*arg_ptr]);
1036 if (options.mindepth < 0)
1037 return false;
1038 (*arg_ptr)++;
1039 return true;
1042 static boolean
1043 parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
1045 struct predicate *our_pred;
1046 uintmax_t num;
1047 enum comparison_type c_type;
1048 time_t t;
1050 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1051 return false;
1052 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
1053 return false;
1054 t = options.cur_day_start + DAYSECS - num * 60;
1055 our_pred = insert_primary (entry);
1056 our_pred->args.info.kind = c_type;
1057 our_pred->args.info.negative = t < 0;
1058 our_pred->args.info.l_val = t;
1059 (*arg_ptr)++;
1060 return true;
1063 static boolean
1064 parse_mtime (const struct parser_table* entry, char **argv, int *arg_ptr)
1066 return insert_time (argv, arg_ptr, entry, pred_mtime);
1069 static boolean
1070 parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
1072 struct predicate *our_pred;
1074 (void) argv;
1075 (void) arg_ptr;
1077 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1078 return false;
1079 if (!check_name_arg("-name", argv[*arg_ptr]))
1080 return false;
1081 fnmatch_sanitycheck();
1083 our_pred = insert_primary (entry);
1084 our_pred->need_stat = our_pred->need_type = false;
1085 our_pred->args.str = argv[*arg_ptr];
1086 (*arg_ptr)++;
1087 return true;
1090 static boolean
1091 parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
1093 struct predicate *our_pred;
1095 (void) &argv;
1096 (void) &arg_ptr;
1098 our_pred = get_new_pred_chk_op (entry);
1099 our_pred->pred_func = pred_negate;
1100 #ifdef DEBUG
1101 our_pred->p_name = find_pred_name (pred_negate);
1102 #endif /* DEBUG */
1103 our_pred->p_type = UNI_OP;
1104 our_pred->p_prec = NEGATE_PREC;
1105 our_pred->need_stat = our_pred->need_type = false;
1106 return true;
1109 static boolean
1110 parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
1112 struct predicate *our_pred;
1113 struct stat stat_newer;
1115 (void) argv;
1116 (void) arg_ptr;
1118 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1119 return false;
1120 if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
1121 error (1, errno, "%s", argv[*arg_ptr]);
1122 our_pred = insert_primary (entry);
1123 our_pred->args.time = stat_newer.st_mtime;
1124 (*arg_ptr)++;
1125 return true;
1128 static boolean
1129 parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
1131 (void) &argv;
1132 (void) &arg_ptr;
1133 (void) entry;
1135 options.no_leaf_check = true;
1136 return true;
1139 #ifdef CACHE_IDS
1140 /* Arbitrary amount by which to increase size
1141 of `uid_unused' and `gid_unused'. */
1142 #define ALLOC_STEP 2048
1144 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1145 char *uid_unused = NULL;
1147 /* Number of elements in `uid_unused'. */
1148 unsigned uid_allocated;
1150 /* Similar for GIDs and group entries. */
1151 char *gid_unused = NULL;
1152 unsigned gid_allocated;
1153 #endif
1155 static boolean
1156 parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
1158 struct predicate *our_pred;
1160 (void) &argv;
1161 (void) &arg_ptr;
1163 our_pred = insert_primary (entry);
1164 #ifdef CACHE_IDS
1165 if (gid_unused == NULL)
1167 struct group *gr;
1169 gid_allocated = ALLOC_STEP;
1170 gid_unused = xmalloc (gid_allocated);
1171 memset (gid_unused, 1, gid_allocated);
1172 setgrent ();
1173 while ((gr = getgrent ()) != NULL)
1175 if ((unsigned) gr->gr_gid >= gid_allocated)
1177 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1178 gid_unused = xrealloc (gid_unused, new_allocated);
1179 memset (gid_unused + gid_allocated, 1,
1180 new_allocated - gid_allocated);
1181 gid_allocated = new_allocated;
1183 gid_unused[(unsigned) gr->gr_gid] = 0;
1185 endgrent ();
1187 #endif
1188 return true;
1191 static boolean
1192 parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
1194 struct predicate *our_pred;
1195 (void) argv;
1196 (void) arg_ptr;
1199 our_pred = insert_primary (entry);
1200 #ifdef CACHE_IDS
1201 if (uid_unused == NULL)
1203 struct passwd *pw;
1205 uid_allocated = ALLOC_STEP;
1206 uid_unused = xmalloc (uid_allocated);
1207 memset (uid_unused, 1, uid_allocated);
1208 setpwent ();
1209 while ((pw = getpwent ()) != NULL)
1211 if ((unsigned) pw->pw_uid >= uid_allocated)
1213 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1214 uid_unused = xrealloc (uid_unused, new_allocated);
1215 memset (uid_unused + uid_allocated, 1,
1216 new_allocated - uid_allocated);
1217 uid_allocated = new_allocated;
1219 uid_unused[(unsigned) pw->pw_uid] = 0;
1221 endpwent ();
1223 #endif
1224 return true;
1227 static boolean
1228 parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
1230 (void) argv;
1231 (void) arg_ptr;
1232 (void) entry;
1234 options.warnings = false;
1235 return true;;
1238 static boolean
1239 parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
1241 return insert_exec_ok ("-ok", entry, argv, arg_ptr);
1244 static boolean
1245 parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
1247 return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
1250 boolean
1251 parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
1253 struct predicate *our_pred;
1255 (void) argv;
1256 (void) arg_ptr;
1258 our_pred = get_new_pred_chk_op (entry);
1259 our_pred->pred_func = pred_open;
1260 #ifdef DEBUG
1261 our_pred->p_name = find_pred_name (pred_open);
1262 #endif /* DEBUG */
1263 our_pred->p_type = OPEN_PAREN;
1264 our_pred->p_prec = NO_PREC;
1265 our_pred->need_stat = our_pred->need_type = false;
1266 return true;
1269 static boolean
1270 parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
1272 struct predicate *our_pred;
1274 (void) argv;
1275 (void) arg_ptr;
1277 our_pred = get_new_pred (entry);
1278 our_pred->pred_func = pred_or;
1279 #ifdef DEBUG
1280 our_pred->p_name = find_pred_name (pred_or);
1281 #endif /* DEBUG */
1282 our_pred->p_type = BI_OP;
1283 our_pred->p_prec = OR_PREC;
1284 our_pred->need_stat = our_pred->need_type = false;
1285 return true;
1288 /* -path is deprecated (at RMS's request) in favour of
1289 * -iwholename. See the node "GNU Manuals" in standards.texi
1290 * for the rationale for this (basically, GNU prefers the use
1291 * of the phrase "file name" to "path name".
1293 * We do not issue a warning that this usage is deprecated
1294 * since HPUX find supports this predicate also.
1296 static boolean
1297 parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
1299 return parse_wholename(entry, argv, arg_ptr);
1302 static boolean
1303 parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
1305 struct predicate *our_pred;
1307 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1308 return false;
1309 our_pred = insert_primary_withpred (entry, pred_path);
1310 our_pred->need_stat = our_pred->need_type = false;
1311 our_pred->args.str = argv[*arg_ptr];
1312 (*arg_ptr)++;
1313 return true;
1316 static boolean
1317 parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
1319 mode_t perm_val;
1320 int mode_start = 0;
1321 boolean havekind = false;
1322 enum permissions_type kind = PERM_EXACT;
1323 struct mode_change *change = NULL;
1324 struct predicate *our_pred;
1326 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1327 return false;
1329 switch (argv[*arg_ptr][0])
1331 case '-':
1332 mode_start = 1;
1333 kind = PERM_AT_LEAST;
1334 havekind = true;
1335 break;
1337 case '+':
1338 change = mode_compile (argv[*arg_ptr]);
1339 if (NULL == change)
1341 /* Most likely the caller is an old script that is still
1342 * using the obsolete GNU syntax '-perm +MODE'. This old
1343 * syntax was withdrawn in favor of '-perm /MODE' because
1344 * it is incompatible with POSIX in some cases, but we
1345 * still support uses of it that are not incompatible with
1346 * POSIX.
1348 mode_start = 1;
1349 kind = PERM_ANY;
1351 else
1353 /* This is a POSIX-compatible usage */
1354 mode_start = 0;
1355 kind = PERM_EXACT;
1357 havekind = true;
1358 break;
1360 case '/': /* GNU extension */
1361 mode_start = 1;
1362 kind = PERM_ANY;
1363 havekind = true;
1364 break;
1366 default:
1367 /* For example, '-perm 0644', which is valid and matches
1368 * only files whose mode is exactly 0644.
1370 * We do nothing here, because mode_start and kind are already
1371 * correctly set.
1373 break;
1376 if (NULL == change)
1378 change = mode_compile (argv[*arg_ptr] + mode_start);
1379 if (NULL == change)
1380 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1382 perm_val = mode_adjust (0, change, 0);
1383 free (change);
1385 our_pred = insert_primary (entry);
1387 if (havekind)
1389 our_pred->args.perm.kind = kind;
1391 else
1394 switch (argv[*arg_ptr][0])
1396 case '-':
1397 our_pred->args.perm.kind = PERM_AT_LEAST;
1398 break;
1399 case '+':
1400 our_pred->args.perm.kind = PERM_ANY;
1401 break;
1402 default:
1403 our_pred->args.perm.kind = PERM_EXACT;
1404 break;
1407 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val))
1409 /* The meaning of -perm /000 will change in the future.
1410 * It currently matches no files, but like -perm -000 it
1411 * should match all files.
1413 error (0, 0,
1414 _("warning: you have specified a mode pattern %s which is "
1415 "equivalent to 000. The meaning of -perm /000 will soon be "
1416 "changed to be consistent with -perm -000; that is, at the "
1417 "moment it matches no files but it will soon be changed to "
1418 "match all files."),
1419 argv[*arg_ptr]);
1422 our_pred->args.perm.val = perm_val & MODE_ALL;
1423 (*arg_ptr)++;
1424 return true;
1427 boolean
1428 parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
1430 struct predicate *our_pred;
1432 (void) argv;
1433 (void) arg_ptr;
1435 our_pred = insert_primary (entry);
1436 /* -print has the side effect of printing. This prevents us
1437 from doing undesired multiple printing when the user has
1438 already specified -print. */
1439 our_pred->side_effects = our_pred->no_default_print = true;
1440 our_pred->need_stat = our_pred->need_type = false;
1441 our_pred->args.printf_vec.segment = NULL;
1442 our_pred->args.printf_vec.stream = stdout;
1443 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
1444 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1446 return true;
1449 static boolean
1450 parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
1452 struct predicate *our_pred;
1454 (void) argv;
1455 (void) arg_ptr;
1457 our_pred = insert_primary (entry);
1458 /* -print0 has the side effect of printing. This prevents us
1459 from doing undesired multiple printing when the user has
1460 already specified -print0. */
1461 our_pred->side_effects = our_pred->no_default_print = true;
1462 our_pred->need_stat = our_pred->need_type = false;
1463 return true;
1466 static boolean
1467 parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
1469 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1470 return false;
1471 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
1474 static boolean
1475 parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
1477 struct predicate *our_pred;
1479 (void) argv;
1480 (void) arg_ptr;
1482 our_pred = insert_primary (entry);
1483 our_pred->need_stat = our_pred->need_type = false;
1484 /* -prune has a side effect that it does not descend into
1485 the current directory. */
1486 our_pred->side_effects = true;
1487 our_pred->no_default_print = false;
1488 return true;
1491 static boolean
1492 parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
1494 struct predicate *our_pred = insert_primary (entry);
1495 (void) argv;
1496 (void) arg_ptr;
1497 our_pred->need_stat = our_pred->need_type = false;
1498 our_pred->side_effects = true; /* Exiting is a side effect... */
1499 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
1500 return true;
1504 static boolean
1505 parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
1507 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1508 return false;
1510 /* collect the regex type name */
1511 options.regex_options = get_regex_type(argv[*arg_ptr]);
1512 (*arg_ptr)++;
1514 return true;
1518 static boolean
1519 parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
1521 return insert_regex (argv, arg_ptr, entry, options.regex_options);
1524 static boolean
1525 insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
1527 struct predicate *our_pred;
1528 struct re_pattern_buffer *re;
1529 const char *error_message;
1531 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1532 return false;
1533 our_pred = insert_primary_withpred (entry, pred_regex);
1534 our_pred->need_stat = our_pred->need_type = false;
1535 re = (struct re_pattern_buffer *)
1536 xmalloc (sizeof (struct re_pattern_buffer));
1537 our_pred->args.regex = re;
1538 re->allocated = 100;
1539 re->buffer = (unsigned char *) xmalloc (re->allocated);
1540 re->fastmap = NULL;
1542 re_set_syntax(regex_options);
1543 re->syntax = regex_options;
1544 re->translate = NULL;
1546 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1547 re);
1548 if (error_message)
1549 error (1, 0, "%s", error_message);
1550 (*arg_ptr)++;
1551 return true;
1554 static boolean
1555 parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
1557 struct predicate *our_pred;
1558 uintmax_t num;
1559 enum comparison_type c_type;
1560 int blksize = 512;
1561 int len;
1563 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1564 return false;
1565 len = strlen (argv[*arg_ptr]);
1566 if (len == 0)
1567 error (1, 0, _("invalid null argument to -size"));
1568 switch (argv[*arg_ptr][len - 1])
1570 case 'b':
1571 blksize = 512;
1572 argv[*arg_ptr][len - 1] = '\0';
1573 break;
1575 case 'c':
1576 blksize = 1;
1577 argv[*arg_ptr][len - 1] = '\0';
1578 break;
1580 case 'k':
1581 blksize = 1024;
1582 argv[*arg_ptr][len - 1] = '\0';
1583 break;
1585 case 'M': /* Megabytes */
1586 blksize = 1024*1024;
1587 argv[*arg_ptr][len - 1] = '\0';
1588 break;
1590 case 'G': /* Gigabytes */
1591 blksize = 1024*1024*1024;
1592 argv[*arg_ptr][len - 1] = '\0';
1593 break;
1595 case 'w':
1596 blksize = 2;
1597 argv[*arg_ptr][len - 1] = '\0';
1598 break;
1600 case '0':
1601 case '1':
1602 case '2':
1603 case '3':
1604 case '4':
1605 case '5':
1606 case '6':
1607 case '7':
1608 case '8':
1609 case '9':
1610 break;
1612 default:
1613 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1615 if (!get_num (argv[*arg_ptr], &num, &c_type))
1616 return false;
1617 our_pred = insert_primary (entry);
1618 our_pred->args.size.kind = c_type;
1619 our_pred->args.size.blocksize = blksize;
1620 our_pred->args.size.size = num;
1621 (*arg_ptr)++;
1622 return true;
1626 static boolean
1627 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
1629 struct predicate *our_pred;
1630 struct stat st;
1632 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1633 return false;
1634 if ((*options.xstat) (argv[*arg_ptr], &st))
1635 error (1, errno, "%s", argv[*arg_ptr]);
1637 our_pred = insert_primary (entry);
1638 our_pred->args.fileid.ino = st.st_ino;
1639 our_pred->args.fileid.dev = st.st_dev;
1640 our_pred->need_type = false;
1641 our_pred->need_stat = true;
1642 (*arg_ptr)++;
1643 return true;
1646 #if 0
1647 static boolean
1648 parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
1650 const char *arg;
1651 const char *errmsg = _("The -show-control-chars option takes a single argument which "
1652 "must be 'literal' or 'safe'");
1654 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1656 error (1, errno, "%s", errmsg);
1657 return false;
1659 else
1661 arg = argv[*arg_ptr];
1663 if (0 == strcmp("literal", arg))
1665 options.literal_control_chars = true;
1667 else if (0 == strcmp("safe", arg))
1669 options.literal_control_chars = false;
1671 else
1673 error (1, errno, "%s", errmsg);
1674 return false;
1676 (*arg_ptr)++; /* consume the argument. */
1677 return true;
1680 #endif
1683 static boolean
1684 parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
1686 struct predicate *our_pred;
1688 (void) argv;
1689 (void) arg_ptr;
1691 our_pred = insert_primary (entry);
1692 our_pred->need_stat = our_pred->need_type = false;
1693 return true;
1696 static boolean
1697 insert_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
1699 struct predicate *our_pred;
1700 (void) argv;
1701 (void) arg_ptr;
1702 our_pred = insert_primary (entry);
1703 our_pred->need_stat = our_pred->need_type = false;
1704 our_pred->side_effects = our_pred->no_default_print = false;
1705 return true;
1708 static boolean
1709 parse_executable (const struct parser_table* entry, char **argv, int *arg_ptr)
1711 return insert_accesscheck(entry, argv, arg_ptr);
1714 static boolean
1715 parse_readable (const struct parser_table* entry, char **argv, int *arg_ptr)
1717 return insert_accesscheck(entry, argv, arg_ptr);
1720 static boolean
1721 parse_writable (const struct parser_table* entry, char **argv, int *arg_ptr)
1723 return insert_accesscheck(entry, argv, arg_ptr);
1726 static boolean
1727 parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
1729 return insert_type (argv, arg_ptr, entry, pred_type);
1732 static boolean
1733 parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
1735 return insert_num (argv, arg_ptr, entry);
1738 static boolean
1739 parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
1741 struct predicate *our_pred;
1742 uintmax_t num_days;
1743 enum comparison_type c_type;
1744 time_t t;
1746 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1747 return false;
1748 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1749 return false;
1750 t = num_days * DAYSECS;
1751 our_pred = insert_primary (entry);
1752 our_pred->args.info.kind = c_type;
1753 our_pred->args.info.negative = t < 0;
1754 our_pred->args.info.l_val = t;
1755 (*arg_ptr)++;
1756 return true;
1759 static boolean
1760 parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
1762 struct passwd *cur_pwd;
1763 struct predicate *our_pred;
1764 uid_t uid;
1765 int uid_len;
1767 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1768 return false;
1769 cur_pwd = getpwnam (argv[*arg_ptr]);
1770 endpwent ();
1771 if (cur_pwd != NULL)
1772 uid = cur_pwd->pw_uid;
1773 else
1775 uid_len = strspn (argv[*arg_ptr], "0123456789");
1776 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1777 return false;
1778 uid = atoi (argv[*arg_ptr]);
1780 our_pred = insert_primary (entry);
1781 our_pred->args.uid = uid;
1782 (*arg_ptr)++;
1783 return true;
1786 static boolean
1787 parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
1789 extern char *version_string;
1790 int features = 0;
1792 (void) argv;
1793 (void) arg_ptr;
1794 (void) entry;
1796 fflush (stderr);
1797 printf (_("GNU find version %s\n"), version_string);
1798 printf (_("Features enabled: "));
1800 #if CACHE_IDS
1801 printf("CACHE_IDS ");
1802 ++features;
1803 #endif
1804 #if DEBUG
1805 printf("DEBUG ");
1806 ++features;
1807 #endif
1808 #if DEBUG_STAT
1809 printf("DEBUG_STAT ");
1810 ++features;
1811 #endif
1812 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1813 printf("D_TYPE ");
1814 ++features;
1815 #endif
1816 #if defined(O_NOFOLLOW)
1817 printf("O_NOFOLLOW(%s) ",
1818 (options.open_nofollow_available ? "enabled" : "disabled"));
1819 ++features;
1820 #endif
1821 #if defined(LEAF_OPTIMISATION)
1822 printf("LEAF_OPTIMISATION ");
1823 ++features;
1824 #endif
1826 if (is_fts_enabled())
1828 printf("FTS ");
1829 ++features;
1832 if (0 == features)
1834 /* For the moment, leave this as English in case someone wants
1835 to parse these strings. */
1836 printf("none");
1838 printf("\n");
1840 exit (0);
1843 static boolean
1844 parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
1846 (void) argv;
1847 (void) arg_ptr;
1848 (void) entry;
1849 options.stay_on_filesystem = true;
1850 return true;
1853 static boolean
1854 parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1856 (void) argv;
1857 (void) arg_ptr;
1858 (void) entry;
1859 options.ignore_readdir_race = true;
1860 return true;
1863 static boolean
1864 parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
1866 (void) argv;
1867 (void) arg_ptr;
1868 (void) entry;
1869 options.ignore_readdir_race = false;
1870 return true;
1873 static boolean
1874 parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
1876 (void) argv;
1877 (void) arg_ptr;
1878 (void) entry;
1879 options.warnings = true;
1880 return true;
1883 static boolean
1884 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
1886 (void) argv;
1887 (void) arg_ptr;
1888 return insert_type (argv, arg_ptr, entry, pred_xtype);
1891 static boolean
1892 insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
1894 mode_t type_cell;
1895 struct predicate *our_pred;
1897 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1898 || (strlen (argv[*arg_ptr]) != 1))
1899 return false;
1900 switch (argv[*arg_ptr][0])
1902 case 'b': /* block special */
1903 type_cell = S_IFBLK;
1904 break;
1905 case 'c': /* character special */
1906 type_cell = S_IFCHR;
1907 break;
1908 case 'd': /* directory */
1909 type_cell = S_IFDIR;
1910 break;
1911 case 'f': /* regular file */
1912 type_cell = S_IFREG;
1913 break;
1914 #ifdef S_IFLNK
1915 case 'l': /* symbolic link */
1916 type_cell = S_IFLNK;
1917 break;
1918 #endif
1919 #ifdef S_IFIFO
1920 case 'p': /* pipe */
1921 type_cell = S_IFIFO;
1922 break;
1923 #endif
1924 #ifdef S_IFSOCK
1925 case 's': /* socket */
1926 type_cell = S_IFSOCK;
1927 break;
1928 #endif
1929 #ifdef S_IFDOOR
1930 case 'D': /* Solaris door */
1931 type_cell = S_IFDOOR;
1932 break;
1933 #endif
1934 default: /* None of the above ... nuke 'em. */
1935 return false;
1937 our_pred = insert_primary_withpred (entry, which_pred);
1939 /* Figure out if we will need to stat the file, because if we don't
1940 * need to follow symlinks, we can avoid a stat call by using
1941 * struct dirent.d_type.
1943 if (which_pred == pred_xtype)
1945 our_pred->need_stat = true;
1946 our_pred->need_type = false;
1948 else
1950 our_pred->need_stat = false; /* struct dirent is enough */
1951 our_pred->need_type = true;
1953 our_pred->args.type = type_cell;
1954 (*arg_ptr)++; /* Move on to next argument. */
1955 return true;
1959 /* Return true if the file accessed via FP is a terminal.
1961 static boolean
1962 stream_is_tty(FILE *fp)
1964 int fd = fileno(fp);
1965 if (-1 == fd)
1967 return false; /* not a valid stream */
1969 else
1971 return isatty(fd) ? true : false;
1978 /* If true, we've determined that the current fprintf predicate
1979 uses stat information. */
1980 static boolean fprintf_stat_needed;
1982 /* XXX: do we need to pass FUNC to this function? */
1983 static boolean
1984 insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
1986 char *format; /* Beginning of unprocessed format string. */
1987 register char *scan; /* Current address in scanning `format'. */
1988 register char *scan2; /* Address inside of element being scanned. */
1989 struct segment **segmentp; /* Address of current segment. */
1990 struct predicate *our_pred;
1992 format = argv[(*arg_ptr)++];
1994 fprintf_stat_needed = false; /* Might be overridden later. */
1995 our_pred = insert_primary_withpred (entry, func);
1996 our_pred->side_effects = our_pred->no_default_print = true;
1997 our_pred->args.printf_vec.stream = fp;
1998 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
1999 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
2000 segmentp = &our_pred->args.printf_vec.segment;
2001 *segmentp = NULL;
2003 for (scan = format; *scan; scan++)
2005 if (*scan == '\\')
2007 scan2 = scan + 1;
2008 if (*scan2 >= '0' && *scan2 <= '7')
2010 register int n, i;
2012 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
2013 i++, scan2++)
2014 n = 8 * n + *scan2 - '0';
2015 scan2--;
2016 *scan = n;
2018 else
2020 switch (*scan2)
2022 case 'a':
2023 *scan = 7;
2024 break;
2025 case 'b':
2026 *scan = '\b';
2027 break;
2028 case 'c':
2029 make_segment (segmentp, format, scan - format, KIND_STOP);
2030 our_pred->need_stat = fprintf_stat_needed;
2031 return true;
2032 case 'f':
2033 *scan = '\f';
2034 break;
2035 case 'n':
2036 *scan = '\n';
2037 break;
2038 case 'r':
2039 *scan = '\r';
2040 break;
2041 case 't':
2042 *scan = '\t';
2043 break;
2044 case 'v':
2045 *scan = '\v';
2046 break;
2047 case '\\':
2048 /* *scan = '\\'; * it already is */
2049 break;
2050 default:
2051 error (0, 0,
2052 _("warning: unrecognized escape `\\%c'"), *scan2);
2053 scan++;
2054 continue;
2057 segmentp = make_segment (segmentp, format, scan - format + 1,
2058 KIND_PLAIN);
2059 format = scan2 + 1; /* Move past the escape. */
2060 scan = scan2; /* Incremented immediately by `for'. */
2062 else if (*scan == '%')
2064 if (scan[1] == '%')
2066 segmentp = make_segment (segmentp, format, scan - format + 1,
2067 KIND_PLAIN);
2068 scan++;
2069 format = scan + 1;
2070 continue;
2072 /* Scan past flags, width and precision, to verify kind. */
2073 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
2074 /* Do nothing. */ ;
2075 while (ISDIGIT (*scan2))
2076 scan2++;
2077 if (*scan2 == '.')
2078 for (scan2++; ISDIGIT (*scan2); scan2++)
2079 /* Do nothing. */ ;
2080 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
2082 segmentp = make_segment (segmentp, format, scan2 - format,
2083 (int) *scan2);
2084 scan = scan2;
2085 format = scan + 1;
2087 else if (strchr ("ACT", *scan2) && scan2[1])
2089 segmentp = make_segment (segmentp, format, scan2 - format,
2090 *scan2 | (scan2[1] << 8));
2091 scan = scan2 + 1;
2092 format = scan + 1;
2093 continue;
2095 else
2097 /* An unrecognized % escape. Print the char after the %. */
2098 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2099 *scan2);
2100 segmentp = make_segment (segmentp, format, scan - format,
2101 KIND_PLAIN);
2102 format = scan + 1;
2103 continue;
2108 if (scan > format)
2109 make_segment (segmentp, format, scan - format, KIND_PLAIN);
2110 our_pred->need_type = false;
2111 our_pred->need_stat = fprintf_stat_needed;
2112 return true;
2115 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2116 from the text in FORMAT, which has length LEN.
2117 Return the address of the `next' pointer of the new segment. */
2119 static struct segment **
2120 make_segment (struct segment **segment, char *format, int len, int kind)
2122 char *fmt;
2124 *segment = (struct segment *) xmalloc (sizeof (struct segment));
2126 (*segment)->kind = kind;
2127 (*segment)->next = NULL;
2128 (*segment)->text_len = len;
2130 fmt = (*segment)->text = xmalloc (len + sizeof "d");
2131 strncpy (fmt, format, len);
2132 fmt += len;
2134 switch (kind & 0xff)
2136 case KIND_PLAIN: /* Plain text string, no % conversion. */
2137 case KIND_STOP: /* Terminate argument, no newline. */
2138 break;
2140 case 'a': /* atime in `ctime' format */
2141 case 'A': /* atime in user-specified strftime format */
2142 case 'c': /* ctime in `ctime' format */
2143 case 'C': /* ctime in user-specified strftime format */
2144 case 'F': /* filesystem type */
2145 case 'g': /* group name */
2146 case 'i': /* inode number */
2147 case 'l': /* object of symlink */
2148 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2149 case 's': /* size in bytes */
2150 case 't': /* mtime in `ctime' format */
2151 case 'T': /* mtime in user-specified strftime format */
2152 case 'u': /* user name */
2153 case 'y': /* file type */
2154 case 'Y': /* symlink pointed file type */
2155 fprintf_stat_needed = true;
2156 /* FALLTHROUGH */
2157 case 'f': /* basename of path */
2158 case 'h': /* leading directories part of path */
2159 case 'H': /* ARGV element file was found under */
2160 case 'p': /* pathname */
2161 case 'P': /* pathname with ARGV element stripped */
2162 *fmt++ = 's';
2163 break;
2165 /* Numeric items that one might expect to honour
2166 * #, 0, + flags but which do not.
2168 case 'G': /* GID number */
2169 case 'U': /* UID number */
2170 case 'b': /* size in 512-byte blocks */
2171 case 'D': /* Filesystem device on which the file exits */
2172 case 'k': /* size in 1K blocks */
2173 case 'n': /* number of links */
2174 fprintf_stat_needed = true;
2175 *fmt++ = 's';
2176 break;
2178 /* Numeric items that DO honour #, 0, + flags.
2180 case 'd': /* depth in search tree (0 = ARGV element) */
2181 *fmt++ = 'd';
2182 break;
2184 case 'm': /* mode as octal number (perms only) */
2185 *fmt++ = 'o';
2186 fprintf_stat_needed = true;
2187 break;
2189 *fmt = '\0';
2191 return &(*segment)->next;
2194 static void
2195 check_path_safety(const char *action)
2197 const char *path = getenv("PATH");
2198 char *s;
2199 s = next_element(path, 1);
2200 while ((s = next_element ((char *) NULL, 1)) != NULL)
2202 if (0 == strcmp(s, "."))
2204 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)"),
2205 action);
2211 /* handles both exec and ok predicate */
2212 #if defined(NEW_EXEC)
2213 /* handles both exec and ok predicate */
2214 static boolean
2215 new_insert_exec_ok (const char *action,
2216 const struct parser_table *entry,
2217 char **argv,
2218 int *arg_ptr)
2220 int start, end; /* Indexes in ARGV of start & end of cmd. */
2221 int i; /* Index into cmd args */
2222 int saw_braces; /* True if previous arg was '{}'. */
2223 boolean allow_plus; /* True if + is a valid terminator */
2224 int brace_count; /* Number of instances of {}. */
2225 PRED_FUNC func = entry->pred_func;
2227 struct predicate *our_pred;
2228 struct exec_val *execp; /* Pointer for efficiency. */
2230 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2231 return false;
2233 our_pred = insert_primary_withpred (entry, func);
2234 our_pred->side_effects = our_pred->no_default_print = true;
2235 execp = &our_pred->args.exec_vec;
2237 if ((func != pred_okdir) && (func != pred_ok))
2239 allow_plus = true;
2240 execp->close_stdin = false;
2242 else
2244 allow_plus = false;
2245 /* If find reads stdin (i.e. for -ok and similar), close stdin
2246 * in the child to prevent some script from consiming the output
2247 * intended for find.
2249 execp->close_stdin = true;
2253 if ((func == pred_execdir) || (func == pred_okdir))
2255 options.ignore_readdir_race = false;
2256 check_path_safety(action);
2257 execp->use_current_dir = true;
2259 else
2261 execp->use_current_dir = false;
2264 our_pred->args.exec_vec.multiple = 0;
2266 /* Count the number of args with path replacements, up until the ';'.
2267 * Also figure out if the command is terminated by ";" or by "+".
2269 start = *arg_ptr;
2270 for (end = start, saw_braces=0, brace_count=0;
2271 (argv[end] != NULL)
2272 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2273 end++)
2275 /* For -exec and -execdir, "{} +" can terminate the command. */
2276 if ( allow_plus
2277 && argv[end][0] == '+' && argv[end][1] == 0
2278 && saw_braces)
2280 our_pred->args.exec_vec.multiple = 1;
2281 break;
2284 saw_braces = 0;
2285 if (strstr (argv[end], "{}"))
2287 saw_braces = 1;
2288 ++brace_count;
2290 if (0 == end && (func == pred_execdir || func == pred_okdir))
2292 /* The POSIX standard says that {} replacement should
2293 * occur even in the utility name. This is insecure
2294 * since it means we will be executing a command whose
2295 * name is chosen according to whatever find finds in
2296 * the filesystem. That can be influenced by an
2297 * attacker. Hence for -execdir and -okdir this is not
2298 * allowed. We can specify this as those options are
2299 * not defined by POSIX.
2301 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2306 /* Fail if no command given or no semicolon found. */
2307 if ((end == start) || (argv[end] == NULL))
2309 *arg_ptr = end;
2310 free(our_pred);
2311 return false;
2314 if (our_pred->args.exec_vec.multiple && brace_count > 1)
2317 const char *suffix;
2318 if (func == pred_execdir)
2319 suffix = "dir";
2320 else
2321 suffix = "";
2323 error(1, 0,
2324 _("Only one instance of {} is supported with -exec%s ... +"),
2325 suffix);
2328 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2329 bc_init_controlinfo(&execp->ctl);
2330 execp->ctl.exec_callback = launch;
2332 if (our_pred->args.exec_vec.multiple)
2334 /* "+" terminator, so we can just append our arguments after the
2335 * command and initial arguments.
2337 execp->replace_vec = NULL;
2338 execp->ctl.replace_pat = NULL;
2339 execp->ctl.rplen = 0;
2340 execp->ctl.lines_per_exec = 0; /* no limit */
2341 execp->ctl.args_per_exec = 0; /* no limit */
2343 /* remember how many arguments there are */
2344 execp->ctl.initial_argc = (end-start) - 1;
2346 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2347 bc_init_state(&execp->ctl, &execp->state, execp);
2349 /* Gather the initial arguments. Skip the {}. */
2350 for (i=start; i<end-1; ++i)
2352 bc_push_arg(&execp->ctl, &execp->state,
2353 argv[i], strlen(argv[i])+1,
2354 NULL, 0,
2358 else
2360 /* Semicolon terminator - more than one {} is supported, so we
2361 * have to do brace-replacement.
2363 execp->num_args = end - start;
2365 execp->ctl.replace_pat = "{}";
2366 execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2367 execp->ctl.lines_per_exec = 0; /* no limit */
2368 execp->ctl.args_per_exec = 0; /* no limit */
2369 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2372 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2373 bc_init_state(&execp->ctl, &execp->state, execp);
2375 /* Remember the (pre-replacement) arguments for later. */
2376 for (i=0; i<execp->num_args; ++i)
2378 execp->replace_vec[i] = argv[i+start];
2382 if (argv[end] == NULL)
2383 *arg_ptr = end;
2384 else
2385 *arg_ptr = end + 1;
2387 return true;
2389 #else
2390 /* handles both exec and ok predicate */
2391 static boolean
2392 old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
2394 int start, end; /* Indexes in ARGV of start & end of cmd. */
2395 int num_paths; /* Number of args with path replacements. */
2396 int path_pos; /* Index in array of path replacements. */
2397 int vec_pos; /* Index in array of args. */
2398 struct predicate *our_pred;
2399 struct exec_val *execp; /* Pointer for efficiency. */
2401 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2402 return false;
2404 /* Count the number of args with path replacements, up until the ';'. */
2405 start = *arg_ptr;
2406 for (end = start, num_paths = 0;
2407 (argv[end] != NULL)
2408 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2409 end++)
2410 if (strstr (argv[end], "{}"))
2411 num_paths++;
2412 /* Fail if no command given or no semicolon found. */
2413 if ((end == start) || (argv[end] == NULL))
2415 *arg_ptr = end;
2416 return false;
2419 our_pred = insert_primary (func);
2420 our_pred->side_effects = our_pred->no_default_print = true;
2421 execp = &our_pred->args.exec_vec;
2422 execp->usercontext = our_pred;
2423 execp->use_current_dir = false;
2424 execp->paths =
2425 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
2426 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
2427 /* Record the positions of all args, and the args with path replacements. */
2428 for (end = start, path_pos = vec_pos = 0;
2429 (argv[end] != NULL)
2430 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2431 end++)
2433 register char *p;
2435 execp->paths[path_pos].count = 0;
2436 for (p = argv[end]; *p; ++p)
2437 if (p[0] == '{' && p[1] == '}')
2439 execp->paths[path_pos].count++;
2440 ++p;
2442 if (execp->paths[path_pos].count)
2444 execp->paths[path_pos].offset = vec_pos;
2445 execp->paths[path_pos].origarg = argv[end];
2446 path_pos++;
2448 execp->vec[vec_pos++] = argv[end];
2450 execp->paths[path_pos].offset = -1;
2451 execp->vec[vec_pos] = NULL;
2453 if (argv[end] == NULL)
2454 *arg_ptr = end;
2455 else
2456 *arg_ptr = end + 1;
2457 return true;
2459 #endif
2463 static boolean
2464 insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
2466 #if defined(NEW_EXEC)
2467 return new_insert_exec_ok(action, entry, argv, arg_ptr);
2468 #else
2469 return old_insert_exec_ok(func, argv, arg_ptr);
2470 #endif
2475 /* Get a number of days and comparison type.
2476 STR is the ASCII representation.
2477 Set *NUM_DAYS to the number of days, taken as being from
2478 the current moment (or possibly midnight). Thus the sense of the
2479 comparison type appears to be reversed.
2480 Set *COMP_TYPE to the kind of comparison that is requested.
2482 Return true if all okay, false if input error.
2484 Used by -atime, -ctime and -mtime (parsers) to
2485 get the appropriate information for a time predicate processor. */
2487 static boolean
2488 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
2490 boolean r = get_num (str, num_days, comp_type);
2491 if (r)
2492 switch (*comp_type)
2494 case COMP_LT: *comp_type = COMP_GT; break;
2495 case COMP_GT: *comp_type = COMP_LT; break;
2496 default: break;
2498 return r;
2501 /* Insert a time predicate PRED.
2502 ARGV is a pointer to the argument array.
2503 ARG_PTR is a pointer to an index into the array, incremented if
2504 all went well.
2506 Return true if input is valid, false if not.
2508 A new predicate node is assigned, along with an argument node
2509 obtained with malloc.
2511 Used by -atime, -ctime, and -mtime parsers. */
2513 static boolean
2514 insert_time (char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred)
2516 struct predicate *our_pred;
2517 uintmax_t num_days;
2518 enum comparison_type c_type;
2519 time_t t;
2521 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2522 return false;
2523 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
2524 return false;
2526 /* Figure out the timestamp value we are looking for. */
2527 t = ( options.cur_day_start - num_days * DAYSECS
2528 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2530 if (1)
2532 /* We introduce a scope in which 'val' can be declared, for the
2533 * benefit of compilers that are really C89 compilers
2534 * which support intmax_t because config.h #defines it
2536 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
2537 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
2538 t = val;
2540 /* Check for possibility of an overflow */
2541 if ( (intmax_t)t != val )
2543 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
2547 our_pred = insert_primary_withpred (entry, pred);
2548 our_pred->args.info.kind = c_type;
2549 our_pred->args.info.negative = t < 0;
2550 our_pred->args.info.l_val = t;
2551 (*arg_ptr)++;
2552 #ifdef DEBUG
2553 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2554 fprintf (stderr, " type: %s %s ",
2555 (c_type == COMP_GT) ? "gt" :
2556 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2557 (c_type == COMP_GT) ? " >" :
2558 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
2559 t = our_pred->args.info.l_val;
2560 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2561 if (c_type == COMP_EQ)
2563 t = our_pred->args.info.l_val += DAYSECS;
2564 fprintf (stderr, " < %ju %s",
2565 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
2566 our_pred->args.info.l_val -= DAYSECS;
2568 #endif /* DEBUG */
2569 return true;
2572 /* Get a number with comparison information.
2573 The sense of the comparison information is 'normal'; that is,
2574 '+' looks for a count > than the number and '-' less than.
2576 STR is the ASCII representation of the number.
2577 Set *NUM to the number.
2578 Set *COMP_TYPE to the kind of comparison that is requested.
2580 Return true if all okay, false if input error. */
2582 static boolean
2583 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
2585 if (str == NULL)
2586 return false;
2587 switch (str[0])
2589 case '+':
2590 *comp_type = COMP_GT;
2591 str++;
2592 break;
2593 case '-':
2594 *comp_type = COMP_LT;
2595 str++;
2596 break;
2597 default:
2598 *comp_type = COMP_EQ;
2599 break;
2602 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
2605 /* Insert a number predicate.
2606 ARGV is a pointer to the argument array.
2607 *ARG_PTR is an index into ARGV, incremented if all went well.
2608 *PRED is the predicate processor to insert.
2610 Return true if input is valid, false if error.
2612 A new predicate node is assigned, along with an argument node
2613 obtained with malloc.
2615 Used by -inum and -links parsers. */
2617 static boolean
2618 insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
2620 struct predicate *our_pred;
2621 uintmax_t num;
2622 enum comparison_type c_type;
2624 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2625 return false;
2626 if (!get_num (argv[*arg_ptr], &num, &c_type))
2627 return false;
2628 our_pred = insert_primary (entry);
2629 our_pred->args.info.kind = c_type;
2630 our_pred->args.info.l_val = num;
2631 (*arg_ptr)++;
2632 #ifdef DEBUG
2633 fprintf (stderr, "inserting %s\n", our_pred->p_name);
2634 fprintf (stderr, " type: %s %s ",
2635 (c_type == COMP_GT) ? "gt" :
2636 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2637 (c_type == COMP_GT) ? " >" :
2638 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2639 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2640 #endif /* DEBUG */
2641 return true;
2644 static FILE *
2645 open_output_file (char *path)
2647 FILE *f;
2649 if (!strcmp (path, "/dev/stderr"))
2650 return stderr;
2651 else if (!strcmp (path, "/dev/stdout"))
2652 return stdout;
2653 f = fopen_safer (path, "w");
2654 if (f == NULL)
2655 error (1, errno, "%s", path);
2656 return f;