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.
|
---|
4 |
|
---|
5 | This program is free software; you can redistribute it and/or modify
|
---|
6 | it under the terms of the GNU General Public License as published by
|
---|
7 | the Free Software Foundation; either version 2, or (at your option)
|
---|
8 | any later version.
|
---|
9 |
|
---|
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.
|
---|
14 |
|
---|
15 | You should have received a copy of the GNU General Public License
|
---|
16 | along with this program; if not, write to the Free Software
|
---|
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
---|
18 | USA.
|
---|
19 | */
|
---|
20 |
|
---|
21 |
|
---|
22 | #include "defs.h"
|
---|
23 | #include <ctype.h>
|
---|
24 | #include <assert.h>
|
---|
25 | #include <pwd.h>
|
---|
26 | #include <grp.h>
|
---|
27 | #include <fnmatch.h>
|
---|
28 | #include "modechange.h"
|
---|
29 | #include "modetype.h"
|
---|
30 | #include "xstrtol.h"
|
---|
31 | #include "xalloc.h"
|
---|
32 | #include "quote.h"
|
---|
33 | #include "quotearg.h"
|
---|
34 | #include "buildcmd.h"
|
---|
35 | #include "nextelem.h"
|
---|
36 | #include "stdio-safer.h"
|
---|
37 | #include "regextype.h"
|
---|
38 |
|
---|
39 | #ifdef HAVE_FCNTL_H
|
---|
40 | #include <fcntl.h>
|
---|
41 | #else
|
---|
42 | #include <sys/file.h>
|
---|
43 | #endif
|
---|
44 |
|
---|
45 | /* The presence of unistd.h is assumed by gnulib these days, so we
|
---|
46 | * might as well assume it too.
|
---|
47 | */
|
---|
48 | /* We need <unistd.h> for isatty(). */
|
---|
49 | #include <unistd.h>
|
---|
50 |
|
---|
51 | #if ENABLE_NLS
|
---|
52 | # include <libintl.h>
|
---|
53 | # define _(Text) gettext (Text)
|
---|
54 | #else
|
---|
55 | # define _(Text) Text
|
---|
56 | #endif
|
---|
57 | #ifdef gettext_noop
|
---|
58 | # define N_(String) gettext_noop (String)
|
---|
59 | #else
|
---|
60 | /* See locate.c for explanation as to why not use (String) */
|
---|
61 | # define N_(String) String
|
---|
62 | #endif
|
---|
63 |
|
---|
64 | #if !defined (isascii) || defined (STDC_HEADERS)
|
---|
65 | #ifdef isascii
|
---|
66 | #undef isascii
|
---|
67 | #endif
|
---|
68 | #define isascii(c) 1
|
---|
69 | #endif
|
---|
70 |
|
---|
71 | #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
|
---|
72 | #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
|
---|
73 |
|
---|
74 | #ifndef HAVE_ENDGRENT
|
---|
75 | #define endgrent()
|
---|
76 | #endif
|
---|
77 | #ifndef HAVE_ENDPWENT
|
---|
78 | #define endpwent()
|
---|
79 | #endif
|
---|
80 | |
---|
81 |
|
---|
82 | static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
|
---|
83 | static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
84 | static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
85 | static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
86 | static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
87 | static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
88 | static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
89 | static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
90 | static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
91 | static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
92 | static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
93 | static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
94 | static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
95 | static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
96 | static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
97 | static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
98 | static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
99 | static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
100 | static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
101 | static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
102 | static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
103 | static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
104 | static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
105 | static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
106 | static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
107 | static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
108 | static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
109 | static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
110 | static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
111 | static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
112 | static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
113 | static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
114 | static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
115 | static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
116 | static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
117 | static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
118 | static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
119 | static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
120 | static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
121 | static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
122 | static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
123 | static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
124 | static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
125 | static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
126 | static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
127 | static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
128 | static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
129 | static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
130 | static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
131 | static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
132 | static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
133 | static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
134 | static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
135 | static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
136 | #if 0
|
---|
137 | static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
138 | #endif
|
---|
139 | static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
140 | static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
141 | static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
142 | static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
143 | static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
144 | static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
145 | static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
146 | static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
147 | static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
148 | static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
149 | static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
150 | static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
151 | static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
152 | static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
153 | static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
154 |
|
---|
155 | boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
|
---|
156 |
|
---|
157 |
|
---|
158 | static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred));
|
---|
159 | static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options));
|
---|
160 | static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr));
|
---|
161 |
|
---|
162 | static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind, struct predicate *pred));
|
---|
163 | static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr));
|
---|
164 | static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
|
---|
165 | static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
|
---|
166 | static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry));
|
---|
167 | static FILE *open_output_file PARAMS((char *path));
|
---|
168 | static boolean stream_is_tty(FILE *fp);
|
---|
169 | static boolean parse_noop PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
|
---|
170 |
|
---|
171 | #define PASTE(x,y) x##y
|
---|
172 | #define STRINGIFY(s) #s
|
---|
173 |
|
---|
174 | #define PARSE_OPTION(what,suffix) \
|
---|
175 | { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
|
---|
176 |
|
---|
177 | #define PARSE_POSOPT(what,suffix) \
|
---|
178 | { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
|
---|
179 |
|
---|
180 | #define PARSE_TEST(what,suffix) \
|
---|
181 | { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
|
---|
182 |
|
---|
183 | #define PARSE_TEST_NP(what,suffix) \
|
---|
184 | { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
|
---|
185 |
|
---|
186 | #define PARSE_ACTION(what,suffix) \
|
---|
187 | { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
|
---|
188 |
|
---|
189 | #define PARSE_ACTION_NP(what,suffix) \
|
---|
190 | { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
|
---|
191 |
|
---|
192 | #define PARSE_PUNCTUATION(what,suffix) \
|
---|
193 | { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
|
---|
194 |
|
---|
195 |
|
---|
196 | /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
|
---|
197 | If they are in some Unix versions of find, they are marked `Unix'. */
|
---|
198 |
|
---|
199 | static struct parser_table const parse_table[] =
|
---|
200 | {
|
---|
201 | PARSE_PUNCTUATION("!", negate),
|
---|
202 | PARSE_PUNCTUATION("not", negate), /* GNU */
|
---|
203 | PARSE_PUNCTUATION("(", open),
|
---|
204 | PARSE_PUNCTUATION(")", close),
|
---|
205 | PARSE_PUNCTUATION(",", comma), /* GNU */
|
---|
206 | PARSE_PUNCTUATION("a", and),
|
---|
207 | PARSE_TEST ("amin", amin), /* GNU */
|
---|
208 | PARSE_PUNCTUATION("and", and), /* GNU */
|
---|
209 | PARSE_TEST ("anewer", anewer), /* GNU */
|
---|
210 | {ARG_TEST, "atime", parse_time, pred_atime},
|
---|
211 | PARSE_TEST ("cmin", cmin), /* GNU */
|
---|
212 | PARSE_TEST ("cnewer", cnewer), /* GNU */
|
---|
213 | {ARG_TEST, "ctime", parse_time, pred_ctime},
|
---|
214 | PARSE_POSOPT ("daystart", daystart), /* GNU */
|
---|
215 | PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
|
---|
216 | PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
|
---|
217 | PARSE_OPTION ("depth", depth),
|
---|
218 | PARSE_TEST ("empty", empty), /* GNU */
|
---|
219 | {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
|
---|
220 | {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
|
---|
221 | PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
|
---|
222 | PARSE_ACTION ("fls", fls), /* GNU */
|
---|
223 | PARSE_POSOPT ("follow", follow), /* GNU, Unix */
|
---|
224 | PARSE_ACTION ("fprint", fprint), /* GNU */
|
---|
225 | PARSE_ACTION ("fprint0", fprint0), /* GNU */
|
---|
226 | {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
|
---|
227 | PARSE_TEST ("fstype", fstype), /* GNU, Unix */
|
---|
228 | PARSE_TEST ("gid", gid), /* GNU */
|
---|
229 | PARSE_TEST ("group", group),
|
---|
230 | PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
|
---|
231 | PARSE_TEST ("ilname", ilname), /* GNU */
|
---|
232 | PARSE_TEST ("iname", iname), /* GNU */
|
---|
233 | PARSE_TEST ("inum", inum), /* GNU, Unix */
|
---|
234 | PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
|
---|
235 | PARSE_TEST_NP ("iregex", iregex), /* GNU */
|
---|
236 | PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
|
---|
237 | PARSE_TEST ("links", links),
|
---|
238 | PARSE_TEST ("lname", lname), /* GNU */
|
---|
239 | PARSE_ACTION ("ls", ls), /* GNU, Unix */
|
---|
240 | PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
|
---|
241 | PARSE_OPTION ("mindepth", mindepth), /* GNU */
|
---|
242 | PARSE_TEST ("mmin", mmin), /* GNU */
|
---|
243 | PARSE_OPTION ("mount", xdev), /* Unix */
|
---|
244 | {ARG_TEST, "mtime", parse_time, pred_mtime},
|
---|
245 | PARSE_TEST ("name", name),
|
---|
246 | #ifdef UNIMPLEMENTED_UNIX
|
---|
247 | PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
|
---|
248 | #endif
|
---|
249 | PARSE_TEST ("newer", newer),
|
---|
250 | PARSE_OPTION ("noleaf", noleaf), /* GNU */
|
---|
251 | PARSE_TEST ("nogroup", nogroup),
|
---|
252 | PARSE_TEST ("nouser", nouser),
|
---|
253 | PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
|
---|
254 | PARSE_POSOPT ("nowarn", nowarn), /* GNU */
|
---|
255 | PARSE_PUNCTUATION("o", or),
|
---|
256 | PARSE_PUNCTUATION("or", or), /* GNU */
|
---|
257 | PARSE_ACTION ("ok", ok),
|
---|
258 | PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
|
---|
259 | PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */
|
---|
260 | PARSE_TEST ("perm", perm),
|
---|
261 | PARSE_ACTION ("print", print),
|
---|
262 | PARSE_ACTION ("print0", print0), /* GNU */
|
---|
263 | {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
|
---|
264 | PARSE_ACTION ("prune", prune),
|
---|
265 | PARSE_ACTION ("quit", quit), /* GNU */
|
---|
266 | {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
|
---|
267 | PARSE_TEST ("regex", regex), /* GNU */
|
---|
268 | PARSE_OPTION ("regextype", regextype), /* GNU */
|
---|
269 | PARSE_TEST ("samefile", samefile), /* GNU */
|
---|
270 | #if 0
|
---|
271 | PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
|
---|
272 | #endif
|
---|
273 | PARSE_TEST ("size", size),
|
---|
274 | PARSE_TEST ("type", type),
|
---|
275 | PARSE_TEST ("uid", uid), /* GNU */
|
---|
276 | PARSE_TEST ("used", used), /* GNU */
|
---|
277 | PARSE_TEST ("user", user),
|
---|
278 | PARSE_OPTION ("warn", warn), /* GNU */
|
---|
279 | PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */
|
---|
280 | {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
|
---|
281 | PARSE_OPTION ("xdev", xdev),
|
---|
282 | PARSE_TEST ("xtype", xtype), /* GNU */
|
---|
283 | #ifdef UNIMPLEMENTED_UNIX
|
---|
284 | /* It's pretty ugly for find to know about archive formats.
|
---|
285 | Plus what it could do with cpio archives is very limited.
|
---|
286 | Better to leave it out. */
|
---|
287 | PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
|
---|
288 | #endif
|
---|
289 | /* gnulib's stdbool.h might have made true and false into macros,
|
---|
290 | * so we can't leave named 'true' and 'false' tokens, so we have
|
---|
291 | * to expeant the relevant entries longhand.
|
---|
292 | */
|
---|
293 | {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
|
---|
294 | {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
|
---|
295 | {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
|
---|
296 |
|
---|
297 | /* Various other cases that don't fit neatly into our macro scheme. */
|
---|
298 | {ARG_TEST, "help", parse_help, NULL}, /* GNU */
|
---|
299 | {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
|
---|
300 | {ARG_TEST, "version", parse_version, NULL}, /* GNU */
|
---|
301 | {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
|
---|
302 | {0, 0, 0, 0}
|
---|
303 | };
|
---|
304 | |
---|
305 |
|
---|
306 |
|
---|
307 | static const char *first_nonoption_arg = NULL;
|
---|
308 | static const struct parser_table *noop = NULL;
|
---|
309 |
|
---|
310 |
|
---|
311 | |
---|
312 |
|
---|
313 | static const struct parser_table*
|
---|
314 | get_noop(void)
|
---|
315 | {
|
---|
316 | int i;
|
---|
317 | if (NULL == noop)
|
---|
318 | {
|
---|
319 | for (i = 0; parse_table[i].parser_name != 0; i++)
|
---|
320 | {
|
---|
321 | if (ARG_NOOP ==parse_table[i].type)
|
---|
322 | {
|
---|
323 | noop = &(parse_table[i]);
|
---|
324 | break;
|
---|
325 | }
|
---|
326 | }
|
---|
327 | }
|
---|
328 | return noop;
|
---|
329 | }
|
---|
330 |
|
---|
331 |
|
---|
332 | |
---|
333 |
|
---|
334 | void
|
---|
335 | set_follow_state(enum SymlinkOption opt)
|
---|
336 | {
|
---|
337 | if (options.debug_options & DebugStat)
|
---|
338 | {
|
---|
339 | /* For DebugStat, the choice is made at runtime within debug_stat()
|
---|
340 | * by checking the contents of the symlink_handling variable.
|
---|
341 | */
|
---|
342 | options.xstat = debug_stat;
|
---|
343 | }
|
---|
344 | else
|
---|
345 | {
|
---|
346 | switch (opt)
|
---|
347 | {
|
---|
348 | case SYMLINK_ALWAYS_DEREF: /* -L */
|
---|
349 | options.xstat = optionl_stat;
|
---|
350 | options.no_leaf_check = true;
|
---|
351 | break;
|
---|
352 |
|
---|
353 | case SYMLINK_NEVER_DEREF: /* -P (default) */
|
---|
354 | options.xstat = optionp_stat;
|
---|
355 | /* Can't turn no_leaf_check off because the user might have specified
|
---|
356 | * -noleaf anyway
|
---|
357 | */
|
---|
358 | break;
|
---|
359 |
|
---|
360 | case SYMLINK_DEREF_ARGSONLY: /* -H */
|
---|
361 | options.xstat = optionh_stat;
|
---|
362 | options.no_leaf_check = true;
|
---|
363 | }
|
---|
364 | }
|
---|
365 | options.symlink_handling = opt;
|
---|
366 | }
|
---|
367 |
|
---|
368 |
|
---|
369 | void
|
---|
370 | parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
|
---|
371 | {
|
---|
372 | (void) args;
|
---|
373 | (void) argno;
|
---|
374 | (void) last;
|
---|
375 | (void) predicates;
|
---|
376 | first_nonoption_arg = NULL;
|
---|
377 | }
|
---|
378 |
|
---|
379 | void
|
---|
380 | parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates)
|
---|
381 | {
|
---|
382 | /* does nothing */
|
---|
383 | (void) args;
|
---|
384 | (void) argno;
|
---|
385 | (void) last;
|
---|
386 | (void) predicates;
|
---|
387 | }
|
---|
388 |
|
---|
389 |
|
---|
390 |
|
---|
391 |
|
---|
392 | /* Return a pointer to the parser function to invoke for predicate
|
---|
393 | SEARCH_NAME.
|
---|
394 | Return NULL if SEARCH_NAME is not a valid predicate name. */
|
---|
395 |
|
---|
396 | const struct parser_table*
|
---|
397 | find_parser (char *search_name)
|
---|
398 | {
|
---|
399 | int i;
|
---|
400 | const char *original_arg = search_name;
|
---|
401 |
|
---|
402 | if (*search_name == '-')
|
---|
403 | search_name++;
|
---|
404 | for (i = 0; parse_table[i].parser_name != 0; i++)
|
---|
405 | {
|
---|
406 | if (strcmp (parse_table[i].parser_name, search_name) == 0)
|
---|
407 | {
|
---|
408 | /* If this is an option, but we have already had a
|
---|
409 | * non-option argument, the user may be under the
|
---|
410 | * impression that the behaviour of the option
|
---|
411 | * argument is conditional on some preceding
|
---|
412 | * tests. This might typically be the case with,
|
---|
413 | * for example, -maxdepth.
|
---|
414 | *
|
---|
415 | * The options -daystart and -follow are exempt
|
---|
416 | * from this treatment, since their positioning
|
---|
417 | * in the command line does have an effect on
|
---|
418 | * subsequent tests but not previous ones. That
|
---|
419 | * might be intentional on the part of the user.
|
---|
420 | */
|
---|
421 | if (parse_table[i].type != ARG_POSITIONAL_OPTION)
|
---|
422 | {
|
---|
423 | /* Something other than -follow/-daystart.
|
---|
424 | * If this is an option, check if it followed
|
---|
425 | * a non-option and if so, issue a warning.
|
---|
426 | */
|
---|
427 | if (parse_table[i].type == ARG_OPTION)
|
---|
428 | {
|
---|
429 | if ((first_nonoption_arg != NULL)
|
---|
430 | && options.warnings )
|
---|
431 | {
|
---|
432 | /* option which follows a non-option */
|
---|
433 | error (0, 0,
|
---|
434 | _("warning: you have specified the %s "
|
---|
435 | "option after a non-option argument %s, "
|
---|
436 | "but options are not positional (%s affects "
|
---|
437 | "tests specified before it as well as those "
|
---|
438 | "specified after it). Please specify options "
|
---|
439 | "before other arguments.\n"),
|
---|
440 | original_arg,
|
---|
441 | first_nonoption_arg,
|
---|
442 | original_arg);
|
---|
443 | }
|
---|
444 | }
|
---|
445 | else
|
---|
446 | {
|
---|
447 | /* Not an option or a positional option,
|
---|
448 | * so remember we've seen it in order to
|
---|
449 | * use it in a possible future warning message.
|
---|
450 | */
|
---|
451 | if (first_nonoption_arg == NULL)
|
---|
452 | {
|
---|
453 | first_nonoption_arg = original_arg;
|
---|
454 | }
|
---|
455 | }
|
---|
456 | }
|
---|
457 |
|
---|
458 | return &parse_table[i];
|
---|
459 | }
|
---|
460 | }
|
---|
461 | return NULL;
|
---|
462 | }
|
---|
463 | |
---|
464 |
|
---|
465 | static float
|
---|
466 | estimate_file_age_success_rate(float num_days)
|
---|
467 | {
|
---|
468 | if (num_days < 0.1)
|
---|
469 | {
|
---|
470 | /* Assume 1% of files have timestamps in the future */
|
---|
471 | return 0.01f;
|
---|
472 | }
|
---|
473 | else if (num_days < 1)
|
---|
474 | {
|
---|
475 | /* Assume 30% of files have timestamps today */
|
---|
476 | return 0.3f;
|
---|
477 | }
|
---|
478 | else if (num_days > 100)
|
---|
479 | {
|
---|
480 | /* Assume 30% of files are very old */
|
---|
481 | return 0.3f;
|
---|
482 | }
|
---|
483 | else
|
---|
484 | {
|
---|
485 | /* Assume 39% of files are between 1 and 100 days old. */
|
---|
486 | return 0.39f;
|
---|
487 | }
|
---|
488 | }
|
---|
489 | |
---|
490 |
|
---|
491 | static float
|
---|
492 | estimate_timestamp_success_rate(time_t when)
|
---|
493 | {
|
---|
494 | int num_days = (when - options.cur_day_start) / 86400;
|
---|
495 | return estimate_file_age_success_rate(num_days);
|
---|
496 | }
|
---|
497 |
|
---|
498 | |
---|
499 |
|
---|
500 | /* The parsers are responsible to continue scanning ARGV for
|
---|
501 | their arguments. Each parser knows what is and isn't
|
---|
502 | allowed for itself.
|
---|
503 |
|
---|
504 | ARGV is the argument array.
|
---|
505 | *ARG_PTR is the index to start at in ARGV,
|
---|
506 | updated to point beyond the last element consumed.
|
---|
507 |
|
---|
508 | The predicate structure is updated with the new information. */
|
---|
509 |
|
---|
510 | static boolean
|
---|
511 | parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
512 | {
|
---|
513 | struct predicate *our_pred;
|
---|
514 | uintmax_t num;
|
---|
515 | enum comparison_type c_type;
|
---|
516 | time_t t;
|
---|
517 |
|
---|
518 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
519 | return false;
|
---|
520 | if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
---|
521 | return false;
|
---|
522 | t = options.cur_day_start + DAYSECS - num * 60;
|
---|
523 | our_pred = insert_primary (entry);
|
---|
524 | our_pred->args.info.kind = c_type;
|
---|
525 | our_pred->args.info.negative = t < 0;
|
---|
526 | our_pred->args.info.l_val = t;
|
---|
527 | our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
---|
528 | (*arg_ptr)++;
|
---|
529 | return true;
|
---|
530 | }
|
---|
531 |
|
---|
532 | static boolean
|
---|
533 | parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
534 | {
|
---|
535 | struct predicate *our_pred;
|
---|
536 |
|
---|
537 | (void) argv;
|
---|
538 | (void) arg_ptr;
|
---|
539 |
|
---|
540 | our_pred = get_new_pred (entry);
|
---|
541 | our_pred->pred_func = pred_and;
|
---|
542 | our_pred->p_type = BI_OP;
|
---|
543 | our_pred->p_prec = AND_PREC;
|
---|
544 | our_pred->need_stat = our_pred->need_type = false;
|
---|
545 | return true;
|
---|
546 | }
|
---|
547 |
|
---|
548 | static boolean
|
---|
549 | parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
550 | {
|
---|
551 | struct predicate *our_pred;
|
---|
552 | struct stat stat_newer;
|
---|
553 |
|
---|
554 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
555 | return false;
|
---|
556 | if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
---|
557 | error (1, errno, "%s", argv[*arg_ptr]);
|
---|
558 | our_pred = insert_primary (entry);
|
---|
559 | our_pred->args.time = stat_newer.st_mtime;
|
---|
560 | our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
---|
561 | (*arg_ptr)++;
|
---|
562 | return true;
|
---|
563 | }
|
---|
564 |
|
---|
565 | boolean
|
---|
566 | parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
567 | {
|
---|
568 | struct predicate *our_pred;
|
---|
569 |
|
---|
570 | (void) argv;
|
---|
571 | (void) arg_ptr;
|
---|
572 |
|
---|
573 | our_pred = get_new_pred (entry);
|
---|
574 | our_pred->pred_func = pred_close;
|
---|
575 | our_pred->p_type = CLOSE_PAREN;
|
---|
576 | our_pred->p_prec = NO_PREC;
|
---|
577 | our_pred->need_stat = our_pred->need_type = false;
|
---|
578 | return true;
|
---|
579 | }
|
---|
580 |
|
---|
581 | static boolean
|
---|
582 | parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
583 | {
|
---|
584 | struct predicate *our_pred;
|
---|
585 | uintmax_t num;
|
---|
586 | enum comparison_type c_type;
|
---|
587 | time_t t;
|
---|
588 |
|
---|
589 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
590 | return false;
|
---|
591 | if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
---|
592 | return false;
|
---|
593 | t = options.cur_day_start + DAYSECS - num * 60;
|
---|
594 | our_pred = insert_primary (entry);
|
---|
595 | our_pred->args.info.kind = c_type;
|
---|
596 | our_pred->args.info.negative = t < 0;
|
---|
597 | our_pred->args.info.l_val = t;
|
---|
598 | our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
---|
599 | (*arg_ptr)++;
|
---|
600 | return true;
|
---|
601 | }
|
---|
602 |
|
---|
603 | static boolean
|
---|
604 | parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
605 | {
|
---|
606 | struct predicate *our_pred;
|
---|
607 | struct stat stat_newer;
|
---|
608 |
|
---|
609 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
610 | return false;
|
---|
611 | if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
---|
612 | error (1, errno, "%s", argv[*arg_ptr]);
|
---|
613 | our_pred = insert_primary (entry);
|
---|
614 | our_pred->args.time = stat_newer.st_mtime;
|
---|
615 | our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
---|
616 | (*arg_ptr)++;
|
---|
617 | return true;
|
---|
618 | }
|
---|
619 |
|
---|
620 | static boolean
|
---|
621 | parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
622 | {
|
---|
623 | struct predicate *our_pred;
|
---|
624 |
|
---|
625 | (void) argv;
|
---|
626 | (void) arg_ptr;
|
---|
627 |
|
---|
628 | our_pred = get_new_pred (entry);
|
---|
629 | our_pred->pred_func = pred_comma;
|
---|
630 | our_pred->p_type = BI_OP;
|
---|
631 | our_pred->p_prec = COMMA_PREC;
|
---|
632 | our_pred->need_stat = our_pred->need_type = false;
|
---|
633 | our_pred->est_success_rate = 1.0f;
|
---|
634 | return true;
|
---|
635 | }
|
---|
636 |
|
---|
637 | static boolean
|
---|
638 | parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
639 | {
|
---|
640 | struct tm *local;
|
---|
641 |
|
---|
642 | (void) entry;
|
---|
643 | (void) argv;
|
---|
644 | (void) arg_ptr;
|
---|
645 |
|
---|
646 | if (options.full_days == false)
|
---|
647 | {
|
---|
648 | options.cur_day_start += DAYSECS;
|
---|
649 | local = localtime (&options.cur_day_start);
|
---|
650 | options.cur_day_start -= (local
|
---|
651 | ? (local->tm_sec + local->tm_min * 60
|
---|
652 | + local->tm_hour * 3600)
|
---|
653 | : options.cur_day_start % DAYSECS);
|
---|
654 | options.full_days = true;
|
---|
655 | }
|
---|
656 | return true;
|
---|
657 | }
|
---|
658 |
|
---|
659 | static boolean
|
---|
660 | parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
|
---|
661 | {
|
---|
662 | struct predicate *our_pred;
|
---|
663 | (void) argv;
|
---|
664 | (void) arg_ptr;
|
---|
665 |
|
---|
666 | our_pred = insert_primary (entry);
|
---|
667 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
668 | /* -delete implies -depth */
|
---|
669 | options.do_dir_first = false;
|
---|
670 | our_pred->est_success_rate = 1.0f;
|
---|
671 | return true;
|
---|
672 | }
|
---|
673 |
|
---|
674 | static boolean
|
---|
675 | parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
676 | {
|
---|
677 | (void) entry;
|
---|
678 | (void) argv;
|
---|
679 | (void) arg_ptr;
|
---|
680 |
|
---|
681 | options.do_dir_first = false;
|
---|
682 | return parse_noop(entry, argv, arg_ptr);
|
---|
683 | }
|
---|
684 |
|
---|
685 | static boolean
|
---|
686 | parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
687 | {
|
---|
688 | (void) argv;
|
---|
689 | (void) arg_ptr;
|
---|
690 |
|
---|
691 | if (options.warnings)
|
---|
692 | {
|
---|
693 | error (0, 0,
|
---|
694 | _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
|
---|
695 | }
|
---|
696 | return parse_depth(entry, argv, arg_ptr);
|
---|
697 | }
|
---|
698 |
|
---|
699 | static boolean
|
---|
700 | parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
701 | {
|
---|
702 | struct predicate *our_pred;
|
---|
703 | (void) argv;
|
---|
704 | (void) arg_ptr;
|
---|
705 |
|
---|
706 | our_pred = insert_primary (entry);
|
---|
707 | our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
|
---|
708 | return true;
|
---|
709 | }
|
---|
710 |
|
---|
711 | static boolean
|
---|
712 | parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
713 | {
|
---|
714 | return insert_exec_ok ("-exec", entry, argv, arg_ptr);
|
---|
715 | }
|
---|
716 |
|
---|
717 | static boolean
|
---|
718 | parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
719 | {
|
---|
720 | return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
|
---|
721 | }
|
---|
722 |
|
---|
723 | static boolean
|
---|
724 | parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
725 | {
|
---|
726 | struct predicate *our_pred;
|
---|
727 |
|
---|
728 | (void) argv;
|
---|
729 | (void) arg_ptr;
|
---|
730 |
|
---|
731 | our_pred = insert_primary (entry);
|
---|
732 | our_pred->need_stat = our_pred->need_type = false;
|
---|
733 | our_pred->side_effects = our_pred->no_default_print = false;
|
---|
734 | our_pred->est_success_rate = 0.0f;
|
---|
735 | return true;
|
---|
736 | }
|
---|
737 |
|
---|
738 | static boolean
|
---|
739 | parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
740 | {
|
---|
741 | struct predicate *our_pred;
|
---|
742 |
|
---|
743 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
744 | return false;
|
---|
745 | our_pred = insert_primary (entry);
|
---|
746 | our_pred->args.stream = open_output_file (argv[*arg_ptr]);
|
---|
747 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
748 | our_pred->est_success_rate = 1.0f;
|
---|
749 | (*arg_ptr)++;
|
---|
750 | return true;
|
---|
751 | }
|
---|
752 |
|
---|
753 | static boolean
|
---|
754 | parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
755 | {
|
---|
756 | FILE *fp;
|
---|
757 |
|
---|
758 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
759 | return false;
|
---|
760 | if (argv[*arg_ptr + 1] == NULL)
|
---|
761 | {
|
---|
762 | /* Ensure we get "missing arg" message, not "invalid arg". */
|
---|
763 | (*arg_ptr)++;
|
---|
764 | return false;
|
---|
765 | }
|
---|
766 | fp = open_output_file (argv[*arg_ptr]);
|
---|
767 | (*arg_ptr)++;
|
---|
768 | return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr);
|
---|
769 | }
|
---|
770 |
|
---|
771 | static boolean
|
---|
772 | parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
773 | {
|
---|
774 | (void) entry;
|
---|
775 | (void) argv;
|
---|
776 | (void) arg_ptr;
|
---|
777 |
|
---|
778 | set_follow_state(SYMLINK_ALWAYS_DEREF);
|
---|
779 | return parse_noop(entry, argv, arg_ptr);
|
---|
780 | }
|
---|
781 |
|
---|
782 | static boolean
|
---|
783 | parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
784 | {
|
---|
785 | struct predicate *our_pred;
|
---|
786 |
|
---|
787 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
788 | return false;
|
---|
789 | our_pred = insert_primary (entry);
|
---|
790 | our_pred->args.printf_vec.segment = NULL;
|
---|
791 | our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
|
---|
792 | our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
|
---|
793 | our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
|
---|
794 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
795 | our_pred->need_stat = our_pred->need_type = false;
|
---|
796 | our_pred->est_success_rate = 1.0f;
|
---|
797 | (*arg_ptr)++;
|
---|
798 | return true;
|
---|
799 | }
|
---|
800 |
|
---|
801 | static boolean
|
---|
802 | parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
803 | {
|
---|
804 | struct predicate *our_pred;
|
---|
805 |
|
---|
806 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
807 | return false;
|
---|
808 | our_pred = insert_primary (entry);
|
---|
809 | our_pred->args.stream = open_output_file (argv[*arg_ptr]);
|
---|
810 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
811 | our_pred->need_stat = our_pred->need_type = false;
|
---|
812 | our_pred->est_success_rate = 1.0f;
|
---|
813 | (*arg_ptr)++;
|
---|
814 | return true;
|
---|
815 | }
|
---|
816 |
|
---|
817 | static float estimate_fstype_success_rate(const char *fsname)
|
---|
818 | {
|
---|
819 | struct stat dir_stat;
|
---|
820 | const char *dir = "/";
|
---|
821 | if (0 == stat(dir, &dir_stat))
|
---|
822 | {
|
---|
823 | const char *fstype = filesystem_type(&dir_stat, dir);
|
---|
824 | /* Assume most files are on the same filesystem type as the root fs. */
|
---|
825 | if (0 == strcmp(fsname, fstype))
|
---|
826 | return 0.7f;
|
---|
827 | else
|
---|
828 | return 0.3f;
|
---|
829 | }
|
---|
830 | return 1.0f;
|
---|
831 | }
|
---|
832 |
|
---|
833 |
|
---|
834 | static boolean
|
---|
835 | parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
836 | {
|
---|
837 | struct predicate *our_pred;
|
---|
838 |
|
---|
839 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
840 | return false;
|
---|
841 | our_pred = insert_primary (entry);
|
---|
842 | our_pred->args.str = argv[*arg_ptr];
|
---|
843 |
|
---|
844 | /* This is an expensive operation, so although there are
|
---|
845 | * circumstances where it is selective, we ignore this fact because
|
---|
846 | * we probably don't want to promote this test to the front anyway.
|
---|
847 | */
|
---|
848 | our_pred->est_success_rate = estimate_fstype_success_rate(argv[*arg_ptr]);
|
---|
849 | (*arg_ptr)++;
|
---|
850 | return true;
|
---|
851 | }
|
---|
852 |
|
---|
853 | static boolean
|
---|
854 | parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
855 | {
|
---|
856 | struct predicate *p = insert_num (argv, arg_ptr, entry);
|
---|
857 | p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
|
---|
858 | return p;
|
---|
859 | }
|
---|
860 |
|
---|
861 | static boolean
|
---|
862 | parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
863 | {
|
---|
864 | struct group *cur_gr;
|
---|
865 | struct predicate *our_pred;
|
---|
866 | gid_t gid;
|
---|
867 | int gid_len;
|
---|
868 |
|
---|
869 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
870 | return false;
|
---|
871 | cur_gr = getgrnam (argv[*arg_ptr]);
|
---|
872 | endgrent ();
|
---|
873 | if (cur_gr != NULL)
|
---|
874 | gid = cur_gr->gr_gid;
|
---|
875 | else
|
---|
876 | {
|
---|
877 | gid_len = strspn (argv[*arg_ptr], "0123456789");
|
---|
878 | if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
|
---|
879 | return false;
|
---|
880 | gid = atoi (argv[*arg_ptr]);
|
---|
881 | }
|
---|
882 | our_pred = insert_primary (entry);
|
---|
883 | our_pred->args.gid = gid;
|
---|
884 | our_pred->est_success_rate = (our_pred->args.info.l_val < 100) ? 0.99 : 0.2;
|
---|
885 | (*arg_ptr)++;
|
---|
886 | return true;
|
---|
887 | }
|
---|
888 |
|
---|
889 | static boolean
|
---|
890 | parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
891 | {
|
---|
892 | (void) entry;
|
---|
893 | (void) argv;
|
---|
894 | (void) arg_ptr;
|
---|
895 |
|
---|
896 | usage(stdout, 0, NULL);
|
---|
897 | puts (_("\n\
|
---|
898 | default path is the current directory; default expression is -print\n\
|
---|
899 | expression may consist of: operators, options, tests, and actions:\n"));
|
---|
900 | puts (_("\
|
---|
901 | operators (decreasing precedence; -and is implicit where no others are given):\n\
|
---|
902 | ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
|
---|
903 | EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
|
---|
904 | puts (_("\
|
---|
905 | positional options (always true): -daystart -follow -regextype\n\n\
|
---|
906 | normal options (always true, specified before other expressions):\n\
|
---|
907 | -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
|
---|
908 | --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
|
---|
909 | puts (_("\
|
---|
910 | tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
|
---|
911 | -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
|
---|
912 | -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
|
---|
913 | -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
|
---|
914 | puts (_("\
|
---|
915 | -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
|
---|
916 | -readable -writable -executable\n\
|
---|
917 | -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
|
---|
918 | -used N -user NAME -xtype [bcdpfls]\n"));
|
---|
919 | puts (_("\
|
---|
920 | actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
|
---|
921 | -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
|
---|
922 | -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
|
---|
923 | -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
|
---|
924 | "));
|
---|
925 | puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
|
---|
926 | page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
|
---|
927 | email to <bug-findutils@gnu.org>."));
|
---|
928 | exit (0);
|
---|
929 | }
|
---|
930 |
|
---|
931 | static float estimate_pattern_match_rate(const char *pattern, int is_regex)
|
---|
932 | {
|
---|
933 | if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
|
---|
934 | {
|
---|
935 | /* A wildcard; assume the pattern matches most files. */
|
---|
936 | return 0.8f;
|
---|
937 | }
|
---|
938 | else
|
---|
939 | {
|
---|
940 | return 0.1f;
|
---|
941 | }
|
---|
942 | }
|
---|
943 |
|
---|
944 | static boolean
|
---|
945 | parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
946 | {
|
---|
947 | struct predicate *our_pred;
|
---|
948 |
|
---|
949 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
950 | return false;
|
---|
951 | our_pred = insert_primary (entry);
|
---|
952 | our_pred->args.str = argv[*arg_ptr];
|
---|
953 | /* Use the generic glob pattern estimator to figure out how many
|
---|
954 | * links will match, but bear in mind that most files won't be links.
|
---|
955 | */
|
---|
956 | our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
957 | (*arg_ptr)++;
|
---|
958 | return true;
|
---|
959 | }
|
---|
960 |
|
---|
961 |
|
---|
962 | /* sanity check the fnmatch() function to make sure
|
---|
963 | * it really is the GNU version.
|
---|
964 | */
|
---|
965 | static boolean
|
---|
966 | fnmatch_sanitycheck(void)
|
---|
967 | {
|
---|
968 | /* fprintf(stderr, "Performing find sanity check..."); */
|
---|
969 | if (0 != fnmatch("foo", "foo", 0)
|
---|
970 | || 0 == fnmatch("Foo", "foo", 0)
|
---|
971 | || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
|
---|
972 | {
|
---|
973 | error (1, 0, _("sanity check of the fnmatch() library function failed."));
|
---|
974 | /* fprintf(stderr, "FAILED\n"); */
|
---|
975 | return false;
|
---|
976 | }
|
---|
977 |
|
---|
978 | /* fprintf(stderr, "OK\n"); */
|
---|
979 | return true;
|
---|
980 | }
|
---|
981 |
|
---|
982 |
|
---|
983 | static boolean
|
---|
984 | check_name_arg(const char *pred, const char *arg)
|
---|
985 | {
|
---|
986 | if (strchr(arg, '/'))
|
---|
987 | {
|
---|
988 | 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'."),
|
---|
989 | pred, arg, arg);
|
---|
990 | }
|
---|
991 | return true; /* allow it anyway */
|
---|
992 | }
|
---|
993 |
|
---|
994 |
|
---|
995 |
|
---|
996 | static boolean
|
---|
997 | parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
998 | {
|
---|
999 | struct predicate *our_pred;
|
---|
1000 |
|
---|
1001 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1002 | return false;
|
---|
1003 | if (!check_name_arg("-iname", argv[*arg_ptr]))
|
---|
1004 | return false;
|
---|
1005 |
|
---|
1006 | fnmatch_sanitycheck();
|
---|
1007 |
|
---|
1008 | our_pred = insert_primary (entry);
|
---|
1009 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1010 | our_pred->args.str = argv[*arg_ptr];
|
---|
1011 | our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
1012 | (*arg_ptr)++;
|
---|
1013 | return true;
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | static boolean
|
---|
1017 | parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1018 | {
|
---|
1019 | struct predicate *p = insert_num (argv, arg_ptr, entry);
|
---|
1020 | /* inode number is exact match only, so very low proportions of files match */
|
---|
1021 | p->est_success_rate = 1e-6;
|
---|
1022 | return p;
|
---|
1023 | }
|
---|
1024 |
|
---|
1025 | /* -ipath is deprecated (at RMS's request) in favour of
|
---|
1026 | * -iwholename. See the node "GNU Manuals" in standards.texi
|
---|
1027 | * for the rationale for this (basically, GNU prefers the use
|
---|
1028 | * of the phrase "file name" to "path name"
|
---|
1029 | */
|
---|
1030 | static boolean
|
---|
1031 | parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1032 | {
|
---|
1033 | error (0, 0,
|
---|
1034 | _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
|
---|
1035 |
|
---|
1036 | return parse_iwholename(entry, argv, arg_ptr);
|
---|
1037 | }
|
---|
1038 |
|
---|
1039 | static boolean
|
---|
1040 | parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1041 | {
|
---|
1042 | struct predicate *our_pred;
|
---|
1043 |
|
---|
1044 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1045 | return false;
|
---|
1046 |
|
---|
1047 | fnmatch_sanitycheck();
|
---|
1048 |
|
---|
1049 | our_pred = insert_primary_withpred (entry, pred_ipath);
|
---|
1050 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1051 | our_pred->args.str = argv[*arg_ptr];
|
---|
1052 | our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
1053 | (*arg_ptr)++;
|
---|
1054 | return true;
|
---|
1055 | }
|
---|
1056 |
|
---|
1057 | static boolean
|
---|
1058 | parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1059 | {
|
---|
1060 | return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
|
---|
1061 | }
|
---|
1062 |
|
---|
1063 | static boolean
|
---|
1064 | parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1065 | {
|
---|
1066 | struct predicate *p = insert_num (argv, arg_ptr, entry);
|
---|
1067 | if (p->args.info.l_val == 1)
|
---|
1068 | p->est_success_rate = 0.99;
|
---|
1069 | else if (p->args.info.l_val == 2)
|
---|
1070 | p->est_success_rate = 0.01;
|
---|
1071 | else
|
---|
1072 | p->est_success_rate = 1e-3;
|
---|
1073 | return p;
|
---|
1074 | }
|
---|
1075 |
|
---|
1076 | static boolean
|
---|
1077 | parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1078 | {
|
---|
1079 | struct predicate *our_pred;
|
---|
1080 |
|
---|
1081 | (void) argv;
|
---|
1082 | (void) arg_ptr;
|
---|
1083 |
|
---|
1084 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1085 | return false;
|
---|
1086 |
|
---|
1087 | fnmatch_sanitycheck();
|
---|
1088 |
|
---|
1089 | our_pred = insert_primary (entry);
|
---|
1090 | our_pred->args.str = argv[*arg_ptr];
|
---|
1091 | our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
1092 | (*arg_ptr)++;
|
---|
1093 | return true;
|
---|
1094 | }
|
---|
1095 |
|
---|
1096 | static boolean
|
---|
1097 | parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1098 | {
|
---|
1099 | struct predicate *our_pred;
|
---|
1100 |
|
---|
1101 | (void) &argv;
|
---|
1102 | (void) &arg_ptr;
|
---|
1103 |
|
---|
1104 | our_pred = insert_primary (entry);
|
---|
1105 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
1106 | return true;
|
---|
1107 | }
|
---|
1108 |
|
---|
1109 | static boolean
|
---|
1110 | parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1111 | {
|
---|
1112 | int depth_len;
|
---|
1113 | (void) entry;
|
---|
1114 |
|
---|
1115 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1116 | return false;
|
---|
1117 | depth_len = strspn (argv[*arg_ptr], "0123456789");
|
---|
1118 | if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
|
---|
1119 | return false;
|
---|
1120 | options.maxdepth = atoi (argv[*arg_ptr]);
|
---|
1121 | if (options.maxdepth < 0)
|
---|
1122 | return false;
|
---|
1123 | (*arg_ptr)++;
|
---|
1124 | return parse_noop(entry, argv, arg_ptr);
|
---|
1125 | }
|
---|
1126 |
|
---|
1127 | static boolean
|
---|
1128 | parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1129 | {
|
---|
1130 | int depth_len;
|
---|
1131 | (void) entry;
|
---|
1132 |
|
---|
1133 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1134 | return false;
|
---|
1135 | depth_len = strspn (argv[*arg_ptr], "0123456789");
|
---|
1136 | if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
|
---|
1137 | return false;
|
---|
1138 | options.mindepth = atoi (argv[*arg_ptr]);
|
---|
1139 | if (options.mindepth < 0)
|
---|
1140 | return false;
|
---|
1141 | (*arg_ptr)++;
|
---|
1142 | return parse_noop(entry, argv, arg_ptr);
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | static boolean
|
---|
1146 | parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1147 | {
|
---|
1148 | struct predicate *our_pred;
|
---|
1149 | uintmax_t num;
|
---|
1150 | enum comparison_type c_type;
|
---|
1151 | time_t t;
|
---|
1152 |
|
---|
1153 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1154 | return false;
|
---|
1155 | if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
---|
1156 | return false;
|
---|
1157 | t = options.cur_day_start + DAYSECS - num * 60;
|
---|
1158 | our_pred = insert_primary (entry);
|
---|
1159 | our_pred->args.info.kind = c_type;
|
---|
1160 | our_pred->args.info.negative = t < 0;
|
---|
1161 | our_pred->args.info.l_val = t;
|
---|
1162 | our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
---|
1163 | (*arg_ptr)++;
|
---|
1164 | return true;
|
---|
1165 | }
|
---|
1166 |
|
---|
1167 | static boolean
|
---|
1168 | parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1169 | {
|
---|
1170 | struct predicate *our_pred;
|
---|
1171 |
|
---|
1172 | (void) argv;
|
---|
1173 | (void) arg_ptr;
|
---|
1174 |
|
---|
1175 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1176 | return false;
|
---|
1177 | if (!check_name_arg("-name", argv[*arg_ptr]))
|
---|
1178 | return false;
|
---|
1179 | fnmatch_sanitycheck();
|
---|
1180 |
|
---|
1181 | our_pred = insert_primary (entry);
|
---|
1182 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1183 | our_pred->args.str = argv[*arg_ptr];
|
---|
1184 | our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
1185 | (*arg_ptr)++;
|
---|
1186 | return true;
|
---|
1187 | }
|
---|
1188 |
|
---|
1189 | static boolean
|
---|
1190 | parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1191 | {
|
---|
1192 | struct predicate *our_pred;
|
---|
1193 |
|
---|
1194 | (void) &argv;
|
---|
1195 | (void) &arg_ptr;
|
---|
1196 |
|
---|
1197 | our_pred = get_new_pred_chk_op (entry);
|
---|
1198 | our_pred->pred_func = pred_negate;
|
---|
1199 | our_pred->p_type = UNI_OP;
|
---|
1200 | our_pred->p_prec = NEGATE_PREC;
|
---|
1201 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1202 | return true;
|
---|
1203 | }
|
---|
1204 |
|
---|
1205 | static boolean
|
---|
1206 | parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1207 | {
|
---|
1208 | struct predicate *our_pred;
|
---|
1209 | struct stat stat_newer;
|
---|
1210 |
|
---|
1211 | (void) argv;
|
---|
1212 | (void) arg_ptr;
|
---|
1213 |
|
---|
1214 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1215 | return false;
|
---|
1216 | if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
---|
1217 | error (1, errno, "%s", argv[*arg_ptr]);
|
---|
1218 | our_pred = insert_primary (entry);
|
---|
1219 | our_pred->args.time = stat_newer.st_mtime;
|
---|
1220 | our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
---|
1221 | (*arg_ptr)++;
|
---|
1222 | return true;
|
---|
1223 | }
|
---|
1224 |
|
---|
1225 | static boolean
|
---|
1226 | parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1227 | {
|
---|
1228 | (void) &argv;
|
---|
1229 | (void) &arg_ptr;
|
---|
1230 | (void) entry;
|
---|
1231 |
|
---|
1232 | options.no_leaf_check = true;
|
---|
1233 | return parse_noop(entry, argv, arg_ptr);
|
---|
1234 | }
|
---|
1235 |
|
---|
1236 | #ifdef CACHE_IDS
|
---|
1237 | /* Arbitrary amount by which to increase size
|
---|
1238 | of `uid_unused' and `gid_unused'. */
|
---|
1239 | #define ALLOC_STEP 2048
|
---|
1240 |
|
---|
1241 | /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
|
---|
1242 | char *uid_unused = NULL;
|
---|
1243 |
|
---|
1244 | /* Number of elements in `uid_unused'. */
|
---|
1245 | unsigned uid_allocated;
|
---|
1246 |
|
---|
1247 | /* Similar for GIDs and group entries. */
|
---|
1248 | char *gid_unused = NULL;
|
---|
1249 | unsigned gid_allocated;
|
---|
1250 | #endif
|
---|
1251 |
|
---|
1252 | static boolean
|
---|
1253 | parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1254 | {
|
---|
1255 | struct predicate *our_pred;
|
---|
1256 |
|
---|
1257 | (void) &argv;
|
---|
1258 | (void) &arg_ptr;
|
---|
1259 |
|
---|
1260 | our_pred = insert_primary (entry);
|
---|
1261 | our_pred->est_success_rate = 1e-4;
|
---|
1262 | #ifdef CACHE_IDS
|
---|
1263 | if (gid_unused == NULL)
|
---|
1264 | {
|
---|
1265 | struct group *gr;
|
---|
1266 |
|
---|
1267 | gid_allocated = ALLOC_STEP;
|
---|
1268 | gid_unused = xmalloc (gid_allocated);
|
---|
1269 | memset (gid_unused, 1, gid_allocated);
|
---|
1270 | setgrent ();
|
---|
1271 | while ((gr = getgrent ()) != NULL)
|
---|
1272 | {
|
---|
1273 | if ((unsigned) gr->gr_gid >= gid_allocated)
|
---|
1274 | {
|
---|
1275 | unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
|
---|
1276 | gid_unused = xrealloc (gid_unused, new_allocated);
|
---|
1277 | memset (gid_unused + gid_allocated, 1,
|
---|
1278 | new_allocated - gid_allocated);
|
---|
1279 | gid_allocated = new_allocated;
|
---|
1280 | }
|
---|
1281 | gid_unused[(unsigned) gr->gr_gid] = 0;
|
---|
1282 | }
|
---|
1283 | endgrent ();
|
---|
1284 | }
|
---|
1285 | #endif
|
---|
1286 | return true;
|
---|
1287 | }
|
---|
1288 |
|
---|
1289 | static boolean
|
---|
1290 | parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1291 | {
|
---|
1292 | struct predicate *our_pred;
|
---|
1293 | (void) argv;
|
---|
1294 | (void) arg_ptr;
|
---|
1295 |
|
---|
1296 |
|
---|
1297 | our_pred = insert_primary (entry);
|
---|
1298 | our_pred->est_success_rate = 1e-3;
|
---|
1299 | #ifdef CACHE_IDS
|
---|
1300 | if (uid_unused == NULL)
|
---|
1301 | {
|
---|
1302 | struct passwd *pw;
|
---|
1303 |
|
---|
1304 | uid_allocated = ALLOC_STEP;
|
---|
1305 | uid_unused = xmalloc (uid_allocated);
|
---|
1306 | memset (uid_unused, 1, uid_allocated);
|
---|
1307 | setpwent ();
|
---|
1308 | while ((pw = getpwent ()) != NULL)
|
---|
1309 | {
|
---|
1310 | if ((unsigned) pw->pw_uid >= uid_allocated)
|
---|
1311 | {
|
---|
1312 | unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
|
---|
1313 | uid_unused = xrealloc (uid_unused, new_allocated);
|
---|
1314 | memset (uid_unused + uid_allocated, 1,
|
---|
1315 | new_allocated - uid_allocated);
|
---|
1316 | uid_allocated = new_allocated;
|
---|
1317 | }
|
---|
1318 | uid_unused[(unsigned) pw->pw_uid] = 0;
|
---|
1319 | }
|
---|
1320 | endpwent ();
|
---|
1321 | }
|
---|
1322 | #endif
|
---|
1323 | return true;
|
---|
1324 | }
|
---|
1325 |
|
---|
1326 | static boolean
|
---|
1327 | parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1328 | {
|
---|
1329 | (void) argv;
|
---|
1330 | (void) arg_ptr;
|
---|
1331 | (void) entry;
|
---|
1332 |
|
---|
1333 | options.warnings = false;
|
---|
1334 | return parse_noop(entry, argv, arg_ptr);
|
---|
1335 | }
|
---|
1336 |
|
---|
1337 | static boolean
|
---|
1338 | parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1339 | {
|
---|
1340 | return insert_exec_ok ("-ok", entry, argv, arg_ptr);
|
---|
1341 | }
|
---|
1342 |
|
---|
1343 | static boolean
|
---|
1344 | parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1345 | {
|
---|
1346 | return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
|
---|
1347 | }
|
---|
1348 |
|
---|
1349 | boolean
|
---|
1350 | parse_open (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1351 | {
|
---|
1352 | struct predicate *our_pred;
|
---|
1353 |
|
---|
1354 | (void) argv;
|
---|
1355 | (void) arg_ptr;
|
---|
1356 |
|
---|
1357 | our_pred = get_new_pred_chk_op (entry);
|
---|
1358 | our_pred->pred_func = pred_open;
|
---|
1359 | our_pred->p_type = OPEN_PAREN;
|
---|
1360 | our_pred->p_prec = NO_PREC;
|
---|
1361 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1362 | return true;
|
---|
1363 | }
|
---|
1364 |
|
---|
1365 | static boolean
|
---|
1366 | parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1367 | {
|
---|
1368 | struct predicate *our_pred;
|
---|
1369 |
|
---|
1370 | (void) argv;
|
---|
1371 | (void) arg_ptr;
|
---|
1372 |
|
---|
1373 | our_pred = get_new_pred (entry);
|
---|
1374 | our_pred->pred_func = pred_or;
|
---|
1375 | our_pred->p_type = BI_OP;
|
---|
1376 | our_pred->p_prec = OR_PREC;
|
---|
1377 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1378 | return true;
|
---|
1379 | }
|
---|
1380 |
|
---|
1381 | /* -path is deprecated (at RMS's request) in favour of
|
---|
1382 | * -iwholename. See the node "GNU Manuals" in standards.texi
|
---|
1383 | * for the rationale for this (basically, GNU prefers the use
|
---|
1384 | * of the phrase "file name" to "path name".
|
---|
1385 | *
|
---|
1386 | * We do not issue a warning that this usage is deprecated
|
---|
1387 | * since HPUX find supports this predicate also.
|
---|
1388 | */
|
---|
1389 | static boolean
|
---|
1390 | parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1391 | {
|
---|
1392 | return parse_wholename(entry, argv, arg_ptr);
|
---|
1393 | }
|
---|
1394 |
|
---|
1395 | static boolean
|
---|
1396 | parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1397 | {
|
---|
1398 | struct predicate *our_pred;
|
---|
1399 |
|
---|
1400 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1401 | return false;
|
---|
1402 | our_pred = insert_primary_withpred (entry, pred_path);
|
---|
1403 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1404 | our_pred->args.str = argv[*arg_ptr];
|
---|
1405 | our_pred->est_success_rate = estimate_pattern_match_rate(our_pred->args.str, 0);
|
---|
1406 | (*arg_ptr)++;
|
---|
1407 | return true;
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | static boolean
|
---|
1411 | parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1412 | {
|
---|
1413 | mode_t perm_val[2];
|
---|
1414 | float rate;
|
---|
1415 | int mode_start = 0;
|
---|
1416 | boolean havekind = false;
|
---|
1417 | enum permissions_type kind = PERM_EXACT;
|
---|
1418 | struct mode_change *change = NULL;
|
---|
1419 | struct predicate *our_pred;
|
---|
1420 |
|
---|
1421 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1422 | return false;
|
---|
1423 |
|
---|
1424 | switch (argv[*arg_ptr][0])
|
---|
1425 | {
|
---|
1426 | case '-':
|
---|
1427 | mode_start = 1;
|
---|
1428 | kind = PERM_AT_LEAST;
|
---|
1429 | havekind = true;
|
---|
1430 | rate = 0.2;
|
---|
1431 | break;
|
---|
1432 |
|
---|
1433 | case '+':
|
---|
1434 | change = mode_compile (argv[*arg_ptr]);
|
---|
1435 | if (NULL == change)
|
---|
1436 | {
|
---|
1437 | /* Most likely the caller is an old script that is still
|
---|
1438 | * using the obsolete GNU syntax '-perm +MODE'. This old
|
---|
1439 | * syntax was withdrawn in favor of '-perm /MODE' because
|
---|
1440 | * it is incompatible with POSIX in some cases, but we
|
---|
1441 | * still support uses of it that are not incompatible with
|
---|
1442 | * POSIX.
|
---|
1443 | */
|
---|
1444 | mode_start = 1;
|
---|
1445 | kind = PERM_ANY;
|
---|
1446 | rate = 0.3;
|
---|
1447 | }
|
---|
1448 | else
|
---|
1449 | {
|
---|
1450 | /* This is a POSIX-compatible usage */
|
---|
1451 | mode_start = 0;
|
---|
1452 | kind = PERM_EXACT;
|
---|
1453 | rate = 0.1;
|
---|
1454 | }
|
---|
1455 | havekind = true;
|
---|
1456 | break;
|
---|
1457 |
|
---|
1458 | case '/': /* GNU extension */
|
---|
1459 | mode_start = 1;
|
---|
1460 | kind = PERM_ANY;
|
---|
1461 | havekind = true;
|
---|
1462 | rate = 0.3;
|
---|
1463 | break;
|
---|
1464 |
|
---|
1465 | default:
|
---|
1466 | /* For example, '-perm 0644', which is valid and matches
|
---|
1467 | * only files whose mode is exactly 0644.
|
---|
1468 | *
|
---|
1469 | * We do nothing here, because mode_start and kind are already
|
---|
1470 | * correctly set.
|
---|
1471 | */
|
---|
1472 | rate = 0.01;
|
---|
1473 | break;
|
---|
1474 | }
|
---|
1475 |
|
---|
1476 | if (NULL == change)
|
---|
1477 | {
|
---|
1478 | change = mode_compile (argv[*arg_ptr] + mode_start);
|
---|
1479 | if (NULL == change)
|
---|
1480 | error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
|
---|
1481 | }
|
---|
1482 | perm_val[0] = mode_adjust (0, false, 0, change, NULL);
|
---|
1483 | perm_val[1] = mode_adjust (0, true, 0, change, NULL);
|
---|
1484 | free (change);
|
---|
1485 |
|
---|
1486 | our_pred = insert_primary (entry);
|
---|
1487 | our_pred->est_success_rate = rate;
|
---|
1488 | if (havekind)
|
---|
1489 | {
|
---|
1490 | our_pred->args.perm.kind = kind;
|
---|
1491 | }
|
---|
1492 | else
|
---|
1493 | {
|
---|
1494 |
|
---|
1495 | switch (argv[*arg_ptr][0])
|
---|
1496 | {
|
---|
1497 | case '-':
|
---|
1498 | our_pred->args.perm.kind = PERM_AT_LEAST;
|
---|
1499 | break;
|
---|
1500 | case '+':
|
---|
1501 | our_pred->args.perm.kind = PERM_ANY;
|
---|
1502 | break;
|
---|
1503 | default:
|
---|
1504 | our_pred->args.perm.kind = PERM_EXACT;
|
---|
1505 | break;
|
---|
1506 | }
|
---|
1507 | }
|
---|
1508 | if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
|
---|
1509 | {
|
---|
1510 | /* The meaning of -perm /000 will change in the future.
|
---|
1511 | * It currently matches no files, but like -perm -000 it
|
---|
1512 | * should match all files.
|
---|
1513 | */
|
---|
1514 | error (0, 0,
|
---|
1515 | _("warning: you have specified a mode pattern %s which is "
|
---|
1516 | "equivalent to 000. The meaning of -perm /000 will soon be "
|
---|
1517 | "changed to be consistent with -perm -000; that is, at the "
|
---|
1518 | "moment it matches no files but it will soon be changed to "
|
---|
1519 | "match all files."),
|
---|
1520 | argv[*arg_ptr]);
|
---|
1521 | }
|
---|
1522 |
|
---|
1523 | memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
|
---|
1524 | (*arg_ptr)++;
|
---|
1525 | return true;
|
---|
1526 | }
|
---|
1527 |
|
---|
1528 | boolean
|
---|
1529 | parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1530 | {
|
---|
1531 | struct predicate *our_pred;
|
---|
1532 |
|
---|
1533 | (void) argv;
|
---|
1534 | (void) arg_ptr;
|
---|
1535 |
|
---|
1536 | our_pred = insert_primary (entry);
|
---|
1537 | /* -print has the side effect of printing. This prevents us
|
---|
1538 | from doing undesired multiple printing when the user has
|
---|
1539 | already specified -print. */
|
---|
1540 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
1541 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1542 | our_pred->args.printf_vec.segment = NULL;
|
---|
1543 | our_pred->args.printf_vec.stream = stdout;
|
---|
1544 | our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
|
---|
1545 | our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
|
---|
1546 |
|
---|
1547 | return true;
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | static boolean
|
---|
1551 | parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1552 | {
|
---|
1553 | struct predicate *our_pred;
|
---|
1554 |
|
---|
1555 | (void) argv;
|
---|
1556 | (void) arg_ptr;
|
---|
1557 |
|
---|
1558 | our_pred = insert_primary (entry);
|
---|
1559 | /* -print0 has the side effect of printing. This prevents us
|
---|
1560 | from doing undesired multiple printing when the user has
|
---|
1561 | already specified -print0. */
|
---|
1562 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
1563 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1564 | return true;
|
---|
1565 | }
|
---|
1566 |
|
---|
1567 | static boolean
|
---|
1568 | parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1569 | {
|
---|
1570 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1571 | return false;
|
---|
1572 | return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr);
|
---|
1573 | }
|
---|
1574 |
|
---|
1575 | static boolean
|
---|
1576 | parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1577 | {
|
---|
1578 | struct predicate *our_pred;
|
---|
1579 |
|
---|
1580 | (void) argv;
|
---|
1581 | (void) arg_ptr;
|
---|
1582 |
|
---|
1583 | our_pred = insert_primary (entry);
|
---|
1584 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1585 | /* -prune has a side effect that it does not descend into
|
---|
1586 | the current directory. */
|
---|
1587 | our_pred->side_effects = true;
|
---|
1588 | our_pred->no_default_print = false;
|
---|
1589 | return true;
|
---|
1590 | }
|
---|
1591 |
|
---|
1592 | static boolean
|
---|
1593 | parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1594 | {
|
---|
1595 | struct predicate *our_pred = insert_primary (entry);
|
---|
1596 | (void) argv;
|
---|
1597 | (void) arg_ptr;
|
---|
1598 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1599 | our_pred->side_effects = true; /* Exiting is a side effect... */
|
---|
1600 | our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
|
---|
1601 | our_pred->est_success_rate = 1e-6;
|
---|
1602 | return true;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 |
|
---|
1606 | static boolean
|
---|
1607 | parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1608 | {
|
---|
1609 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1610 | return false;
|
---|
1611 |
|
---|
1612 | /* collect the regex type name */
|
---|
1613 | options.regex_options = get_regex_type(argv[*arg_ptr]);
|
---|
1614 | (*arg_ptr)++;
|
---|
1615 |
|
---|
1616 | return parse_noop(entry, argv, arg_ptr);
|
---|
1617 | }
|
---|
1618 |
|
---|
1619 |
|
---|
1620 | static boolean
|
---|
1621 | parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1622 | {
|
---|
1623 | return insert_regex (argv, arg_ptr, entry, options.regex_options);
|
---|
1624 | }
|
---|
1625 |
|
---|
1626 | static boolean
|
---|
1627 | insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options)
|
---|
1628 | {
|
---|
1629 | struct predicate *our_pred;
|
---|
1630 | struct re_pattern_buffer *re;
|
---|
1631 | const char *error_message;
|
---|
1632 |
|
---|
1633 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1634 | return false;
|
---|
1635 | our_pred = insert_primary_withpred (entry, pred_regex);
|
---|
1636 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1637 | re = (struct re_pattern_buffer *)
|
---|
1638 | xmalloc (sizeof (struct re_pattern_buffer));
|
---|
1639 | our_pred->args.regex = re;
|
---|
1640 | re->allocated = 100;
|
---|
1641 | re->buffer = (unsigned char *) xmalloc (re->allocated);
|
---|
1642 | re->fastmap = NULL;
|
---|
1643 |
|
---|
1644 | re_set_syntax(regex_options);
|
---|
1645 | re->syntax = regex_options;
|
---|
1646 | re->translate = NULL;
|
---|
1647 |
|
---|
1648 | error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
|
---|
1649 | re);
|
---|
1650 | if (error_message)
|
---|
1651 | error (1, 0, "%s", error_message);
|
---|
1652 | our_pred->est_success_rate = estimate_pattern_match_rate(argv[*arg_ptr], 1);
|
---|
1653 | (*arg_ptr)++;
|
---|
1654 | return true;
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 | static boolean
|
---|
1658 | parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1659 | {
|
---|
1660 | struct predicate *our_pred;
|
---|
1661 | uintmax_t num;
|
---|
1662 | enum comparison_type c_type;
|
---|
1663 | int blksize = 512;
|
---|
1664 | int len;
|
---|
1665 | float rate = 1.0;
|
---|
1666 |
|
---|
1667 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1668 | return false;
|
---|
1669 | len = strlen (argv[*arg_ptr]);
|
---|
1670 | if (len == 0)
|
---|
1671 | error (1, 0, _("invalid null argument to -size"));
|
---|
1672 | switch (argv[*arg_ptr][len - 1])
|
---|
1673 | {
|
---|
1674 | case 'b':
|
---|
1675 | blksize = 512;
|
---|
1676 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1677 | break;
|
---|
1678 |
|
---|
1679 | case 'c':
|
---|
1680 | blksize = 1;
|
---|
1681 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1682 | break;
|
---|
1683 |
|
---|
1684 | case 'k':
|
---|
1685 | blksize = 1024;
|
---|
1686 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1687 | break;
|
---|
1688 |
|
---|
1689 | case 'M': /* Megabytes */
|
---|
1690 | blksize = 1024*1024;
|
---|
1691 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1692 | break;
|
---|
1693 |
|
---|
1694 | case 'G': /* Gigabytes */
|
---|
1695 | blksize = 1024*1024*1024;
|
---|
1696 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1697 | break;
|
---|
1698 |
|
---|
1699 | case 'w':
|
---|
1700 | blksize = 2;
|
---|
1701 | argv[*arg_ptr][len - 1] = '\0';
|
---|
1702 | break;
|
---|
1703 |
|
---|
1704 | case '0':
|
---|
1705 | case '1':
|
---|
1706 | case '2':
|
---|
1707 | case '3':
|
---|
1708 | case '4':
|
---|
1709 | case '5':
|
---|
1710 | case '6':
|
---|
1711 | case '7':
|
---|
1712 | case '8':
|
---|
1713 | case '9':
|
---|
1714 | break;
|
---|
1715 |
|
---|
1716 | default:
|
---|
1717 | error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
|
---|
1718 | }
|
---|
1719 | if (!get_num (argv[*arg_ptr], &num, &c_type))
|
---|
1720 | return false;
|
---|
1721 | our_pred = insert_primary (entry);
|
---|
1722 | our_pred->args.size.kind = c_type;
|
---|
1723 | our_pred->args.size.blocksize = blksize;
|
---|
1724 | our_pred->args.size.size = num;
|
---|
1725 | our_pred->need_stat = true;
|
---|
1726 | our_pred->need_type = false;
|
---|
1727 |
|
---|
1728 | if (COMP_GT == c_type)
|
---|
1729 | our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
|
---|
1730 | else if (COMP_LT == c_type)
|
---|
1731 | our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
|
---|
1732 | else
|
---|
1733 | our_pred->est_success_rate = 0.01;
|
---|
1734 |
|
---|
1735 | (*arg_ptr)++;
|
---|
1736 | return true;
|
---|
1737 | }
|
---|
1738 |
|
---|
1739 |
|
---|
1740 | static boolean
|
---|
1741 | parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1742 | {
|
---|
1743 | struct predicate *our_pred;
|
---|
1744 | struct stat st;
|
---|
1745 |
|
---|
1746 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1747 | return false;
|
---|
1748 | if ((*options.xstat) (argv[*arg_ptr], &st))
|
---|
1749 | error (1, errno, "%s", argv[*arg_ptr]);
|
---|
1750 |
|
---|
1751 | our_pred = insert_primary (entry);
|
---|
1752 | our_pred->args.fileid.ino = st.st_ino;
|
---|
1753 | our_pred->args.fileid.dev = st.st_dev;
|
---|
1754 | our_pred->need_type = false;
|
---|
1755 | our_pred->need_stat = true;
|
---|
1756 | our_pred->est_success_rate = 0.01f;
|
---|
1757 | (*arg_ptr)++;
|
---|
1758 | return true;
|
---|
1759 | }
|
---|
1760 |
|
---|
1761 | #if 0
|
---|
1762 | static boolean
|
---|
1763 | parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1764 | {
|
---|
1765 | const char *arg;
|
---|
1766 | const char *errmsg = _("The -show-control-chars option takes a single argument which "
|
---|
1767 | "must be 'literal' or 'safe'");
|
---|
1768 |
|
---|
1769 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1770 | {
|
---|
1771 | error (1, errno, "%s", errmsg);
|
---|
1772 | return false;
|
---|
1773 | }
|
---|
1774 | else
|
---|
1775 | {
|
---|
1776 | arg = argv[*arg_ptr];
|
---|
1777 |
|
---|
1778 | if (0 == strcmp("literal", arg))
|
---|
1779 | {
|
---|
1780 | options.literal_control_chars = true;
|
---|
1781 | }
|
---|
1782 | else if (0 == strcmp("safe", arg))
|
---|
1783 | {
|
---|
1784 | options.literal_control_chars = false;
|
---|
1785 | }
|
---|
1786 | else
|
---|
1787 | {
|
---|
1788 | error (1, errno, "%s", errmsg);
|
---|
1789 | return false;
|
---|
1790 | }
|
---|
1791 | (*arg_ptr)++; /* consume the argument. */
|
---|
1792 | return true;
|
---|
1793 | }
|
---|
1794 | }
|
---|
1795 | #endif
|
---|
1796 |
|
---|
1797 |
|
---|
1798 | static boolean
|
---|
1799 | parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1800 | {
|
---|
1801 | struct predicate *our_pred;
|
---|
1802 |
|
---|
1803 | (void) argv;
|
---|
1804 | (void) arg_ptr;
|
---|
1805 |
|
---|
1806 | our_pred = insert_primary (entry);
|
---|
1807 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1808 | our_pred->est_success_rate = 1.0f;
|
---|
1809 | return true;
|
---|
1810 | }
|
---|
1811 |
|
---|
1812 | static boolean
|
---|
1813 | parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1814 | {
|
---|
1815 | (void) entry;
|
---|
1816 | return parse_true(get_noop(), argv, arg_ptr);
|
---|
1817 | }
|
---|
1818 |
|
---|
1819 | static boolean
|
---|
1820 | parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1821 | {
|
---|
1822 | struct predicate *our_pred;
|
---|
1823 | (void) argv;
|
---|
1824 | (void) arg_ptr;
|
---|
1825 | our_pred = insert_primary (entry);
|
---|
1826 | our_pred->need_stat = our_pred->need_type = false;
|
---|
1827 | our_pred->side_effects = our_pred->no_default_print = false;
|
---|
1828 | if (our_pred->pred_func == pred_executable)
|
---|
1829 | our_pred->est_success_rate = 0.2;
|
---|
1830 | else
|
---|
1831 | our_pred->est_success_rate = 0.9;
|
---|
1832 | return true;
|
---|
1833 | }
|
---|
1834 |
|
---|
1835 | static boolean
|
---|
1836 | parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1837 | {
|
---|
1838 | return insert_type (argv, arg_ptr, entry, pred_type);
|
---|
1839 | }
|
---|
1840 |
|
---|
1841 | static boolean
|
---|
1842 | parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1843 | {
|
---|
1844 | struct predicate *p = insert_num (argv, arg_ptr, entry);
|
---|
1845 | p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
|
---|
1846 | return p;
|
---|
1847 | }
|
---|
1848 |
|
---|
1849 | static boolean
|
---|
1850 | parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1851 | {
|
---|
1852 | struct predicate *our_pred;
|
---|
1853 | uintmax_t num_days;
|
---|
1854 | enum comparison_type c_type;
|
---|
1855 | time_t t;
|
---|
1856 |
|
---|
1857 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1858 | return false;
|
---|
1859 | if (!get_num (argv[*arg_ptr], &num_days, &c_type))
|
---|
1860 | return false;
|
---|
1861 | t = num_days * DAYSECS;
|
---|
1862 | our_pred = insert_primary (entry);
|
---|
1863 | our_pred->args.info.kind = c_type;
|
---|
1864 | our_pred->args.info.negative = t < 0;
|
---|
1865 | our_pred->args.info.l_val = t;
|
---|
1866 | our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
|
---|
1867 | (*arg_ptr)++;
|
---|
1868 | return true;
|
---|
1869 | }
|
---|
1870 |
|
---|
1871 | static boolean
|
---|
1872 | parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1873 | {
|
---|
1874 | struct passwd *cur_pwd;
|
---|
1875 | struct predicate *our_pred;
|
---|
1876 | uid_t uid;
|
---|
1877 | int uid_len;
|
---|
1878 |
|
---|
1879 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
1880 | return false;
|
---|
1881 | cur_pwd = getpwnam (argv[*arg_ptr]);
|
---|
1882 | endpwent ();
|
---|
1883 | if (cur_pwd != NULL)
|
---|
1884 | uid = cur_pwd->pw_uid;
|
---|
1885 | else
|
---|
1886 | {
|
---|
1887 | uid_len = strspn (argv[*arg_ptr], "0123456789");
|
---|
1888 | if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
|
---|
1889 | return false;
|
---|
1890 | uid = atoi (argv[*arg_ptr]);
|
---|
1891 | }
|
---|
1892 | our_pred = insert_primary (entry);
|
---|
1893 | our_pred->args.uid = uid;
|
---|
1894 | our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
|
---|
1895 | (*arg_ptr)++;
|
---|
1896 | return true;
|
---|
1897 | }
|
---|
1898 |
|
---|
1899 | static boolean
|
---|
1900 | parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1901 | {
|
---|
1902 | extern char *version_string;
|
---|
1903 | int features = 0;
|
---|
1904 |
|
---|
1905 | (void) argv;
|
---|
1906 | (void) arg_ptr;
|
---|
1907 | (void) entry;
|
---|
1908 |
|
---|
1909 | fflush (stderr);
|
---|
1910 | printf (_("GNU find version %s\n"), version_string);
|
---|
1911 | printf (_("Features enabled: "));
|
---|
1912 |
|
---|
1913 | #if CACHE_IDS
|
---|
1914 | printf("CACHE_IDS ");
|
---|
1915 | ++features;
|
---|
1916 | #endif
|
---|
1917 | #if DEBUG
|
---|
1918 | printf("DEBUG ");
|
---|
1919 | ++features;
|
---|
1920 | #endif
|
---|
1921 | #if DEBUG_STAT
|
---|
1922 | printf("DEBUG_STAT ");
|
---|
1923 | ++features;
|
---|
1924 | #endif
|
---|
1925 | #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
|
---|
1926 | printf("D_TYPE ");
|
---|
1927 | ++features;
|
---|
1928 | #endif
|
---|
1929 | #if defined(O_NOFOLLOW)
|
---|
1930 | printf("O_NOFOLLOW(%s) ",
|
---|
1931 | (options.open_nofollow_available ? "enabled" : "disabled"));
|
---|
1932 | ++features;
|
---|
1933 | #endif
|
---|
1934 | #if defined(LEAF_OPTIMISATION)
|
---|
1935 | printf("LEAF_OPTIMISATION ");
|
---|
1936 | ++features;
|
---|
1937 | #endif
|
---|
1938 |
|
---|
1939 | if (is_fts_enabled())
|
---|
1940 | {
|
---|
1941 | printf("FTS ");
|
---|
1942 | ++features;
|
---|
1943 | }
|
---|
1944 |
|
---|
1945 | printf("CBO(level=%d) ", (int)(options.optimisation_level));
|
---|
1946 | ++features;
|
---|
1947 |
|
---|
1948 | if (0 == features)
|
---|
1949 | {
|
---|
1950 | /* For the moment, leave this as English in case someone wants
|
---|
1951 | to parse these strings. */
|
---|
1952 | printf("none");
|
---|
1953 | }
|
---|
1954 | printf("\n");
|
---|
1955 |
|
---|
1956 | exit (0);
|
---|
1957 | }
|
---|
1958 |
|
---|
1959 | static boolean
|
---|
1960 | parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1961 | {
|
---|
1962 | (void) argv;
|
---|
1963 | (void) arg_ptr;
|
---|
1964 | (void) entry;
|
---|
1965 | options.stay_on_filesystem = true;
|
---|
1966 | return parse_noop(entry, argv, arg_ptr);
|
---|
1967 | }
|
---|
1968 |
|
---|
1969 | static boolean
|
---|
1970 | parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1971 | {
|
---|
1972 | (void) argv;
|
---|
1973 | (void) arg_ptr;
|
---|
1974 | (void) entry;
|
---|
1975 | options.ignore_readdir_race = true;
|
---|
1976 | return parse_noop(entry, argv, arg_ptr);
|
---|
1977 | }
|
---|
1978 |
|
---|
1979 | static boolean
|
---|
1980 | parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1981 | {
|
---|
1982 | (void) argv;
|
---|
1983 | (void) arg_ptr;
|
---|
1984 | (void) entry;
|
---|
1985 | options.ignore_readdir_race = false;
|
---|
1986 | return parse_noop(entry, argv, arg_ptr);
|
---|
1987 | }
|
---|
1988 |
|
---|
1989 | static boolean
|
---|
1990 | parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
1991 | {
|
---|
1992 | (void) argv;
|
---|
1993 | (void) arg_ptr;
|
---|
1994 | (void) entry;
|
---|
1995 | options.warnings = true;
|
---|
1996 | return parse_noop(entry, argv, arg_ptr);
|
---|
1997 | }
|
---|
1998 |
|
---|
1999 | static boolean
|
---|
2000 | parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
|
---|
2001 | {
|
---|
2002 | (void) argv;
|
---|
2003 | (void) arg_ptr;
|
---|
2004 | return insert_type (argv, arg_ptr, entry, pred_xtype);
|
---|
2005 | }
|
---|
2006 | |
---|
2007 |
|
---|
2008 | static boolean
|
---|
2009 | insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)
|
---|
2010 | {
|
---|
2011 | mode_t type_cell;
|
---|
2012 | struct predicate *our_pred;
|
---|
2013 | float rate = 0.5;
|
---|
2014 |
|
---|
2015 | if ((argv == NULL) || (argv[*arg_ptr] == NULL)
|
---|
2016 | || (strlen (argv[*arg_ptr]) != 1))
|
---|
2017 | return false;
|
---|
2018 | switch (argv[*arg_ptr][0])
|
---|
2019 | {
|
---|
2020 | case 'b': /* block special */
|
---|
2021 | type_cell = S_IFBLK;
|
---|
2022 | rate = 0.01f;
|
---|
2023 | break;
|
---|
2024 | case 'c': /* character special */
|
---|
2025 | type_cell = S_IFCHR;
|
---|
2026 | rate = 0.01f;
|
---|
2027 | break;
|
---|
2028 | case 'd': /* directory */
|
---|
2029 | type_cell = S_IFDIR;
|
---|
2030 | rate = 0.4f;
|
---|
2031 | break;
|
---|
2032 | case 'f': /* regular file */
|
---|
2033 | type_cell = S_IFREG;
|
---|
2034 | rate = 0.95f;
|
---|
2035 | break;
|
---|
2036 | #ifdef S_IFLNK
|
---|
2037 | case 'l': /* symbolic link */
|
---|
2038 | type_cell = S_IFLNK;
|
---|
2039 | rate = 0.1f;
|
---|
2040 | break;
|
---|
2041 | #endif
|
---|
2042 | #ifdef S_IFIFO
|
---|
2043 | case 'p': /* pipe */
|
---|
2044 | type_cell = S_IFIFO;
|
---|
2045 | rate = 0.01f;
|
---|
2046 | break;
|
---|
2047 | #endif
|
---|
2048 | #ifdef S_IFSOCK
|
---|
2049 | case 's': /* socket */
|
---|
2050 | type_cell = S_IFSOCK;
|
---|
2051 | rate = 0.01f;
|
---|
2052 | break;
|
---|
2053 | #endif
|
---|
2054 | #ifdef S_IFDOOR
|
---|
2055 | case 'D': /* Solaris door */
|
---|
2056 | type_cell = S_IFDOOR;
|
---|
2057 | rate = 0.01f;
|
---|
2058 | break;
|
---|
2059 | #endif
|
---|
2060 | default: /* None of the above ... nuke 'em. */
|
---|
2061 | return false;
|
---|
2062 | }
|
---|
2063 | our_pred = insert_primary_withpred (entry, which_pred);
|
---|
2064 | our_pred->est_success_rate = rate;
|
---|
2065 |
|
---|
2066 | /* Figure out if we will need to stat the file, because if we don't
|
---|
2067 | * need to follow symlinks, we can avoid a stat call by using
|
---|
2068 | * struct dirent.d_type.
|
---|
2069 | */
|
---|
2070 | if (which_pred == pred_xtype)
|
---|
2071 | {
|
---|
2072 | our_pred->need_stat = true;
|
---|
2073 | our_pred->need_type = false;
|
---|
2074 | }
|
---|
2075 | else
|
---|
2076 | {
|
---|
2077 | our_pred->need_stat = false; /* struct dirent is enough */
|
---|
2078 | our_pred->need_type = true;
|
---|
2079 | }
|
---|
2080 | our_pred->args.type = type_cell;
|
---|
2081 | (*arg_ptr)++; /* Move on to next argument. */
|
---|
2082 | return true;
|
---|
2083 | }
|
---|
2084 |
|
---|
2085 |
|
---|
2086 | /* Return true if the file accessed via FP is a terminal.
|
---|
2087 | */
|
---|
2088 | static boolean
|
---|
2089 | stream_is_tty(FILE *fp)
|
---|
2090 | {
|
---|
2091 | int fd = fileno(fp);
|
---|
2092 | if (-1 == fd)
|
---|
2093 | {
|
---|
2094 | return false; /* not a valid stream */
|
---|
2095 | }
|
---|
2096 | else
|
---|
2097 | {
|
---|
2098 | return isatty(fd) ? true : false;
|
---|
2099 | }
|
---|
2100 |
|
---|
2101 | }
|
---|
2102 |
|
---|
2103 |
|
---|
2104 |
|
---|
2105 |
|
---|
2106 | /* XXX: do we need to pass FUNC to this function? */
|
---|
2107 | static boolean
|
---|
2108 | insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr)
|
---|
2109 | {
|
---|
2110 | char *format; /* Beginning of unprocessed format string. */
|
---|
2111 | register char *scan; /* Current address in scanning `format'. */
|
---|
2112 | register char *scan2; /* Address inside of element being scanned. */
|
---|
2113 | struct segment **segmentp; /* Address of current segment. */
|
---|
2114 | struct predicate *our_pred;
|
---|
2115 |
|
---|
2116 | format = argv[(*arg_ptr)++];
|
---|
2117 |
|
---|
2118 | our_pred = insert_primary_withpred (entry, func);
|
---|
2119 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
2120 | our_pred->args.printf_vec.stream = fp;
|
---|
2121 | our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
|
---|
2122 | our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
|
---|
2123 | our_pred->need_type = false;
|
---|
2124 | our_pred->need_stat = false;
|
---|
2125 |
|
---|
2126 | segmentp = &our_pred->args.printf_vec.segment;
|
---|
2127 | *segmentp = NULL;
|
---|
2128 |
|
---|
2129 | for (scan = format; *scan; scan++)
|
---|
2130 | {
|
---|
2131 | if (*scan == '\\')
|
---|
2132 | {
|
---|
2133 | scan2 = scan + 1;
|
---|
2134 | if (*scan2 >= '0' && *scan2 <= '7')
|
---|
2135 | {
|
---|
2136 | register int n, i;
|
---|
2137 |
|
---|
2138 | for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
|
---|
2139 | i++, scan2++)
|
---|
2140 | n = 8 * n + *scan2 - '0';
|
---|
2141 | scan2--;
|
---|
2142 | *scan = n;
|
---|
2143 | }
|
---|
2144 | else
|
---|
2145 | {
|
---|
2146 | switch (*scan2)
|
---|
2147 | {
|
---|
2148 | case 'a':
|
---|
2149 | *scan = 7;
|
---|
2150 | break;
|
---|
2151 | case 'b':
|
---|
2152 | *scan = '\b';
|
---|
2153 | break;
|
---|
2154 | case 'c':
|
---|
2155 | make_segment (segmentp, format, scan - format, KIND_STOP,
|
---|
2156 | our_pred);
|
---|
2157 | if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
|
---|
2158 | our_pred->p_cost = NeedsStatInfo;
|
---|
2159 | return true;
|
---|
2160 | case 'f':
|
---|
2161 | *scan = '\f';
|
---|
2162 | break;
|
---|
2163 | case 'n':
|
---|
2164 | *scan = '\n';
|
---|
2165 | break;
|
---|
2166 | case 'r':
|
---|
2167 | *scan = '\r';
|
---|
2168 | break;
|
---|
2169 | case 't':
|
---|
2170 | *scan = '\t';
|
---|
2171 | break;
|
---|
2172 | case 'v':
|
---|
2173 | *scan = '\v';
|
---|
2174 | break;
|
---|
2175 | case '\\':
|
---|
2176 | /* *scan = '\\'; * it already is */
|
---|
2177 | break;
|
---|
2178 | default:
|
---|
2179 | error (0, 0,
|
---|
2180 | _("warning: unrecognized escape `\\%c'"), *scan2);
|
---|
2181 | scan++;
|
---|
2182 | continue;
|
---|
2183 | }
|
---|
2184 | }
|
---|
2185 | segmentp = make_segment (segmentp, format, scan - format + 1,
|
---|
2186 | KIND_PLAIN, our_pred);
|
---|
2187 | format = scan2 + 1; /* Move past the escape. */
|
---|
2188 | scan = scan2; /* Incremented immediately by `for'. */
|
---|
2189 | }
|
---|
2190 | else if (*scan == '%')
|
---|
2191 | {
|
---|
2192 | if (scan[1] == 0)
|
---|
2193 | {
|
---|
2194 | /* Trailing %. We don't like those. */
|
---|
2195 | error (1, 0, _("error: %s at end of format string"), scan);
|
---|
2196 | }
|
---|
2197 | else if (scan[1] == '%')
|
---|
2198 | {
|
---|
2199 | segmentp = make_segment (segmentp, format, scan - format + 1,
|
---|
2200 | KIND_PLAIN, our_pred);
|
---|
2201 | scan++;
|
---|
2202 | format = scan + 1;
|
---|
2203 | continue;
|
---|
2204 | }
|
---|
2205 | /* Scan past flags, width and precision, to verify kind. */
|
---|
2206 | for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
|
---|
2207 | /* Do nothing. */ ;
|
---|
2208 | while (ISDIGIT (*scan2))
|
---|
2209 | scan2++;
|
---|
2210 | if (*scan2 == '.')
|
---|
2211 | for (scan2++; ISDIGIT (*scan2); scan2++)
|
---|
2212 | /* Do nothing. */ ;
|
---|
2213 | if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
|
---|
2214 | {
|
---|
2215 | segmentp = make_segment (segmentp, format, scan2 - format,
|
---|
2216 | (int) *scan2, our_pred);
|
---|
2217 | scan = scan2;
|
---|
2218 | format = scan + 1;
|
---|
2219 | }
|
---|
2220 | else if (strchr ("ACT", *scan2) && scan2[1])
|
---|
2221 | {
|
---|
2222 | segmentp = make_segment (segmentp, format, scan2 - format,
|
---|
2223 | *scan2 | (scan2[1] << 8),
|
---|
2224 | our_pred);
|
---|
2225 | scan = scan2 + 1;
|
---|
2226 | format = scan + 1;
|
---|
2227 | continue;
|
---|
2228 | }
|
---|
2229 | else
|
---|
2230 | {
|
---|
2231 | /* An unrecognized % escape. Print the char after the %. */
|
---|
2232 | error (0, 0, _("warning: unrecognized format directive `%%%c'"),
|
---|
2233 | *scan2);
|
---|
2234 | segmentp = make_segment (segmentp, format, scan - format,
|
---|
2235 | KIND_PLAIN, our_pred);
|
---|
2236 | format = scan + 1;
|
---|
2237 | continue;
|
---|
2238 | }
|
---|
2239 | }
|
---|
2240 | }
|
---|
2241 |
|
---|
2242 | if (scan > format)
|
---|
2243 | make_segment (segmentp, format, scan - format, KIND_PLAIN,
|
---|
2244 | our_pred);
|
---|
2245 | return true;
|
---|
2246 | }
|
---|
2247 |
|
---|
2248 | /* Create a new fprintf segment in *SEGMENT, with type KIND,
|
---|
2249 | from the text in FORMAT, which has length LEN.
|
---|
2250 | Return the address of the `next' pointer of the new segment. */
|
---|
2251 |
|
---|
2252 | static struct segment **
|
---|
2253 | make_segment (struct segment **segment, char *format, int len, int kind,
|
---|
2254 | struct predicate *pred)
|
---|
2255 | {
|
---|
2256 | enum EvaluationCost mycost = NeedsNothing;
|
---|
2257 | char *fmt;
|
---|
2258 |
|
---|
2259 | *segment = (struct segment *) xmalloc (sizeof (struct segment));
|
---|
2260 |
|
---|
2261 | (*segment)->kind = kind;
|
---|
2262 | (*segment)->next = NULL;
|
---|
2263 | (*segment)->text_len = len;
|
---|
2264 |
|
---|
2265 | fmt = (*segment)->text = xmalloc (len + sizeof "d");
|
---|
2266 | strncpy (fmt, format, len);
|
---|
2267 | fmt += len;
|
---|
2268 |
|
---|
2269 | switch (kind & 0xff)
|
---|
2270 | {
|
---|
2271 | case KIND_PLAIN: /* Plain text string, no % conversion. */
|
---|
2272 | case KIND_STOP: /* Terminate argument, no newline. */
|
---|
2273 | break;
|
---|
2274 |
|
---|
2275 | case 'l': /* object of symlink */
|
---|
2276 | pred->need_stat = true;
|
---|
2277 | mycost = NeedsLinkName;
|
---|
2278 | *fmt++ = 's';
|
---|
2279 | break;
|
---|
2280 |
|
---|
2281 | case 'y': /* file type */
|
---|
2282 | pred->need_type = true;
|
---|
2283 | mycost = NeedsType;
|
---|
2284 | *fmt++ = 's';
|
---|
2285 | break;
|
---|
2286 |
|
---|
2287 | case 'a': /* atime in `ctime' format */
|
---|
2288 | case 'A': /* atime in user-specified strftime format */
|
---|
2289 | case 'c': /* ctime in `ctime' format */
|
---|
2290 | case 'C': /* ctime in user-specified strftime format */
|
---|
2291 | case 'F': /* filesystem type */
|
---|
2292 | case 'g': /* group name */
|
---|
2293 | case 'i': /* inode number */
|
---|
2294 | case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
|
---|
2295 | case 's': /* size in bytes */
|
---|
2296 | case 't': /* mtime in `ctime' format */
|
---|
2297 | case 'T': /* mtime in user-specified strftime format */
|
---|
2298 | case 'u': /* user name */
|
---|
2299 | pred->need_stat = true;
|
---|
2300 | mycost = NeedsStatInfo;
|
---|
2301 | *fmt++ = 's';
|
---|
2302 | break;
|
---|
2303 |
|
---|
2304 | case 'Y': /* symlink pointed file type */
|
---|
2305 | pred->need_stat = true;
|
---|
2306 | mycost = NeedsType; /* true for amortised effect */
|
---|
2307 | *fmt++ = 's';
|
---|
2308 | break;
|
---|
2309 |
|
---|
2310 | case 'f': /* basename of path */
|
---|
2311 | case 'h': /* leading directories part of path */
|
---|
2312 | case 'H': /* ARGV element file was found under */
|
---|
2313 | case 'p': /* pathname */
|
---|
2314 | case 'P': /* pathname with ARGV element stripped */
|
---|
2315 | *fmt++ = 's';
|
---|
2316 | break;
|
---|
2317 |
|
---|
2318 | /* Numeric items that one might expect to honour
|
---|
2319 | * #, 0, + flags but which do not.
|
---|
2320 | */
|
---|
2321 | case 'G': /* GID number */
|
---|
2322 | case 'U': /* UID number */
|
---|
2323 | case 'b': /* size in 512-byte blocks */
|
---|
2324 | case 'D': /* Filesystem device on which the file exits */
|
---|
2325 | case 'k': /* size in 1K blocks */
|
---|
2326 | case 'n': /* number of links */
|
---|
2327 | pred->need_stat = true;
|
---|
2328 | mycost = NeedsStatInfo;
|
---|
2329 | *fmt++ = 's';
|
---|
2330 | break;
|
---|
2331 |
|
---|
2332 | /* Numeric items that DO honour #, 0, + flags.
|
---|
2333 | */
|
---|
2334 | case 'd': /* depth in search tree (0 = ARGV element) */
|
---|
2335 | *fmt++ = 'd';
|
---|
2336 | break;
|
---|
2337 |
|
---|
2338 | case 'm': /* mode as octal number (perms only) */
|
---|
2339 | *fmt++ = 'o';
|
---|
2340 | pred->need_stat = true;
|
---|
2341 | mycost = NeedsStatInfo;
|
---|
2342 | break;
|
---|
2343 | }
|
---|
2344 | *fmt = '\0';
|
---|
2345 |
|
---|
2346 | if (mycost > pred->p_cost)
|
---|
2347 | pred->p_cost = mycost;
|
---|
2348 | return &(*segment)->next;
|
---|
2349 | }
|
---|
2350 | |
---|
2351 |
|
---|
2352 | static void
|
---|
2353 | check_path_safety(const char *action)
|
---|
2354 | {
|
---|
2355 | const char *path = getenv("PATH");
|
---|
2356 | char *s;
|
---|
2357 | s = next_element(path, 1);
|
---|
2358 | while ((s = next_element ((char *) NULL, 1)) != NULL)
|
---|
2359 | {
|
---|
2360 | if (0 == strcmp(s, "."))
|
---|
2361 | {
|
---|
2362 | 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)"),
|
---|
2363 | action);
|
---|
2364 | }
|
---|
2365 | }
|
---|
2366 | }
|
---|
2367 |
|
---|
2368 | |
---|
2369 |
|
---|
2370 | /* handles both exec and ok predicate */
|
---|
2371 | #if defined(NEW_EXEC)
|
---|
2372 | /* handles both exec and ok predicate */
|
---|
2373 | static boolean
|
---|
2374 | new_insert_exec_ok (const char *action,
|
---|
2375 | const struct parser_table *entry,
|
---|
2376 | char **argv,
|
---|
2377 | int *arg_ptr)
|
---|
2378 | {
|
---|
2379 | int start, end; /* Indexes in ARGV of start & end of cmd. */
|
---|
2380 | int i; /* Index into cmd args */
|
---|
2381 | int saw_braces; /* True if previous arg was '{}'. */
|
---|
2382 | boolean allow_plus; /* True if + is a valid terminator */
|
---|
2383 | int brace_count; /* Number of instances of {}. */
|
---|
2384 | PRED_FUNC func = entry->pred_func;
|
---|
2385 | enum BC_INIT_STATUS bcstatus;
|
---|
2386 |
|
---|
2387 | struct predicate *our_pred;
|
---|
2388 | struct exec_val *execp; /* Pointer for efficiency. */
|
---|
2389 |
|
---|
2390 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
2391 | return false;
|
---|
2392 |
|
---|
2393 | our_pred = insert_primary_withpred (entry, func);
|
---|
2394 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
2395 | our_pred->need_type = our_pred->need_stat = false;
|
---|
2396 |
|
---|
2397 | execp = &our_pred->args.exec_vec;
|
---|
2398 |
|
---|
2399 | if ((func != pred_okdir) && (func != pred_ok))
|
---|
2400 | {
|
---|
2401 | allow_plus = true;
|
---|
2402 | execp->close_stdin = false;
|
---|
2403 | }
|
---|
2404 | else
|
---|
2405 | {
|
---|
2406 | allow_plus = false;
|
---|
2407 | /* If find reads stdin (i.e. for -ok and similar), close stdin
|
---|
2408 | * in the child to prevent some script from consiming the output
|
---|
2409 | * intended for find.
|
---|
2410 | */
|
---|
2411 | execp->close_stdin = true;
|
---|
2412 | }
|
---|
2413 |
|
---|
2414 |
|
---|
2415 | if ((func == pred_execdir) || (func == pred_okdir))
|
---|
2416 | {
|
---|
2417 | options.ignore_readdir_race = false;
|
---|
2418 | check_path_safety(action);
|
---|
2419 | execp->use_current_dir = true;
|
---|
2420 | }
|
---|
2421 | else
|
---|
2422 | {
|
---|
2423 | execp->use_current_dir = false;
|
---|
2424 | }
|
---|
2425 |
|
---|
2426 | our_pred->args.exec_vec.multiple = 0;
|
---|
2427 |
|
---|
2428 | /* Count the number of args with path replacements, up until the ';'.
|
---|
2429 | * Also figure out if the command is terminated by ";" or by "+".
|
---|
2430 | */
|
---|
2431 | start = *arg_ptr;
|
---|
2432 | for (end = start, saw_braces=0, brace_count=0;
|
---|
2433 | (argv[end] != NULL)
|
---|
2434 | && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
|
---|
2435 | end++)
|
---|
2436 | {
|
---|
2437 | /* For -exec and -execdir, "{} +" can terminate the command. */
|
---|
2438 | if ( allow_plus
|
---|
2439 | && argv[end][0] == '+' && argv[end][1] == 0
|
---|
2440 | && saw_braces)
|
---|
2441 | {
|
---|
2442 | our_pred->args.exec_vec.multiple = 1;
|
---|
2443 | break;
|
---|
2444 | }
|
---|
2445 |
|
---|
2446 | saw_braces = 0;
|
---|
2447 | if (strstr (argv[end], "{}"))
|
---|
2448 | {
|
---|
2449 | saw_braces = 1;
|
---|
2450 | ++brace_count;
|
---|
2451 |
|
---|
2452 | if (0 == end && (func == pred_execdir || func == pred_okdir))
|
---|
2453 | {
|
---|
2454 | /* The POSIX standard says that {} replacement should
|
---|
2455 | * occur even in the utility name. This is insecure
|
---|
2456 | * since it means we will be executing a command whose
|
---|
2457 | * name is chosen according to whatever find finds in
|
---|
2458 | * the filesystem. That can be influenced by an
|
---|
2459 | * attacker. Hence for -execdir and -okdir this is not
|
---|
2460 | * allowed. We can specify this as those options are
|
---|
2461 | * not defined by POSIX.
|
---|
2462 | */
|
---|
2463 | error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
|
---|
2464 | }
|
---|
2465 | }
|
---|
2466 | }
|
---|
2467 |
|
---|
2468 | /* Fail if no command given or no semicolon found. */
|
---|
2469 | if ((end == start) || (argv[end] == NULL))
|
---|
2470 | {
|
---|
2471 | *arg_ptr = end;
|
---|
2472 | free(our_pred);
|
---|
2473 | return false;
|
---|
2474 | }
|
---|
2475 |
|
---|
2476 | if (our_pred->args.exec_vec.multiple && brace_count > 1)
|
---|
2477 | {
|
---|
2478 |
|
---|
2479 | const char *suffix;
|
---|
2480 | if (func == pred_execdir)
|
---|
2481 | suffix = "dir";
|
---|
2482 | else
|
---|
2483 | suffix = "";
|
---|
2484 |
|
---|
2485 | error(1, 0,
|
---|
2486 | _("Only one instance of {} is supported with -exec%s ... +"),
|
---|
2487 | suffix);
|
---|
2488 | }
|
---|
2489 |
|
---|
2490 | /* We use a switch statement here so that
|
---|
2491 | * the compiler warns us when we forget to handle a
|
---|
2492 | * newly invented enum value.
|
---|
2493 | */
|
---|
2494 | bcstatus = bc_init_controlinfo(&execp->ctl);
|
---|
2495 | switch (bcstatus)
|
---|
2496 | {
|
---|
2497 | case BC_INIT_ENV_TOO_BIG:
|
---|
2498 | error(1, 0,
|
---|
2499 | _("The environment is too large for exec()."));
|
---|
2500 | break;
|
---|
2501 | case BC_INIT_OK:
|
---|
2502 | /* Good news. Carry on. */
|
---|
2503 | break;
|
---|
2504 | }
|
---|
2505 | bc_use_sensible_arg_max(&execp->ctl);
|
---|
2506 |
|
---|
2507 |
|
---|
2508 | execp->ctl.exec_callback = launch;
|
---|
2509 |
|
---|
2510 | if (our_pred->args.exec_vec.multiple)
|
---|
2511 | {
|
---|
2512 | /* "+" terminator, so we can just append our arguments after the
|
---|
2513 | * command and initial arguments.
|
---|
2514 | */
|
---|
2515 | execp->replace_vec = NULL;
|
---|
2516 | execp->ctl.replace_pat = NULL;
|
---|
2517 | execp->ctl.rplen = 0;
|
---|
2518 | execp->ctl.lines_per_exec = 0; /* no limit */
|
---|
2519 | execp->ctl.args_per_exec = 0; /* no limit */
|
---|
2520 |
|
---|
2521 | /* remember how many arguments there are */
|
---|
2522 | execp->ctl.initial_argc = (end-start) - 1;
|
---|
2523 |
|
---|
2524 | /* execp->state = xmalloc(sizeof struct buildcmd_state); */
|
---|
2525 | bc_init_state(&execp->ctl, &execp->state, execp);
|
---|
2526 |
|
---|
2527 | /* Gather the initial arguments. Skip the {}. */
|
---|
2528 | for (i=start; i<end-1; ++i)
|
---|
2529 | {
|
---|
2530 | bc_push_arg(&execp->ctl, &execp->state,
|
---|
2531 | argv[i], strlen(argv[i])+1,
|
---|
2532 | NULL, 0,
|
---|
2533 | 1);
|
---|
2534 | }
|
---|
2535 | }
|
---|
2536 | else
|
---|
2537 | {
|
---|
2538 | /* Semicolon terminator - more than one {} is supported, so we
|
---|
2539 | * have to do brace-replacement.
|
---|
2540 | */
|
---|
2541 | execp->num_args = end - start;
|
---|
2542 |
|
---|
2543 | execp->ctl.replace_pat = "{}";
|
---|
2544 | execp->ctl.rplen = strlen(execp->ctl.replace_pat);
|
---|
2545 | execp->ctl.lines_per_exec = 0; /* no limit */
|
---|
2546 | execp->ctl.args_per_exec = 0; /* no limit */
|
---|
2547 | execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
|
---|
2548 |
|
---|
2549 |
|
---|
2550 | /* execp->state = xmalloc(sizeof(*(execp->state))); */
|
---|
2551 | bc_init_state(&execp->ctl, &execp->state, execp);
|
---|
2552 |
|
---|
2553 | /* Remember the (pre-replacement) arguments for later. */
|
---|
2554 | for (i=0; i<execp->num_args; ++i)
|
---|
2555 | {
|
---|
2556 | execp->replace_vec[i] = argv[i+start];
|
---|
2557 | }
|
---|
2558 | }
|
---|
2559 |
|
---|
2560 | if (argv[end] == NULL)
|
---|
2561 | *arg_ptr = end;
|
---|
2562 | else
|
---|
2563 | *arg_ptr = end + 1;
|
---|
2564 |
|
---|
2565 | return true;
|
---|
2566 | }
|
---|
2567 | #else
|
---|
2568 | /* handles both exec and ok predicate */
|
---|
2569 | static boolean
|
---|
2570 | old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
|
---|
2571 | {
|
---|
2572 | int start, end; /* Indexes in ARGV of start & end of cmd. */
|
---|
2573 | int num_paths; /* Number of args with path replacements. */
|
---|
2574 | int path_pos; /* Index in array of path replacements. */
|
---|
2575 | int vec_pos; /* Index in array of args. */
|
---|
2576 | struct predicate *our_pred;
|
---|
2577 | struct exec_val *execp; /* Pointer for efficiency. */
|
---|
2578 |
|
---|
2579 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
2580 | return false;
|
---|
2581 |
|
---|
2582 | /* Count the number of args with path replacements, up until the ';'. */
|
---|
2583 | start = *arg_ptr;
|
---|
2584 | for (end = start, num_paths = 0;
|
---|
2585 | (argv[end] != NULL)
|
---|
2586 | && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
|
---|
2587 | end++)
|
---|
2588 | if (strstr (argv[end], "{}"))
|
---|
2589 | num_paths++;
|
---|
2590 | /* Fail if no command given or no semicolon found. */
|
---|
2591 | if ((end == start) || (argv[end] == NULL))
|
---|
2592 | {
|
---|
2593 | *arg_ptr = end;
|
---|
2594 | return false;
|
---|
2595 | }
|
---|
2596 |
|
---|
2597 | our_pred = insert_primary (func);
|
---|
2598 | our_pred->side_effects = our_pred->no_default_print = true;
|
---|
2599 | execp = &our_pred->args.exec_vec;
|
---|
2600 | execp->usercontext = our_pred;
|
---|
2601 | execp->use_current_dir = false;
|
---|
2602 | execp->paths =
|
---|
2603 | (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
|
---|
2604 | execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
|
---|
2605 | /* Record the positions of all args, and the args with path replacements. */
|
---|
2606 | for (end = start, path_pos = vec_pos = 0;
|
---|
2607 | (argv[end] != NULL)
|
---|
2608 | && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
|
---|
2609 | end++)
|
---|
2610 | {
|
---|
2611 | register char *p;
|
---|
2612 |
|
---|
2613 | execp->paths[path_pos].count = 0;
|
---|
2614 | for (p = argv[end]; *p; ++p)
|
---|
2615 | if (p[0] == '{' && p[1] == '}')
|
---|
2616 | {
|
---|
2617 | execp->paths[path_pos].count++;
|
---|
2618 | ++p;
|
---|
2619 | }
|
---|
2620 | if (execp->paths[path_pos].count)
|
---|
2621 | {
|
---|
2622 | execp->paths[path_pos].offset = vec_pos;
|
---|
2623 | execp->paths[path_pos].origarg = argv[end];
|
---|
2624 | path_pos++;
|
---|
2625 | }
|
---|
2626 | execp->vec[vec_pos++] = argv[end];
|
---|
2627 | }
|
---|
2628 | execp->paths[path_pos].offset = -1;
|
---|
2629 | execp->vec[vec_pos] = NULL;
|
---|
2630 |
|
---|
2631 | if (argv[end] == NULL)
|
---|
2632 | *arg_ptr = end;
|
---|
2633 | else
|
---|
2634 | *arg_ptr = end + 1;
|
---|
2635 | return true;
|
---|
2636 | }
|
---|
2637 | #endif
|
---|
2638 |
|
---|
2639 |
|
---|
2640 |
|
---|
2641 | static boolean
|
---|
2642 | insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr)
|
---|
2643 | {
|
---|
2644 | #if defined(NEW_EXEC)
|
---|
2645 | return new_insert_exec_ok(action, entry, argv, arg_ptr);
|
---|
2646 | #else
|
---|
2647 | return old_insert_exec_ok(func, argv, arg_ptr);
|
---|
2648 | #endif
|
---|
2649 | }
|
---|
2650 |
|
---|
2651 |
|
---|
2652 | |
---|
2653 |
|
---|
2654 | /* Get a number of days and comparison type.
|
---|
2655 | STR is the ASCII representation.
|
---|
2656 | Set *NUM_DAYS to the number of days, taken as being from
|
---|
2657 | the current moment (or possibly midnight). Thus the sense of the
|
---|
2658 | comparison type appears to be reversed.
|
---|
2659 | Set *COMP_TYPE to the kind of comparison that is requested.
|
---|
2660 |
|
---|
2661 | Return true if all okay, false if input error.
|
---|
2662 |
|
---|
2663 | Used by -atime, -ctime and -mtime (parsers) to
|
---|
2664 | get the appropriate information for a time predicate processor. */
|
---|
2665 |
|
---|
2666 | static boolean
|
---|
2667 | get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
|
---|
2668 | {
|
---|
2669 | boolean r = get_num (str, num_days, comp_type);
|
---|
2670 | if (r)
|
---|
2671 | switch (*comp_type)
|
---|
2672 | {
|
---|
2673 | case COMP_LT: *comp_type = COMP_GT; break;
|
---|
2674 | case COMP_GT: *comp_type = COMP_LT; break;
|
---|
2675 | default: break;
|
---|
2676 | }
|
---|
2677 | return r;
|
---|
2678 | }
|
---|
2679 | |
---|
2680 |
|
---|
2681 | /* Insert a time predicate PRED.
|
---|
2682 | ARGV is a pointer to the argument array.
|
---|
2683 | ARG_PTR is a pointer to an index into the array, incremented if
|
---|
2684 | all went well.
|
---|
2685 |
|
---|
2686 | Return true if input is valid, false if not.
|
---|
2687 |
|
---|
2688 | A new predicate node is assigned, along with an argument node
|
---|
2689 | obtained with malloc.
|
---|
2690 |
|
---|
2691 | Used by -atime, -ctime, and -mtime parsers. */
|
---|
2692 |
|
---|
2693 | static boolean
|
---|
2694 | parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
|
---|
2695 | {
|
---|
2696 | struct predicate *our_pred;
|
---|
2697 | uintmax_t num_days;
|
---|
2698 | enum comparison_type c_type;
|
---|
2699 | time_t t;
|
---|
2700 |
|
---|
2701 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
2702 | return false;
|
---|
2703 | if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
|
---|
2704 | return false;
|
---|
2705 |
|
---|
2706 | /* Figure out the timestamp value we are looking for. */
|
---|
2707 | t = ( options.cur_day_start - num_days * DAYSECS
|
---|
2708 | + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
|
---|
2709 |
|
---|
2710 | if (1)
|
---|
2711 | {
|
---|
2712 | /* We introduce a scope in which 'val' can be declared, for the
|
---|
2713 | * benefit of compilers that are really C89 compilers
|
---|
2714 | * which support intmax_t because config.h #defines it
|
---|
2715 | */
|
---|
2716 | intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
|
---|
2717 | + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
|
---|
2718 | t = val;
|
---|
2719 |
|
---|
2720 | /* Check for possibility of an overflow */
|
---|
2721 | if ( (intmax_t)t != val )
|
---|
2722 | {
|
---|
2723 | error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
|
---|
2724 | }
|
---|
2725 | }
|
---|
2726 |
|
---|
2727 | our_pred = insert_primary (entry);
|
---|
2728 | our_pred->args.info.kind = c_type;
|
---|
2729 | our_pred->args.info.negative = t < 0;
|
---|
2730 | our_pred->args.info.l_val = t;
|
---|
2731 | our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
|
---|
2732 | (*arg_ptr)++;
|
---|
2733 |
|
---|
2734 | if (options.debug_options & DebugExpressionTree)
|
---|
2735 | {
|
---|
2736 | fprintf (stderr, "inserting %s\n", our_pred->p_name);
|
---|
2737 | fprintf (stderr, " type: %s %s ",
|
---|
2738 | (c_type == COMP_GT) ? "gt" :
|
---|
2739 | ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
|
---|
2740 | (c_type == COMP_GT) ? " >" :
|
---|
2741 | ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
|
---|
2742 | t = our_pred->args.info.l_val;
|
---|
2743 | fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
|
---|
2744 | if (c_type == COMP_EQ)
|
---|
2745 | {
|
---|
2746 | t = our_pred->args.info.l_val += DAYSECS;
|
---|
2747 | fprintf (stderr, " < %ju %s",
|
---|
2748 | (uintmax_t) our_pred->args.info.l_val, ctime (&t));
|
---|
2749 | our_pred->args.info.l_val -= DAYSECS;
|
---|
2750 | }
|
---|
2751 | }
|
---|
2752 |
|
---|
2753 | return true;
|
---|
2754 | }
|
---|
2755 | |
---|
2756 |
|
---|
2757 | /* Get a number with comparison information.
|
---|
2758 | The sense of the comparison information is 'normal'; that is,
|
---|
2759 | '+' looks for a count > than the number and '-' less than.
|
---|
2760 |
|
---|
2761 | STR is the ASCII representation of the number.
|
---|
2762 | Set *NUM to the number.
|
---|
2763 | Set *COMP_TYPE to the kind of comparison that is requested.
|
---|
2764 |
|
---|
2765 | Return true if all okay, false if input error. */
|
---|
2766 |
|
---|
2767 | static boolean
|
---|
2768 | get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
|
---|
2769 | {
|
---|
2770 | if (str == NULL)
|
---|
2771 | return false;
|
---|
2772 | switch (str[0])
|
---|
2773 | {
|
---|
2774 | case '+':
|
---|
2775 | *comp_type = COMP_GT;
|
---|
2776 | str++;
|
---|
2777 | break;
|
---|
2778 | case '-':
|
---|
2779 | *comp_type = COMP_LT;
|
---|
2780 | str++;
|
---|
2781 | break;
|
---|
2782 | default:
|
---|
2783 | *comp_type = COMP_EQ;
|
---|
2784 | break;
|
---|
2785 | }
|
---|
2786 |
|
---|
2787 | return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
|
---|
2788 | }
|
---|
2789 | |
---|
2790 |
|
---|
2791 | /* Insert a number predicate.
|
---|
2792 | ARGV is a pointer to the argument array.
|
---|
2793 | *ARG_PTR is an index into ARGV, incremented if all went well.
|
---|
2794 | *PRED is the predicate processor to insert.
|
---|
2795 |
|
---|
2796 | Return true if input is valid, false if error.
|
---|
2797 |
|
---|
2798 | A new predicate node is assigned, along with an argument node
|
---|
2799 | obtained with malloc.
|
---|
2800 |
|
---|
2801 | Used by -inum and -links parsers. */
|
---|
2802 |
|
---|
2803 | static struct predicate *
|
---|
2804 | insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
|
---|
2805 | {
|
---|
2806 | struct predicate *our_pred;
|
---|
2807 | uintmax_t num;
|
---|
2808 | enum comparison_type c_type;
|
---|
2809 |
|
---|
2810 | if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
---|
2811 | return NULL;
|
---|
2812 | if (!get_num (argv[*arg_ptr], &num, &c_type))
|
---|
2813 | return NULL;
|
---|
2814 | our_pred = insert_primary (entry);
|
---|
2815 | our_pred->args.info.kind = c_type;
|
---|
2816 | our_pred->args.info.l_val = num;
|
---|
2817 | (*arg_ptr)++;
|
---|
2818 |
|
---|
2819 | if (options.debug_options & DebugExpressionTree)
|
---|
2820 | {
|
---|
2821 | fprintf (stderr, "inserting %s\n", our_pred->p_name);
|
---|
2822 | fprintf (stderr, " type: %s %s ",
|
---|
2823 | (c_type == COMP_GT) ? "gt" :
|
---|
2824 | ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
|
---|
2825 | (c_type == COMP_GT) ? " >" :
|
---|
2826 | ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
|
---|
2827 | fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
|
---|
2828 | }
|
---|
2829 | return our_pred;
|
---|
2830 | }
|
---|
2831 |
|
---|
2832 | static FILE *
|
---|
2833 | open_output_file (char *path)
|
---|
2834 | {
|
---|
2835 | FILE *f;
|
---|
2836 |
|
---|
2837 | if (!strcmp (path, "/dev/stderr"))
|
---|
2838 | return stderr;
|
---|
2839 | else if (!strcmp (path, "/dev/stdout"))
|
---|
2840 | return stdout;
|
---|
2841 | f = fopen_safer (path, "w");
|
---|
2842 | if (f == NULL)
|
---|
2843 | error (1, errno, "%s", path);
|
---|
2844 | return f;
|
---|
2845 | }
|
---|