143
190
static struct parser_table const parse_table[] =
146
{"not", parse_negate}, /* GNU */
149
{",", parse_comma}, /* GNU */
151
{"amin", parse_amin}, /* GNU */
152
{"and", parse_and}, /* GNU */
153
{"anewer", parse_anewer}, /* GNU */
154
{"atime", parse_atime},
155
{"cmin", parse_cmin}, /* GNU */
156
{"cnewer", parse_cnewer}, /* GNU */
192
{ARG_PUNCTUATION, "!", parse_negate},
193
{ARG_PUNCTUATION, "not", parse_negate}, /* GNU */
194
{ARG_PUNCTUATION, "(", parse_open},
195
{ARG_PUNCTUATION, ")", parse_close},
196
{ARG_PUNCTUATION, ",", parse_comma}, /* GNU */
197
{ARG_PUNCTUATION, "a", parse_and},
198
{ARG_TEST, "amin", parse_amin}, /* GNU */
199
{ARG_PUNCTUATION, "and", parse_and}, /* GNU */
200
{ARG_TEST, "anewer", parse_anewer}, /* GNU */
201
{ARG_TEST, "atime", parse_atime},
202
{ARG_TEST, "cmin", parse_cmin}, /* GNU */
203
{ARG_TEST, "cnewer", parse_cnewer}, /* GNU */
157
204
#ifdef UNIMPLEMENTED_UNIX
158
205
/* It's pretty ugly for find to know about archive formats.
159
206
Plus what it could do with cpio archives is very limited.
160
207
Better to leave it out. */
161
{"cpio", parse_cpio}, /* Unix */
163
{"ctime", parse_ctime},
164
{"daystart", parse_daystart}, /* GNU */
165
{"depth", parse_depth},
166
{"empty", parse_empty}, /* GNU */
167
{"exec", parse_exec},
168
{"false", parse_false}, /* GNU */
169
{"fls", parse_fls}, /* GNU */
170
{"follow", parse_follow}, /* GNU, Unix */
171
{"fprint", parse_fprint}, /* GNU */
172
{"fprint0", parse_fprint0}, /* GNU */
173
{"fprintf", parse_fprintf}, /* GNU */
174
{"fstype", parse_fstype}, /* GNU, Unix */
175
{"gid", parse_gid}, /* GNU */
176
{"group", parse_group},
177
{"help", parse_help}, /* GNU */
178
{"-help", parse_help}, /* GNU */
179
{"ilname", parse_ilname}, /* GNU */
180
{"iname", parse_iname}, /* GNU */
181
{"inum", parse_inum}, /* GNU, Unix */
182
{"ipath", parse_ipath}, /* GNU */
183
{"iregex", parse_iregex}, /* GNU */
184
{"links", parse_links},
185
{"lname", parse_lname}, /* GNU */
186
{"ls", parse_ls}, /* GNU, Unix */
187
{"maxdepth", parse_maxdepth}, /* GNU */
188
{"mindepth", parse_mindepth}, /* GNU */
189
{"mmin", parse_mmin}, /* GNU */
190
{"mount", parse_xdev}, /* Unix */
191
{"mtime", parse_mtime},
192
{"name", parse_name},
193
#ifdef UNIMPLEMENTED_UNIX
194
{"ncpio", parse_ncpio}, /* Unix */
196
{"newer", parse_newer},
197
{"noleaf", parse_noleaf}, /* GNU */
198
{"nogroup", parse_nogroup},
199
{"nouser", parse_nouser},
201
{"or", parse_or}, /* GNU */
203
{"path", parse_path}, /* GNU, HP-UX */
204
{"perm", parse_perm},
205
{"print", parse_print},
206
{"print0", parse_print0}, /* GNU */
207
{"printf", parse_printf}, /* GNU */
208
{"prune", parse_prune},
209
{"regex", parse_regex}, /* GNU */
210
{"size", parse_size},
211
{"true", parse_true}, /* GNU */
212
{"type", parse_type},
213
{"uid", parse_uid}, /* GNU */
214
{"used", parse_used}, /* GNU */
215
{"user", parse_user},
216
{"version", parse_version}, /* GNU */
217
{"-version", parse_version}, /* GNU */
218
{"xdev", parse_xdev},
219
{"xtype", parse_xtype}, /* GNU */
208
{ARG_UNIMPLEMENTED, "cpio", parse_cpio}, /* Unix */
210
{ARG_TEST, "ctime", parse_ctime},
211
{ARG_POSITIONAL_OPTION, "daystart", parse_daystart}, /* GNU */
212
{ARG_ACTION, "delete", parse_delete}, /* GNU, Mac OS, FreeBSD */
213
{ARG_OPTION, "d", parse_d}, /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
214
{ARG_OPTION, "depth", parse_depth},
215
{ARG_TEST, "empty", parse_empty}, /* GNU */
216
{ARG_ACTION, "exec", parse_exec},
217
{ARG_ACTION, "execdir", parse_execdir}, /* *BSD, GNU */
218
{ARG_TEST, "false", parse_false}, /* GNU */
219
{ARG_ACTION, "fls", parse_fls}, /* GNU */
220
{ARG_POSITIONAL_OPTION, "follow", parse_follow}, /* GNU, Unix */
221
{ARG_ACTION, "fprint", parse_fprint}, /* GNU */
222
{ARG_ACTION, "fprint0", parse_fprint0}, /* GNU */
223
{ARG_ACTION, "fprintf", parse_fprintf}, /* GNU */
224
{ARG_TEST, "fstype", parse_fstype}, /* GNU, Unix */
225
{ARG_TEST, "gid", parse_gid}, /* GNU */
226
{ARG_TEST, "group", parse_group},
227
{ARG_TEST, "help", parse_help}, /* GNU */
228
{ARG_TEST, "-help", parse_help}, /* GNU */
229
{ARG_OPTION, "ignore_readdir_race", parse_ignore_race}, /* GNU */
230
{ARG_TEST, "ilname", parse_ilname}, /* GNU */
231
{ARG_TEST, "iname", parse_iname}, /* GNU */
232
{ARG_TEST, "inum", parse_inum}, /* GNU, Unix */
233
{ARG_TEST, "ipath", parse_ipath}, /* GNU, deprecated in favour of iwholename */
234
{ARG_TEST, "iregex", parse_iregex}, /* GNU */
235
{ARG_TEST, "iwholename", parse_iwholename}, /* GNU */
236
{ARG_TEST, "links", parse_links},
237
{ARG_TEST, "lname", parse_lname}, /* GNU */
238
{ARG_ACTION, "ls", parse_ls}, /* GNU, Unix */
239
{ARG_OPTION, "maxdepth", parse_maxdepth}, /* GNU */
240
{ARG_OPTION, "mindepth", parse_mindepth}, /* GNU */
241
{ARG_TEST, "mmin", parse_mmin}, /* GNU */
242
{ARG_OPTION, "mount", parse_xdev}, /* Unix */
243
{ARG_TEST, "mtime", parse_mtime},
244
{ARG_TEST, "name", parse_name},
245
#ifdef UNIMPLEMENTED_UNIX
246
{ARG_UNIMPLEMENTED, "ncpio", parse_ncpio}, /* Unix */
248
{ARG_TEST, "newer", parse_newer},
249
{ARG_OPTION, "noleaf", parse_noleaf}, /* GNU */
250
{ARG_TEST, "nogroup", parse_nogroup},
251
{ARG_TEST, "nouser", parse_nouser},
252
{ARG_OPTION, "noignore_readdir_race", parse_noignore_race},/* GNU */
253
{ARG_OPTION, "nowarn", parse_nowarn}, /* GNU */
254
{ARG_PUNCTUATION, "o", parse_or},
255
{ARG_PUNCTUATION, "or", parse_or}, /* GNU */
256
{ARG_ACTION, "ok", parse_ok},
257
{ARG_ACTION, "okdir", parse_okdir}, /* GNU (-execdir is BSD) */
258
{ARG_TEST, "path", parse_path}, /* GNU, HP-UX, GNU prefers wholename */
259
{ARG_TEST, "perm", parse_perm},
260
{ARG_ACTION, "print", parse_print},
261
{ARG_ACTION, "print0", parse_print0}, /* GNU */
262
{ARG_ACTION, "printf", parse_printf}, /* GNU */
263
{ARG_TEST, "prune", parse_prune},
264
{ARG_ACTION, "quit", parse_quit}, /* GNU */
265
{ARG_TEST, "regex", parse_regex}, /* GNU */
266
{ARG_TEST, "samefile", parse_samefile}, /* GNU */
267
{ARG_TEST, "size", parse_size},
268
{ARG_TEST, "true", parse_true}, /* GNU */
269
{ARG_TEST, "type", parse_type},
270
{ARG_TEST, "uid", parse_uid}, /* GNU */
271
{ARG_TEST, "used", parse_used}, /* GNU */
272
{ARG_TEST, "user", parse_user},
273
{ARG_TEST, "version", parse_version}, /* GNU */
274
{ARG_TEST, "-version", parse_version}, /* GNU */
275
{ARG_OPTION, "warn", parse_warn}, /* GNU */
276
{ARG_TEST, "wholename", parse_wholename}, /* GNU, replaces -path */
277
{ARG_OPTION, "xdev", parse_xdev},
278
{ARG_TEST, "xtype", parse_xtype}, /* GNU */
283
static const char *first_nonoption_arg = NULL;
223
285
/* Return a pointer to the parser function to invoke for predicate
225
287
Return NULL if SEARCH_NAME is not a valid predicate name. */
228
290
find_parser (char *search_name)
293
const char *original_arg = search_name;
232
295
if (*search_name == '-')
234
297
for (i = 0; parse_table[i].parser_name != 0; i++)
235
if (strcmp (parse_table[i].parser_name, search_name) == 0)
236
return (parse_table[i].parser_func);
299
if (strcmp (parse_table[i].parser_name, search_name) == 0)
301
/* If this is an option, but we have already had a
302
* non-option argument, the user may be under the
303
* impression that the behaviour of the option
304
* argument is conditional on some preceding
305
* tests. This might typically be the case with,
306
* for example, -maxdepth.
308
* The options -daystart and -follow are exempt
309
* from this treatment, since their positioning
310
* in the command line does have an effect on
311
* subsequent tests but not previous ones. That
312
* might be intentional on the part of the user.
314
if (parse_table[i].type != ARG_POSITIONAL_OPTION)
316
/* Something other than -follow/-daystart.
317
* If this is an option, check if it followed
318
* a non-option and if so, issue a warning.
320
if (parse_table[i].type == ARG_OPTION)
322
if ((first_nonoption_arg != NULL)
323
&& options.warnings )
325
/* option which folows a non-option */
327
_("warning: you have specified the %s "
328
"option after a non-option argument %s, "
329
"but options are not positional (%s affects "
330
"tests specified before it as well as those "
331
"specified after it). Please specify options "
332
"before other arguments.\n"),
340
/* Not an option or a positional option,
341
* so remember we've seen it in order to
342
* use it in a possible future warning message.
344
if (first_nonoption_arg == NULL)
346
first_nonoption_arg = original_arg;
351
return (parse_table[i].parser_func);
240
357
/* The parsers are responsible to continue scanning ARGV for
1460
1979
return (&(*segment)->next);
1463
/* handles both exec and ok predicate */
1465
insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1983
check_path_safety(const char *action)
1985
const char *path = getenv("PATH");
1987
s = next_element(path, 1);
1988
while ((s = next_element ((char *) NULL, 1)) != NULL)
1990
if (0 == strcmp(s, "."))
1992
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)"),
1999
/* handles both exec and ok predicate */
2000
#if defined(NEW_EXEC)
2001
/* handles both exec and ok predicate */
2003
new_insert_exec_ok (const char *action,
2008
int start, end; /* Indexes in ARGV of start & end of cmd. */
2009
int i; /* Index into cmd args */
2010
int saw_braces; /* True if previous arg was '{}'. */
2011
boolean allow_plus; /* True if + is a valid terminator */
2012
int brace_count; /* Number of instances of {}. */
2014
struct predicate *our_pred;
2015
struct exec_val *execp; /* Pointer for efficiency. */
2017
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2020
our_pred = insert_primary (func);
2021
our_pred->side_effects = true;
2022
our_pred->no_default_print = true;
2023
execp = &our_pred->args.exec_vec;
2025
if ((func != pred_okdir) && (func != pred_ok))
2030
if ((func == pred_execdir) || (func == pred_okdir))
2032
options.ignore_readdir_race = false;
2033
check_path_safety(action);
2034
execp->use_current_dir = true;
2038
execp->use_current_dir = false;
2041
our_pred->args.exec_vec.multiple = 0;
2043
/* Count the number of args with path replacements, up until the ';'.
2044
* Also figure out if the command is terminated by ";" or by "+".
2047
for (end = start, saw_braces=0, brace_count=0;
2049
&& ((argv[end][0] != ';') || (argv[end][1] != '\0'));
2052
/* For -exec and -execdir, "{} +" can terminate the command. */
2054
&& argv[end][0] == '+' && argv[end][1] == 0
2057
our_pred->args.exec_vec.multiple = 1;
2062
if (strstr (argv[end], "{}"))
2067
if (0 == end && (func == pred_execdir || func == pred_okdir))
2069
/* The POSIX standard says that {} replacement should
2070
* occur even in the utility name. This is insecure
2071
* since it means we will be executing a command whose
2072
* name is chosen according to whatever find finds in
2073
* the filesystem. That can be influenced by an
2074
* attacker. Hence for -execdir and -okdir this is not
2075
* allowed. We can specify this as those options are
2076
* not defined by POSIX.
2078
error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2083
/* Fail if no command given or no semicolon found. */
2084
if ((end == start) || (argv[end] == NULL))
2091
if (our_pred->args.exec_vec.multiple && brace_count > 1)
2095
if (func == pred_execdir)
2101
_("Only one instance of {} is supported with -exec%s ... +"),
2105
/* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2106
bc_init_controlinfo(&execp->ctl);
2107
execp->ctl.exec_callback = launch;
2109
if (our_pred->args.exec_vec.multiple)
2111
/* "+" terminator, so we can just append our arguments after the
2112
* command and initial arguments.
2114
execp->replace_vec = NULL;
2115
execp->ctl.replace_pat = NULL;
2116
execp->ctl.rplen = 0;
2117
execp->ctl.lines_per_exec = 0; /* no limit */
2118
execp->ctl.args_per_exec = 0; /* no limit */
2120
/* remember how many arguments there are */
2121
execp->ctl.initial_argc = (end-start) - 1;
2123
/* execp->state = xmalloc(sizeof struct buildcmd_state); */
2124
bc_init_state(&execp->ctl, &execp->state, execp);
2126
/* Gather the initial arguments. Skip the {}. */
2127
for (i=start; i<end-1; ++i)
2129
bc_push_arg(&execp->ctl, &execp->state,
2130
argv[i], strlen(argv[i])+1,
2137
/* Semicolon terminator - more than one {} is supported, so we
2138
* have to do brace-replacement.
2140
execp->num_args = end - start;
2142
execp->ctl.replace_pat = "{}";
2143
execp->ctl.rplen = strlen(execp->ctl.replace_pat);
2144
execp->ctl.lines_per_exec = 0; /* no limit */
2145
execp->ctl.args_per_exec = 0; /* no limit */
2146
execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
2149
/* execp->state = xmalloc(sizeof(*(execp->state))); */
2150
bc_init_state(&execp->ctl, &execp->state, execp);
2152
/* Remember the (pre-replacement) arguments for later. */
2153
for (i=0; i<execp->num_args; ++i)
2155
execp->replace_vec[i] = argv[i+start];
2159
if (argv[end] == NULL)
2167
/* handles both exec and ok predicate */
2169
old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1467
2171
int start, end; /* Indexes in ARGV of start & end of cmd. */
1468
2172
int num_paths; /* Number of args with path replacements. */