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)
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,
28 #include "modechange.h"
36 #include "stdio-safer.h"
37 #include "regextype.h"
45 /* The presence of unistd.h is assumed by gnulib these days, so we
46 * might as well assume it too.
48 /* We need <unistd.h> for isatty(). */
53 # define _(Text) gettext (Text)
58 # define N_(String) gettext_noop (String)
60 /* See locate.c for explanation as to why not use (String) */
61 # define N_(String) String
64 #if !defined (isascii) || defined (STDC_HEADERS)
71 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
72 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
81 static boolean parse_accesscheck
PARAMS((const struct parser_table
* entry
, char **argv
, int *arg_ptr
));
82 static boolean parse_amin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
83 static boolean parse_and
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
84 static boolean parse_anewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
85 static boolean parse_cmin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
86 static boolean parse_cnewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
87 static boolean parse_comma
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
88 static boolean parse_daystart
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
89 static boolean parse_delete
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
90 static boolean parse_d
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
91 static boolean parse_depth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
92 static boolean parse_empty
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
93 static boolean parse_exec
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
94 static boolean parse_execdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
95 static boolean parse_false
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
96 static boolean parse_fls
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
97 static boolean parse_fprintf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
98 static boolean parse_follow
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
99 static boolean parse_fprint
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
100 static boolean parse_fprint0
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
101 static boolean parse_fstype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
102 static boolean parse_gid
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
103 static boolean parse_group
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
104 static boolean parse_help
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
105 static boolean parse_ilname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
106 static boolean parse_iname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
107 static boolean parse_inum
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
108 static boolean parse_ipath
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
109 static boolean parse_iregex
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
110 static boolean parse_iwholename
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
111 static boolean parse_links
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
112 static boolean parse_lname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
113 static boolean parse_ls
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
114 static boolean parse_maxdepth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
115 static boolean parse_mindepth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
116 static boolean parse_mmin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
117 static boolean parse_name
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
118 static boolean parse_negate
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
119 static boolean parse_newer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
120 static boolean parse_noleaf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
121 static boolean parse_nogroup
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
122 static boolean parse_nouser
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
123 static boolean parse_nowarn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
124 static boolean parse_ok
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
125 static boolean parse_okdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
126 static boolean parse_or
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
127 static boolean parse_path
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
128 static boolean parse_perm
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
129 static boolean parse_print0
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
130 static boolean parse_printf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
131 static boolean parse_prune
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
132 static boolean parse_regex
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
133 static boolean parse_regextype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
134 static boolean parse_samefile
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
136 static boolean parse_show_control_chars
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
138 static boolean parse_size
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
139 static boolean parse_time
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
140 static boolean parse_true
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
141 static boolean parse_type
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
142 static boolean parse_uid
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
143 static boolean parse_used
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
144 static boolean parse_user
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
145 static boolean parse_version
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
146 static boolean parse_wholename
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
147 static boolean parse_xdev
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
148 static boolean parse_ignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
149 static boolean parse_noignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
150 static boolean parse_warn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
151 static boolean parse_xtype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
152 static boolean parse_quit
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
154 boolean parse_print
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
157 static boolean insert_type
PARAMS((char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
));
158 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
, int regex_options
));
159 static boolean insert_fprintf
PARAMS((FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char *argv
[], int *arg_ptr
));
161 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
, struct predicate
*pred
));
162 static boolean insert_exec_ok
PARAMS((const char *action
, const struct parser_table
*entry
, char *argv
[], int *arg_ptr
));
163 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
164 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
165 static struct predicate
* insert_num
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
));
166 static FILE *open_output_file
PARAMS((char *path
));
167 static boolean
stream_is_tty(FILE *fp
);
168 static boolean parse_noop
PARAMS((const struct parser_table
* entry
, char **argv
, int *arg_ptr
));
170 #define PASTE(x,y) x##y
171 #define STRINGIFY(s) #s
173 #define PARSE_OPTION(what,suffix) \
174 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
176 #define PARSE_POSOPT(what,suffix) \
177 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
179 #define PARSE_TEST(what,suffix) \
180 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
182 #define PARSE_TEST_NP(what,suffix) \
183 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_ACTION(what,suffix) \
186 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
188 #define PARSE_ACTION_NP(what,suffix) \
189 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
191 #define PARSE_PUNCTUATION(what,suffix) \
192 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
195 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
196 If they are in some Unix versions of find, they are marked `Unix'. */
198 static struct parser_table
const parse_table
[] =
200 PARSE_PUNCTUATION("!", negate
),
201 PARSE_PUNCTUATION("not", negate
), /* GNU */
202 PARSE_PUNCTUATION("(", open
),
203 PARSE_PUNCTUATION(")", close
),
204 PARSE_PUNCTUATION(",", comma
), /* GNU */
205 PARSE_PUNCTUATION("a", and),
206 PARSE_TEST ("amin", amin
), /* GNU */
207 PARSE_PUNCTUATION("and", and), /* GNU */
208 PARSE_TEST ("anewer", anewer
), /* GNU */
209 {ARG_TEST
, "atime", parse_time
, pred_atime
},
210 PARSE_TEST ("cmin", cmin
), /* GNU */
211 PARSE_TEST ("cnewer", cnewer
), /* GNU */
212 {ARG_TEST
, "ctime", parse_time
, pred_ctime
},
213 PARSE_POSOPT ("daystart", daystart
), /* GNU */
214 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
215 PARSE_OPTION ("d", d
), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
216 PARSE_OPTION ("depth", depth
),
217 PARSE_TEST ("empty", empty
), /* GNU */
218 {ARG_ACTION
, "exec", parse_exec
, pred_exec
}, /* POSIX */
219 {ARG_TEST
, "executable", parse_accesscheck
, pred_executable
}, /* GNU, 4.3.0+ */
220 PARSE_ACTION ("execdir", execdir
), /* *BSD, GNU */
221 PARSE_ACTION ("fls", fls
), /* GNU */
222 PARSE_POSOPT ("follow", follow
), /* GNU, Unix */
223 PARSE_ACTION ("fprint", fprint
), /* GNU */
224 PARSE_ACTION ("fprint0", fprint0
), /* GNU */
225 {ARG_ACTION
, "fprintf", parse_fprintf
, pred_fprintf
}, /* GNU */
226 PARSE_TEST ("fstype", fstype
), /* GNU, Unix */
227 PARSE_TEST ("gid", gid
), /* GNU */
228 PARSE_TEST ("group", group
),
229 PARSE_OPTION ("ignore_readdir_race", ignore_race
), /* GNU */
230 PARSE_TEST ("ilname", ilname
), /* GNU */
231 PARSE_TEST ("iname", iname
), /* GNU */
232 PARSE_TEST ("inum", inum
), /* GNU, Unix */
233 PARSE_TEST ("ipath", ipath
), /* GNU, deprecated in favour of iwholename */
234 PARSE_TEST_NP ("iregex", iregex
), /* GNU */
235 PARSE_TEST_NP ("iwholename", iwholename
), /* GNU */
236 PARSE_TEST ("links", links
),
237 PARSE_TEST ("lname", lname
), /* GNU */
238 PARSE_ACTION ("ls", ls
), /* GNU, Unix */
239 PARSE_OPTION ("maxdepth", maxdepth
), /* GNU */
240 PARSE_OPTION ("mindepth", mindepth
), /* GNU */
241 PARSE_TEST ("mmin", mmin
), /* GNU */
242 PARSE_OPTION ("mount", xdev
), /* Unix */
243 {ARG_TEST
, "mtime", parse_time
, pred_mtime
},
244 PARSE_TEST ("name", name
),
245 #ifdef UNIMPLEMENTED_UNIX
246 PARSE(ARG_UNIMPLEMENTED
, "ncpio", ncpio
), /* Unix */
248 PARSE_TEST ("newer", newer
),
249 PARSE_OPTION ("noleaf", noleaf
), /* GNU */
250 PARSE_TEST ("nogroup", nogroup
),
251 PARSE_TEST ("nouser", nouser
),
252 PARSE_OPTION ("noignore_readdir_race", noignore_race
), /* GNU */
253 PARSE_OPTION ("nowarn", nowarn
), /* GNU */
254 PARSE_PUNCTUATION("o", or),
255 PARSE_PUNCTUATION("or", or), /* GNU */
256 PARSE_ACTION ("ok", ok
),
257 PARSE_ACTION ("okdir", okdir
), /* GNU (-execdir is BSD) */
258 PARSE_TEST ("path", path
), /* GNU, HP-UX, GNU prefers wholename */
259 PARSE_TEST ("perm", perm
),
260 PARSE_ACTION ("print", print
),
261 PARSE_ACTION ("print0", print0
), /* GNU */
262 {ARG_ACTION
, "printf", parse_printf
, NULL
}, /* GNU */
263 PARSE_ACTION ("prune", prune
),
264 PARSE_ACTION ("quit", quit
), /* GNU */
265 {ARG_TEST
, "readable", parse_accesscheck
, pred_readable
}, /* GNU, 4.3.0+ */
266 PARSE_TEST ("regex", regex
), /* GNU */
267 PARSE_OPTION ("regextype", regextype
), /* GNU */
268 PARSE_TEST ("samefile", samefile
), /* GNU */
270 PARSE_OPTION ("show-control-chars", show_control_chars
), /* GNU, 4.3.0+ */
272 PARSE_TEST ("size", size
),
273 PARSE_TEST ("type", type
),
274 PARSE_TEST ("uid", uid
), /* GNU */
275 PARSE_TEST ("used", used
), /* GNU */
276 PARSE_TEST ("user", user
),
277 PARSE_OPTION ("warn", warn
), /* GNU */
278 PARSE_TEST_NP ("wholename", wholename
), /* GNU, replaces -path */
279 {ARG_TEST
, "writable", parse_accesscheck
, pred_writable
}, /* GNU, 4.3.0+ */
280 PARSE_OPTION ("xdev", xdev
),
281 PARSE_TEST ("xtype", xtype
), /* GNU */
282 #ifdef UNIMPLEMENTED_UNIX
283 /* It's pretty ugly for find to know about archive formats.
284 Plus what it could do with cpio archives is very limited.
285 Better to leave it out. */
286 PARSE(ARG_UNIMPLEMENTED
, "cpio", cpio
), /* Unix */
288 /* gnulib's stdbool.h might have made true and false into macros,
289 * so we can't leave named 'true' and 'false' tokens, so we have
290 * to expeant the relevant entries longhand.
292 {ARG_TEST
, "false", parse_false
, pred_false
}, /* GNU */
293 {ARG_TEST
, "true", parse_true
, pred_true
}, /* GNU */
294 {ARG_NOOP
, "noop", NULL
, pred_true
}, /* GNU, internal use only */
296 /* Various other cases that don't fit neatly into our macro scheme. */
297 {ARG_TEST
, "help", parse_help
, NULL
}, /* GNU */
298 {ARG_TEST
, "-help", parse_help
, NULL
}, /* GNU */
299 {ARG_TEST
, "version", parse_version
, NULL
}, /* GNU */
300 {ARG_TEST
, "-version", parse_version
, NULL
}, /* GNU */
305 static const char *first_nonoption_arg
= NULL
;
306 static const struct parser_table
*noop
= NULL
;
310 static const struct parser_table
*
316 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
318 if (ARG_NOOP
==parse_table
[i
].type
)
320 noop
= &(parse_table
[i
]);
331 set_follow_state(enum SymlinkOption opt
)
333 if (options
.debug_options
& DebugStat
)
335 /* For DebugStat, the choice is made at runtime within debug_stat()
336 * by checking the contents of the symlink_handling variable.
338 options
.xstat
= debug_stat
;
344 case SYMLINK_ALWAYS_DEREF
: /* -L */
345 options
.xstat
= optionl_stat
;
346 options
.no_leaf_check
= true;
349 case SYMLINK_NEVER_DEREF
: /* -P (default) */
350 options
.xstat
= optionp_stat
;
351 /* Can't turn no_leaf_check off because the user might have specified
356 case SYMLINK_DEREF_ARGSONLY
: /* -H */
357 options
.xstat
= optionh_stat
;
358 options
.no_leaf_check
= true;
361 options
.symlink_handling
= opt
;
366 parse_begin_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
372 first_nonoption_arg
= NULL
;
376 parse_end_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
388 /* Return a pointer to the parser function to invoke for predicate
390 Return NULL if SEARCH_NAME is not a valid predicate name. */
392 const struct parser_table
*
393 find_parser (char *search_name
)
396 const char *original_arg
= search_name
;
398 if (*search_name
== '-')
400 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
402 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
404 /* If this is an option, but we have already had a
405 * non-option argument, the user may be under the
406 * impression that the behaviour of the option
407 * argument is conditional on some preceding
408 * tests. This might typically be the case with,
409 * for example, -maxdepth.
411 * The options -daystart and -follow are exempt
412 * from this treatment, since their positioning
413 * in the command line does have an effect on
414 * subsequent tests but not previous ones. That
415 * might be intentional on the part of the user.
417 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
419 /* Something other than -follow/-daystart.
420 * If this is an option, check if it followed
421 * a non-option and if so, issue a warning.
423 if (parse_table
[i
].type
== ARG_OPTION
)
425 if ((first_nonoption_arg
!= NULL
)
426 && options
.warnings
)
428 /* option which follows a non-option */
430 _("warning: you have specified the %s "
431 "option after a non-option argument %s, "
432 "but options are not positional (%s affects "
433 "tests specified before it as well as those "
434 "specified after it). Please specify options "
435 "before other arguments.\n"),
443 /* Not an option or a positional option,
444 * so remember we've seen it in order to
445 * use it in a possible future warning message.
447 if (first_nonoption_arg
== NULL
)
449 first_nonoption_arg
= original_arg
;
454 return &parse_table
[i
];
461 estimate_file_age_success_rate(float num_days
)
465 /* Assume 1% of files have timestamps in the future */
468 else if (num_days
< 1)
470 /* Assume 30% of files have timestamps today */
473 else if (num_days
> 100)
475 /* Assume 30% of files are very old */
480 /* Assume 39% of files are between 1 and 100 days old. */
486 estimate_timestamp_success_rate(time_t when
)
488 int num_days
= (when
- options
.cur_day_start
) / 86400;
489 return estimate_file_age_success_rate(num_days
);
493 /* The parsers are responsible to continue scanning ARGV for
494 their arguments. Each parser knows what is and isn't
497 ARGV is the argument array.
498 *ARG_PTR is the index to start at in ARGV,
499 updated to point beyond the last element consumed.
501 The predicate structure is updated with the new information. */
504 parse_amin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
506 struct predicate
*our_pred
;
508 enum comparison_type c_type
;
511 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
513 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
515 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
516 our_pred
= insert_primary (entry
);
517 our_pred
->args
.info
.kind
= c_type
;
518 our_pred
->args
.info
.negative
= t
< 0;
519 our_pred
->args
.info
.l_val
= t
;
520 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
526 parse_and (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
528 struct predicate
*our_pred
;
533 our_pred
= get_new_pred (entry
);
534 our_pred
->pred_func
= pred_and
;
535 our_pred
->p_type
= BI_OP
;
536 our_pred
->p_prec
= AND_PREC
;
537 our_pred
->need_stat
= our_pred
->need_type
= false;
542 parse_anewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
544 struct predicate
*our_pred
;
545 struct stat stat_newer
;
547 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
549 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
550 error (1, errno
, "%s", argv
[*arg_ptr
]);
551 our_pred
= insert_primary (entry
);
552 our_pred
->args
.time
= stat_newer
.st_mtime
;
553 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
559 parse_close (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
561 struct predicate
*our_pred
;
566 our_pred
= get_new_pred (entry
);
567 our_pred
->pred_func
= pred_close
;
568 our_pred
->p_type
= CLOSE_PAREN
;
569 our_pred
->p_prec
= NO_PREC
;
570 our_pred
->need_stat
= our_pred
->need_type
= false;
575 parse_cmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
577 struct predicate
*our_pred
;
579 enum comparison_type c_type
;
582 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
584 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
586 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
587 our_pred
= insert_primary (entry
);
588 our_pred
->args
.info
.kind
= c_type
;
589 our_pred
->args
.info
.negative
= t
< 0;
590 our_pred
->args
.info
.l_val
= t
;
591 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
597 parse_cnewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
599 struct predicate
*our_pred
;
600 struct stat stat_newer
;
602 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
604 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
605 error (1, errno
, "%s", argv
[*arg_ptr
]);
606 our_pred
= insert_primary (entry
);
607 our_pred
->args
.time
= stat_newer
.st_mtime
;
608 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
614 parse_comma (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
616 struct predicate
*our_pred
;
621 our_pred
= get_new_pred (entry
);
622 our_pred
->pred_func
= pred_comma
;
623 our_pred
->p_type
= BI_OP
;
624 our_pred
->p_prec
= COMMA_PREC
;
625 our_pred
->need_stat
= our_pred
->need_type
= false;
626 our_pred
->est_success_rate
= 1.0f
;
631 parse_daystart (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
639 if (options
.full_days
== false)
641 options
.cur_day_start
+= DAYSECS
;
642 local
= localtime (&options
.cur_day_start
);
643 options
.cur_day_start
-= (local
644 ? (local
->tm_sec
+ local
->tm_min
* 60
645 + local
->tm_hour
* 3600)
646 : options
.cur_day_start
% DAYSECS
);
647 options
.full_days
= true;
653 parse_delete (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
655 struct predicate
*our_pred
;
659 our_pred
= insert_primary (entry
);
660 our_pred
->side_effects
= our_pred
->no_default_print
= true;
661 /* -delete implies -depth */
662 options
.do_dir_first
= false;
663 our_pred
->est_success_rate
= 1.0f
;
668 parse_depth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
674 options
.do_dir_first
= false;
675 return parse_noop(entry
, argv
, arg_ptr
);
679 parse_d (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
684 if (options
.warnings
)
687 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
689 return parse_depth(entry
, argv
, arg_ptr
);
693 parse_empty (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
695 struct predicate
*our_pred
;
699 our_pred
= insert_primary (entry
);
700 our_pred
->est_success_rate
= 0.01f
; /* assume 1% of files are empty. */
705 parse_exec (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
707 return insert_exec_ok ("-exec", entry
, argv
, arg_ptr
);
711 parse_execdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
713 return insert_exec_ok ("-execdir", entry
, argv
, arg_ptr
);
717 parse_false (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
719 struct predicate
*our_pred
;
724 our_pred
= insert_primary (entry
);
725 our_pred
->need_stat
= our_pred
->need_type
= false;
726 our_pred
->side_effects
= our_pred
->no_default_print
= false;
727 our_pred
->est_success_rate
= 0.0f
;
732 parse_fls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
734 struct predicate
*our_pred
;
736 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
738 our_pred
= insert_primary (entry
);
739 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
740 our_pred
->side_effects
= our_pred
->no_default_print
= true;
741 our_pred
->est_success_rate
= 1.0f
;
747 parse_fprintf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
751 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
753 if (argv
[*arg_ptr
+ 1] == NULL
)
755 /* Ensure we get "missing arg" message, not "invalid arg". */
759 fp
= open_output_file (argv
[*arg_ptr
]);
761 return insert_fprintf (fp
, entry
, pred_fprintf
, argv
, arg_ptr
);
765 parse_follow (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
771 set_follow_state(SYMLINK_ALWAYS_DEREF
);
772 return parse_noop(entry
, argv
, arg_ptr
);
776 parse_fprint (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
778 struct predicate
*our_pred
;
780 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
782 our_pred
= insert_primary (entry
);
783 our_pred
->args
.printf_vec
.segment
= NULL
;
784 our_pred
->args
.printf_vec
.stream
= open_output_file (argv
[*arg_ptr
]);
785 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(our_pred
->args
.printf_vec
.stream
);
786 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
787 our_pred
->side_effects
= our_pred
->no_default_print
= true;
788 our_pred
->need_stat
= our_pred
->need_type
= false;
789 our_pred
->est_success_rate
= 1.0f
;
795 parse_fprint0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
797 struct predicate
*our_pred
;
799 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
801 our_pred
= insert_primary (entry
);
802 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
803 our_pred
->side_effects
= our_pred
->no_default_print
= true;
804 our_pred
->need_stat
= our_pred
->need_type
= false;
805 our_pred
->est_success_rate
= 1.0f
;
810 static float estimate_fstype_success_rate(const char *fsname
)
812 struct stat dir_stat
;
813 const char *dir
= "/";
814 if (0 == stat(dir
, &dir_stat
))
816 const char *fstype
= filesystem_type(&dir_stat
, dir
);
817 /* Assume most files are on the same filesystem type as the root fs. */
818 if (0 == strcmp(fsname
, fstype
))
828 parse_fstype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
830 struct predicate
*our_pred
;
832 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
834 our_pred
= insert_primary (entry
);
835 our_pred
->args
.str
= argv
[*arg_ptr
];
837 /* This is an expensive operation, so although there are
838 * circumstances where it is selective, we ignore this fact because
839 * we probably don't want to promote this test to the front anyway.
841 our_pred
->est_success_rate
= estimate_fstype_success_rate(argv
[*arg_ptr
]);
847 parse_gid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
849 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
850 p
->est_success_rate
= (p
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
855 parse_group (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
857 struct group
*cur_gr
;
858 struct predicate
*our_pred
;
862 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
864 cur_gr
= getgrnam (argv
[*arg_ptr
]);
867 gid
= cur_gr
->gr_gid
;
870 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
871 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
873 gid
= atoi (argv
[*arg_ptr
]);
875 our_pred
= insert_primary (entry
);
876 our_pred
->args
.gid
= gid
;
877 our_pred
->est_success_rate
= (our_pred
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
883 parse_help (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
889 usage(stdout
, 0, NULL
);
891 default path is the current directory; default expression is -print\n\
892 expression may consist of: operators, options, tests, and actions:\n"));
894 operators (decreasing precedence; -and is implicit where no others are given):\n\
895 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
896 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
898 positional options (always true): -daystart -follow -regextype\n\n\
899 normal options (always true, specified before other expressions):\n\
900 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
901 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
903 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
904 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
905 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
906 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
908 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
909 -readable -writable -executable\n\
910 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
911 -used N -user NAME -xtype [bcdpfls]\n"));
913 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
914 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
915 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
916 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
918 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
919 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
920 email to <bug-findutils@gnu.org>."));
924 static float estimate_pattern_match_rate(const char *pattern
, int is_regex
)
926 if (strpbrk(pattern
, "*?[") || (is_regex
&& strpbrk(pattern
, ".")))
928 /* A wildcard; assume the pattern matches most files. */
938 parse_ilname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
940 struct predicate
*our_pred
;
942 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
944 our_pred
= insert_primary (entry
);
945 our_pred
->args
.str
= argv
[*arg_ptr
];
946 /* Use the generic glob pattern estimator to figure out how many
947 * links will match, but bear in mind that most files won't be links.
949 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
955 /* sanity check the fnmatch() function to make sure
956 * it really is the GNU version.
959 fnmatch_sanitycheck(void)
961 /* fprintf(stderr, "Performing find sanity check..."); */
962 if (0 != fnmatch("foo", "foo", 0)
963 || 0 == fnmatch("Foo", "foo", 0)
964 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
966 error (1, 0, _("sanity check of the fnmatch() library function failed."));
967 /* fprintf(stderr, "FAILED\n"); */
971 /* fprintf(stderr, "OK\n"); */
977 check_name_arg(const char *pred
, const char *arg
)
979 if (strchr(arg
, '/'))
981 error(0, 0,_("warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '%s %s' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ %s'."),
984 return true; /* allow it anyway */
990 parse_iname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
992 struct predicate
*our_pred
;
994 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
996 if (!check_name_arg("-iname", argv
[*arg_ptr
]))
999 fnmatch_sanitycheck();
1001 our_pred
= insert_primary (entry
);
1002 our_pred
->need_stat
= our_pred
->need_type
= false;
1003 our_pred
->args
.str
= argv
[*arg_ptr
];
1004 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1010 parse_inum (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1012 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1013 /* inode number is exact match only, so very low proportions of files match */
1014 p
->est_success_rate
= 1e-6;
1018 /* -ipath is deprecated (at RMS's request) in favour of
1019 * -iwholename. See the node "GNU Manuals" in standards.texi
1020 * for the rationale for this (basically, GNU prefers the use
1021 * of the phrase "file name" to "path name"
1024 parse_ipath (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1027 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1029 return parse_iwholename(entry
, argv
, arg_ptr
);
1033 parse_iwholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1035 struct predicate
*our_pred
;
1037 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1040 fnmatch_sanitycheck();
1042 our_pred
= insert_primary_withpred (entry
, pred_ipath
);
1043 our_pred
->need_stat
= our_pred
->need_type
= false;
1044 our_pred
->args
.str
= argv
[*arg_ptr
];
1045 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1051 parse_iregex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1053 return insert_regex (argv
, arg_ptr
, entry
, RE_ICASE
|options
.regex_options
);
1057 parse_links (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1059 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1060 if (p
->args
.info
.l_val
== 1)
1061 p
->est_success_rate
= 0.99;
1062 else if (p
->args
.info
.l_val
== 2)
1063 p
->est_success_rate
= 0.01;
1065 p
->est_success_rate
= 1e-3;
1070 parse_lname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1072 struct predicate
*our_pred
;
1077 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1080 fnmatch_sanitycheck();
1082 our_pred
= insert_primary (entry
);
1083 our_pred
->args
.str
= argv
[*arg_ptr
];
1084 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1090 parse_ls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1092 struct predicate
*our_pred
;
1097 our_pred
= insert_primary (entry
);
1098 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1103 parse_maxdepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1108 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1110 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1111 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1113 options
.maxdepth
= atoi (argv
[*arg_ptr
]);
1114 if (options
.maxdepth
< 0)
1117 return parse_noop(entry
, argv
, arg_ptr
);
1121 parse_mindepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1126 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1128 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1129 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1131 options
.mindepth
= atoi (argv
[*arg_ptr
]);
1132 if (options
.mindepth
< 0)
1135 return parse_noop(entry
, argv
, arg_ptr
);
1139 parse_mmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1141 struct predicate
*our_pred
;
1143 enum comparison_type c_type
;
1146 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1148 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
1150 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
1151 our_pred
= insert_primary (entry
);
1152 our_pred
->args
.info
.kind
= c_type
;
1153 our_pred
->args
.info
.negative
= t
< 0;
1154 our_pred
->args
.info
.l_val
= t
;
1155 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
1161 parse_name (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1163 struct predicate
*our_pred
;
1168 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1170 if (!check_name_arg("-name", argv
[*arg_ptr
]))
1172 fnmatch_sanitycheck();
1174 our_pred
= insert_primary (entry
);
1175 our_pred
->need_stat
= our_pred
->need_type
= false;
1176 our_pred
->args
.str
= argv
[*arg_ptr
];
1177 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1183 parse_negate (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1185 struct predicate
*our_pred
;
1190 our_pred
= get_new_pred_chk_op (entry
);
1191 our_pred
->pred_func
= pred_negate
;
1192 our_pred
->p_type
= UNI_OP
;
1193 our_pred
->p_prec
= NEGATE_PREC
;
1194 our_pred
->need_stat
= our_pred
->need_type
= false;
1199 parse_newer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1201 struct predicate
*our_pred
;
1202 struct stat stat_newer
;
1207 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1209 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
1210 error (1, errno
, "%s", argv
[*arg_ptr
]);
1211 our_pred
= insert_primary (entry
);
1212 our_pred
->args
.time
= stat_newer
.st_mtime
;
1213 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
1219 parse_noleaf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1225 options
.no_leaf_check
= true;
1226 return parse_noop(entry
, argv
, arg_ptr
);
1230 /* Arbitrary amount by which to increase size
1231 of `uid_unused' and `gid_unused'. */
1232 #define ALLOC_STEP 2048
1234 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1235 char *uid_unused
= NULL
;
1237 /* Number of elements in `uid_unused'. */
1238 unsigned uid_allocated
;
1240 /* Similar for GIDs and group entries. */
1241 char *gid_unused
= NULL
;
1242 unsigned gid_allocated
;
1246 parse_nogroup (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1248 struct predicate
*our_pred
;
1253 our_pred
= insert_primary (entry
);
1254 our_pred
->est_success_rate
= 1e-4;
1256 if (gid_unused
== NULL
)
1260 gid_allocated
= ALLOC_STEP
;
1261 gid_unused
= xmalloc (gid_allocated
);
1262 memset (gid_unused
, 1, gid_allocated
);
1264 while ((gr
= getgrent ()) != NULL
)
1266 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1268 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1269 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1270 memset (gid_unused
+ gid_allocated
, 1,
1271 new_allocated
- gid_allocated
);
1272 gid_allocated
= new_allocated
;
1274 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1283 parse_nouser (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1285 struct predicate
*our_pred
;
1290 our_pred
= insert_primary (entry
);
1291 our_pred
->est_success_rate
= 1e-3;
1293 if (uid_unused
== NULL
)
1297 uid_allocated
= ALLOC_STEP
;
1298 uid_unused
= xmalloc (uid_allocated
);
1299 memset (uid_unused
, 1, uid_allocated
);
1301 while ((pw
= getpwent ()) != NULL
)
1303 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1305 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1306 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1307 memset (uid_unused
+ uid_allocated
, 1,
1308 new_allocated
- uid_allocated
);
1309 uid_allocated
= new_allocated
;
1311 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1320 parse_nowarn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1326 options
.warnings
= false;
1327 return parse_noop(entry
, argv
, arg_ptr
);
1331 parse_ok (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1333 return insert_exec_ok ("-ok", entry
, argv
, arg_ptr
);
1337 parse_okdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1339 return insert_exec_ok ("-okdir", entry
, argv
, arg_ptr
);
1343 parse_open (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1345 struct predicate
*our_pred
;
1350 our_pred
= get_new_pred_chk_op (entry
);
1351 our_pred
->pred_func
= pred_open
;
1352 our_pred
->p_type
= OPEN_PAREN
;
1353 our_pred
->p_prec
= NO_PREC
;
1354 our_pred
->need_stat
= our_pred
->need_type
= false;
1359 parse_or (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1361 struct predicate
*our_pred
;
1366 our_pred
= get_new_pred (entry
);
1367 our_pred
->pred_func
= pred_or
;
1368 our_pred
->p_type
= BI_OP
;
1369 our_pred
->p_prec
= OR_PREC
;
1370 our_pred
->need_stat
= our_pred
->need_type
= false;
1374 /* -path is deprecated (at RMS's request) in favour of
1375 * -iwholename. See the node "GNU Manuals" in standards.texi
1376 * for the rationale for this (basically, GNU prefers the use
1377 * of the phrase "file name" to "path name".
1379 * We do not issue a warning that this usage is deprecated
1380 * since HPUX find supports this predicate also.
1383 parse_path (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1385 return parse_wholename(entry
, argv
, arg_ptr
);
1389 parse_wholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1391 struct predicate
*our_pred
;
1393 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1395 our_pred
= insert_primary_withpred (entry
, pred_path
);
1396 our_pred
->need_stat
= our_pred
->need_type
= false;
1397 our_pred
->args
.str
= argv
[*arg_ptr
];
1398 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1404 parse_perm (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1409 boolean havekind
= false;
1410 enum permissions_type kind
= PERM_EXACT
;
1411 struct mode_change
*change
= NULL
;
1412 struct predicate
*our_pred
;
1414 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1417 switch (argv
[*arg_ptr
][0])
1421 kind
= PERM_AT_LEAST
;
1427 change
= mode_compile (argv
[*arg_ptr
]);
1430 /* Most likely the caller is an old script that is still
1431 * using the obsolete GNU syntax '-perm +MODE'. This old
1432 * syntax was withdrawn in favor of '-perm /MODE' because
1433 * it is incompatible with POSIX in some cases, but we
1434 * still support uses of it that are not incompatible with
1443 /* This is a POSIX-compatible usage */
1451 case '/': /* GNU extension */
1459 /* For example, '-perm 0644', which is valid and matches
1460 * only files whose mode is exactly 0644.
1462 * We do nothing here, because mode_start and kind are already
1471 change
= mode_compile (argv
[*arg_ptr
] + mode_start
);
1473 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1475 perm_val
= mode_adjust (0, change
, 0);
1478 our_pred
= insert_primary (entry
);
1479 our_pred
->est_success_rate
= rate
;
1482 our_pred
->args
.perm
.kind
= kind
;
1487 switch (argv
[*arg_ptr
][0])
1490 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1493 our_pred
->args
.perm
.kind
= PERM_ANY
;
1496 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1500 if (('/' == argv
[*arg_ptr
][0]) && (0 == perm_val
))
1502 /* The meaning of -perm /000 will change in the future.
1503 * It currently matches no files, but like -perm -000 it
1504 * should match all files.
1507 _("warning: you have specified a mode pattern %s which is "
1508 "equivalent to 000. The meaning of -perm /000 will soon be "
1509 "changed to be consistent with -perm -000; that is, at the "
1510 "moment it matches no files but it will soon be changed to "
1511 "match all files."),
1515 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1521 parse_print (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1523 struct predicate
*our_pred
;
1528 our_pred
= insert_primary (entry
);
1529 /* -print has the side effect of printing. This prevents us
1530 from doing undesired multiple printing when the user has
1531 already specified -print. */
1532 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1533 our_pred
->need_stat
= our_pred
->need_type
= false;
1534 our_pred
->args
.printf_vec
.segment
= NULL
;
1535 our_pred
->args
.printf_vec
.stream
= stdout
;
1536 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(stdout
);
1537 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
1543 parse_print0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1545 struct predicate
*our_pred
;
1550 our_pred
= insert_primary (entry
);
1551 /* -print0 has the side effect of printing. This prevents us
1552 from doing undesired multiple printing when the user has
1553 already specified -print0. */
1554 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1555 our_pred
->need_stat
= our_pred
->need_type
= false;
1560 parse_printf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1562 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1564 return insert_fprintf (stdout
, entry
, pred_fprintf
, argv
, arg_ptr
);
1568 parse_prune (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1570 struct predicate
*our_pred
;
1575 our_pred
= insert_primary (entry
);
1576 our_pred
->need_stat
= our_pred
->need_type
= false;
1577 /* -prune has a side effect that it does not descend into
1578 the current directory. */
1579 our_pred
->side_effects
= true;
1580 our_pred
->no_default_print
= false;
1585 parse_quit (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1587 struct predicate
*our_pred
= insert_primary (entry
);
1590 our_pred
->need_stat
= our_pred
->need_type
= false;
1591 our_pred
->side_effects
= true; /* Exiting is a side effect... */
1592 our_pred
->no_default_print
= false; /* Don't inhibit the default print, though. */
1593 our_pred
->est_success_rate
= 1e-6;
1599 parse_regextype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1601 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1604 /* collect the regex type name */
1605 options
.regex_options
= get_regex_type(argv
[*arg_ptr
]);
1608 return parse_noop(entry
, argv
, arg_ptr
);
1613 parse_regex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1615 return insert_regex (argv
, arg_ptr
, entry
, options
.regex_options
);
1619 insert_regex (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, int regex_options
)
1621 struct predicate
*our_pred
;
1622 struct re_pattern_buffer
*re
;
1623 const char *error_message
;
1625 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1627 our_pred
= insert_primary_withpred (entry
, pred_regex
);
1628 our_pred
->need_stat
= our_pred
->need_type
= false;
1629 re
= (struct re_pattern_buffer
*)
1630 xmalloc (sizeof (struct re_pattern_buffer
));
1631 our_pred
->args
.regex
= re
;
1632 re
->allocated
= 100;
1633 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1636 re_set_syntax(regex_options
);
1637 re
->syntax
= regex_options
;
1638 re
->translate
= NULL
;
1640 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1643 error (1, 0, "%s", error_message
);
1645 our_pred
->est_success_rate
= estimate_pattern_match_rate(argv
[*arg_ptr
], 1);
1650 parse_size (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1652 struct predicate
*our_pred
;
1654 enum comparison_type c_type
;
1659 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1661 len
= strlen (argv
[*arg_ptr
]);
1663 error (1, 0, _("invalid null argument to -size"));
1664 switch (argv
[*arg_ptr
][len
- 1])
1668 argv
[*arg_ptr
][len
- 1] = '\0';
1673 argv
[*arg_ptr
][len
- 1] = '\0';
1678 argv
[*arg_ptr
][len
- 1] = '\0';
1681 case 'M': /* Megabytes */
1682 blksize
= 1024*1024;
1683 argv
[*arg_ptr
][len
- 1] = '\0';
1686 case 'G': /* Gigabytes */
1687 blksize
= 1024*1024*1024;
1688 argv
[*arg_ptr
][len
- 1] = '\0';
1693 argv
[*arg_ptr
][len
- 1] = '\0';
1709 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1711 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1713 our_pred
= insert_primary (entry
);
1714 our_pred
->args
.size
.kind
= c_type
;
1715 our_pred
->args
.size
.blocksize
= blksize
;
1716 our_pred
->args
.size
.size
= num
;
1717 our_pred
->need_stat
= true;
1718 our_pred
->need_type
= false;
1720 if (COMP_GT
== c_type
)
1721 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.1 : 0.9;
1722 else if (COMP_LT
== c_type
)
1723 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.9 : 0.1;
1725 our_pred
->est_success_rate
= 0.01;
1733 parse_samefile (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1735 struct predicate
*our_pred
;
1738 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1740 if ((*options
.xstat
) (argv
[*arg_ptr
], &st
))
1741 error (1, errno
, "%s", argv
[*arg_ptr
]);
1743 our_pred
= insert_primary (entry
);
1744 our_pred
->args
.fileid
.ino
= st
.st_ino
;
1745 our_pred
->args
.fileid
.dev
= st
.st_dev
;
1746 our_pred
->need_type
= false;
1747 our_pred
->need_stat
= true;
1748 our_pred
->est_success_rate
= 0.01f
;
1755 parse_show_control_chars (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1758 const char *errmsg
= _("The -show-control-chars option takes a single argument which "
1759 "must be 'literal' or 'safe'");
1761 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1763 error (1, errno
, "%s", errmsg
);
1768 arg
= argv
[*arg_ptr
];
1770 if (0 == strcmp("literal", arg
))
1772 options
.literal_control_chars
= true;
1774 else if (0 == strcmp("safe", arg
))
1776 options
.literal_control_chars
= false;
1780 error (1, errno
, "%s", errmsg
);
1783 (*arg_ptr
)++; /* consume the argument. */
1791 parse_true (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1793 struct predicate
*our_pred
;
1798 our_pred
= insert_primary (entry
);
1799 our_pred
->need_stat
= our_pred
->need_type
= false;
1800 our_pred
->est_success_rate
= 1.0f
;
1805 parse_noop (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1808 return parse_true(get_noop(), argv
, arg_ptr
);
1812 parse_accesscheck (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1814 struct predicate
*our_pred
;
1817 our_pred
= insert_primary (entry
);
1818 our_pred
->need_stat
= our_pred
->need_type
= false;
1819 our_pred
->side_effects
= our_pred
->no_default_print
= false;
1820 if (our_pred
->pred_func
== pred_executable
)
1821 our_pred
->est_success_rate
= 0.2;
1823 our_pred
->est_success_rate
= 0.9;
1828 parse_type (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1830 return insert_type (argv
, arg_ptr
, entry
, pred_type
);
1834 parse_uid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1836 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1837 p
->est_success_rate
= (p
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
1842 parse_used (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1844 struct predicate
*our_pred
;
1846 enum comparison_type c_type
;
1849 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1851 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1853 t
= num_days
* DAYSECS
;
1854 our_pred
= insert_primary (entry
);
1855 our_pred
->args
.info
.kind
= c_type
;
1856 our_pred
->args
.info
.negative
= t
< 0;
1857 our_pred
->args
.info
.l_val
= t
;
1858 our_pred
->est_success_rate
= estimate_file_age_success_rate(num_days
);
1864 parse_user (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1866 struct passwd
*cur_pwd
;
1867 struct predicate
*our_pred
;
1871 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1873 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1875 if (cur_pwd
!= NULL
)
1876 uid
= cur_pwd
->pw_uid
;
1879 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1880 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1882 uid
= atoi (argv
[*arg_ptr
]);
1884 our_pred
= insert_primary (entry
);
1885 our_pred
->args
.uid
= uid
;
1886 our_pred
->est_success_rate
= (our_pred
->args
.uid
< 100) ? 0.99 : 0.2;
1892 parse_version (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1894 extern char *version_string
;
1902 printf (_("GNU find version %s\n"), version_string
);
1903 printf (_("Features enabled: "));
1906 printf("CACHE_IDS ");
1914 printf("DEBUG_STAT ");
1917 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1921 #if defined(O_NOFOLLOW)
1922 printf("O_NOFOLLOW(%s) ",
1923 (options
.open_nofollow_available
? "enabled" : "disabled"));
1926 #if defined(LEAF_OPTIMISATION)
1927 printf("LEAF_OPTIMISATION ");
1931 if (is_fts_enabled())
1937 printf("CBO(level=%d) ", (int)(options
.optimisation_level
));
1942 /* For the moment, leave this as English in case someone wants
1943 to parse these strings. */
1952 parse_xdev (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1957 options
.stay_on_filesystem
= true;
1958 return parse_noop(entry
, argv
, arg_ptr
);
1962 parse_ignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1967 options
.ignore_readdir_race
= true;
1968 return parse_noop(entry
, argv
, arg_ptr
);
1972 parse_noignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1977 options
.ignore_readdir_race
= false;
1978 return parse_noop(entry
, argv
, arg_ptr
);
1982 parse_warn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1987 options
.warnings
= true;
1988 return parse_noop(entry
, argv
, arg_ptr
);
1992 parse_xtype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1996 return insert_type (argv
, arg_ptr
, entry
, pred_xtype
);
2000 insert_type (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
)
2003 struct predicate
*our_pred
;
2006 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
2007 || (strlen (argv
[*arg_ptr
]) != 1))
2009 switch (argv
[*arg_ptr
][0])
2011 case 'b': /* block special */
2012 type_cell
= S_IFBLK
;
2015 case 'c': /* character special */
2016 type_cell
= S_IFCHR
;
2019 case 'd': /* directory */
2020 type_cell
= S_IFDIR
;
2023 case 'f': /* regular file */
2024 type_cell
= S_IFREG
;
2028 case 'l': /* symbolic link */
2029 type_cell
= S_IFLNK
;
2034 case 'p': /* pipe */
2035 type_cell
= S_IFIFO
;
2040 case 's': /* socket */
2041 type_cell
= S_IFSOCK
;
2046 case 'D': /* Solaris door */
2047 type_cell
= S_IFDOOR
;
2051 default: /* None of the above ... nuke 'em. */
2054 our_pred
= insert_primary_withpred (entry
, which_pred
);
2055 our_pred
->est_success_rate
= rate
;
2057 /* Figure out if we will need to stat the file, because if we don't
2058 * need to follow symlinks, we can avoid a stat call by using
2059 * struct dirent.d_type.
2061 if (which_pred
== pred_xtype
)
2063 our_pred
->need_stat
= true;
2064 our_pred
->need_type
= false;
2068 our_pred
->need_stat
= false; /* struct dirent is enough */
2069 our_pred
->need_type
= true;
2071 our_pred
->args
.type
= type_cell
;
2072 (*arg_ptr
)++; /* Move on to next argument. */
2077 /* Return true if the file accessed via FP is a terminal.
2080 stream_is_tty(FILE *fp
)
2082 int fd
= fileno(fp
);
2085 return false; /* not a valid stream */
2089 return isatty(fd
) ? true : false;
2097 /* XXX: do we need to pass FUNC to this function? */
2099 insert_fprintf (FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char **argv
, int *arg_ptr
)
2101 char *format
; /* Beginning of unprocessed format string. */
2102 register char *scan
; /* Current address in scanning `format'. */
2103 register char *scan2
; /* Address inside of element being scanned. */
2104 struct segment
**segmentp
; /* Address of current segment. */
2105 struct predicate
*our_pred
;
2107 format
= argv
[(*arg_ptr
)++];
2109 our_pred
= insert_primary_withpred (entry
, func
);
2110 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2111 our_pred
->args
.printf_vec
.stream
= fp
;
2112 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(fp
);
2113 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
2114 our_pred
->need_type
= false;
2115 our_pred
->need_stat
= false;
2117 segmentp
= &our_pred
->args
.printf_vec
.segment
;
2120 for (scan
= format
; *scan
; scan
++)
2125 if (*scan2
>= '0' && *scan2
<= '7')
2129 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
2131 n
= 8 * n
+ *scan2
- '0';
2146 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
,
2148 if (our_pred
->need_stat
&& (our_pred
->p_cost
< NeedsStatInfo
))
2149 our_pred
->p_cost
= NeedsStatInfo
;
2167 /* *scan = '\\'; * it already is */
2171 _("warning: unrecognized escape `\\%c'"), *scan2
);
2176 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2177 KIND_PLAIN
, our_pred
);
2178 format
= scan2
+ 1; /* Move past the escape. */
2179 scan
= scan2
; /* Incremented immediately by `for'. */
2181 else if (*scan
== '%')
2185 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2186 KIND_PLAIN
, our_pred
);
2191 /* Scan past flags, width and precision, to verify kind. */
2192 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
2194 while (ISDIGIT (*scan2
))
2197 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
2199 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2
))
2201 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2202 (int) *scan2
, our_pred
);
2206 else if (strchr ("ACT", *scan2
) && scan2
[1])
2208 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2209 *scan2
| (scan2
[1] << 8),
2217 /* An unrecognized % escape. Print the char after the %. */
2218 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2220 segmentp
= make_segment (segmentp
, format
, scan
- format
,
2221 KIND_PLAIN
, our_pred
);
2229 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
,
2234 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2235 from the text in FORMAT, which has length LEN.
2236 Return the address of the `next' pointer of the new segment. */
2238 static struct segment
**
2239 make_segment (struct segment
**segment
, char *format
, int len
, int kind
,
2240 struct predicate
*pred
)
2242 enum EvaluationCost mycost
= NeedsNothing
;
2245 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
2247 (*segment
)->kind
= kind
;
2248 (*segment
)->next
= NULL
;
2249 (*segment
)->text_len
= len
;
2251 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
2252 strncpy (fmt
, format
, len
);
2255 switch (kind
& 0xff)
2257 case KIND_PLAIN
: /* Plain text string, no % conversion. */
2258 case KIND_STOP
: /* Terminate argument, no newline. */
2261 case 'l': /* object of symlink */
2262 pred
->need_stat
= true;
2263 mycost
= NeedsLinkName
;
2267 case 'y': /* file type */
2268 pred
->need_type
= true;
2273 case 'a': /* atime in `ctime' format */
2274 case 'A': /* atime in user-specified strftime format */
2275 case 'c': /* ctime in `ctime' format */
2276 case 'C': /* ctime in user-specified strftime format */
2277 case 'F': /* filesystem type */
2278 case 'g': /* group name */
2279 case 'i': /* inode number */
2280 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2281 case 's': /* size in bytes */
2282 case 't': /* mtime in `ctime' format */
2283 case 'T': /* mtime in user-specified strftime format */
2284 case 'u': /* user name */
2285 pred
->need_stat
= true;
2286 mycost
= NeedsStatInfo
;
2290 case 'Y': /* symlink pointed file type */
2291 pred
->need_stat
= true;
2292 mycost
= NeedsType
; /* true for amortised effect */
2296 case 'f': /* basename of path */
2297 case 'h': /* leading directories part of path */
2298 case 'H': /* ARGV element file was found under */
2299 case 'p': /* pathname */
2300 case 'P': /* pathname with ARGV element stripped */
2304 /* Numeric items that one might expect to honour
2305 * #, 0, + flags but which do not.
2307 case 'G': /* GID number */
2308 case 'U': /* UID number */
2309 case 'b': /* size in 512-byte blocks */
2310 case 'D': /* Filesystem device on which the file exits */
2311 case 'k': /* size in 1K blocks */
2312 case 'n': /* number of links */
2313 pred
->need_stat
= true;
2314 mycost
= NeedsStatInfo
;
2318 /* Numeric items that DO honour #, 0, + flags.
2320 case 'd': /* depth in search tree (0 = ARGV element) */
2324 case 'm': /* mode as octal number (perms only) */
2326 pred
->need_stat
= true;
2327 mycost
= NeedsStatInfo
;
2332 if (mycost
> pred
->p_cost
)
2333 pred
->p_cost
= mycost
;
2334 return &(*segment
)->next
;
2338 check_path_safety(const char *action
)
2340 const char *path
= getenv("PATH");
2342 s
= next_element(path
, 1);
2343 while ((s
= next_element ((char *) NULL
, 1)) != NULL
)
2345 if (0 == strcmp(s
, "."))
2347 error(1, 0, _("The current directory is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove the current directory from your $PATH (that is, remove \".\" or leading or trailing colons)"),
2354 /* handles both exec and ok predicate */
2355 #if defined(NEW_EXEC)
2356 /* handles both exec and ok predicate */
2358 new_insert_exec_ok (const char *action
,
2359 const struct parser_table
*entry
,
2363 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2364 int i
; /* Index into cmd args */
2365 int saw_braces
; /* True if previous arg was '{}'. */
2366 boolean allow_plus
; /* True if + is a valid terminator */
2367 int brace_count
; /* Number of instances of {}. */
2368 PRED_FUNC func
= entry
->pred_func
;
2370 struct predicate
*our_pred
;
2371 struct exec_val
*execp
; /* Pointer for efficiency. */
2373 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2376 our_pred
= insert_primary_withpred (entry
, func
);
2377 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2378 our_pred
->need_type
= our_pred
->need_stat
= false;
2380 execp
= &our_pred
->args
.exec_vec
;
2382 if ((func
!= pred_okdir
) && (func
!= pred_ok
))
2385 execp
->close_stdin
= false;
2390 /* If find reads stdin (i.e. for -ok and similar), close stdin
2391 * in the child to prevent some script from consiming the output
2392 * intended for find.
2394 execp
->close_stdin
= true;
2398 if ((func
== pred_execdir
) || (func
== pred_okdir
))
2400 options
.ignore_readdir_race
= false;
2401 check_path_safety(action
);
2402 execp
->use_current_dir
= true;
2406 execp
->use_current_dir
= false;
2409 our_pred
->args
.exec_vec
.multiple
= 0;
2411 /* Count the number of args with path replacements, up until the ';'.
2412 * Also figure out if the command is terminated by ";" or by "+".
2415 for (end
= start
, saw_braces
=0, brace_count
=0;
2417 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2420 /* For -exec and -execdir, "{} +" can terminate the command. */
2422 && argv
[end
][0] == '+' && argv
[end
][1] == 0
2425 our_pred
->args
.exec_vec
.multiple
= 1;
2430 if (strstr (argv
[end
], "{}"))
2435 if (0 == end
&& (func
== pred_execdir
|| func
== pred_okdir
))
2437 /* The POSIX standard says that {} replacement should
2438 * occur even in the utility name. This is insecure
2439 * since it means we will be executing a command whose
2440 * name is chosen according to whatever find finds in
2441 * the filesystem. That can be influenced by an
2442 * attacker. Hence for -execdir and -okdir this is not
2443 * allowed. We can specify this as those options are
2444 * not defined by POSIX.
2446 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2451 /* Fail if no command given or no semicolon found. */
2452 if ((end
== start
) || (argv
[end
] == NULL
))
2459 if (our_pred
->args
.exec_vec
.multiple
&& brace_count
> 1)
2463 if (func
== pred_execdir
)
2469 _("Only one instance of {} is supported with -exec%s ... +"),
2473 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2474 bc_init_controlinfo(&execp
->ctl
);
2475 execp
->ctl
.exec_callback
= launch
;
2477 if (our_pred
->args
.exec_vec
.multiple
)
2479 /* "+" terminator, so we can just append our arguments after the
2480 * command and initial arguments.
2482 execp
->replace_vec
= NULL
;
2483 execp
->ctl
.replace_pat
= NULL
;
2484 execp
->ctl
.rplen
= 0;
2485 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2486 execp
->ctl
.args_per_exec
= 0; /* no limit */
2488 /* remember how many arguments there are */
2489 execp
->ctl
.initial_argc
= (end
-start
) - 1;
2491 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2492 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2494 /* Gather the initial arguments. Skip the {}. */
2495 for (i
=start
; i
<end
-1; ++i
)
2497 bc_push_arg(&execp
->ctl
, &execp
->state
,
2498 argv
[i
], strlen(argv
[i
])+1,
2505 /* Semicolon terminator - more than one {} is supported, so we
2506 * have to do brace-replacement.
2508 execp
->num_args
= end
- start
;
2510 execp
->ctl
.replace_pat
= "{}";
2511 execp
->ctl
.rplen
= strlen(execp
->ctl
.replace_pat
);
2512 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2513 execp
->ctl
.args_per_exec
= 0; /* no limit */
2514 execp
->replace_vec
= xmalloc(sizeof(char*)*execp
->num_args
);
2517 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2518 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2520 /* Remember the (pre-replacement) arguments for later. */
2521 for (i
=0; i
<execp
->num_args
; ++i
)
2523 execp
->replace_vec
[i
] = argv
[i
+start
];
2527 if (argv
[end
] == NULL
)
2535 /* handles both exec and ok predicate */
2537 old_insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
2539 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2540 int num_paths
; /* Number of args with path replacements. */
2541 int path_pos
; /* Index in array of path replacements. */
2542 int vec_pos
; /* Index in array of args. */
2543 struct predicate
*our_pred
;
2544 struct exec_val
*execp
; /* Pointer for efficiency. */
2546 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2549 /* Count the number of args with path replacements, up until the ';'. */
2551 for (end
= start
, num_paths
= 0;
2553 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2555 if (strstr (argv
[end
], "{}"))
2557 /* Fail if no command given or no semicolon found. */
2558 if ((end
== start
) || (argv
[end
] == NULL
))
2564 our_pred
= insert_primary (func
);
2565 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2566 execp
= &our_pred
->args
.exec_vec
;
2567 execp
->usercontext
= our_pred
;
2568 execp
->use_current_dir
= false;
2570 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
2571 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
2572 /* Record the positions of all args, and the args with path replacements. */
2573 for (end
= start
, path_pos
= vec_pos
= 0;
2575 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2580 execp
->paths
[path_pos
].count
= 0;
2581 for (p
= argv
[end
]; *p
; ++p
)
2582 if (p
[0] == '{' && p
[1] == '}')
2584 execp
->paths
[path_pos
].count
++;
2587 if (execp
->paths
[path_pos
].count
)
2589 execp
->paths
[path_pos
].offset
= vec_pos
;
2590 execp
->paths
[path_pos
].origarg
= argv
[end
];
2593 execp
->vec
[vec_pos
++] = argv
[end
];
2595 execp
->paths
[path_pos
].offset
= -1;
2596 execp
->vec
[vec_pos
] = NULL
;
2598 if (argv
[end
] == NULL
)
2609 insert_exec_ok (const char *action
, const struct parser_table
*entry
, char **argv
, int *arg_ptr
)
2611 #if defined(NEW_EXEC)
2612 return new_insert_exec_ok(action
, entry
, argv
, arg_ptr
);
2614 return old_insert_exec_ok(func
, argv
, arg_ptr
);
2620 /* Get a number of days and comparison type.
2621 STR is the ASCII representation.
2622 Set *NUM_DAYS to the number of days, taken as being from
2623 the current moment (or possibly midnight). Thus the sense of the
2624 comparison type appears to be reversed.
2625 Set *COMP_TYPE to the kind of comparison that is requested.
2627 Return true if all okay, false if input error.
2629 Used by -atime, -ctime and -mtime (parsers) to
2630 get the appropriate information for a time predicate processor. */
2633 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
2635 boolean r
= get_num (str
, num_days
, comp_type
);
2639 case COMP_LT
: *comp_type
= COMP_GT
; break;
2640 case COMP_GT
: *comp_type
= COMP_LT
; break;
2646 /* Insert a time predicate PRED.
2647 ARGV is a pointer to the argument array.
2648 ARG_PTR is a pointer to an index into the array, incremented if
2651 Return true if input is valid, false if not.
2653 A new predicate node is assigned, along with an argument node
2654 obtained with malloc.
2656 Used by -atime, -ctime, and -mtime parsers. */
2659 parse_time (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
2661 struct predicate
*our_pred
;
2663 enum comparison_type c_type
;
2666 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2668 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
2671 /* Figure out the timestamp value we are looking for. */
2672 t
= ( options
.cur_day_start
- num_days
* DAYSECS
2673 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2677 /* We introduce a scope in which 'val' can be declared, for the
2678 * benefit of compilers that are really C89 compilers
2679 * which support intmax_t because config.h #defines it
2681 intmax_t val
= ( (intmax_t)options
.cur_day_start
- num_days
* DAYSECS
2682 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2685 /* Check for possibility of an overflow */
2686 if ( (intmax_t)t
!= val
)
2688 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
2692 our_pred
= insert_primary (entry
);
2693 our_pred
->args
.info
.kind
= c_type
;
2694 our_pred
->args
.info
.negative
= t
< 0;
2695 our_pred
->args
.info
.l_val
= t
;
2696 our_pred
->est_success_rate
= estimate_file_age_success_rate(num_days
);
2699 if (options
.debug_options
& DebugExpressionTree
)
2701 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2702 fprintf (stderr
, " type: %s %s ",
2703 (c_type
== COMP_GT
) ? "gt" :
2704 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2705 (c_type
== COMP_GT
) ? " >" :
2706 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
2707 t
= our_pred
->args
.info
.l_val
;
2708 fprintf (stderr
, "%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2709 if (c_type
== COMP_EQ
)
2711 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
2712 fprintf (stderr
, " < %ju %s",
2713 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2714 our_pred
->args
.info
.l_val
-= DAYSECS
;
2721 /* Get a number with comparison information.
2722 The sense of the comparison information is 'normal'; that is,
2723 '+' looks for a count > than the number and '-' less than.
2725 STR is the ASCII representation of the number.
2726 Set *NUM to the number.
2727 Set *COMP_TYPE to the kind of comparison that is requested.
2729 Return true if all okay, false if input error. */
2732 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
2739 *comp_type
= COMP_GT
;
2743 *comp_type
= COMP_LT
;
2747 *comp_type
= COMP_EQ
;
2751 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
2754 /* Insert a number predicate.
2755 ARGV is a pointer to the argument array.
2756 *ARG_PTR is an index into ARGV, incremented if all went well.
2757 *PRED is the predicate processor to insert.
2759 Return true if input is valid, false if error.
2761 A new predicate node is assigned, along with an argument node
2762 obtained with malloc.
2764 Used by -inum and -links parsers. */
2766 static struct predicate
*
2767 insert_num (char **argv
, int *arg_ptr
, const struct parser_table
*entry
)
2769 struct predicate
*our_pred
;
2771 enum comparison_type c_type
;
2773 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2775 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2777 our_pred
= insert_primary (entry
);
2778 our_pred
->args
.info
.kind
= c_type
;
2779 our_pred
->args
.info
.l_val
= num
;
2782 if (options
.debug_options
& DebugExpressionTree
)
2784 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2785 fprintf (stderr
, " type: %s %s ",
2786 (c_type
== COMP_GT
) ? "gt" :
2787 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2788 (c_type
== COMP_GT
) ? " >" :
2789 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2790 fprintf (stderr
, "%ju\n", our_pred
->args
.info
.l_val
);
2796 open_output_file (char *path
)
2800 if (!strcmp (path
, "/dev/stderr"))
2802 else if (!strcmp (path
, "/dev/stdout"))
2804 f
= fopen_safer (path
, "w");
2806 error (1, errno
, "%s", path
);