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,
29 #include "modechange.h"
37 #include "stdio-safer.h"
38 #include "regextype.h"
39 #include "stat-time.h"
42 #include "gnulib-version.h"
50 /* The presence of unistd.h is assumed by gnulib these days, so we
51 * might as well assume it too.
53 /* We need <unistd.h> for isatty(). */
58 # define _(Text) gettext (Text)
63 # define N_(String) gettext_noop (String)
65 /* See locate.c for explanation as to why not use (String) */
66 # define N_(String) String
69 #if !defined (isascii) || defined (STDC_HEADERS)
76 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
77 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
86 static boolean parse_accesscheck
PARAMS((const struct parser_table
* entry
, char **argv
, int *arg_ptr
));
87 static boolean parse_amin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
88 static boolean parse_and
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
89 static boolean parse_anewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
90 static boolean parse_cmin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
91 static boolean parse_cnewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
92 static boolean parse_comma
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
93 static boolean parse_daystart
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
94 static boolean parse_delete
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
95 static boolean parse_d
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
96 static boolean parse_depth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
97 static boolean parse_empty
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
98 static boolean parse_exec
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
99 static boolean parse_execdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
100 static boolean parse_false
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
101 static boolean parse_fls
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
102 static boolean parse_fprintf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
103 static boolean parse_follow
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
104 static boolean parse_fprint
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
105 static boolean parse_fprint0
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
106 static boolean parse_fstype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
107 static boolean parse_gid
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
108 static boolean parse_group
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
109 static boolean parse_help
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
110 static boolean parse_ilname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
111 static boolean parse_iname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
112 static boolean parse_inum
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
113 static boolean parse_ipath
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
114 static boolean parse_iregex
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
115 static boolean parse_iwholename
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
116 static boolean parse_links
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
117 static boolean parse_lname
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
118 static boolean parse_ls
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
119 static boolean parse_maxdepth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
120 static boolean parse_mindepth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
121 static boolean parse_mmin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
122 static boolean parse_name
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
123 static boolean parse_negate
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
124 static boolean parse_newer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
125 static boolean parse_newerXY
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
126 static boolean parse_noleaf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
127 static boolean parse_nogroup
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
128 static boolean parse_nouser
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
129 static boolean parse_nowarn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
130 static boolean parse_ok
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
131 static boolean parse_okdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
132 static boolean parse_or
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
133 static boolean parse_path
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
134 static boolean parse_perm
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
135 static boolean parse_print0
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
136 static boolean parse_printf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
137 static boolean parse_prune
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
138 static boolean parse_regex
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
139 static boolean parse_regextype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
140 static boolean parse_samefile
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
142 static boolean parse_show_control_chars
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
144 static boolean parse_size
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
145 static boolean parse_time
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
146 static boolean parse_true
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
147 static boolean parse_type
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
148 static boolean parse_uid
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
149 static boolean parse_used
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
150 static boolean parse_user
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
151 static boolean parse_version
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
152 static boolean parse_wholename
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
153 static boolean parse_xdev
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
154 static boolean parse_ignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
155 static boolean parse_noignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
156 static boolean parse_warn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
157 static boolean parse_xtype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
158 static boolean parse_quit
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
160 boolean parse_print
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
163 static boolean insert_type
PARAMS((char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
));
164 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
, int regex_options
));
165 static boolean insert_fprintf
PARAMS((FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char *argv
[], int *arg_ptr
));
167 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
,
168 int kind
, char format_char
, char aux_format_char
,
169 struct predicate
*pred
));
170 static boolean insert_exec_ok
PARAMS((const char *action
, const struct parser_table
*entry
, int dirfd
, char *argv
[], int *arg_ptr
));
171 static boolean get_comp_type
PARAMS((char **str
, enum comparison_type
*comp_type
));
172 static boolean get_relative_timestamp
PARAMS((char *str
, struct time_val
*tval
, time_t origin
, double sec_per_unit
, const char *overflowmessage
));
173 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
174 static struct predicate
* insert_num
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
));
175 static FILE *open_output_file
PARAMS((char *path
));
176 static boolean
stream_is_tty(FILE *fp
);
177 static boolean parse_noop
PARAMS((const struct parser_table
* entry
, char **argv
, int *arg_ptr
));
179 #define PASTE(x,y) x##y
180 #define STRINGIFY(s) #s
182 #define PARSE_OPTION(what,suffix) \
183 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_POSOPT(what,suffix) \
186 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
188 #define PARSE_TEST(what,suffix) \
189 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
191 #define PARSE_TEST_NP(what,suffix) \
192 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
194 #define PARSE_ACTION(what,suffix) \
195 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
197 #define PARSE_ACTION_NP(what,suffix) \
198 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
200 #define PARSE_PUNCTUATION(what,suffix) \
201 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
204 /* Predicates we cannot handle in the usual way */
205 static struct parser_table
const parse_entry_newerXY
=
207 ARG_SPECIAL_PARSE
, "newerXY", parse_newerXY
, pred_newerXY
/* BSD */
210 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
211 If they are in some Unix versions of find, they are marked `Unix'. */
213 static struct parser_table
const parse_table
[] =
215 PARSE_PUNCTUATION("!", negate
),
216 PARSE_PUNCTUATION("not", negate
), /* GNU */
217 PARSE_PUNCTUATION("(", open
),
218 PARSE_PUNCTUATION(")", close
),
219 PARSE_PUNCTUATION(",", comma
), /* GNU */
220 PARSE_PUNCTUATION("a", and),
221 PARSE_TEST ("amin", amin
), /* GNU */
222 PARSE_PUNCTUATION("and", and), /* GNU */
223 PARSE_TEST ("anewer", anewer
), /* GNU */
224 {ARG_TEST
, "atime", parse_time
, pred_atime
},
225 PARSE_TEST ("cmin", cmin
), /* GNU */
226 PARSE_TEST ("cnewer", cnewer
), /* GNU */
227 {ARG_TEST
, "ctime", parse_time
, pred_ctime
},
228 PARSE_POSOPT ("daystart", daystart
), /* GNU */
229 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
230 PARSE_OPTION ("d", d
), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
231 PARSE_OPTION ("depth", depth
),
232 PARSE_TEST ("empty", empty
), /* GNU */
233 {ARG_ACTION
, "exec", parse_exec
, pred_exec
}, /* POSIX */
234 {ARG_TEST
, "executable", parse_accesscheck
, pred_executable
}, /* GNU, 4.3.0+ */
235 PARSE_ACTION ("execdir", execdir
), /* *BSD, GNU */
236 PARSE_ACTION ("fls", fls
), /* GNU */
237 PARSE_POSOPT ("follow", follow
), /* GNU, Unix */
238 PARSE_ACTION ("fprint", fprint
), /* GNU */
239 PARSE_ACTION ("fprint0", fprint0
), /* GNU */
240 {ARG_ACTION
, "fprintf", parse_fprintf
, pred_fprintf
}, /* GNU */
241 PARSE_TEST ("fstype", fstype
), /* GNU, Unix */
242 PARSE_TEST ("gid", gid
), /* GNU */
243 PARSE_TEST ("group", group
),
244 PARSE_OPTION ("ignore_readdir_race", ignore_race
), /* GNU */
245 PARSE_TEST ("ilname", ilname
), /* GNU */
246 PARSE_TEST ("iname", iname
), /* GNU */
247 PARSE_TEST ("inum", inum
), /* GNU, Unix */
248 PARSE_TEST ("ipath", ipath
), /* GNU, deprecated in favour of iwholename */
249 PARSE_TEST_NP ("iregex", iregex
), /* GNU */
250 PARSE_TEST_NP ("iwholename", iwholename
), /* GNU */
251 PARSE_TEST ("links", links
),
252 PARSE_TEST ("lname", lname
), /* GNU */
253 PARSE_ACTION ("ls", ls
), /* GNU, Unix */
254 PARSE_OPTION ("maxdepth", maxdepth
), /* GNU */
255 PARSE_OPTION ("mindepth", mindepth
), /* GNU */
256 PARSE_TEST ("mmin", mmin
), /* GNU */
257 PARSE_OPTION ("mount", xdev
), /* Unix */
258 {ARG_TEST
, "mtime", parse_time
, pred_mtime
},
259 PARSE_TEST ("name", name
),
260 #ifdef UNIMPLEMENTED_UNIX
261 PARSE(ARG_UNIMPLEMENTED
, "ncpio", ncpio
), /* Unix */
263 PARSE_TEST ("newer", newer
),
264 {ARG_TEST
, "atime", parse_time
, pred_atime
},
265 PARSE_OPTION ("noleaf", noleaf
), /* GNU */
266 PARSE_TEST ("nogroup", nogroup
),
267 PARSE_TEST ("nouser", nouser
),
268 PARSE_OPTION ("noignore_readdir_race", noignore_race
), /* GNU */
269 PARSE_POSOPT ("nowarn", nowarn
), /* GNU */
270 PARSE_PUNCTUATION("o", or),
271 PARSE_PUNCTUATION("or", or), /* GNU */
272 PARSE_ACTION ("ok", ok
),
273 PARSE_ACTION ("okdir", okdir
), /* GNU (-execdir is BSD) */
274 PARSE_TEST ("path", path
), /* GNU, HP-UX, GNU prefers wholename */
275 PARSE_TEST ("perm", perm
),
276 PARSE_ACTION ("print", print
),
277 PARSE_ACTION ("print0", print0
), /* GNU */
278 {ARG_ACTION
, "printf", parse_printf
, NULL
}, /* GNU */
279 PARSE_ACTION ("prune", prune
),
280 PARSE_ACTION ("quit", quit
), /* GNU */
281 {ARG_TEST
, "readable", parse_accesscheck
, pred_readable
}, /* GNU, 4.3.0+ */
282 PARSE_TEST ("regex", regex
), /* GNU */
283 PARSE_OPTION ("regextype", regextype
), /* GNU */
284 PARSE_TEST ("samefile", samefile
), /* GNU */
286 PARSE_OPTION ("show-control-chars", show_control_chars
), /* GNU, 4.3.0+ */
288 PARSE_TEST ("size", size
),
289 PARSE_TEST ("type", type
),
290 PARSE_TEST ("uid", uid
), /* GNU */
291 PARSE_TEST ("used", used
), /* GNU */
292 PARSE_TEST ("user", user
),
293 PARSE_OPTION ("warn", warn
), /* GNU */
294 PARSE_TEST_NP ("wholename", wholename
), /* GNU, replaces -path */
295 {ARG_TEST
, "writable", parse_accesscheck
, pred_writable
}, /* GNU, 4.3.0+ */
296 PARSE_OPTION ("xdev", xdev
),
297 PARSE_TEST ("xtype", xtype
), /* GNU */
298 #ifdef UNIMPLEMENTED_UNIX
299 /* It's pretty ugly for find to know about archive formats.
300 Plus what it could do with cpio archives is very limited.
301 Better to leave it out. */
302 PARSE(ARG_UNIMPLEMENTED
, "cpio", cpio
), /* Unix */
304 /* gnulib's stdbool.h might have made true and false into macros,
305 * so we can't leave named 'true' and 'false' tokens, so we have
306 * to expeant the relevant entries longhand.
308 {ARG_TEST
, "false", parse_false
, pred_false
}, /* GNU */
309 {ARG_TEST
, "true", parse_true
, pred_true
}, /* GNU */
310 {ARG_NOOP
, "noop", NULL
, pred_true
}, /* GNU, internal use only */
312 /* Various other cases that don't fit neatly into our macro scheme. */
313 {ARG_TEST
, "help", parse_help
, NULL
}, /* GNU */
314 {ARG_TEST
, "-help", parse_help
, NULL
}, /* GNU */
315 {ARG_TEST
, "version", parse_version
, NULL
}, /* GNU */
316 {ARG_TEST
, "-version", parse_version
, NULL
}, /* GNU */
321 static const char *first_nonoption_arg
= NULL
;
322 static const struct parser_table
*noop
= NULL
;
325 static const struct parser_table
*
331 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
333 if (ARG_NOOP
==parse_table
[i
].type
)
335 noop
= &(parse_table
[i
]);
344 get_stat_Ytime(const struct stat
*p
,
346 struct timespec
*ret
)
351 *ret
= get_stat_atime(p
);
354 *ret
= get_stat_birthtime(p
);
355 return (ret
->tv_nsec
>= 0);
357 *ret
= get_stat_ctime(p
);
360 *ret
= get_stat_mtime(p
);
370 set_follow_state(enum SymlinkOption opt
)
372 if (options
.debug_options
& DebugStat
)
374 /* For DebugStat, the choice is made at runtime within debug_stat()
375 * by checking the contents of the symlink_handling variable.
377 options
.xstat
= debug_stat
;
383 case SYMLINK_ALWAYS_DEREF
: /* -L */
384 options
.xstat
= optionl_stat
;
385 options
.no_leaf_check
= true;
388 case SYMLINK_NEVER_DEREF
: /* -P (default) */
389 options
.xstat
= optionp_stat
;
390 /* Can't turn no_leaf_check off because the user might have specified
395 case SYMLINK_DEREF_ARGSONLY
: /* -H */
396 options
.xstat
= optionh_stat
;
397 options
.no_leaf_check
= true;
400 options
.symlink_handling
= opt
;
405 parse_begin_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
411 first_nonoption_arg
= NULL
;
415 parse_end_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
425 /* Check that it is legal to fid the given primary in its
426 * position and return it.
428 const struct parser_table
*
429 found_parser(const char *original_arg
, const struct parser_table
*entry
)
431 /* If this is an option, but we have already had a
432 * non-option argument, the user may be under the
433 * impression that the behaviour of the option
434 * argument is conditional on some preceding
435 * tests. This might typically be the case with,
436 * for example, -maxdepth.
438 * The options -daystart and -follow are exempt
439 * from this treatment, since their positioning
440 * in the command line does have an effect on
441 * subsequent tests but not previous ones. That
442 * might be intentional on the part of the user.
444 if (entry
->type
!= ARG_POSITIONAL_OPTION
)
446 /* Something other than -follow/-daystart.
447 * If this is an option, check if it followed
448 * a non-option and if so, issue a warning.
450 if (entry
->type
== ARG_OPTION
)
452 if ((first_nonoption_arg
!= NULL
)
453 && options
.warnings
)
455 /* option which follows a non-option */
457 _("warning: you have specified the %s "
458 "option after a non-option argument %s, "
459 "but options are not positional (%s affects "
460 "tests specified before it as well as those "
461 "specified after it). Please specify options "
462 "before other arguments.\n"),
470 /* Not an option or a positional option,
471 * so remember we've seen it in order to
472 * use it in a possible future warning message.
474 if (first_nonoption_arg
== NULL
)
476 first_nonoption_arg
= original_arg
;
485 /* Return a pointer to the parser function to invoke for predicate
487 Return NULL if SEARCH_NAME is not a valid predicate name. */
489 const struct parser_table
*
490 find_parser (char *search_name
)
493 const struct parser_table
*p
;
494 const char *original_arg
= search_name
;
496 /* Ugh. Special case -newerXY. */
497 if (0 == strncmp("-newer", search_name
, 6)
498 && (8 == strlen(search_name
)))
500 return found_parser(original_arg
, &parse_entry_newerXY
);
503 if (*search_name
== '-')
506 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
508 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
510 return found_parser(original_arg
, &parse_table
[i
]);
517 estimate_file_age_success_rate(float num_days
)
521 /* Assume 1% of files have timestamps in the future */
524 else if (num_days
< 1)
526 /* Assume 30% of files have timestamps today */
529 else if (num_days
> 100)
531 /* Assume 30% of files are very old */
536 /* Assume 39% of files are between 1 and 100 days old. */
542 estimate_timestamp_success_rate(time_t when
)
544 int num_days
= (options
.cur_day_start
- when
) / 86400;
545 return estimate_file_age_success_rate(num_days
);
548 /* The parsers are responsible to continue scanning ARGV for
549 their arguments. Each parser knows what is and isn't
552 ARGV is the argument array.
553 *ARG_PTR is the index to start at in ARGV,
554 updated to point beyond the last element consumed.
556 The predicate structure is updated with the new information. */
560 parse_and (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
562 struct predicate
*our_pred
;
567 our_pred
= get_new_pred (entry
);
568 our_pred
->pred_func
= pred_and
;
569 our_pred
->p_type
= BI_OP
;
570 our_pred
->p_prec
= AND_PREC
;
571 our_pred
->need_stat
= our_pred
->need_type
= false;
576 parse_anewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
578 struct predicate
*our_pred
;
579 struct stat stat_newer
;
581 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
583 set_stat_placeholders(&stat_newer
);
584 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
585 error (1, errno
, "%s", argv
[*arg_ptr
]);
586 our_pred
= insert_primary (entry
);
587 our_pred
->args
.reftime
.xval
= XVAL_ATIME
;
588 our_pred
->args
.reftime
.ts
= get_stat_mtime(&stat_newer
);
589 our_pred
->args
.reftime
.kind
= COMP_GT
;
590 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
596 parse_close (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
598 struct predicate
*our_pred
;
603 our_pred
= get_new_pred (entry
);
604 our_pred
->pred_func
= pred_close
;
605 our_pred
->p_type
= CLOSE_PAREN
;
606 our_pred
->p_prec
= NO_PREC
;
607 our_pred
->need_stat
= our_pred
->need_type
= false;
612 parse_cnewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
614 struct predicate
*our_pred
;
615 struct stat stat_newer
;
617 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
619 set_stat_placeholders(&stat_newer
);
620 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
621 error (1, errno
, "%s", argv
[*arg_ptr
]);
622 our_pred
= insert_primary (entry
);
623 our_pred
->args
.reftime
.xval
= XVAL_CTIME
; /* like -newercm */
624 our_pred
->args
.reftime
.ts
= get_stat_mtime(&stat_newer
);
625 our_pred
->args
.reftime
.kind
= COMP_GT
;
626 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
632 parse_comma (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
634 struct predicate
*our_pred
;
639 our_pred
= get_new_pred (entry
);
640 our_pred
->pred_func
= pred_comma
;
641 our_pred
->p_type
= BI_OP
;
642 our_pred
->p_prec
= COMMA_PREC
;
643 our_pred
->need_stat
= our_pred
->need_type
= false;
644 our_pred
->est_success_rate
= 1.0f
;
649 parse_daystart (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
657 if (options
.full_days
== false)
659 options
.cur_day_start
+= DAYSECS
;
660 local
= localtime (&options
.cur_day_start
);
661 options
.cur_day_start
-= (local
662 ? (local
->tm_sec
+ local
->tm_min
* 60
663 + local
->tm_hour
* 3600)
664 : options
.cur_day_start
% DAYSECS
);
665 options
.full_days
= true;
671 parse_delete (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
673 struct predicate
*our_pred
;
677 our_pred
= insert_primary (entry
);
678 our_pred
->side_effects
= our_pred
->no_default_print
= true;
679 /* -delete implies -depth */
680 options
.do_dir_first
= false;
681 our_pred
->est_success_rate
= 1.0f
;
686 parse_depth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
692 options
.do_dir_first
= false;
693 return parse_noop(entry
, argv
, arg_ptr
);
697 parse_d (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
702 if (options
.warnings
)
705 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
707 return parse_depth(entry
, argv
, arg_ptr
);
711 parse_empty (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
713 struct predicate
*our_pred
;
717 our_pred
= insert_primary (entry
);
718 our_pred
->est_success_rate
= 0.01f
; /* assume 1% of files are empty. */
723 parse_exec (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
725 return insert_exec_ok ("-exec", entry
, get_start_dirfd(), argv
, arg_ptr
);
729 parse_execdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
731 return insert_exec_ok ("-execdir", entry
, -1, argv
, arg_ptr
);
735 parse_false (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
737 struct predicate
*our_pred
;
742 our_pred
= insert_primary (entry
);
743 our_pred
->need_stat
= our_pred
->need_type
= false;
744 our_pred
->side_effects
= our_pred
->no_default_print
= false;
745 our_pred
->est_success_rate
= 0.0f
;
750 parse_fls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
752 struct predicate
*our_pred
;
754 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
756 our_pred
= insert_primary (entry
);
757 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
758 our_pred
->side_effects
= our_pred
->no_default_print
= true;
759 our_pred
->est_success_rate
= 1.0f
;
765 parse_fprintf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
769 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
771 if (argv
[*arg_ptr
+ 1] == NULL
)
773 /* Ensure we get "missing arg" message, not "invalid arg". */
777 fp
= open_output_file (argv
[*arg_ptr
]);
779 return insert_fprintf (fp
, entry
, pred_fprintf
, argv
, arg_ptr
);
783 parse_follow (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
789 set_follow_state(SYMLINK_ALWAYS_DEREF
);
790 return parse_noop(entry
, argv
, arg_ptr
);
794 parse_fprint (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
796 struct predicate
*our_pred
;
798 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
800 our_pred
= insert_primary (entry
);
801 our_pred
->args
.printf_vec
.segment
= NULL
;
802 our_pred
->args
.printf_vec
.stream
= open_output_file (argv
[*arg_ptr
]);
803 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(our_pred
->args
.printf_vec
.stream
);
804 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
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
;
813 parse_fprint0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
815 struct predicate
*our_pred
;
817 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
819 our_pred
= insert_primary (entry
);
820 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
821 our_pred
->side_effects
= our_pred
->no_default_print
= true;
822 our_pred
->need_stat
= our_pred
->need_type
= false;
823 our_pred
->est_success_rate
= 1.0f
;
828 static float estimate_fstype_success_rate(const char *fsname
)
830 struct stat dir_stat
;
831 const char *dir
= "/";
832 if (0 == stat(dir
, &dir_stat
))
834 const char *fstype
= filesystem_type(&dir_stat
, dir
);
835 /* Assume most files are on the same filesystem type as the root fs. */
836 if (0 == strcmp(fsname
, fstype
))
846 parse_fstype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
848 struct predicate
*our_pred
;
850 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
852 our_pred
= insert_primary (entry
);
853 our_pred
->args
.str
= argv
[*arg_ptr
];
855 /* This is an expensive operation, so although there are
856 * circumstances where it is selective, we ignore this fact because
857 * we probably don't want to promote this test to the front anyway.
859 our_pred
->est_success_rate
= estimate_fstype_success_rate(argv
[*arg_ptr
]);
865 parse_gid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
867 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
868 p
->est_success_rate
= (p
->args
.numinfo
.l_val
< 100) ? 0.99 : 0.2;
873 parse_group (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
875 struct group
*cur_gr
;
876 struct predicate
*our_pred
;
880 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
882 cur_gr
= getgrnam (argv
[*arg_ptr
]);
885 gid
= cur_gr
->gr_gid
;
888 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
889 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
891 gid
= atoi (argv
[*arg_ptr
]);
893 our_pred
= insert_primary (entry
);
894 our_pred
->args
.gid
= gid
;
895 our_pred
->est_success_rate
= (our_pred
->args
.numinfo
.l_val
< 100) ? 0.99 : 0.2;
901 parse_help (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
907 usage(stdout
, 0, NULL
);
909 default path is the current directory; default expression is -print\n\
910 expression may consist of: operators, options, tests, and actions:\n"));
912 operators (decreasing precedence; -and is implicit where no others are given):\n\
913 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
914 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
916 positional options (always true): -daystart -follow -regextype\n\n\
917 normal options (always true, specified before other expressions):\n\
918 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
919 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
921 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
922 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
923 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
924 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
926 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
927 -readable -writable -executable\n\
928 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
929 -used N -user NAME -xtype [bcdpfls]\n"));
931 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
932 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
933 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
934 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
936 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
937 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
938 email to <bug-findutils@gnu.org>."));
943 estimate_pattern_match_rate(const char *pattern
, int is_regex
)
945 if (strpbrk(pattern
, "*?[") || (is_regex
&& strpbrk(pattern
, ".")))
947 /* A wildcard; assume the pattern matches most files. */
957 parse_ilname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
959 struct predicate
*our_pred
;
961 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
963 our_pred
= insert_primary (entry
);
964 our_pred
->args
.str
= argv
[*arg_ptr
];
965 /* Use the generic glob pattern estimator to figure out how many
966 * links will match, but bear in mind that most files won't be links.
968 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
974 /* sanity check the fnmatch() function to make sure
975 * it really is the GNU version.
978 fnmatch_sanitycheck(void)
980 /* fprintf(stderr, "Performing find sanity check..."); */
981 if (0 != fnmatch("foo", "foo", 0)
982 || 0 == fnmatch("Foo", "foo", 0)
983 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
985 error (1, 0, _("sanity check of the fnmatch() library function failed."));
986 /* fprintf(stderr, "FAILED\n"); */
990 /* fprintf(stderr, "OK\n"); */
996 check_name_arg(const char *pred
, const char *arg
)
998 if (strchr(arg
, '/'))
1000 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'."),
1003 return true; /* allow it anyway */
1009 parse_iname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1011 struct predicate
*our_pred
;
1013 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1015 if (!check_name_arg("-iname", argv
[*arg_ptr
]))
1018 fnmatch_sanitycheck();
1020 our_pred
= insert_primary (entry
);
1021 our_pred
->need_stat
= our_pred
->need_type
= false;
1022 our_pred
->args
.str
= argv
[*arg_ptr
];
1023 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1029 parse_inum (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1031 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1032 /* inode number is exact match only, so very low proportions of files match */
1033 p
->est_success_rate
= 1e-6;
1037 /* -ipath is deprecated (at RMS's request) in favour of
1038 * -iwholename. See the node "GNU Manuals" in standards.texi
1039 * for the rationale for this (basically, GNU prefers the use
1040 * of the phrase "file name" to "path name"
1043 parse_ipath (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1046 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
1048 return parse_iwholename(entry
, argv
, arg_ptr
);
1052 parse_iwholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1054 struct predicate
*our_pred
;
1056 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1059 fnmatch_sanitycheck();
1061 our_pred
= insert_primary_withpred (entry
, pred_ipath
);
1062 our_pred
->need_stat
= our_pred
->need_type
= false;
1063 our_pred
->args
.str
= argv
[*arg_ptr
];
1064 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1070 parse_iregex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1072 return insert_regex (argv
, arg_ptr
, entry
, RE_ICASE
|options
.regex_options
);
1076 parse_links (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1078 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
1079 if (p
->args
.numinfo
.l_val
== 1)
1080 p
->est_success_rate
= 0.99;
1081 else if (p
->args
.numinfo
.l_val
== 2)
1082 p
->est_success_rate
= 0.01;
1084 p
->est_success_rate
= 1e-3;
1089 parse_lname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1091 struct predicate
*our_pred
;
1096 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1099 fnmatch_sanitycheck();
1101 our_pred
= insert_primary (entry
);
1102 our_pred
->args
.str
= argv
[*arg_ptr
];
1103 our_pred
->est_success_rate
= 0.1 * estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1109 parse_ls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1111 struct predicate
*our_pred
;
1116 our_pred
= insert_primary (entry
);
1117 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1122 parse_maxdepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1127 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1129 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1130 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1132 options
.maxdepth
= atoi (argv
[*arg_ptr
]);
1133 if (options
.maxdepth
< 0)
1136 return parse_noop(entry
, argv
, arg_ptr
);
1140 parse_mindepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1145 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1147 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1148 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1150 options
.mindepth
= atoi (argv
[*arg_ptr
]);
1151 if (options
.mindepth
< 0)
1154 return parse_noop(entry
, argv
, arg_ptr
);
1159 do_parse_xmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
, enum xval xv
)
1161 struct predicate
*our_pred
;
1162 struct time_val tval
;
1164 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1168 if (!get_relative_timestamp(argv
[*arg_ptr
], &tval
,
1169 options
.cur_day_start
+ DAYSECS
, 60,
1170 "arithmetic overflow while converting %s minutes to a number of seconds"))
1173 our_pred
= insert_primary (entry
);
1174 our_pred
->args
.reftime
= tval
;
1175 our_pred
->est_success_rate
= estimate_timestamp_success_rate(tval
.ts
.tv_sec
);
1180 parse_amin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1182 return do_parse_xmin(entry
, argv
, arg_ptr
, XVAL_ATIME
);
1186 parse_cmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1188 return do_parse_xmin(entry
, argv
, arg_ptr
, XVAL_CTIME
);
1193 parse_mmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1195 return do_parse_xmin(entry
, argv
, arg_ptr
, XVAL_MTIME
);
1199 parse_name (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1201 struct predicate
*our_pred
;
1206 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1208 if (!check_name_arg("-name", argv
[*arg_ptr
]))
1210 fnmatch_sanitycheck();
1212 our_pred
= insert_primary (entry
);
1213 our_pred
->need_stat
= our_pred
->need_type
= false;
1214 our_pred
->args
.str
= argv
[*arg_ptr
];
1215 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1221 parse_negate (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1223 struct predicate
*our_pred
;
1228 our_pred
= get_new_pred_chk_op (entry
);
1229 our_pred
->pred_func
= pred_negate
;
1230 our_pred
->p_type
= UNI_OP
;
1231 our_pred
->p_prec
= NEGATE_PREC
;
1232 our_pred
->need_stat
= our_pred
->need_type
= false;
1237 parse_newer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1239 struct predicate
*our_pred
;
1240 struct stat stat_newer
;
1245 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1247 set_stat_placeholders(&stat_newer
);
1248 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
1249 error (1, errno
, "%s", argv
[*arg_ptr
]);
1250 our_pred
= insert_primary (entry
);
1251 our_pred
->args
.reftime
.ts
= get_stat_mtime(&stat_newer
);
1252 our_pred
->args
.reftime
.xval
= XVAL_MTIME
;
1253 our_pred
->args
.reftime
.kind
= COMP_GT
;
1254 our_pred
->est_success_rate
= estimate_timestamp_success_rate(stat_newer
.st_mtime
);
1261 parse_newerXY (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1266 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1270 else if (8u != strlen(argv
[*arg_ptr
]))
1277 const char validchars
[] = "aBcmt";
1279 assert(0 == strncmp("-newer", argv
[*arg_ptr
], 6));
1280 x
= argv
[*arg_ptr
][6];
1281 y
= argv
[*arg_ptr
][7];
1284 #if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
1285 if ('B' == x
|| 'B' == y
)
1288 _("This system does not provide a way to find the birth time of a file."));
1293 /* -newertY (for any Y) is invalid. */
1295 || 0 == strchr(validchars
, x
)
1296 || 0 == strchr( validchars
, y
))
1302 struct predicate
*our_pred
;
1304 /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
1305 * past the test name (for most other tests, this is already done)
1309 our_pred
= insert_primary (entry
);
1315 our_pred
->args
.reftime
.xval
= XVAL_ATIME
;
1318 our_pred
->args
.reftime
.xval
= XVAL_BIRTHTIME
;
1321 our_pred
->args
.reftime
.xval
= XVAL_CTIME
;
1324 our_pred
->args
.reftime
.xval
= XVAL_MTIME
;
1327 assert(strchr(validchars
, x
));
1333 if (!get_date(&our_pred
->args
.reftime
.ts
,
1335 &options
.start_time
))
1338 _("I cannot figure out how to interpret `%s' as a date or time"),
1344 struct stat stat_newer
;
1346 /* Stat the named file. */
1347 set_stat_placeholders(&stat_newer
);
1348 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
1349 error (1, errno
, "%s", argv
[*arg_ptr
]);
1351 if (!get_stat_Ytime(&stat_newer
, y
, &our_pred
->args
.reftime
.ts
))
1353 /* We cannot extract a timestamp from the struct stat. */
1354 error(1, 0, _("Cannot obtain birth time of file `%s'"),
1358 our_pred
->args
.reftime
.kind
= COMP_GT
;
1359 our_pred
->est_success_rate
= estimate_timestamp_success_rate(our_pred
->args
.reftime
.ts
.tv_sec
);
1362 assert(our_pred
->pred_func
!= NULL
);
1363 assert(our_pred
->pred_func
== pred_newerXY
);
1364 assert(our_pred
->need_stat
);
1372 parse_noleaf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1378 options
.no_leaf_check
= true;
1379 return parse_noop(entry
, argv
, arg_ptr
);
1383 /* Arbitrary amount by which to increase size
1384 of `uid_unused' and `gid_unused'. */
1385 #define ALLOC_STEP 2048
1387 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1388 char *uid_unused
= NULL
;
1390 /* Number of elements in `uid_unused'. */
1391 unsigned uid_allocated
;
1393 /* Similar for GIDs and group entries. */
1394 char *gid_unused
= NULL
;
1395 unsigned gid_allocated
;
1399 parse_nogroup (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1401 struct predicate
*our_pred
;
1406 our_pred
= insert_primary (entry
);
1407 our_pred
->est_success_rate
= 1e-4;
1409 if (gid_unused
== NULL
)
1413 gid_allocated
= ALLOC_STEP
;
1414 gid_unused
= xmalloc (gid_allocated
);
1415 memset (gid_unused
, 1, gid_allocated
);
1417 while ((gr
= getgrent ()) != NULL
)
1419 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1421 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1422 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1423 memset (gid_unused
+ gid_allocated
, 1,
1424 new_allocated
- gid_allocated
);
1425 gid_allocated
= new_allocated
;
1427 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1436 parse_nouser (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1438 struct predicate
*our_pred
;
1443 our_pred
= insert_primary (entry
);
1444 our_pred
->est_success_rate
= 1e-3;
1446 if (uid_unused
== NULL
)
1450 uid_allocated
= ALLOC_STEP
;
1451 uid_unused
= xmalloc (uid_allocated
);
1452 memset (uid_unused
, 1, uid_allocated
);
1454 while ((pw
= getpwent ()) != NULL
)
1456 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1458 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1459 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1460 memset (uid_unused
+ uid_allocated
, 1,
1461 new_allocated
- uid_allocated
);
1462 uid_allocated
= new_allocated
;
1464 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1473 parse_nowarn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1479 options
.warnings
= false;
1480 return parse_noop(entry
, argv
, arg_ptr
);
1484 parse_ok (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1486 return insert_exec_ok ("-ok", entry
, get_start_dirfd(), argv
, arg_ptr
);
1490 parse_okdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1492 return insert_exec_ok ("-okdir", entry
, -1, argv
, arg_ptr
);
1496 parse_open (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1498 struct predicate
*our_pred
;
1503 our_pred
= get_new_pred_chk_op (entry
);
1504 our_pred
->pred_func
= pred_open
;
1505 our_pred
->p_type
= OPEN_PAREN
;
1506 our_pred
->p_prec
= NO_PREC
;
1507 our_pred
->need_stat
= our_pred
->need_type
= false;
1512 parse_or (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1514 struct predicate
*our_pred
;
1519 our_pred
= get_new_pred (entry
);
1520 our_pred
->pred_func
= pred_or
;
1521 our_pred
->p_type
= BI_OP
;
1522 our_pred
->p_prec
= OR_PREC
;
1523 our_pred
->need_stat
= our_pred
->need_type
= false;
1527 /* -path is deprecated (at RMS's request) in favour of
1528 * -iwholename. See the node "GNU Manuals" in standards.texi
1529 * for the rationale for this (basically, GNU prefers the use
1530 * of the phrase "file name" to "path name".
1532 * We do not issue a warning that this usage is deprecated
1533 * since HPUX find supports this predicate also.
1536 parse_path (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1538 return parse_wholename(entry
, argv
, arg_ptr
);
1542 parse_wholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1544 struct predicate
*our_pred
;
1546 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1548 our_pred
= insert_primary_withpred (entry
, pred_path
);
1549 our_pred
->need_stat
= our_pred
->need_type
= false;
1550 our_pred
->args
.str
= argv
[*arg_ptr
];
1551 our_pred
->est_success_rate
= estimate_pattern_match_rate(our_pred
->args
.str
, 0);
1557 parse_perm (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1562 boolean havekind
= false;
1563 enum permissions_type kind
= PERM_EXACT
;
1564 struct mode_change
*change
= NULL
;
1565 struct predicate
*our_pred
;
1567 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1570 switch (argv
[*arg_ptr
][0])
1574 kind
= PERM_AT_LEAST
;
1580 change
= mode_compile (argv
[*arg_ptr
]);
1583 /* Most likely the caller is an old script that is still
1584 * using the obsolete GNU syntax '-perm +MODE'. This old
1585 * syntax was withdrawn in favor of '-perm /MODE' because
1586 * it is incompatible with POSIX in some cases, but we
1587 * still support uses of it that are not incompatible with
1596 /* This is a POSIX-compatible usage */
1604 case '/': /* GNU extension */
1612 /* For example, '-perm 0644', which is valid and matches
1613 * only files whose mode is exactly 0644.
1624 change
= mode_compile (argv
[*arg_ptr
] + mode_start
);
1626 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1628 perm_val
[0] = mode_adjust (0, false, 0, change
, NULL
);
1629 perm_val
[1] = mode_adjust (0, true, 0, change
, NULL
);
1632 if (('/' == argv
[*arg_ptr
][0]) && (0 == perm_val
[0]) && (0 == perm_val
[1]))
1634 /* The meaning of -perm /000 will change in the future. It
1635 * currently matches no files, but like -perm -000 it should
1638 * Starting in 2005, we used to issue a warning message
1639 * informing the user that the behaviour would change in the
1640 * future. We have now changed the behaviour and issue a
1641 * warning message that the behaviour recently changed.
1644 _("warning: you have specified a mode pattern %s (which is "
1645 "equivalent to /000). The meaning of -perm /000 has now been "
1646 "changed to be consistent with -perm -000; that is, while it "
1647 "used to match no files, it now matches all files."),
1650 kind
= PERM_AT_LEAST
;
1653 /* The "magic" number below is just the fraction of files on my
1654 * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
1655 * Actual totals are 1472 and 1073833.
1657 rate
= 0.9986; /* probably matches anything but a broken symlink */
1660 our_pred
= insert_primary (entry
);
1661 our_pred
->est_success_rate
= rate
;
1664 our_pred
->args
.perm
.kind
= kind
;
1669 switch (argv
[*arg_ptr
][0])
1672 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1675 our_pred
->args
.perm
.kind
= PERM_ANY
;
1678 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1682 memcpy (our_pred
->args
.perm
.val
, perm_val
, sizeof perm_val
);
1688 parse_print (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1690 struct predicate
*our_pred
;
1695 our_pred
= insert_primary (entry
);
1696 /* -print has the side effect of printing. This prevents us
1697 from doing undesired multiple printing when the user has
1698 already specified -print. */
1699 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1700 our_pred
->need_stat
= our_pred
->need_type
= false;
1701 our_pred
->args
.printf_vec
.segment
= NULL
;
1702 our_pred
->args
.printf_vec
.stream
= stdout
;
1703 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(stdout
);
1704 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
1710 parse_print0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1712 struct predicate
*our_pred
;
1717 our_pred
= insert_primary (entry
);
1718 /* -print0 has the side effect of printing. This prevents us
1719 from doing undesired multiple printing when the user has
1720 already specified -print0. */
1721 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1722 our_pred
->need_stat
= our_pred
->need_type
= false;
1727 parse_printf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1729 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1731 return insert_fprintf (stdout
, entry
, pred_fprintf
, argv
, arg_ptr
);
1735 parse_prune (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1737 struct predicate
*our_pred
;
1742 our_pred
= insert_primary (entry
);
1743 our_pred
->need_stat
= our_pred
->need_type
= false;
1744 /* -prune has a side effect that it does not descend into
1745 the current directory. */
1746 our_pred
->side_effects
= true;
1747 our_pred
->no_default_print
= false;
1752 parse_quit (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1754 struct predicate
*our_pred
= insert_primary (entry
);
1757 our_pred
->need_stat
= our_pred
->need_type
= false;
1758 our_pred
->side_effects
= true; /* Exiting is a side effect... */
1759 our_pred
->no_default_print
= false; /* Don't inhibit the default print, though. */
1760 our_pred
->est_success_rate
= 1.0f
;
1766 parse_regextype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1768 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1771 /* collect the regex type name */
1772 options
.regex_options
= get_regex_type(argv
[*arg_ptr
]);
1775 return parse_noop(entry
, argv
, arg_ptr
);
1780 parse_regex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1782 return insert_regex (argv
, arg_ptr
, entry
, options
.regex_options
);
1786 insert_regex (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, int regex_options
)
1788 struct predicate
*our_pred
;
1789 struct re_pattern_buffer
*re
;
1790 const char *error_message
;
1792 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1794 our_pred
= insert_primary_withpred (entry
, pred_regex
);
1795 our_pred
->need_stat
= our_pred
->need_type
= false;
1796 re
= (struct re_pattern_buffer
*)
1797 xmalloc (sizeof (struct re_pattern_buffer
));
1798 our_pred
->args
.regex
= re
;
1799 re
->allocated
= 100;
1800 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1803 re_set_syntax(regex_options
);
1804 re
->syntax
= regex_options
;
1805 re
->translate
= NULL
;
1807 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1810 error (1, 0, "%s", error_message
);
1811 our_pred
->est_success_rate
= estimate_pattern_match_rate(argv
[*arg_ptr
], 1);
1817 parse_size (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1819 struct predicate
*our_pred
;
1821 enum comparison_type c_type
;
1825 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1827 len
= strlen (argv
[*arg_ptr
]);
1829 error (1, 0, _("invalid null argument to -size"));
1830 switch (argv
[*arg_ptr
][len
- 1])
1834 argv
[*arg_ptr
][len
- 1] = '\0';
1839 argv
[*arg_ptr
][len
- 1] = '\0';
1844 argv
[*arg_ptr
][len
- 1] = '\0';
1847 case 'M': /* Megabytes */
1848 blksize
= 1024*1024;
1849 argv
[*arg_ptr
][len
- 1] = '\0';
1852 case 'G': /* Gigabytes */
1853 blksize
= 1024*1024*1024;
1854 argv
[*arg_ptr
][len
- 1] = '\0';
1859 argv
[*arg_ptr
][len
- 1] = '\0';
1875 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1877 /* TODO: accept fractional megabytes etc. ? */
1878 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1880 our_pred
= insert_primary (entry
);
1881 our_pred
->args
.size
.kind
= c_type
;
1882 our_pred
->args
.size
.blocksize
= blksize
;
1883 our_pred
->args
.size
.size
= num
;
1884 our_pred
->need_stat
= true;
1885 our_pred
->need_type
= false;
1887 if (COMP_GT
== c_type
)
1888 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.1 : 0.9;
1889 else if (COMP_LT
== c_type
)
1890 our_pred
->est_success_rate
= (num
*blksize
> 20480) ? 0.9 : 0.1;
1892 our_pred
->est_success_rate
= 0.01;
1900 parse_samefile (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1902 struct predicate
*our_pred
;
1905 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1907 set_stat_placeholders(&st
);
1908 if ((*options
.xstat
) (argv
[*arg_ptr
], &st
))
1909 error (1, errno
, "%s", argv
[*arg_ptr
]);
1911 our_pred
= insert_primary (entry
);
1912 our_pred
->args
.fileid
.ino
= st
.st_ino
;
1913 our_pred
->args
.fileid
.dev
= st
.st_dev
;
1914 our_pred
->need_type
= false;
1915 our_pred
->need_stat
= true;
1916 our_pred
->est_success_rate
= 0.01f
;
1923 parse_show_control_chars (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1926 const char *errmsg
= _("The -show-control-chars option takes a single argument which "
1927 "must be 'literal' or 'safe'");
1929 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1931 error (1, errno
, "%s", errmsg
);
1936 arg
= argv
[*arg_ptr
];
1938 if (0 == strcmp("literal", arg
))
1940 options
.literal_control_chars
= true;
1942 else if (0 == strcmp("safe", arg
))
1944 options
.literal_control_chars
= false;
1948 error (1, errno
, "%s", errmsg
);
1951 (*arg_ptr
)++; /* consume the argument. */
1959 parse_true (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1961 struct predicate
*our_pred
;
1966 our_pred
= insert_primary (entry
);
1967 our_pred
->need_stat
= our_pred
->need_type
= false;
1968 our_pred
->est_success_rate
= 1.0f
;
1973 parse_noop (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1976 return parse_true(get_noop(), argv
, arg_ptr
);
1980 parse_accesscheck (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1982 struct predicate
*our_pred
;
1985 our_pred
= insert_primary (entry
);
1986 our_pred
->need_stat
= our_pred
->need_type
= false;
1987 our_pred
->side_effects
= our_pred
->no_default_print
= false;
1988 if (our_pred
->pred_func
== pred_executable
)
1989 our_pred
->est_success_rate
= 0.2;
1991 our_pred
->est_success_rate
= 0.9;
1996 parse_type (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1998 return insert_type (argv
, arg_ptr
, entry
, pred_type
);
2002 parse_uid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2004 struct predicate
*p
= insert_num (argv
, arg_ptr
, entry
);
2005 p
->est_success_rate
= (p
->args
.numinfo
.l_val
< 100) ? 0.99 : 0.2;
2010 parse_used (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2012 struct predicate
*our_pred
;
2013 struct time_val tval
;
2014 const char *errmsg
= "arithmetic overflow while converting %s days to a number of seconds";
2016 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2019 /* The timespec is actually a delta value, so we use an origin of 0. */
2020 if (!get_relative_timestamp(argv
[*arg_ptr
], &tval
, 0, DAYSECS
, errmsg
))
2023 our_pred
= insert_primary (entry
);
2024 our_pred
->args
.reftime
= tval
;
2025 our_pred
->est_success_rate
= estimate_file_age_success_rate(tval
.ts
.tv_sec
/ DAYSECS
);
2031 parse_user (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2033 struct passwd
*cur_pwd
;
2034 struct predicate
*our_pred
;
2038 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2040 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
2042 if (cur_pwd
!= NULL
)
2043 uid
= cur_pwd
->pw_uid
;
2046 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
2047 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
2049 uid
= atoi (argv
[*arg_ptr
]);
2051 our_pred
= insert_primary (entry
);
2052 our_pred
->args
.uid
= uid
;
2053 our_pred
->est_success_rate
= (our_pred
->args
.uid
< 100) ? 0.99 : 0.2;
2059 parse_version (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2061 extern char *version_string
;
2070 printf (_("GNU find version %s\n"), version_string
);
2071 printf (_("Built using GNU gnulib version %s\n"), gnulib_version
);
2072 printf (_("Features enabled: "));
2075 printf("CACHE_IDS ");
2083 printf("DEBUG_STAT ");
2086 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
2090 #if defined(O_NOFOLLOW)
2091 printf("O_NOFOLLOW(%s) ",
2092 (options
.open_nofollow_available
? "enabled" : "disabled"));
2095 #if defined(LEAF_OPTIMISATION)
2096 printf("LEAF_OPTIMISATION ");
2101 if (is_fts_enabled(&flags
))
2107 if (flags
& FTS_CWDFD
)
2113 printf("FTS_CWDFD");
2119 printf("CBO(level=%d) ", (int)(options
.optimisation_level
));
2124 /* For the moment, leave this as English in case someone wants
2125 to parse these strings. */
2134 parse_xdev (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2139 options
.stay_on_filesystem
= true;
2140 return parse_noop(entry
, argv
, arg_ptr
);
2144 parse_ignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2149 options
.ignore_readdir_race
= true;
2150 return parse_noop(entry
, argv
, arg_ptr
);
2154 parse_noignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2159 options
.ignore_readdir_race
= false;
2160 return parse_noop(entry
, argv
, arg_ptr
);
2164 parse_warn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2169 options
.warnings
= true;
2170 return parse_noop(entry
, argv
, arg_ptr
);
2174 parse_xtype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
2178 return insert_type (argv
, arg_ptr
, entry
, pred_xtype
);
2182 insert_type (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
)
2185 struct predicate
*our_pred
;
2188 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
2189 || (strlen (argv
[*arg_ptr
]) != 1))
2191 switch (argv
[*arg_ptr
][0])
2193 case 'b': /* block special */
2194 type_cell
= S_IFBLK
;
2197 case 'c': /* character special */
2198 type_cell
= S_IFCHR
;
2201 case 'd': /* directory */
2202 type_cell
= S_IFDIR
;
2205 case 'f': /* regular file */
2206 type_cell
= S_IFREG
;
2210 case 'l': /* symbolic link */
2211 type_cell
= S_IFLNK
;
2216 case 'p': /* pipe */
2217 type_cell
= S_IFIFO
;
2222 case 's': /* socket */
2223 type_cell
= S_IFSOCK
;
2228 case 'D': /* Solaris door */
2229 type_cell
= S_IFDOOR
;
2233 default: /* None of the above ... nuke 'em. */
2236 our_pred
= insert_primary_withpred (entry
, which_pred
);
2237 our_pred
->est_success_rate
= rate
;
2239 /* Figure out if we will need to stat the file, because if we don't
2240 * need to follow symlinks, we can avoid a stat call by using
2241 * struct dirent.d_type.
2243 if (which_pred
== pred_xtype
)
2245 our_pred
->need_stat
= true;
2246 our_pred
->need_type
= false;
2250 our_pred
->need_stat
= false; /* struct dirent is enough */
2251 our_pred
->need_type
= true;
2253 our_pred
->args
.type
= type_cell
;
2254 (*arg_ptr
)++; /* Move on to next argument. */
2259 /* Return true if the file accessed via FP is a terminal.
2262 stream_is_tty(FILE *fp
)
2264 int fd
= fileno(fp
);
2267 return false; /* not a valid stream */
2271 return isatty(fd
) ? true : false;
2279 /* XXX: do we need to pass FUNC to this function? */
2281 insert_fprintf (FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char **argv
, int *arg_ptr
)
2283 char *format
; /* Beginning of unprocessed format string. */
2284 register char *scan
; /* Current address in scanning `format'. */
2285 register char *scan2
; /* Address inside of element being scanned. */
2286 struct segment
**segmentp
; /* Address of current segment. */
2287 struct predicate
*our_pred
;
2289 format
= argv
[(*arg_ptr
)++];
2291 our_pred
= insert_primary_withpred (entry
, func
);
2292 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2293 our_pred
->args
.printf_vec
.stream
= fp
;
2294 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(fp
);
2295 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
2296 our_pred
->need_type
= false;
2297 our_pred
->need_stat
= false;
2298 our_pred
->p_cost
= NeedsNothing
;
2300 segmentp
= &our_pred
->args
.printf_vec
.segment
;
2303 for (scan
= format
; *scan
; scan
++)
2308 if (*scan2
>= '0' && *scan2
<= '7')
2312 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
2314 n
= 8 * n
+ *scan2
- '0';
2329 make_segment (segmentp
, format
, scan
- format
,
2332 if (our_pred
->need_stat
&& (our_pred
->p_cost
< NeedsStatInfo
))
2333 our_pred
->p_cost
= NeedsStatInfo
;
2351 /* *scan = '\\'; * it already is */
2355 _("warning: unrecognized escape `\\%c'"), *scan2
);
2360 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2363 format
= scan2
+ 1; /* Move past the escape. */
2364 scan
= scan2
; /* Incremented immediately by `for'. */
2366 else if (*scan
== '%')
2370 /* Trailing %. We don't like those. */
2371 error (1, 0, _("error: %s at end of format string"), scan
);
2373 else if (scan
[1] == '%')
2375 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2382 /* Scan past flags, width and precision, to verify kind. */
2383 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
2385 while (ISDIGIT (*scan2
))
2388 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
2390 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2
))
2392 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2393 KIND_FORMAT
, *scan2
, 0,
2398 else if (strchr ("ABCT", *scan2
) && scan2
[1])
2400 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2401 KIND_FORMAT
, scan2
[0], scan2
[1],
2409 /* An unrecognized % escape. Print the char after the %. */
2410 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2412 segmentp
= make_segment (segmentp
, format
, scan
- format
,
2422 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
, 0, 0,
2427 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2428 from the text in FORMAT, which has length LEN.
2429 Return the address of the `next' pointer of the new segment. */
2431 static struct segment
**
2432 make_segment (struct segment
**segment
,
2437 char aux_format_char
,
2438 struct predicate
*pred
)
2440 enum EvaluationCost mycost
= NeedsNothing
;
2443 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
2445 (*segment
)->segkind
= kind
;
2446 (*segment
)->format_char
[0] = format_char
;
2447 (*segment
)->format_char
[1] = aux_format_char
;
2448 (*segment
)->next
= NULL
;
2449 (*segment
)->text_len
= len
;
2451 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
2452 strncpy (fmt
, format
, len
);
2457 case KIND_PLAIN
: /* Plain text string, no % conversion. */
2458 case KIND_STOP
: /* Terminate argument, no newline. */
2459 assert(0 == format_char
);
2460 assert(0 == aux_format_char
);
2462 if (mycost
> pred
->p_cost
)
2463 pred
->p_cost
= NeedsNothing
;
2464 return &(*segment
)->next
;
2468 assert(kind
== KIND_FORMAT
);
2469 switch (format_char
)
2471 case 'l': /* object of symlink */
2472 pred
->need_stat
= true;
2473 mycost
= NeedsLinkName
;
2477 case 'y': /* file type */
2478 pred
->need_type
= true;
2483 case 'a': /* atime in `ctime' format */
2484 case 'A': /* atime in user-specified strftime format */
2485 case 'B': /* birth time in user-specified strftime format */
2486 case 'c': /* ctime in `ctime' format */
2487 case 'C': /* ctime in user-specified strftime format */
2488 case 'F': /* filesystem type */
2489 case 'g': /* group name */
2490 case 'i': /* inode number */
2491 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2492 case 's': /* size in bytes */
2493 case 't': /* mtime in `ctime' format */
2494 case 'T': /* mtime in user-specified strftime format */
2495 case 'u': /* user name */
2496 pred
->need_stat
= true;
2497 mycost
= NeedsStatInfo
;
2501 case 'S': /* sparseness */
2502 pred
->need_stat
= true;
2503 mycost
= NeedsStatInfo
;
2507 case 'Y': /* symlink pointed file type */
2508 pred
->need_stat
= true;
2509 mycost
= NeedsType
; /* true for amortised effect */
2513 case 'f': /* basename of path */
2514 case 'h': /* leading directories part of path */
2515 case 'p': /* pathname */
2516 case 'P': /* pathname with ARGV element stripped */
2520 case 'H': /* ARGV element file was found under */
2524 /* Numeric items that one might expect to honour
2525 * #, 0, + flags but which do not.
2527 case 'G': /* GID number */
2528 case 'U': /* UID number */
2529 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
2530 case 'D': /* Filesystem device on which the file exits */
2531 case 'k': /* size in 1K blocks */
2532 case 'n': /* number of links */
2533 pred
->need_stat
= true;
2534 mycost
= NeedsStatInfo
;
2538 /* Numeric items that DO honour #, 0, + flags.
2540 case 'd': /* depth in search tree (0 = ARGV element) */
2544 case 'm': /* mode as octal number (perms only) */
2546 pred
->need_stat
= true;
2547 mycost
= NeedsStatInfo
;
2554 _("error: the format directive `%%%c' is reserved for future use"),
2561 if (mycost
> pred
->p_cost
)
2562 pred
->p_cost
= mycost
;
2563 return &(*segment
)->next
;
2567 check_path_safety(const char *action
, char **argv
)
2569 const char *path
= getenv("PATH");
2574 s
= next_element(path
, 1);
2575 while ((s
= next_element ((char *) NULL
, 1)) != NULL
)
2577 if (0 == strcmp(s
, "."))
2579 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)"),
2582 else if ('/' != s
[0])
2584 /* Relative paths are also dangerous in $PATH. */
2585 error(1, 0, _("The ralative path %s is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove that entry from $PATH"),
2592 /* handles both exec and ok predicate */
2594 new_insert_exec_ok (const char *action
,
2595 const struct parser_table
*entry
,
2600 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2601 int i
; /* Index into cmd args */
2602 int saw_braces
; /* True if previous arg was '{}'. */
2603 boolean allow_plus
; /* True if + is a valid terminator */
2604 int brace_count
; /* Number of instances of {}. */
2605 PRED_FUNC func
= entry
->pred_func
;
2606 enum BC_INIT_STATUS bcstatus
;
2608 struct predicate
*our_pred
;
2609 struct exec_val
*execp
; /* Pointer for efficiency. */
2611 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2614 our_pred
= insert_primary_withpred (entry
, func
);
2615 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2616 our_pred
->need_type
= our_pred
->need_stat
= false;
2618 execp
= &our_pred
->args
.exec_vec
;
2620 if ((func
!= pred_okdir
) && (func
!= pred_ok
))
2623 execp
->close_stdin
= false;
2628 /* If find reads stdin (i.e. for -ok and similar), close stdin
2629 * in the child to prevent some script from consiming the output
2630 * intended for find.
2632 execp
->close_stdin
= true;
2636 if ((func
== pred_execdir
) || (func
== pred_okdir
))
2638 options
.ignore_readdir_race
= false;
2639 check_path_safety(action
, argv
);
2640 execp
->use_current_dir
= true;
2644 execp
->use_current_dir
= false;
2647 our_pred
->args
.exec_vec
.multiple
= 0;
2649 /* Count the number of args with path replacements, up until the ';'.
2650 * Also figure out if the command is terminated by ";" or by "+".
2653 for (end
= start
, saw_braces
=0, brace_count
=0;
2655 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2658 /* For -exec and -execdir, "{} +" can terminate the command. */
2660 && argv
[end
][0] == '+' && argv
[end
][1] == 0
2663 our_pred
->args
.exec_vec
.multiple
= 1;
2668 if (strstr (argv
[end
], "{}")) /* XXX: wrong for multibyte locales */
2673 if (0 == end
&& (func
== pred_execdir
|| func
== pred_okdir
))
2675 /* The POSIX standard says that {} replacement should
2676 * occur even in the utility name. This is insecure
2677 * since it means we will be executing a command whose
2678 * name is chosen according to whatever find finds in
2679 * the filesystem. That can be influenced by an
2680 * attacker. Hence for -execdir and -okdir this is not
2681 * allowed. We can specify this as those options are
2682 * not defined by POSIX.
2684 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2689 /* Fail if no command given or no semicolon found. */
2690 if ((end
== start
) || (argv
[end
] == NULL
))
2697 if (our_pred
->args
.exec_vec
.multiple
&& brace_count
> 1)
2701 if (func
== pred_execdir
)
2707 _("Only one instance of {} is supported with -exec%s ... +"),
2711 /* We use a switch statement here so that
2712 * the compiler warns us when we forget to handle a
2713 * newly invented enum value.
2715 bcstatus
= bc_init_controlinfo(&execp
->ctl
);
2718 case BC_INIT_ENV_TOO_BIG
:
2720 _("The environment is too large for exec()."));
2723 /* Good news. Carry on. */
2726 bc_use_sensible_arg_max(&execp
->ctl
);
2729 execp
->ctl
.exec_callback
= launch
;
2731 if (our_pred
->args
.exec_vec
.multiple
)
2733 /* "+" terminator, so we can just append our arguments after the
2734 * command and initial arguments.
2736 execp
->replace_vec
= NULL
;
2737 execp
->ctl
.replace_pat
= NULL
;
2738 execp
->ctl
.rplen
= 0;
2739 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2740 execp
->ctl
.args_per_exec
= 0; /* no limit */
2742 /* remember how many arguments there are */
2743 execp
->ctl
.initial_argc
= (end
-start
) - 1;
2745 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2746 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2748 /* Gather the initial arguments. Skip the {}. */
2749 for (i
=start
; i
<end
-1; ++i
)
2751 bc_push_arg(&execp
->ctl
, &execp
->state
,
2752 argv
[i
], strlen(argv
[i
])+1,
2759 /* Semicolon terminator - more than one {} is supported, so we
2760 * have to do brace-replacement.
2762 execp
->num_args
= end
- start
;
2764 execp
->ctl
.replace_pat
= "{}";
2765 execp
->ctl
.rplen
= strlen(execp
->ctl
.replace_pat
);
2766 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2767 execp
->ctl
.args_per_exec
= 0; /* no limit */
2768 execp
->replace_vec
= xmalloc(sizeof(char*)*execp
->num_args
);
2771 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2772 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2774 /* Remember the (pre-replacement) arguments for later. */
2775 for (i
=0; i
<execp
->num_args
; ++i
)
2777 execp
->replace_vec
[i
] = argv
[i
+start
];
2781 if (argv
[end
] == NULL
)
2792 insert_exec_ok (const char *action
, const struct parser_table
*entry
, int dirfd
, char **argv
, int *arg_ptr
)
2794 return new_insert_exec_ok(action
, entry
, dirfd
, argv
, arg_ptr
);
2799 /* Get a timestamp and comparison type.
2801 STR is the ASCII representation.
2802 Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
2803 relative to ORIGIN (usually the current moment or midnight).
2804 Thus the sense of the comparison type appears to be reversed.
2805 Set *COMP_TYPE to the kind of comparison that is requested.
2806 Issue OVERFLOWMESSAGE if overflow occurs.
2807 Return true if all okay, false if input error.
2809 Used by -atime, -ctime and -mtime (parsers) to
2810 get the appropriate information for a time predicate processor. */
2813 get_relative_timestamp (char *str
,
2814 struct time_val
*result
,
2816 double sec_per_unit
,
2817 const char *overflowmessage
)
2820 double offset
, seconds
, f
;
2822 if (get_comp_type(&str
, &result
->kind
))
2824 /* Invert the sense of the comparison */
2825 switch (result
->kind
)
2827 case COMP_LT
: result
->kind
= COMP_GT
; break;
2828 case COMP_GT
: result
->kind
= COMP_LT
; break;
2832 /* Convert the ASCII number into floating-point. */
2833 if (xstrtod(str
, NULL
, &offset
, strtod
))
2835 /* Separate the floating point number the user specified
2836 * (which is a number of days, or minutes, etc) into an
2837 * integral number of seconds (SECONDS) and a fraction (F).
2839 f
= modf(offset
* sec_per_unit
, &seconds
);
2841 result
->ts
.tv_sec
= origin
- seconds
;
2842 result
->ts
.tv_nsec
= fabs(f
* 1e9
);
2844 /* Check for overflow. */
2845 checkval
= (uintmax_t)origin
- seconds
;
2846 if (checkval
!= result
->ts
.tv_sec
)
2848 /* an overflow has occurred. */
2849 error (1, 0, overflowmessage
, str
);
2855 /* Conversion from ASCII to double failed. */
2865 /* Insert a time predicate based on the information in ENTRY.
2866 ARGV is a pointer to the argument array.
2867 ARG_PTR is a pointer to an index into the array, incremented if
2870 Return true if input is valid, false if not.
2872 A new predicate node is assigned, along with an argument node
2873 obtained with malloc.
2875 Used by -atime, -ctime, and -mtime parsers. */
2878 parse_time (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
2880 struct predicate
*our_pred
;
2881 struct time_val tval
;
2882 enum comparison_type comp
;
2884 const char *errmsg
= "arithmetic overflow while converting %s days to a number of seconds";
2887 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2890 /* Decide the origin by previewing the comparison type. */
2891 origin
= options
.cur_day_start
;
2893 if (get_comp_type(&s
, &comp
))
2895 /* Remember, we invert the sense of the comparison, so this tests against COMP_LT instead of COMP_GT... */
2896 if (COMP_LT
== tval
.kind
)
2898 uintmax_t expected
= origin
+ (DAYSECS
-1);
2899 origin
+= (DAYSECS
-1);
2900 if (origin
!= expected
)
2903 _("arithmetic overflow when trying to calculate the end of today"));
2906 /* We discard the value of comp here, as get_relative_timestamp
2907 * will set tval.kind.
2911 if (!get_relative_timestamp(argv
[*arg_ptr
], &tval
, origin
, DAYSECS
, errmsg
))
2914 our_pred
= insert_primary (entry
);
2915 our_pred
->args
.reftime
= tval
;
2916 our_pred
->est_success_rate
= estimate_timestamp_success_rate(tval
.ts
.tv_sec
);
2919 if (options
.debug_options
& DebugExpressionTree
)
2923 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2924 fprintf (stderr
, " type: %s %s ",
2925 (tval
.kind
== COMP_GT
) ? "gt" :
2926 ((tval
.kind
== COMP_LT
) ? "lt" : ((tval
.kind
== COMP_EQ
) ? "eq" : "?")),
2927 (tval
.kind
== COMP_GT
) ? " >" :
2928 ((tval
.kind
== COMP_LT
) ? " <" : ((tval
.kind
== COMP_EQ
) ? ">=" : " ?")));
2929 t
= our_pred
->args
.reftime
.ts
.tv_sec
;
2930 fprintf (stderr
, "%ju %s", (uintmax_t) our_pred
->args
.reftime
.ts
.tv_sec
, ctime (&t
));
2931 if (tval
.kind
== COMP_EQ
)
2933 t
= our_pred
->args
.reftime
.ts
.tv_sec
+= DAYSECS
;
2934 fprintf (stderr
, " < %ju %s",
2935 (uintmax_t) our_pred
->args
.reftime
.ts
.tv_sec
, ctime (&t
));
2936 our_pred
->args
.reftime
.ts
.tv_sec
-= DAYSECS
;
2943 /* Get the comparison type prefix (if any) from a number argument.
2944 The prefix is at *STR.
2945 Set *COMP_TYPE to the kind of comparison that is requested.
2946 Advance *STR beyond any initial comparison prefix.
2948 Return true if all okay, false if input error. */
2950 get_comp_type(char **str
, enum comparison_type
*comp_type
)
2955 *comp_type
= COMP_GT
;
2959 *comp_type
= COMP_LT
;
2963 *comp_type
= COMP_EQ
;
2973 /* Get a number with comparison information.
2974 The sense of the comparison information is 'normal'; that is,
2975 '+' looks for a count > than the number and '-' less than.
2977 STR is the ASCII representation of the number.
2978 Set *NUM to the number.
2979 Set *COMP_TYPE to the kind of comparison that is requested.
2981 Return true if all okay, false if input error. */
2986 enum comparison_type
*comp_type
)
2993 /* Figure out the comparison type if the caller accepts one. */
2996 if (!get_comp_type(&str
, comp_type
))
3000 return xstrtoumax (str
, &pend
, 10, num
, "") == LONGINT_OK
;
3003 /* Insert a number predicate.
3004 ARGV is a pointer to the argument array.
3005 *ARG_PTR is an index into ARGV, incremented if all went well.
3006 *PRED is the predicate processor to insert.
3008 Return true if input is valid, false if error.
3010 A new predicate node is assigned, along with an argument node
3011 obtained with malloc.
3013 Used by -inum and -links parsers. */
3015 static struct predicate
*
3016 insert_num (char **argv
, int *arg_ptr
, const struct parser_table
*entry
)
3018 struct predicate
*our_pred
;
3020 enum comparison_type c_type
;
3022 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
3024 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
3026 our_pred
= insert_primary (entry
);
3027 our_pred
->args
.numinfo
.kind
= c_type
;
3028 our_pred
->args
.numinfo
.l_val
= num
;
3031 if (options
.debug_options
& DebugExpressionTree
)
3033 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
3034 fprintf (stderr
, " type: %s %s ",
3035 (c_type
== COMP_GT
) ? "gt" :
3036 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
3037 (c_type
== COMP_GT
) ? " >" :
3038 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
3039 fprintf (stderr
, "%ju\n", our_pred
->args
.numinfo
.l_val
);
3045 open_output_file (char *path
)
3049 if (!strcmp (path
, "/dev/stderr"))
3051 else if (!strcmp (path
, "/dev/stdout"))
3053 f
= fopen_safer (path
, "w");
3055 error (1, errno
, "%s", path
);