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, 2006 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
,
162 int kind
, char format_char
, char aux_format_char
,
163 struct predicate
*pred
));
164 static boolean insert_exec_ok
PARAMS((const char *action
, const struct parser_table
*entry
, char *argv
[], int *arg_ptr
));
165 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
166 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
167 static struct predicate
* insert_num
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
));
168 static FILE *open_output_file
PARAMS((char *path
));
169 static boolean
stream_is_tty(FILE *fp
);
170 static boolean parse_noop
PARAMS((const struct parser_table
* entry
, char **argv
, int *arg_ptr
));
172 #define PASTE(x,y) x##y
173 #define STRINGIFY(s) #s
175 #define PARSE_OPTION(what,suffix) \
176 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
178 #define PARSE_POSOPT(what,suffix) \
179 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
181 #define PARSE_TEST(what,suffix) \
182 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
184 #define PARSE_TEST_NP(what,suffix) \
185 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
187 #define PARSE_ACTION(what,suffix) \
188 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
190 #define PARSE_ACTION_NP(what,suffix) \
191 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
193 #define PARSE_PUNCTUATION(what,suffix) \
194 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
197 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
198 If they are in some Unix versions of find, they are marked `Unix'. */
200 static struct parser_table
const parse_table
[] =
202 PARSE_PUNCTUATION("!", negate
),
203 PARSE_PUNCTUATION("not", negate
), /* GNU */
204 PARSE_PUNCTUATION("(", open
),
205 PARSE_PUNCTUATION(")", close
),
206 PARSE_PUNCTUATION(",", comma
), /* GNU */
207 PARSE_PUNCTUATION("a", and),
208 PARSE_TEST ("amin", amin
), /* GNU */
209 PARSE_PUNCTUATION("and", and), /* GNU */
210 PARSE_TEST ("anewer", anewer
), /* GNU */
211 {ARG_TEST
, "atime", parse_time
, pred_atime
},
212 PARSE_TEST ("cmin", cmin
), /* GNU */
213 PARSE_TEST ("cnewer", cnewer
), /* GNU */
214 {ARG_TEST
, "ctime", parse_time
, pred_ctime
},
215 PARSE_POSOPT ("daystart", daystart
), /* GNU */
216 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
217 PARSE_OPTION ("d", d
), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
218 PARSE_OPTION ("depth", depth
),
219 PARSE_TEST ("empty", empty
), /* GNU */
220 {ARG_ACTION
, "exec", parse_exec
, pred_exec
}, /* POSIX */
221 {ARG_TEST
, "executable", parse_accesscheck
, pred_executable
}, /* GNU, 4.3.0+ */
222 PARSE_ACTION ("execdir", execdir
), /* *BSD, GNU */
223 PARSE_ACTION ("fls", fls
), /* GNU */
224 PARSE_POSOPT ("follow", follow
), /* GNU, Unix */
225 PARSE_ACTION ("fprint", fprint
), /* GNU */
226 PARSE_ACTION ("fprint0", fprint0
), /* GNU */
227 {ARG_ACTION
, "fprintf", parse_fprintf
, pred_fprintf
}, /* GNU */
228 PARSE_TEST ("fstype", fstype
), /* GNU, Unix */
229 PARSE_TEST ("gid", gid
), /* GNU */
230 PARSE_TEST ("group", group
),
231 PARSE_OPTION ("ignore_readdir_race", ignore_race
), /* GNU */
232 PARSE_TEST ("ilname", ilname
), /* GNU */
233 PARSE_TEST ("iname", iname
), /* GNU */
234 PARSE_TEST ("inum", inum
), /* GNU, Unix */
235 PARSE_TEST ("ipath", ipath
), /* GNU, deprecated in favour of iwholename */
236 PARSE_TEST_NP ("iregex", iregex
), /* GNU */
237 PARSE_TEST_NP ("iwholename", iwholename
), /* GNU */
238 PARSE_TEST ("links", links
),
239 PARSE_TEST ("lname", lname
), /* GNU */
240 PARSE_ACTION ("ls", ls
), /* GNU, Unix */
241 PARSE_OPTION ("maxdepth", maxdepth
), /* GNU */
242 PARSE_OPTION ("mindepth", mindepth
), /* GNU */
243 PARSE_TEST ("mmin", mmin
), /* GNU */
244 PARSE_OPTION ("mount", xdev
), /* Unix */
245 {ARG_TEST
, "mtime", parse_time
, pred_mtime
},
246 PARSE_TEST ("name", name
),
247 #ifdef UNIMPLEMENTED_UNIX
248 PARSE(ARG_UNIMPLEMENTED
, "ncpio", ncpio
), /* Unix */
250 PARSE_TEST ("newer", newer
),
251 PARSE_OPTION ("noleaf", noleaf
), /* GNU */
252 PARSE_TEST ("nogroup", nogroup
),
253 PARSE_TEST ("nouser", nouser
),
254 PARSE_OPTION ("noignore_readdir_race", noignore_race
), /* GNU */
255 PARSE_POSOPT ("nowarn", nowarn
), /* GNU */
256 PARSE_PUNCTUATION("o", or),
257 PARSE_PUNCTUATION("or", or), /* GNU */
258 PARSE_ACTION ("ok", ok
),
259 PARSE_ACTION ("okdir", okdir
), /* GNU (-execdir is BSD) */
260 PARSE_TEST ("path", path
), /* GNU, HP-UX, GNU prefers wholename */
261 PARSE_TEST ("perm", perm
),
262 PARSE_ACTION ("print", print
),
263 PARSE_ACTION ("print0", print0
), /* GNU */
264 {ARG_ACTION
, "printf", parse_printf
, NULL
}, /* GNU */
265 PARSE_ACTION ("prune", prune
),
266 PARSE_ACTION ("quit", quit
), /* GNU */
267 {ARG_TEST
, "readable", parse_accesscheck
, pred_readable
}, /* GNU, 4.3.0+ */
268 PARSE_TEST ("regex", regex
), /* GNU */
269 PARSE_OPTION ("regextype", regextype
), /* GNU */
270 PARSE_TEST ("samefile", samefile
), /* GNU */
272 PARSE_OPTION ("show-control-chars", show_control_chars
), /* GNU, 4.3.0+ */
274 PARSE_TEST ("size", size
),
275 PARSE_TEST ("type", type
),
276 PARSE_TEST ("uid", uid
), /* GNU */
277 PARSE_TEST ("used", used
), /* GNU */
278 PARSE_TEST ("user", user
),
279 PARSE_OPTION ("warn", warn
), /* GNU */
280 PARSE_TEST_NP ("wholename", wholename
), /* GNU, replaces -path */
281 {ARG_TEST
, "writable", parse_accesscheck
, pred_writable
}, /* GNU, 4.3.0+ */
282 PARSE_OPTION ("xdev", xdev
),
283 PARSE_TEST ("xtype", xtype
), /* GNU */
284 #ifdef UNIMPLEMENTED_UNIX
285 /* It's pretty ugly for find to know about archive formats.
286 Plus what it could do with cpio archives is very limited.
287 Better to leave it out. */
288 PARSE(ARG_UNIMPLEMENTED
, "cpio", cpio
), /* Unix */
290 /* gnulib's stdbool.h might have made true and false into macros,
291 * so we can't leave named 'true' and 'false' tokens, so we have
292 * to expeant the relevant entries longhand.
294 {ARG_TEST
, "false", parse_false
, pred_false
}, /* GNU */
295 {ARG_TEST
, "true", parse_true
, pred_true
}, /* GNU */
296 {ARG_NOOP
, "noop", NULL
, pred_true
}, /* GNU, internal use only */
298 /* Various other cases that don't fit neatly into our macro scheme. */
299 {ARG_TEST
, "help", parse_help
, NULL
}, /* GNU */
300 {ARG_TEST
, "-help", parse_help
, NULL
}, /* GNU */
301 {ARG_TEST
, "version", parse_version
, NULL
}, /* GNU */
302 {ARG_TEST
, "-version", parse_version
, NULL
}, /* GNU */
307 static const char *first_nonoption_arg
= NULL
;
308 static const struct parser_table
*noop
= NULL
;
312 static const struct parser_table
*
318 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
320 if (ARG_NOOP
==parse_table
[i
].type
)
322 noop
= &(parse_table
[i
]);
333 set_follow_state(enum SymlinkOption opt
)
335 if (options
.debug_options
& DebugStat
)
337 /* For DebugStat, the choice is made at runtime within debug_stat()
338 * by checking the contents of the symlink_handling variable.
340 options
.xstat
= debug_stat
;
346 case SYMLINK_ALWAYS_DEREF
: /* -L */
347 options
.xstat
= optionl_stat
;
348 options
.no_leaf_check
= true;
351 case SYMLINK_NEVER_DEREF
: /* -P (default) */
352 options
.xstat
= optionp_stat
;
353 /* Can't turn no_leaf_check off because the user might have specified
358 case SYMLINK_DEREF_ARGSONLY
: /* -H */
359 options
.xstat
= optionh_stat
;
360 options
.no_leaf_check
= true;
363 options
.symlink_handling
= opt
;
368 parse_begin_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
374 first_nonoption_arg
= NULL
;
378 parse_end_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
390 /* Return a pointer to the parser function to invoke for predicate
392 Return NULL if SEARCH_NAME is not a valid predicate name. */
394 const struct parser_table
*
395 find_parser (char *search_name
)
398 const char *original_arg
= search_name
;
400 if (*search_name
== '-')
402 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
404 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
406 /* If this is an option, but we have already had a
407 * non-option argument, the user may be under the
408 * impression that the behaviour of the option
409 * argument is conditional on some preceding
410 * tests. This might typically be the case with,
411 * for example, -maxdepth.
413 * The options -daystart and -follow are exempt
414 * from this treatment, since their positioning
415 * in the command line does have an effect on
416 * subsequent tests but not previous ones. That
417 * might be intentional on the part of the user.
419 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
421 /* Something other than -follow/-daystart.
422 * If this is an option, check if it followed
423 * a non-option and if so, issue a warning.
425 if (parse_table
[i
].type
== ARG_OPTION
)
427 if ((first_nonoption_arg
!= NULL
)
428 && options
.warnings
)
430 /* option which follows a non-option */
432 _("warning: you have specified the %s "
433 "option after a non-option argument %s, "
434 "but options are not positional (%s affects "
435 "tests specified before it as well as those "
436 "specified after it). Please specify options "
437 "before other arguments.\n"),
445 /* Not an option or a positional option,
446 * so remember we've seen it in order to
447 * use it in a possible future warning message.
449 if (first_nonoption_arg
== NULL
)
451 first_nonoption_arg
= original_arg
;
456 return &parse_table
[i
];
463 estimate_file_age_success_rate(float num_days
)
467 /* Assume 1% of files have timestamps in the future */
470 else if (num_days
< 1)
472 /* Assume 30% of files have timestamps today */
475 else if (num_days
> 100)
477 /* Assume 30% of files are very old */
482 /* Assume 39% of files are between 1 and 100 days old. */
488 estimate_timestamp_success_rate(time_t when
)
490 int num_days
= (when
- options
.cur_day_start
) / 86400;
491 return estimate_file_age_success_rate(num_days
);
495 /* The parsers are responsible to continue scanning ARGV for
496 their arguments. Each parser knows what is and isn't
499 ARGV is the argument array.
500 *ARG_PTR is the index to start at in ARGV,
501 updated to point beyond the last element consumed.
503 The predicate structure is updated with the new information. */
506 parse_amin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
508 struct predicate
*our_pred
;
510 enum comparison_type c_type
;
513 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
515 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
517 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
518 our_pred
= insert_primary (entry
);
519 our_pred
->args
.info
.kind
= c_type
;
520 our_pred
->args
.info
.negative
= t
< 0;
521 our_pred
->args
.info
.l_val
= t
;
522 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
528 parse_and (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
530 struct predicate
*our_pred
;
535 our_pred
= get_new_pred (entry
);
536 our_pred
->pred_func
= pred_and
;
537 our_pred
->p_type
= BI_OP
;
538 our_pred
->p_prec
= AND_PREC
;
539 our_pred
->need_stat
= our_pred
->need_type
= false;
544 parse_anewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
546 struct predicate
*our_pred
;
547 struct stat stat_newer
;
549 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
551 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
552 error (1, errno
, "%s", argv
[*arg_ptr
]);
553 our_pred
= insert_primary (entry
);
554 our_pred
->args
.time
= stat_newer
.st_mtime
;
555 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
561 parse_close (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
563 struct predicate
*our_pred
;
568 our_pred
= get_new_pred (entry
);
569 our_pred
->pred_func
= pred_close
;
570 our_pred
->p_type
= CLOSE_PAREN
;
571 our_pred
->p_prec
= NO_PREC
;
572 our_pred
->need_stat
= our_pred
->need_type
= false;
577 parse_cmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
579 struct predicate
*our_pred
;
581 enum comparison_type c_type
;
584 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
586 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
588 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
589 our_pred
= insert_primary (entry
);
590 our_pred
->args
.info
.kind
= c_type
;
591 our_pred
->args
.info
.negative
= t
< 0;
592 our_pred
->args
.info
.l_val
= t
;
593 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
599 parse_cnewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
601 struct predicate
*our_pred
;
602 struct stat stat_newer
;
604 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
606 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
607 error (1, errno
, "%s", argv
[*arg_ptr
]);
608 our_pred
= insert_primary (entry
);
609 our_pred
->args
.time
= stat_newer
.st_mtime
;
610 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
616 parse_comma (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
618 struct predicate
*our_pred
;
623 our_pred
= get_new_pred (entry
);
624 our_pred
->pred_func
= pred_comma
;
625 our_pred
->p_type
= BI_OP
;
626 our_pred
->p_prec
= COMMA_PREC
;
627 our_pred
->need_stat
= our_pred
->need_type
= false;
628 our_pred
->est_success_rate
= 1.0f
;
633 parse_daystart (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
641 if (options
.full_days
== false)
643 options
.cur_day_start
+= DAYSECS
;
644 local
= localtime (&options
.cur_day_start
);
645 options
.cur_day_start
-= (local
646 ? (local
->tm_sec
+ local
->tm_min
* 60
647 + local
->tm_hour
* 3600)
648 : options
.cur_day_start
% DAYSECS
);
649 options
.full_days
= true;
655 parse_delete (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
657 struct predicate
*our_pred
;
661 our_pred
= insert_primary (entry
);
662 our_pred
->side_effects
= our_pred
->no_default_print
= true;
663 /* -delete implies -depth */
664 options
.do_dir_first
= false;
665 our_pred
->est_success_rate
= 1.0f
;
670 parse_depth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
676 options
.do_dir_first
= false;
677 return parse_noop(entry
, argv
, arg_ptr
);
681 parse_d (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
686 if (options
.warnings
)
689 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
691 return parse_depth(entry
, argv
, arg_ptr
);
695 parse_empty (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
697 struct predicate
*our_pred
;
701 our_pred
= insert_primary (entry
);
702 our_pred
->est_success_rate
= 0.01f
; /* assume 1% of files are empty. */
707 parse_exec (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
709 return insert_exec_ok ("-exec", entry
, argv
, arg_ptr
);
713 parse_execdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
715 return insert_exec_ok ("-execdir", entry
, argv
, arg_ptr
);
719 parse_false (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
721 struct predicate
*our_pred
;
726 our_pred
= insert_primary (entry
);
727 our_pred
->need_stat
= our_pred
->need_type
= false;
728 our_pred
->side_effects
= our_pred
->no_default_print
= false;
729 our_pred
->est_success_rate
= 0.0f
;
734 parse_fls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
736 struct predicate
*our_pred
;
738 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
740 our_pred
= insert_primary (entry
);
741 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
742 our_pred
->side_effects
= our_pred
->no_default_print
= true;
743 our_pred
->est_success_rate
= 1.0f
;
749 parse_fprintf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
753 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
755 if (argv
[*arg_ptr
+ 1] == NULL
)
757 /* Ensure we get "missing arg" message, not "invalid arg". */
761 fp
= open_output_file (argv
[*arg_ptr
]);
763 return insert_fprintf (fp
, entry
, pred_fprintf
, argv
, arg_ptr
);
767 parse_follow (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
773 set_follow_state(SYMLINK_ALWAYS_DEREF
);
774 return parse_noop(entry
, argv
, arg_ptr
);
778 parse_fprint (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
780 struct predicate
*our_pred
;
782 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
784 our_pred
= insert_primary (entry
);
785 our_pred
->args
.printf_vec
.segment
= NULL
;
786 our_pred
->args
.printf_vec
.stream
= open_output_file (argv
[*arg_ptr
]);
787 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(our_pred
->args
.printf_vec
.stream
);
788 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
789 our_pred
->side_effects
= our_pred
->no_default_print
= true;
790 our_pred
->need_stat
= our_pred
->need_type
= false;
791 our_pred
->est_success_rate
= 1.0f
;
797 parse_fprint0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
799 struct predicate
*our_pred
;
801 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
803 our_pred
= insert_primary (entry
);
804 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
805 our_pred
->side_effects
= our_pred
->no_default_print
= true;
806 our_pred
->need_stat
= our_pred
->need_type
= false;
807 our_pred
->est_success_rate
= 1.0f
;
812 static float estimate_fstype_success_rate(const char *fsname
)
814 struct stat dir_stat
;
815 const char *dir
= "/";
816 if (0 == stat(dir
, &dir_stat
))
818 const char *fstype
= filesystem_type(&dir_stat
, dir
);
819 /* Assume most files are on the same filesystem type as the root fs. */
820 if (0 == strcmp(fsname
, fstype
))
830 parse_fstype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
832 struct predicate
*our_pred
;
834 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
836 our_pred
= insert_primary (entry
);
837 our_pred
->args
.str
= argv
[*arg_ptr
];
839 /* This is an expensive operation, so although there are
840 * circumstances where it is selective, we ignore this fact because
841 * we probably don't want to promote this test to the front anyway.
843 our_pred
->est_success_rate
= estimate_fstype_success_rate(argv
[*arg_ptr
]);
849 parse_gid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
851 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
852 p
->est_success_rate
= (p
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
857 parse_group (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
859 struct group
*cur_gr
;
860 struct predicate
*our_pred
;
864 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
866 cur_gr
= getgrnam (argv
[*arg_ptr
]);
869 gid
= cur_gr
->gr_gid
;
872 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
873 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
875 gid
= atoi (argv
[*arg_ptr
]);
877 our_pred
= insert_primary (entry
);
878 our_pred
->args
.gid
= gid
;
879 our_pred
->est_success_rate
= (our_pred
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
885 parse_help (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
891 usage(stdout
, 0, NULL
);
893 default path is the current directory; default expression is -print\n\
894 expression may consist of: operators, options, tests, and actions:\n"));
896 operators (decreasing precedence; -and is implicit where no others are given):\n\
897 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
898 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
900 positional options (always true): -daystart -follow -regextype\n\n\
901 normal options (always true, specified before other expressions):\n\
902 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
903 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
905 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
906 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
907 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
908 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
910 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
911 -readable -writable -executable\n\
912 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
913 -used N -user NAME -xtype [bcdpfls]\n"));
915 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
916 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
917 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
918 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
920 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
921 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
922 email to <bug-findutils@gnu.org>."));
926 static float estimate_pattern_match_rate(const char *pattern
, int is_regex
)
928 if (strpbrk(pattern
, "*?[") || (is_regex
&& strpbrk(pattern
, ".")))
930 /* A wildcard; assume the pattern matches most files. */
940 parse_ilname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
942 struct predicate
*our_pred
;
944 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
946 our_pred
= insert_primary (entry
);
947 our_pred
->args
.str
= argv
[*arg_ptr
];
948 /* Use the generic glob pattern estimator to figure out how many
949 * links will match, but bear in mind that most files won't be links.
951 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
957 /* sanity check the fnmatch() function to make sure
958 * it really is the GNU version.
961 fnmatch_sanitycheck(void)
963 /* fprintf(stderr, "Performing find sanity check..."); */
964 if (0 != fnmatch("foo", "foo", 0)
965 || 0 == fnmatch("Foo", "foo", 0)
966 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
968 error (1, 0, _("sanity check of the fnmatch() library function failed."));
969 /* fprintf(stderr, "FAILED\n"); */
973 /* fprintf(stderr, "OK\n"); */
979 check_name_arg(const char *pred
, const char *arg
)
981 if (strchr(arg
, '/'))
983 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'."),
986 return true; /* allow it anyway */
992 parse_iname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
994 struct predicate
*our_pred
;
996 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
998 if (!check_name_arg("-iname", argv
[*arg_ptr
]))
1001 fnmatch_sanitycheck();
1003 our_pred
= insert_primary (entry
);
1004 our_pred
->need_stat
= our_pred
->need_type
= false;
1005 our_pred
->args
.str
= argv
[*arg_ptr
];
1006 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1012 parse_inum (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1014 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1015 /* inode number is exact match only, so very low proportions of files match */
1016 p
->est_success_rate
= 1e-6;
1020 /* -ipath is deprecated (at RMS's request) in favour of
1021 * -iwholename. See the node "GNU Manuals" in standards.texi
1022 * for the rationale for this (basically, GNU prefers the use
1023 * of the phrase "file name" to "path name"
1026 parse_ipath (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1029 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1031 return parse_iwholename(entry
, argv
, arg_ptr
);
1035 parse_iwholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1037 struct predicate
*our_pred
;
1039 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1042 fnmatch_sanitycheck();
1044 our_pred
= insert_primary_withpred (entry
, pred_ipath
);
1045 our_pred
->need_stat
= our_pred
->need_type
= false;
1046 our_pred
->args
.str
= argv
[*arg_ptr
];
1047 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1053 parse_iregex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1055 return insert_regex (argv
, arg_ptr
, entry
, RE_ICASE
|options
.regex_options
);
1059 parse_links (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1061 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1062 if (p
->args
.info
.l_val
== 1)
1063 p
->est_success_rate
= 0.99;
1064 else if (p
->args
.info
.l_val
== 2)
1065 p
->est_success_rate
= 0.01;
1067 p
->est_success_rate
= 1e-3;
1072 parse_lname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1074 struct predicate
*our_pred
;
1079 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1082 fnmatch_sanitycheck();
1084 our_pred
= insert_primary (entry
);
1085 our_pred
->args
.str
= argv
[*arg_ptr
];
1086 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1092 parse_ls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1094 struct predicate
*our_pred
;
1099 our_pred
= insert_primary (entry
);
1100 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1105 parse_maxdepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1110 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1112 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1113 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1115 options
.maxdepth
= atoi (argv
[*arg_ptr
]);
1116 if (options
.maxdepth
< 0)
1119 return parse_noop(entry
, argv
, arg_ptr
);
1123 parse_mindepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1128 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1130 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1131 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1133 options
.mindepth
= atoi (argv
[*arg_ptr
]);
1134 if (options
.mindepth
< 0)
1137 return parse_noop(entry
, argv
, arg_ptr
);
1141 parse_mmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1143 struct predicate
*our_pred
;
1145 enum comparison_type c_type
;
1148 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1150 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
1152 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
1153 our_pred
= insert_primary (entry
);
1154 our_pred
->args
.info
.kind
= c_type
;
1155 our_pred
->args
.info
.negative
= t
< 0;
1156 our_pred
->args
.info
.l_val
= t
;
1157 our_pred
->est_success_rate
= estimate_file_age_success_rate(num
);
1163 parse_name (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1165 struct predicate
*our_pred
;
1170 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1172 if (!check_name_arg("-name", argv
[*arg_ptr
]))
1174 fnmatch_sanitycheck();
1176 our_pred
= insert_primary (entry
);
1177 our_pred
->need_stat
= our_pred
->need_type
= false;
1178 our_pred
->args
.str
= argv
[*arg_ptr
];
1179 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1185 parse_negate (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1187 struct predicate
*our_pred
;
1192 our_pred
= get_new_pred_chk_op (entry
);
1193 our_pred
->pred_func
= pred_negate
;
1194 our_pred
->p_type
= UNI_OP
;
1195 our_pred
->p_prec
= NEGATE_PREC
;
1196 our_pred
->need_stat
= our_pred
->need_type
= false;
1201 parse_newer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1203 struct predicate
*our_pred
;
1204 struct stat stat_newer
;
1209 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1211 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
1212 error (1, errno
, "%s", argv
[*arg_ptr
]);
1213 our_pred
= insert_primary (entry
);
1214 our_pred
->args
.time
= stat_newer
.st_mtime
;
1215 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
1221 parse_noleaf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1227 options
.no_leaf_check
= true;
1228 return parse_noop(entry
, argv
, arg_ptr
);
1232 /* Arbitrary amount by which to increase size
1233 of `uid_unused' and `gid_unused'. */
1234 #define ALLOC_STEP 2048
1236 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1237 char *uid_unused
= NULL
;
1239 /* Number of elements in `uid_unused'. */
1240 unsigned uid_allocated
;
1242 /* Similar for GIDs and group entries. */
1243 char *gid_unused
= NULL
;
1244 unsigned gid_allocated
;
1248 parse_nogroup (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1250 struct predicate
*our_pred
;
1255 our_pred
= insert_primary (entry
);
1256 our_pred
->est_success_rate
= 1e-4;
1258 if (gid_unused
== NULL
)
1262 gid_allocated
= ALLOC_STEP
;
1263 gid_unused
= xmalloc (gid_allocated
);
1264 memset (gid_unused
, 1, gid_allocated
);
1266 while ((gr
= getgrent ()) != NULL
)
1268 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1270 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1271 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1272 memset (gid_unused
+ gid_allocated
, 1,
1273 new_allocated
- gid_allocated
);
1274 gid_allocated
= new_allocated
;
1276 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1285 parse_nouser (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1287 struct predicate
*our_pred
;
1292 our_pred
= insert_primary (entry
);
1293 our_pred
->est_success_rate
= 1e-3;
1295 if (uid_unused
== NULL
)
1299 uid_allocated
= ALLOC_STEP
;
1300 uid_unused
= xmalloc (uid_allocated
);
1301 memset (uid_unused
, 1, uid_allocated
);
1303 while ((pw
= getpwent ()) != NULL
)
1305 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1307 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1308 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1309 memset (uid_unused
+ uid_allocated
, 1,
1310 new_allocated
- uid_allocated
);
1311 uid_allocated
= new_allocated
;
1313 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1322 parse_nowarn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1328 options
.warnings
= false;
1329 return parse_noop(entry
, argv
, arg_ptr
);
1333 parse_ok (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1335 return insert_exec_ok ("-ok", entry
, argv
, arg_ptr
);
1339 parse_okdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1341 return insert_exec_ok ("-okdir", entry
, argv
, arg_ptr
);
1345 parse_open (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1347 struct predicate
*our_pred
;
1352 our_pred
= get_new_pred_chk_op (entry
);
1353 our_pred
->pred_func
= pred_open
;
1354 our_pred
->p_type
= OPEN_PAREN
;
1355 our_pred
->p_prec
= NO_PREC
;
1356 our_pred
->need_stat
= our_pred
->need_type
= false;
1361 parse_or (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1363 struct predicate
*our_pred
;
1368 our_pred
= get_new_pred (entry
);
1369 our_pred
->pred_func
= pred_or
;
1370 our_pred
->p_type
= BI_OP
;
1371 our_pred
->p_prec
= OR_PREC
;
1372 our_pred
->need_stat
= our_pred
->need_type
= false;
1376 /* -path is deprecated (at RMS's request) in favour of
1377 * -iwholename. See the node "GNU Manuals" in standards.texi
1378 * for the rationale for this (basically, GNU prefers the use
1379 * of the phrase "file name" to "path name".
1381 * We do not issue a warning that this usage is deprecated
1382 * since HPUX find supports this predicate also.
1385 parse_path (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1387 return parse_wholename(entry
, argv
, arg_ptr
);
1391 parse_wholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1393 struct predicate
*our_pred
;
1395 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1397 our_pred
= insert_primary_withpred (entry
, pred_path
);
1398 our_pred
->need_stat
= our_pred
->need_type
= false;
1399 our_pred
->args
.str
= argv
[*arg_ptr
];
1400 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1406 parse_perm (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1411 boolean havekind
= false;
1412 enum permissions_type kind
= PERM_EXACT
;
1413 struct mode_change
*change
= NULL
;
1414 struct predicate
*our_pred
;
1416 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1419 switch (argv
[*arg_ptr
][0])
1423 kind
= PERM_AT_LEAST
;
1429 change
= mode_compile (argv
[*arg_ptr
]);
1432 /* Most likely the caller is an old script that is still
1433 * using the obsolete GNU syntax '-perm +MODE'. This old
1434 * syntax was withdrawn in favor of '-perm /MODE' because
1435 * it is incompatible with POSIX in some cases, but we
1436 * still support uses of it that are not incompatible with
1445 /* This is a POSIX-compatible usage */
1453 case '/': /* GNU extension */
1461 /* For example, '-perm 0644', which is valid and matches
1462 * only files whose mode is exactly 0644.
1464 * We do nothing here, because mode_start and kind are already
1473 change
= mode_compile (argv
[*arg_ptr
] + mode_start
);
1475 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1477 perm_val
[0] = mode_adjust (0, false, 0, change
, NULL
);
1478 perm_val
[1] = mode_adjust (0, true, 0, change
, NULL
);
1481 our_pred
= insert_primary (entry
);
1482 our_pred
->est_success_rate
= rate
;
1485 our_pred
->args
.perm
.kind
= kind
;
1490 switch (argv
[*arg_ptr
][0])
1493 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1496 our_pred
->args
.perm
.kind
= PERM_ANY
;
1499 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1503 if (('/' == argv
[*arg_ptr
][0]) && (0 == perm_val
[0]) && (0 == perm_val
[1]))
1505 /* The meaning of -perm /000 will change in the future.
1506 * It currently matches no files, but like -perm -000 it
1507 * should match all files.
1510 _("warning: you have specified a mode pattern %s which is "
1511 "equivalent to 000. The meaning of -perm /000 will soon be "
1512 "changed to be consistent with -perm -000; that is, at the "
1513 "moment it matches no files but it will soon be changed to "
1514 "match all files."),
1518 memcpy (our_pred
->args
.perm
.val
, perm_val
, sizeof perm_val
);
1524 parse_print (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1526 struct predicate
*our_pred
;
1531 our_pred
= insert_primary (entry
);
1532 /* -print has the side effect of printing. This prevents us
1533 from doing undesired multiple printing when the user has
1534 already specified -print. */
1535 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1536 our_pred
->need_stat
= our_pred
->need_type
= false;
1537 our_pred
->args
.printf_vec
.segment
= NULL
;
1538 our_pred
->args
.printf_vec
.stream
= stdout
;
1539 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(stdout
);
1540 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
1546 parse_print0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1548 struct predicate
*our_pred
;
1553 our_pred
= insert_primary (entry
);
1554 /* -print0 has the side effect of printing. This prevents us
1555 from doing undesired multiple printing when the user has
1556 already specified -print0. */
1557 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1558 our_pred
->need_stat
= our_pred
->need_type
= false;
1563 parse_printf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1565 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1567 return insert_fprintf (stdout
, entry
, pred_fprintf
, argv
, arg_ptr
);
1571 parse_prune (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1573 struct predicate
*our_pred
;
1578 our_pred
= insert_primary (entry
);
1579 our_pred
->need_stat
= our_pred
->need_type
= false;
1580 /* -prune has a side effect that it does not descend into
1581 the current directory. */
1582 our_pred
->side_effects
= true;
1583 our_pred
->no_default_print
= false;
1588 parse_quit (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1590 struct predicate
*our_pred
= insert_primary (entry
);
1593 our_pred
->need_stat
= our_pred
->need_type
= false;
1594 our_pred
->side_effects
= true; /* Exiting is a side effect... */
1595 our_pred
->no_default_print
= false; /* Don't inhibit the default print, though. */
1596 our_pred
->est_success_rate
= 1e-6;
1602 parse_regextype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1604 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1607 /* collect the regex type name */
1608 options
.regex_options
= get_regex_type(argv
[*arg_ptr
]);
1611 return parse_noop(entry
, argv
, arg_ptr
);
1616 parse_regex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1618 return insert_regex (argv
, arg_ptr
, entry
, options
.regex_options
);
1622 insert_regex (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, int regex_options
)
1624 struct predicate
*our_pred
;
1625 struct re_pattern_buffer
*re
;
1626 const char *error_message
;
1628 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1630 our_pred
= insert_primary_withpred (entry
, pred_regex
);
1631 our_pred
->need_stat
= our_pred
->need_type
= false;
1632 re
= (struct re_pattern_buffer
*)
1633 xmalloc (sizeof (struct re_pattern_buffer
));
1634 our_pred
->args
.regex
= re
;
1635 re
->allocated
= 100;
1636 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1639 re_set_syntax(regex_options
);
1640 re
->syntax
= regex_options
;
1641 re
->translate
= NULL
;
1643 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1646 error (1, 0, "%s", error_message
);
1647 our_pred
->est_success_rate
= estimate_pattern_match_rate(argv
[*arg_ptr
], 1);
1653 parse_size (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1655 struct predicate
*our_pred
;
1657 enum comparison_type c_type
;
1662 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1664 len
= strlen (argv
[*arg_ptr
]);
1666 error (1, 0, _("invalid null argument to -size"));
1667 switch (argv
[*arg_ptr
][len
- 1])
1671 argv
[*arg_ptr
][len
- 1] = '\0';
1676 argv
[*arg_ptr
][len
- 1] = '\0';
1681 argv
[*arg_ptr
][len
- 1] = '\0';
1684 case 'M': /* Megabytes */
1685 blksize
= 1024*1024;
1686 argv
[*arg_ptr
][len
- 1] = '\0';
1689 case 'G': /* Gigabytes */
1690 blksize
= 1024*1024*1024;
1691 argv
[*arg_ptr
][len
- 1] = '\0';
1696 argv
[*arg_ptr
][len
- 1] = '\0';
1712 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1714 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1716 our_pred
= insert_primary (entry
);
1717 our_pred
->args
.size
.kind
= c_type
;
1718 our_pred
->args
.size
.blocksize
= blksize
;
1719 our_pred
->args
.size
.size
= num
;
1720 our_pred
->need_stat
= true;
1721 our_pred
->need_type
= false;
1723 if (COMP_GT
== c_type
)
1724 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.1 : 0.9;
1725 else if (COMP_LT
== c_type
)
1726 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.9 : 0.1;
1728 our_pred
->est_success_rate
= 0.01;
1736 parse_samefile (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1738 struct predicate
*our_pred
;
1741 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1743 if ((*options
.xstat
) (argv
[*arg_ptr
], &st
))
1744 error (1, errno
, "%s", argv
[*arg_ptr
]);
1746 our_pred
= insert_primary (entry
);
1747 our_pred
->args
.fileid
.ino
= st
.st_ino
;
1748 our_pred
->args
.fileid
.dev
= st
.st_dev
;
1749 our_pred
->need_type
= false;
1750 our_pred
->need_stat
= true;
1751 our_pred
->est_success_rate
= 0.01f
;
1758 parse_show_control_chars (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1761 const char *errmsg
= _("The -show-control-chars option takes a single argument which "
1762 "must be 'literal' or 'safe'");
1764 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1766 error (1, errno
, "%s", errmsg
);
1771 arg
= argv
[*arg_ptr
];
1773 if (0 == strcmp("literal", arg
))
1775 options
.literal_control_chars
= true;
1777 else if (0 == strcmp("safe", arg
))
1779 options
.literal_control_chars
= false;
1783 error (1, errno
, "%s", errmsg
);
1786 (*arg_ptr
)++; /* consume the argument. */
1794 parse_true (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1796 struct predicate
*our_pred
;
1801 our_pred
= insert_primary (entry
);
1802 our_pred
->need_stat
= our_pred
->need_type
= false;
1803 our_pred
->est_success_rate
= 1.0f
;
1808 parse_noop (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1811 return parse_true(get_noop(), argv
, arg_ptr
);
1815 parse_accesscheck (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1817 struct predicate
*our_pred
;
1820 our_pred
= insert_primary (entry
);
1821 our_pred
->need_stat
= our_pred
->need_type
= false;
1822 our_pred
->side_effects
= our_pred
->no_default_print
= false;
1823 if (our_pred
->pred_func
== pred_executable
)
1824 our_pred
->est_success_rate
= 0.2;
1826 our_pred
->est_success_rate
= 0.9;
1831 parse_type (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1833 return insert_type (argv
, arg_ptr
, entry
, pred_type
);
1837 parse_uid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1839 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1840 p
->est_success_rate
= (p
->args
.info
.l_val
< 100) ? 0.99 : 0.2;
1845 parse_used (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1847 struct predicate
*our_pred
;
1849 enum comparison_type c_type
;
1852 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1854 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1856 t
= num_days
* DAYSECS
;
1857 our_pred
= insert_primary (entry
);
1858 our_pred
->args
.info
.kind
= c_type
;
1859 our_pred
->args
.info
.negative
= t
< 0;
1860 our_pred
->args
.info
.l_val
= t
;
1861 our_pred
->est_success_rate
= estimate_file_age_success_rate(num_days
);
1867 parse_user (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1869 struct passwd
*cur_pwd
;
1870 struct predicate
*our_pred
;
1874 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1876 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1878 if (cur_pwd
!= NULL
)
1879 uid
= cur_pwd
->pw_uid
;
1882 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1883 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1885 uid
= atoi (argv
[*arg_ptr
]);
1887 our_pred
= insert_primary (entry
);
1888 our_pred
->args
.uid
= uid
;
1889 our_pred
->est_success_rate
= (our_pred
->args
.uid
< 100) ? 0.99 : 0.2;
1895 parse_version (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1897 extern char *version_string
;
1905 printf (_("GNU find version %s\n"), version_string
);
1906 printf (_("Features enabled: "));
1909 printf("CACHE_IDS ");
1917 printf("DEBUG_STAT ");
1920 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1924 #if defined(O_NOFOLLOW)
1925 printf("O_NOFOLLOW(%s) ",
1926 (options
.open_nofollow_available
? "enabled" : "disabled"));
1929 #if defined(LEAF_OPTIMISATION)
1930 printf("LEAF_OPTIMISATION ");
1934 if (is_fts_enabled())
1940 printf("CBO(level=%d) ", (int)(options
.optimisation_level
));
1945 /* For the moment, leave this as English in case someone wants
1946 to parse these strings. */
1955 parse_xdev (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1960 options
.stay_on_filesystem
= true;
1961 return parse_noop(entry
, argv
, arg_ptr
);
1965 parse_ignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1970 options
.ignore_readdir_race
= true;
1971 return parse_noop(entry
, argv
, arg_ptr
);
1975 parse_noignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1980 options
.ignore_readdir_race
= false;
1981 return parse_noop(entry
, argv
, arg_ptr
);
1985 parse_warn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1990 options
.warnings
= true;
1991 return parse_noop(entry
, argv
, arg_ptr
);
1995 parse_xtype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1999 return insert_type (argv
, arg_ptr
, entry
, pred_xtype
);
2003 insert_type (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
)
2006 struct predicate
*our_pred
;
2009 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
2010 || (strlen (argv
[*arg_ptr
]) != 1))
2012 switch (argv
[*arg_ptr
][0])
2014 case 'b': /* block special */
2015 type_cell
= S_IFBLK
;
2018 case 'c': /* character special */
2019 type_cell
= S_IFCHR
;
2022 case 'd': /* directory */
2023 type_cell
= S_IFDIR
;
2026 case 'f': /* regular file */
2027 type_cell
= S_IFREG
;
2031 case 'l': /* symbolic link */
2032 type_cell
= S_IFLNK
;
2037 case 'p': /* pipe */
2038 type_cell
= S_IFIFO
;
2043 case 's': /* socket */
2044 type_cell
= S_IFSOCK
;
2049 case 'D': /* Solaris door */
2050 type_cell
= S_IFDOOR
;
2054 default: /* None of the above ... nuke 'em. */
2057 our_pred
= insert_primary_withpred (entry
, which_pred
);
2058 our_pred
->est_success_rate
= rate
;
2060 /* Figure out if we will need to stat the file, because if we don't
2061 * need to follow symlinks, we can avoid a stat call by using
2062 * struct dirent.d_type.
2064 if (which_pred
== pred_xtype
)
2066 our_pred
->need_stat
= true;
2067 our_pred
->need_type
= false;
2071 our_pred
->need_stat
= false; /* struct dirent is enough */
2072 our_pred
->need_type
= true;
2074 our_pred
->args
.type
= type_cell
;
2075 (*arg_ptr
)++; /* Move on to next argument. */
2080 /* Return true if the file accessed via FP is a terminal.
2083 stream_is_tty(FILE *fp
)
2085 int fd
= fileno(fp
);
2088 return false; /* not a valid stream */
2092 return isatty(fd
) ? true : false;
2100 /* XXX: do we need to pass FUNC to this function? */
2102 insert_fprintf (FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char **argv
, int *arg_ptr
)
2104 char *format
; /* Beginning of unprocessed format string. */
2105 register char *scan
; /* Current address in scanning `format'. */
2106 register char *scan2
; /* Address inside of element being scanned. */
2107 struct segment
**segmentp
; /* Address of current segment. */
2108 struct predicate
*our_pred
;
2110 format
= argv
[(*arg_ptr
)++];
2112 our_pred
= insert_primary_withpred (entry
, func
);
2113 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2114 our_pred
->args
.printf_vec
.stream
= fp
;
2115 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(fp
);
2116 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
2117 our_pred
->need_type
= false;
2118 our_pred
->need_stat
= false;
2120 segmentp
= &our_pred
->args
.printf_vec
.segment
;
2123 for (scan
= format
; *scan
; scan
++)
2128 if (*scan2
>= '0' && *scan2
<= '7')
2132 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
2134 n
= 8 * n
+ *scan2
- '0';
2149 make_segment (segmentp
, format
, scan
- format
,
2152 if (our_pred
->need_stat
&& (our_pred
->p_cost
< NeedsStatInfo
))
2153 our_pred
->p_cost
= NeedsStatInfo
;
2171 /* *scan = '\\'; * it already is */
2175 _("warning: unrecognized escape `\\%c'"), *scan2
);
2180 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2183 format
= scan2
+ 1; /* Move past the escape. */
2184 scan
= scan2
; /* Incremented immediately by `for'. */
2186 else if (*scan
== '%')
2190 /* Trailing %. We don't like those. */
2191 error (1, 0, _("error: %s at end of format string"), scan
);
2193 else if (scan
[1] == '%')
2195 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2202 /* Scan past flags, width and precision, to verify kind. */
2203 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
2205 while (ISDIGIT (*scan2
))
2208 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
2210 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2
))
2212 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2213 KIND_FORMAT
, *scan2
, 0,
2218 else if (strchr ("ACT", *scan2
) && scan2
[1])
2220 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2221 KIND_FORMAT
, scan2
[0], scan2
[1],
2229 /* An unrecognized % escape. Print the char after the %. */
2230 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2232 segmentp
= make_segment (segmentp
, format
, scan
- format
,
2242 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
, 0, 0,
2247 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2248 from the text in FORMAT, which has length LEN.
2249 Return the address of the `next' pointer of the new segment. */
2251 static struct segment
**
2252 make_segment (struct segment
**segment
,
2257 char aux_format_char
,
2258 struct predicate
*pred
)
2260 enum EvaluationCost mycost
= NeedsNothing
;
2263 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
2265 (*segment
)->segkind
= kind
;
2266 (*segment
)->format_char
[0] = format_char
;
2267 (*segment
)->format_char
[1] = aux_format_char
;
2268 (*segment
)->next
= NULL
;
2269 (*segment
)->text_len
= len
;
2271 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
2272 strncpy (fmt
, format
, len
);
2277 case KIND_PLAIN
: /* Plain text string, no % conversion. */
2278 case KIND_STOP
: /* Terminate argument, no newline. */
2279 assert(0 == format_char
);
2280 assert(0 == aux_format_char
);
2282 if (mycost
> pred
->p_cost
)
2283 pred
->p_cost
= NeedsNothing
;
2284 return &(*segment
)->next
;
2288 assert(kind
== KIND_FORMAT
);
2289 switch (format_char
)
2291 case 'l': /* object of symlink */
2292 pred
->need_stat
= true;
2293 mycost
= NeedsLinkName
;
2297 case 'y': /* file type */
2298 pred
->need_type
= true;
2303 case 'a': /* atime in `ctime' format */
2304 case 'A': /* atime in user-specified strftime format */
2305 case 'c': /* ctime in `ctime' format */
2306 case 'C': /* ctime in user-specified strftime format */
2307 case 'F': /* filesystem type */
2308 case 'g': /* group name */
2309 case 'i': /* inode number */
2310 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2311 case 's': /* size in bytes */
2312 case 't': /* mtime in `ctime' format */
2313 case 'T': /* mtime in user-specified strftime format */
2314 case 'u': /* user name */
2315 pred
->need_stat
= true;
2316 mycost
= NeedsStatInfo
;
2320 case 'S': /* sparseness */
2321 pred
->need_stat
= true;
2322 mycost
= NeedsStatInfo
;
2326 case 'Y': /* symlink pointed file type */
2327 pred
->need_stat
= true;
2328 mycost
= NeedsType
; /* true for amortised effect */
2332 case 'f': /* basename of path */
2333 case 'h': /* leading directories part of path */
2334 case 'p': /* pathname */
2335 case 'P': /* pathname with ARGV element stripped */
2339 case 'H': /* ARGV element file was found under */
2343 /* Numeric items that one might expect to honour
2344 * #, 0, + flags but which do not.
2346 case 'G': /* GID number */
2347 case 'U': /* UID number */
2348 case 'b': /* size in 512-byte blocks */
2349 case 'D': /* Filesystem device on which the file exits */
2350 case 'k': /* size in 1K blocks */
2351 case 'n': /* number of links */
2352 pred
->need_stat
= true;
2353 mycost
= NeedsStatInfo
;
2357 /* Numeric items that DO honour #, 0, + flags.
2359 case 'd': /* depth in search tree (0 = ARGV element) */
2363 case 'm': /* mode as octal number (perms only) */
2365 pred
->need_stat
= true;
2366 mycost
= NeedsStatInfo
;
2373 _("error: the format directive `%%%c' is reserved for future use"),
2380 if (mycost
> pred
->p_cost
)
2381 pred
->p_cost
= mycost
;
2382 return &(*segment
)->next
;
2386 check_path_safety(const char *action
)
2388 const char *path
= getenv("PATH");
2390 s
= next_element(path
, 1);
2391 while ((s
= next_element ((char *) NULL
, 1)) != NULL
)
2393 if (0 == strcmp(s
, "."))
2395 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)"),
2402 /* handles both exec and ok predicate */
2403 #if defined(NEW_EXEC)
2404 /* handles both exec and ok predicate */
2406 new_insert_exec_ok (const char *action
,
2407 const struct parser_table
*entry
,
2411 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2412 int i
; /* Index into cmd args */
2413 int saw_braces
; /* True if previous arg was '{}'. */
2414 boolean allow_plus
; /* True if + is a valid terminator */
2415 int brace_count
; /* Number of instances of {}. */
2416 PRED_FUNC func
= entry
->pred_func
;
2417 enum BC_INIT_STATUS bcstatus
;
2419 struct predicate
*our_pred
;
2420 struct exec_val
*execp
; /* Pointer for efficiency. */
2422 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2425 our_pred
= insert_primary_withpred (entry
, func
);
2426 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2427 our_pred
->need_type
= our_pred
->need_stat
= false;
2429 execp
= &our_pred
->args
.exec_vec
;
2431 if ((func
!= pred_okdir
) && (func
!= pred_ok
))
2434 execp
->close_stdin
= false;
2439 /* If find reads stdin (i.e. for -ok and similar), close stdin
2440 * in the child to prevent some script from consiming the output
2441 * intended for find.
2443 execp
->close_stdin
= true;
2447 if ((func
== pred_execdir
) || (func
== pred_okdir
))
2449 options
.ignore_readdir_race
= false;
2450 check_path_safety(action
);
2451 execp
->use_current_dir
= true;
2455 execp
->use_current_dir
= false;
2458 our_pred
->args
.exec_vec
.multiple
= 0;
2460 /* Count the number of args with path replacements, up until the ';'.
2461 * Also figure out if the command is terminated by ";" or by "+".
2464 for (end
= start
, saw_braces
=0, brace_count
=0;
2466 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2469 /* For -exec and -execdir, "{} +" can terminate the command. */
2471 && argv
[end
][0] == '+' && argv
[end
][1] == 0
2474 our_pred
->args
.exec_vec
.multiple
= 1;
2479 if (strstr (argv
[end
], "{}"))
2484 if (0 == end
&& (func
== pred_execdir
|| func
== pred_okdir
))
2486 /* The POSIX standard says that {} replacement should
2487 * occur even in the utility name. This is insecure
2488 * since it means we will be executing a command whose
2489 * name is chosen according to whatever find finds in
2490 * the filesystem. That can be influenced by an
2491 * attacker. Hence for -execdir and -okdir this is not
2492 * allowed. We can specify this as those options are
2493 * not defined by POSIX.
2495 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2500 /* Fail if no command given or no semicolon found. */
2501 if ((end
== start
) || (argv
[end
] == NULL
))
2508 if (our_pred
->args
.exec_vec
.multiple
&& brace_count
> 1)
2512 if (func
== pred_execdir
)
2518 _("Only one instance of {} is supported with -exec%s ... +"),
2522 /* We use a switch statement here so that
2523 * the compiler warns us when we forget to handle a
2524 * newly invented enum value.
2526 bcstatus
= bc_init_controlinfo(&execp
->ctl
);
2529 case BC_INIT_ENV_TOO_BIG
:
2531 _("The environment is too large for exec()."));
2534 /* Good news. Carry on. */
2537 bc_use_sensible_arg_max(&execp
->ctl
);
2540 execp
->ctl
.exec_callback
= launch
;
2542 if (our_pred
->args
.exec_vec
.multiple
)
2544 /* "+" terminator, so we can just append our arguments after the
2545 * command and initial arguments.
2547 execp
->replace_vec
= NULL
;
2548 execp
->ctl
.replace_pat
= NULL
;
2549 execp
->ctl
.rplen
= 0;
2550 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2551 execp
->ctl
.args_per_exec
= 0; /* no limit */
2553 /* remember how many arguments there are */
2554 execp
->ctl
.initial_argc
= (end
-start
) - 1;
2556 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2557 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2559 /* Gather the initial arguments. Skip the {}. */
2560 for (i
=start
; i
<end
-1; ++i
)
2562 bc_push_arg(&execp
->ctl
, &execp
->state
,
2563 argv
[i
], strlen(argv
[i
])+1,
2570 /* Semicolon terminator - more than one {} is supported, so we
2571 * have to do brace-replacement.
2573 execp
->num_args
= end
- start
;
2575 execp
->ctl
.replace_pat
= "{}";
2576 execp
->ctl
.rplen
= strlen(execp
->ctl
.replace_pat
);
2577 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2578 execp
->ctl
.args_per_exec
= 0; /* no limit */
2579 execp
->replace_vec
= xmalloc(sizeof(char*)*execp
->num_args
);
2582 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2583 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2585 /* Remember the (pre-replacement) arguments for later. */
2586 for (i
=0; i
<execp
->num_args
; ++i
)
2588 execp
->replace_vec
[i
] = argv
[i
+start
];
2592 if (argv
[end
] == NULL
)
2600 /* handles both exec and ok predicate */
2602 old_insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
2604 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2605 int num_paths
; /* Number of args with path replacements. */
2606 int path_pos
; /* Index in array of path replacements. */
2607 int vec_pos
; /* Index in array of args. */
2608 struct predicate
*our_pred
;
2609 struct exec_val
*execp
; /* Pointer for efficiency. */
2611 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2614 /* Count the number of args with path replacements, up until the ';'. */
2616 for (end
= start
, num_paths
= 0;
2618 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2620 if (strstr (argv
[end
], "{}"))
2622 /* Fail if no command given or no semicolon found. */
2623 if ((end
== start
) || (argv
[end
] == NULL
))
2629 our_pred
= insert_primary (func
);
2630 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2631 execp
= &our_pred
->args
.exec_vec
;
2632 execp
->usercontext
= our_pred
;
2633 execp
->use_current_dir
= false;
2635 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
2636 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
2637 /* Record the positions of all args, and the args with path replacements. */
2638 for (end
= start
, path_pos
= vec_pos
= 0;
2640 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2645 execp
->paths
[path_pos
].count
= 0;
2646 for (p
= argv
[end
]; *p
; ++p
)
2647 if (p
[0] == '{' && p
[1] == '}')
2649 execp
->paths
[path_pos
].count
++;
2652 if (execp
->paths
[path_pos
].count
)
2654 execp
->paths
[path_pos
].offset
= vec_pos
;
2655 execp
->paths
[path_pos
].origarg
= argv
[end
];
2658 execp
->vec
[vec_pos
++] = argv
[end
];
2660 execp
->paths
[path_pos
].offset
= -1;
2661 execp
->vec
[vec_pos
] = NULL
;
2663 if (argv
[end
] == NULL
)
2674 insert_exec_ok (const char *action
, const struct parser_table
*entry
, char **argv
, int *arg_ptr
)
2676 #if defined(NEW_EXEC)
2677 return new_insert_exec_ok(action
, entry
, argv
, arg_ptr
);
2679 return old_insert_exec_ok(func
, argv
, arg_ptr
);
2685 /* Get a number of days and comparison type.
2686 STR is the ASCII representation.
2687 Set *NUM_DAYS to the number of days, taken as being from
2688 the current moment (or possibly midnight). Thus the sense of the
2689 comparison type appears to be reversed.
2690 Set *COMP_TYPE to the kind of comparison that is requested.
2692 Return true if all okay, false if input error.
2694 Used by -atime, -ctime and -mtime (parsers) to
2695 get the appropriate information for a time predicate processor. */
2698 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
2700 boolean r
= get_num (str
, num_days
, comp_type
);
2704 case COMP_LT
: *comp_type
= COMP_GT
; break;
2705 case COMP_GT
: *comp_type
= COMP_LT
; break;
2711 /* Insert a time predicate PRED.
2712 ARGV is a pointer to the argument array.
2713 ARG_PTR is a pointer to an index into the array, incremented if
2716 Return true if input is valid, false if not.
2718 A new predicate node is assigned, along with an argument node
2719 obtained with malloc.
2721 Used by -atime, -ctime, and -mtime parsers. */
2724 parse_time (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
2726 struct predicate
*our_pred
;
2728 enum comparison_type c_type
;
2731 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2733 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
2736 /* Figure out the timestamp value we are looking for. */
2737 t
= ( options
.cur_day_start
- num_days
* DAYSECS
2738 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2742 /* We introduce a scope in which 'val' can be declared, for the
2743 * benefit of compilers that are really C89 compilers
2744 * which support intmax_t because config.h #defines it
2746 intmax_t val
= ( (intmax_t)options
.cur_day_start
- num_days
* DAYSECS
2747 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2750 /* Check for possibility of an overflow */
2751 if ( (intmax_t)t
!= val
)
2753 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
2757 our_pred
= insert_primary (entry
);
2758 our_pred
->args
.info
.kind
= c_type
;
2759 our_pred
->args
.info
.negative
= t
< 0;
2760 our_pred
->args
.info
.l_val
= t
;
2761 our_pred
->est_success_rate
= estimate_file_age_success_rate(num_days
);
2764 if (options
.debug_options
& DebugExpressionTree
)
2766 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2767 fprintf (stderr
, " type: %s %s ",
2768 (c_type
== COMP_GT
) ? "gt" :
2769 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2770 (c_type
== COMP_GT
) ? " >" :
2771 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
2772 t
= our_pred
->args
.info
.l_val
;
2773 fprintf (stderr
, "%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2774 if (c_type
== COMP_EQ
)
2776 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
2777 fprintf (stderr
, " < %ju %s",
2778 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2779 our_pred
->args
.info
.l_val
-= DAYSECS
;
2786 /* Get a number with comparison information.
2787 The sense of the comparison information is 'normal'; that is,
2788 '+' looks for a count > than the number and '-' less than.
2790 STR is the ASCII representation of the number.
2791 Set *NUM to the number.
2792 Set *COMP_TYPE to the kind of comparison that is requested.
2794 Return true if all okay, false if input error. */
2797 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
2804 *comp_type
= COMP_GT
;
2808 *comp_type
= COMP_LT
;
2812 *comp_type
= COMP_EQ
;
2816 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
2819 /* Insert a number predicate.
2820 ARGV is a pointer to the argument array.
2821 *ARG_PTR is an index into ARGV, incremented if all went well.
2822 *PRED is the predicate processor to insert.
2824 Return true if input is valid, false if error.
2826 A new predicate node is assigned, along with an argument node
2827 obtained with malloc.
2829 Used by -inum and -links parsers. */
2831 static struct predicate
*
2832 insert_num (char **argv
, int *arg_ptr
, const struct parser_table
*entry
)
2834 struct predicate
*our_pred
;
2836 enum comparison_type c_type
;
2838 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2840 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2842 our_pred
= insert_primary (entry
);
2843 our_pred
->args
.info
.kind
= c_type
;
2844 our_pred
->args
.info
.l_val
= num
;
2847 if (options
.debug_options
& DebugExpressionTree
)
2849 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2850 fprintf (stderr
, " type: %s %s ",
2851 (c_type
== COMP_GT
) ? "gt" :
2852 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2853 (c_type
== COMP_GT
) ? " >" :
2854 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2855 fprintf (stderr
, "%ju\n", our_pred
->args
.info
.l_val
);
2861 open_output_file (char *path
)
2865 if (!strcmp (path
, "/dev/stderr"))
2867 else if (!strcmp (path
, "/dev/stdout"))
2869 f
= fopen_safer (path
, "w");
2871 error (1, errno
, "%s", path
);