1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3 2004, 2005 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
27 #include "modechange.h"
35 #include "stdio-safer.h"
36 #include "regextype.h"
44 /* The presence of unistd.h is assumed by gnulib these days, so we
45 * might as well assume it too.
47 /* We need <unistd.h> for isatty(). */
52 # define _(Text) gettext (Text)
57 # define N_(String) gettext_noop (String)
59 /* See locate.c for explanation as to why not use (String) */
60 # define N_(String) String
63 #if !defined (isascii) || defined (STDC_HEADERS)
70 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
71 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
80 static boolean parse_amin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
81 static boolean parse_and
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
82 static boolean parse_anewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
83 static boolean parse_atime
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
84 static boolean parse_cmin
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
85 static boolean parse_cnewer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
86 static boolean parse_comma
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
87 static boolean parse_ctime
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
88 static boolean parse_daystart
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
89 static boolean parse_delete
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
90 static boolean parse_d
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
91 static boolean parse_depth
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
92 static boolean parse_empty
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
93 static boolean parse_exec
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
94 static boolean parse_execdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
95 static boolean parse_executable
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_mtime
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
119 static boolean parse_name
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
120 static boolean parse_negate
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
121 static boolean parse_newer
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
122 static boolean parse_noleaf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
123 static boolean parse_nogroup
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
124 static boolean parse_nouser
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
125 static boolean parse_nowarn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
126 static boolean parse_ok
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
127 static boolean parse_okdir
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
128 static boolean parse_or
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
129 static boolean parse_path
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
130 static boolean parse_perm
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
131 static boolean parse_print0
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
132 static boolean parse_printf
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
133 static boolean parse_prune
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
134 static boolean parse_readable
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
135 static boolean parse_regex
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
136 static boolean parse_regextype
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
137 static boolean parse_samefile
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
138 static boolean parse_show_control_chars
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
139 static boolean parse_size
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
140 static boolean parse_true
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
141 static boolean parse_type
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
142 static boolean parse_uid
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
143 static boolean parse_used
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
144 static boolean parse_user
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
145 static boolean parse_version
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
146 static boolean parse_wholename
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
147 static boolean parse_xdev
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
148 static boolean parse_ignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
149 static boolean parse_noignore_race
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
150 static boolean parse_warn
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
151 static boolean parse_writable
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
));
155 boolean parse_print
PARAMS((const struct parser_table
*, char *argv
[], int *arg_ptr
));
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
));
162 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
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 insert_time
PARAMS((char **argv
, int *arg_ptr
, const struct parser_table
* entry
, PRED_FUNC pred
));
166 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
167 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, const struct parser_table
*entry
));
168 static FILE *open_output_file
PARAMS((char *path
));
169 static boolean
stream_is_tty(FILE *fp
);
172 char *find_pred_name
PARAMS((PRED_FUNC pred_func
));
176 #define PASTE(x,y) x##y
177 #define STRINGIFY(s) #s
179 #define PARSE_OPTION(what,suffix) \
180 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
182 #define PARSE_POSOPT(what,suffix) \
183 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
185 #define PARSE_TEST(what,suffix) \
186 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
188 #define PARSE_TEST_NP(what,suffix) \
189 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
191 #define PARSE_ACTION(what,suffix) \
192 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
194 #define PARSE_ACTION_NP(what,suffix) \
195 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
197 #define PARSE_PUNCTUATION(what,suffix) \
198 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
201 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
202 If they are in some Unix versions of find, they are marked `Unix'. */
204 static struct parser_table
const parse_table
[] =
206 PARSE_PUNCTUATION("!", negate
),
207 PARSE_PUNCTUATION("not", negate
), /* GNU */
208 PARSE_PUNCTUATION("(", open
),
209 PARSE_PUNCTUATION(")", close
),
210 PARSE_PUNCTUATION(",", comma
), /* GNU */
211 PARSE_PUNCTUATION("a", and),
212 PARSE_TEST ("amin", amin
), /* GNU */
213 PARSE_PUNCTUATION("and", and), /* GNU */
214 PARSE_TEST ("anewer", anewer
), /* GNU */
215 PARSE_TEST ("atime", atime
),
216 PARSE_TEST ("cmin", cmin
), /* GNU */
217 PARSE_TEST ("cnewer", cnewer
), /* GNU */
218 PARSE_TEST ("ctime", ctime
),
219 PARSE_POSOPT ("daystart", daystart
), /* GNU */
220 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
221 PARSE_OPTION ("d", d
), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
222 PARSE_OPTION ("depth", depth
),
223 PARSE_TEST ("empty", empty
), /* GNU */
224 {ARG_ACTION
, "exec", parse_exec
, pred_exec
}, /* POSIX */
225 PARSE_TEST ("executable", executable
), /* GNU, 4.3.0+ */
226 PARSE_ACTION ("execdir", execdir
), /* *BSD, GNU */
227 PARSE_ACTION ("fls", fls
), /* GNU */
228 PARSE_POSOPT ("follow", follow
), /* GNU, Unix */
229 PARSE_ACTION ("fprint", fprint
), /* GNU */
230 PARSE_ACTION ("fprint0", fprint0
), /* GNU */
231 {ARG_ACTION
, "fprintf", parse_fprintf
, pred_fprintf
}, /* GNU */
232 PARSE_TEST ("fstype", fstype
), /* GNU, Unix */
233 PARSE_TEST ("gid", gid
), /* GNU */
234 PARSE_TEST ("group", group
),
235 PARSE_OPTION ("ignore_readdir_race", ignore_race
), /* GNU */
236 PARSE_TEST ("ilname", ilname
), /* GNU */
237 PARSE_TEST ("iname", iname
), /* GNU */
238 PARSE_TEST ("inum", inum
), /* GNU, Unix */
239 PARSE_TEST ("ipath", ipath
), /* GNU, deprecated in favour of iwholename */
240 PARSE_TEST_NP ("iregex", iregex
), /* GNU */
241 PARSE_TEST_NP ("iwholename", iwholename
), /* GNU */
242 PARSE_TEST ("links", links
),
243 PARSE_TEST ("lname", lname
), /* GNU */
244 PARSE_ACTION ("ls", ls
), /* GNU, Unix */
245 PARSE_OPTION ("maxdepth", maxdepth
), /* GNU */
246 PARSE_OPTION ("mindepth", mindepth
), /* GNU */
247 PARSE_TEST ("mmin", mmin
), /* GNU */
248 PARSE_OPTION ("mount", xdev
), /* Unix */
249 PARSE_TEST ("mtime", mtime
),
250 PARSE_TEST ("name", name
),
251 #ifdef UNIMPLEMENTED_UNIX
252 PARSE(ARG_UNIMPLEMENTED
, "ncpio", ncpio
), /* Unix */
254 PARSE_TEST ("newer", newer
),
255 PARSE_OPTION ("noleaf", noleaf
), /* GNU */
256 PARSE_TEST ("nogroup", nogroup
),
257 PARSE_TEST ("nouser", nouser
),
258 PARSE_OPTION ("noignore_readdir_race", noignore_race
), /* GNU */
259 PARSE_OPTION ("nowarn", nowarn
), /* GNU */
260 PARSE_PUNCTUATION("o", or),
261 PARSE_PUNCTUATION("or", or), /* GNU */
262 PARSE_ACTION ("ok", ok
),
263 PARSE_ACTION ("okdir", okdir
), /* GNU (-execdir is BSD) */
264 PARSE_TEST ("path", path
), /* GNU, HP-UX, GNU prefers wholename */
265 PARSE_TEST ("perm", perm
),
266 PARSE_ACTION ("print", print
),
267 PARSE_ACTION ("print0", print0
), /* GNU */
268 {ARG_ACTION
, "printf", parse_printf
, NULL
}, /* GNU */
269 PARSE_ACTION ("prune", prune
),
270 PARSE_ACTION ("quit", quit
), /* GNU */
271 PARSE_TEST ("readable", readable
), /* GNU, 4.3.0+ */
272 PARSE_TEST ("regex", regex
), /* GNU */
273 PARSE_OPTION ("regextype", regextype
), /* GNU */
274 PARSE_TEST ("samefile", samefile
), /* GNU */
276 PARSE_OPTION ("show-control-chars", show_control_chars
), /* GNU, 4.3.0+ */
278 PARSE_TEST ("size", size
),
279 PARSE_TEST ("type", type
),
280 PARSE_TEST ("uid", uid
), /* GNU */
281 PARSE_TEST ("used", used
), /* GNU */
282 PARSE_TEST ("user", user
),
283 PARSE_OPTION ("warn", warn
), /* GNU */
284 PARSE_TEST_NP ("wholename", wholename
), /* GNU, replaces -path */
285 PARSE_TEST ("writable", writable
), /* GNU, 4.3.0+ */
286 PARSE_OPTION ("xdev", xdev
),
287 PARSE_TEST ("xtype", xtype
), /* GNU */
288 #ifdef UNIMPLEMENTED_UNIX
289 /* It's pretty ugly for find to know about archive formats.
290 Plus what it could do with cpio archives is very limited.
291 Better to leave it out. */
292 PARSE(ARG_UNIMPLEMENTED
, "cpio", cpio
), /* Unix */
294 /* gnulib's stdbool.h might have made true and false into macros,
295 * so we can't leave named 'true' and 'false' tokens, so we have
296 * to expeant the relevant entries longhand.
298 {ARG_TEST
, "false", parse_false
, pred_false
}, /* GNU */
299 {ARG_TEST
, "true", parse_true
, pred_true
}, /* GNU */
301 /* Various other cases that don't fit neatly into our macro scheme. */
302 {ARG_TEST
, "help", parse_help
, NULL
}, /* GNU */
303 {ARG_TEST
, "-help", parse_help
, NULL
}, /* GNU */
304 {ARG_TEST
, "version", parse_version
, NULL
}, /* GNU */
305 {ARG_TEST
, "-version", parse_version
, NULL
}, /* GNU */
310 static const char *first_nonoption_arg
= NULL
;
316 set_follow_state(enum SymlinkOption opt
)
320 case SYMLINK_ALWAYS_DEREF
: /* -L */
321 options
.xstat
= optionl_stat
;
322 options
.no_leaf_check
= true;
325 case SYMLINK_NEVER_DEREF
: /* -P (default) */
326 options
.xstat
= optionp_stat
;
327 /* Can't turn no_leaf_check off because the user might have specified
332 case SYMLINK_DEREF_ARGSONLY
: /* -H */
333 options
.xstat
= optionh_stat
;
334 options
.no_leaf_check
= true;
337 options
.symlink_handling
= opt
;
339 /* For DEBUG_STAT, the choice is made at runtime within debug_stat()
340 * by checking the contents of the symlink_handling variable.
342 #if defined(DEBUG_STAT)
343 options
.xstat
= debug_stat
;
344 #endif /* !DEBUG_STAT */
349 parse_begin_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
355 first_nonoption_arg
= NULL
;
359 parse_end_user_args (char **args
, int argno
, const struct predicate
*last
, const struct predicate
*predicates
)
371 /* Return a pointer to the parser function to invoke for predicate
373 Return NULL if SEARCH_NAME is not a valid predicate name. */
375 const struct parser_table
*
376 find_parser (char *search_name
)
379 const char *original_arg
= search_name
;
381 if (*search_name
== '-')
383 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
385 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
387 /* If this is an option, but we have already had a
388 * non-option argument, the user may be under the
389 * impression that the behaviour of the option
390 * argument is conditional on some preceding
391 * tests. This might typically be the case with,
392 * for example, -maxdepth.
394 * The options -daystart and -follow are exempt
395 * from this treatment, since their positioning
396 * in the command line does have an effect on
397 * subsequent tests but not previous ones. That
398 * might be intentional on the part of the user.
400 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
402 /* Something other than -follow/-daystart.
403 * If this is an option, check if it followed
404 * a non-option and if so, issue a warning.
406 if (parse_table
[i
].type
== ARG_OPTION
)
408 if ((first_nonoption_arg
!= NULL
)
409 && options
.warnings
)
411 /* option which follows a non-option */
413 _("warning: you have specified the %s "
414 "option after a non-option argument %s, "
415 "but options are not positional (%s affects "
416 "tests specified before it as well as those "
417 "specified after it). Please specify options "
418 "before other arguments.\n"),
426 /* Not an option or a positional option,
427 * so remember we've seen it in order to
428 * use it in a possible future warning message.
430 if (first_nonoption_arg
== NULL
)
432 first_nonoption_arg
= original_arg
;
437 return &parse_table
[i
];
443 /* The parsers are responsible to continue scanning ARGV for
444 their arguments. Each parser knows what is and isn't
447 ARGV is the argument array.
448 *ARG_PTR is the index to start at in ARGV,
449 updated to point beyond the last element consumed.
451 The predicate structure is updated with the new information. */
454 parse_amin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
456 struct predicate
*our_pred
;
458 enum comparison_type c_type
;
461 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
463 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
465 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
466 our_pred
= insert_primary (entry
);
467 our_pred
->args
.info
.kind
= c_type
;
468 our_pred
->args
.info
.negative
= t
< 0;
469 our_pred
->args
.info
.l_val
= t
;
475 parse_and (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
477 struct predicate
*our_pred
;
482 our_pred
= get_new_pred (entry
);
483 our_pred
->pred_func
= pred_and
;
485 our_pred
->p_name
= find_pred_name (pred_and
);
487 our_pred
->p_type
= BI_OP
;
488 our_pred
->p_prec
= AND_PREC
;
489 our_pred
->need_stat
= our_pred
->need_type
= false;
494 parse_anewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
496 struct predicate
*our_pred
;
497 struct stat stat_newer
;
499 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
501 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
502 error (1, errno
, "%s", argv
[*arg_ptr
]);
503 our_pred
= insert_primary (entry
);
504 our_pred
->args
.time
= stat_newer
.st_mtime
;
510 parse_atime (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
512 return insert_time (argv
, arg_ptr
, entry
, pred_atime
);
516 parse_close (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
518 struct predicate
*our_pred
;
523 our_pred
= get_new_pred (entry
);
524 our_pred
->pred_func
= pred_close
;
526 our_pred
->p_name
= find_pred_name (pred_close
);
528 our_pred
->p_type
= CLOSE_PAREN
;
529 our_pred
->p_prec
= NO_PREC
;
530 our_pred
->need_stat
= our_pred
->need_type
= false;
535 parse_cmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
537 struct predicate
*our_pred
;
539 enum comparison_type c_type
;
542 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
544 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
546 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
547 our_pred
= insert_primary (entry
);
548 our_pred
->args
.info
.kind
= c_type
;
549 our_pred
->args
.info
.negative
= t
< 0;
550 our_pred
->args
.info
.l_val
= t
;
556 parse_cnewer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
558 struct predicate
*our_pred
;
559 struct stat stat_newer
;
561 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
563 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
564 error (1, errno
, "%s", argv
[*arg_ptr
]);
565 our_pred
= insert_primary (entry
);
566 our_pred
->args
.time
= stat_newer
.st_mtime
;
572 parse_comma (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
574 struct predicate
*our_pred
;
579 our_pred
= get_new_pred (entry
);
580 our_pred
->pred_func
= pred_comma
;
582 our_pred
->p_name
= find_pred_name (pred_comma
);
584 our_pred
->p_type
= BI_OP
;
585 our_pred
->p_prec
= COMMA_PREC
;
586 our_pred
->need_stat
= our_pred
->need_type
= false;
591 parse_ctime (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
593 return insert_time (argv
, arg_ptr
, entry
, pred_ctime
);
597 parse_daystart (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
605 if (options
.full_days
== false)
607 options
.cur_day_start
+= DAYSECS
;
608 local
= localtime (&options
.cur_day_start
);
609 options
.cur_day_start
-= (local
610 ? (local
->tm_sec
+ local
->tm_min
* 60
611 + local
->tm_hour
* 3600)
612 : options
.cur_day_start
% DAYSECS
);
613 options
.full_days
= true;
619 parse_delete (const struct parser_table
* entry
, char *argv
[], int *arg_ptr
)
621 struct predicate
*our_pred
;
625 our_pred
= insert_primary (entry
);
626 our_pred
->side_effects
= our_pred
->no_default_print
= true;
627 /* -delete implies -depth */
628 options
.do_dir_first
= false;
633 parse_depth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
639 options
.do_dir_first
= false;
644 parse_d (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
649 if (options
.warnings
)
652 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
654 return parse_depth(entry
, argv
, arg_ptr
);
658 parse_empty (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
663 insert_primary (entry
);
668 parse_exec (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
670 return insert_exec_ok ("-exec", entry
, argv
, arg_ptr
);
674 parse_execdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
676 return insert_exec_ok ("-execdir", entry
, argv
, arg_ptr
);
680 parse_false (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
682 struct predicate
*our_pred
;
687 our_pred
= insert_primary (entry
);
688 our_pred
->need_stat
= our_pred
->need_type
= false;
689 our_pred
->side_effects
= our_pred
->no_default_print
= false;
694 parse_fls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
696 struct predicate
*our_pred
;
698 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
700 our_pred
= insert_primary (entry
);
701 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
702 our_pred
->side_effects
= our_pred
->no_default_print
= true;
708 parse_fprintf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
712 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
714 if (argv
[*arg_ptr
+ 1] == NULL
)
716 /* Ensure we get "missing arg" message, not "invalid arg". */
720 fp
= open_output_file (argv
[*arg_ptr
]);
722 return insert_fprintf (fp
, entry
, pred_fprintf
, argv
, arg_ptr
);
726 parse_follow (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
732 set_follow_state(SYMLINK_ALWAYS_DEREF
);
737 parse_fprint (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
739 struct predicate
*our_pred
;
741 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
743 our_pred
= insert_primary (entry
);
744 our_pred
->args
.printf_vec
.segment
= NULL
;
745 our_pred
->args
.printf_vec
.stream
= open_output_file (argv
[*arg_ptr
]);
746 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(our_pred
->args
.printf_vec
.stream
);
747 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
748 our_pred
->side_effects
= our_pred
->no_default_print
= true;
749 our_pred
->need_stat
= our_pred
->need_type
= false;
755 parse_fprint0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
757 struct predicate
*our_pred
;
759 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
761 our_pred
= insert_primary (entry
);
762 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
763 our_pred
->side_effects
= our_pred
->no_default_print
= true;
764 our_pred
->need_stat
= our_pred
->need_type
= false;
770 parse_fstype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
772 struct predicate
*our_pred
;
774 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
776 our_pred
= insert_primary (entry
);
777 our_pred
->args
.str
= argv
[*arg_ptr
];
783 parse_gid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
785 return insert_num (argv
, arg_ptr
, entry
);
789 parse_group (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
791 struct group
*cur_gr
;
792 struct predicate
*our_pred
;
796 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
798 cur_gr
= getgrnam (argv
[*arg_ptr
]);
801 gid
= cur_gr
->gr_gid
;
804 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
805 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
807 gid
= atoi (argv
[*arg_ptr
]);
809 our_pred
= insert_primary (entry
);
810 our_pred
->args
.gid
= gid
;
816 parse_help (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
823 Usage: %s [path...] [expression]\n"), program_name
);
825 default path is the current directory; default expression is -print\n\
826 expression may consist of: operators, options, tests, and actions:\n"));
828 operators (decreasing precedence; -and is implicit where no others are given):\n\
829 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
830 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
832 positional options (always true): -daystart -follow -regextype\n\n\
833 normal options (always true, specified before other expressions):\n\
834 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
835 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
837 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
838 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
839 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
840 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
842 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
843 -readable -writable -executable\n\
844 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
845 -used N -user NAME -xtype [bcdpfls]\n"));
847 actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
848 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
849 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
850 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
852 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
853 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
854 email to <bug-findutils@gnu.org>."));
859 parse_ilname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
861 struct predicate
*our_pred
;
863 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
865 our_pred
= insert_primary (entry
);
866 our_pred
->args
.str
= argv
[*arg_ptr
];
872 /* sanity check the fnmatch() function to make sure
873 * it really is the GNU version.
876 fnmatch_sanitycheck(void)
878 /* fprintf(stderr, "Performing find sanity check..."); */
879 if (0 != fnmatch("foo", "foo", 0)
880 || 0 == fnmatch("Foo", "foo", 0)
881 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
883 error (1, 0, _("sanity check of the fnmatch() library function failed."));
884 /* fprintf(stderr, "FAILED\n"); */
888 /* fprintf(stderr, "OK\n"); */
894 check_name_arg(const char *pred
, const char *arg
)
896 if (strchr(arg
, '/'))
898 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'."),
901 return true; /* allow it anyway */
907 parse_iname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
909 struct predicate
*our_pred
;
911 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
913 if (!check_name_arg("-iname", argv
[*arg_ptr
]))
916 fnmatch_sanitycheck();
918 our_pred
= insert_primary (entry
);
919 our_pred
->need_stat
= our_pred
->need_type
= false;
920 our_pred
->args
.str
= argv
[*arg_ptr
];
926 parse_inum (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
928 return insert_num (argv
, arg_ptr
, entry
);
931 /* -ipath is deprecated (at RMS's request) in favour of
932 * -iwholename. See the node "GNU Manuals" in standards.texi
933 * for the rationale for this (basically, GNU prefers the use
934 * of the phrase "file name" to "path name"
937 parse_ipath (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
940 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
942 return parse_iwholename(entry
, argv
, arg_ptr
);
946 parse_iwholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
948 struct predicate
*our_pred
;
950 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
953 fnmatch_sanitycheck();
955 our_pred
= insert_primary_withpred (entry
, pred_ipath
);
956 our_pred
->need_stat
= our_pred
->need_type
= false;
957 our_pred
->args
.str
= argv
[*arg_ptr
];
963 parse_iregex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
965 return insert_regex (argv
, arg_ptr
, entry
, RE_ICASE
|options
.regex_options
);
969 parse_links (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
971 return insert_num (argv
, arg_ptr
, entry
);
975 parse_lname (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
977 struct predicate
*our_pred
;
982 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
985 fnmatch_sanitycheck();
987 our_pred
= insert_primary (entry
);
988 our_pred
->args
.str
= argv
[*arg_ptr
];
994 parse_ls (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
996 struct predicate
*our_pred
;
1001 our_pred
= insert_primary (entry
);
1002 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1007 parse_maxdepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1012 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1014 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1015 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1017 options
.maxdepth
= atoi (argv
[*arg_ptr
]);
1018 if (options
.maxdepth
< 0)
1025 parse_mindepth (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1030 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1032 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
1033 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
1035 options
.mindepth
= atoi (argv
[*arg_ptr
]);
1036 if (options
.mindepth
< 0)
1043 parse_mmin (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1045 struct predicate
*our_pred
;
1047 enum comparison_type c_type
;
1050 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1052 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
1054 t
= options
.cur_day_start
+ DAYSECS
- num
* 60;
1055 our_pred
= insert_primary (entry
);
1056 our_pred
->args
.info
.kind
= c_type
;
1057 our_pred
->args
.info
.negative
= t
< 0;
1058 our_pred
->args
.info
.l_val
= t
;
1064 parse_mtime (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1066 return insert_time (argv
, arg_ptr
, entry
, pred_mtime
);
1070 parse_name (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1072 struct predicate
*our_pred
;
1077 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1079 if (!check_name_arg("-name", argv
[*arg_ptr
]))
1081 fnmatch_sanitycheck();
1083 our_pred
= insert_primary (entry
);
1084 our_pred
->need_stat
= our_pred
->need_type
= false;
1085 our_pred
->args
.str
= argv
[*arg_ptr
];
1091 parse_negate (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1093 struct predicate
*our_pred
;
1098 our_pred
= get_new_pred_chk_op (entry
);
1099 our_pred
->pred_func
= pred_negate
;
1101 our_pred
->p_name
= find_pred_name (pred_negate
);
1103 our_pred
->p_type
= UNI_OP
;
1104 our_pred
->p_prec
= NEGATE_PREC
;
1105 our_pred
->need_stat
= our_pred
->need_type
= false;
1110 parse_newer (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1112 struct predicate
*our_pred
;
1113 struct stat stat_newer
;
1118 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1120 if ((*options
.xstat
) (argv
[*arg_ptr
], &stat_newer
))
1121 error (1, errno
, "%s", argv
[*arg_ptr
]);
1122 our_pred
= insert_primary (entry
);
1123 our_pred
->args
.time
= stat_newer
.st_mtime
;
1129 parse_noleaf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1135 options
.no_leaf_check
= true;
1140 /* Arbitrary amount by which to increase size
1141 of `uid_unused' and `gid_unused'. */
1142 #define ALLOC_STEP 2048
1144 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1145 char *uid_unused
= NULL
;
1147 /* Number of elements in `uid_unused'. */
1148 unsigned uid_allocated
;
1150 /* Similar for GIDs and group entries. */
1151 char *gid_unused
= NULL
;
1152 unsigned gid_allocated
;
1156 parse_nogroup (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1158 struct predicate
*our_pred
;
1163 our_pred
= insert_primary (entry
);
1165 if (gid_unused
== NULL
)
1169 gid_allocated
= ALLOC_STEP
;
1170 gid_unused
= xmalloc (gid_allocated
);
1171 memset (gid_unused
, 1, gid_allocated
);
1173 while ((gr
= getgrent ()) != NULL
)
1175 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1177 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1178 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1179 memset (gid_unused
+ gid_allocated
, 1,
1180 new_allocated
- gid_allocated
);
1181 gid_allocated
= new_allocated
;
1183 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1192 parse_nouser (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1194 struct predicate
*our_pred
;
1199 our_pred
= insert_primary (entry
);
1201 if (uid_unused
== NULL
)
1205 uid_allocated
= ALLOC_STEP
;
1206 uid_unused
= xmalloc (uid_allocated
);
1207 memset (uid_unused
, 1, uid_allocated
);
1209 while ((pw
= getpwent ()) != NULL
)
1211 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1213 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1214 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1215 memset (uid_unused
+ uid_allocated
, 1,
1216 new_allocated
- uid_allocated
);
1217 uid_allocated
= new_allocated
;
1219 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1228 parse_nowarn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1234 options
.warnings
= false;
1239 parse_ok (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1241 return insert_exec_ok ("-ok", entry
, argv
, arg_ptr
);
1245 parse_okdir (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1247 return insert_exec_ok ("-okdir", entry
, argv
, arg_ptr
);
1251 parse_open (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1253 struct predicate
*our_pred
;
1258 our_pred
= get_new_pred_chk_op (entry
);
1259 our_pred
->pred_func
= pred_open
;
1261 our_pred
->p_name
= find_pred_name (pred_open
);
1263 our_pred
->p_type
= OPEN_PAREN
;
1264 our_pred
->p_prec
= NO_PREC
;
1265 our_pred
->need_stat
= our_pred
->need_type
= false;
1270 parse_or (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1272 struct predicate
*our_pred
;
1277 our_pred
= get_new_pred (entry
);
1278 our_pred
->pred_func
= pred_or
;
1280 our_pred
->p_name
= find_pred_name (pred_or
);
1282 our_pred
->p_type
= BI_OP
;
1283 our_pred
->p_prec
= OR_PREC
;
1284 our_pred
->need_stat
= our_pred
->need_type
= false;
1288 /* -path is deprecated (at RMS's request) in favour of
1289 * -iwholename. See the node "GNU Manuals" in standards.texi
1290 * for the rationale for this (basically, GNU prefers the use
1291 * of the phrase "file name" to "path name".
1293 * We do not issue a warning that this usage is deprecated
1294 * since HPUX find supports this predicate also.
1297 parse_path (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1299 return parse_wholename(entry
, argv
, arg_ptr
);
1303 parse_wholename (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1305 struct predicate
*our_pred
;
1307 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1309 our_pred
= insert_primary_withpred (entry
, pred_path
);
1310 our_pred
->need_stat
= our_pred
->need_type
= false;
1311 our_pred
->args
.str
= argv
[*arg_ptr
];
1317 parse_perm (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1321 boolean havekind
= false;
1322 enum permissions_type kind
= PERM_EXACT
;
1323 struct mode_change
*change
= NULL
;
1324 struct predicate
*our_pred
;
1326 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1329 switch (argv
[*arg_ptr
][0])
1333 kind
= PERM_AT_LEAST
;
1338 change
= mode_compile (argv
[*arg_ptr
]);
1341 /* Most likely the caller is an old script that is still
1342 * using the obsolete GNU syntax '-perm +MODE'. This old
1343 * syntax was withdrawn in favor of '-perm /MODE' because
1344 * it is incompatible with POSIX in some cases, but we
1345 * still support uses of it that are not incompatible with
1353 /* This is a POSIX-compatible usage */
1360 case '/': /* GNU extension */
1367 /* For example, '-perm 0644', which is valid and matches
1368 * only files whose mode is exactly 0644.
1370 * We do nothing here, because mode_start and kind are already
1378 change
= mode_compile (argv
[*arg_ptr
] + mode_start
);
1380 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1382 perm_val
= mode_adjust (0, change
, 0);
1385 our_pred
= insert_primary (entry
);
1389 our_pred
->args
.perm
.kind
= kind
;
1394 switch (argv
[*arg_ptr
][0])
1397 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1400 our_pred
->args
.perm
.kind
= PERM_ANY
;
1403 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1407 if (('/' == argv
[*arg_ptr
][0]) && (0 == perm_val
))
1409 /* The meaning of -perm /000 will change in the future.
1410 * It currently matches no files, but like -perm -000 it
1411 * should match all files.
1414 _("warning: you have specified a mode pattern %s which is "
1415 "equivalent to 000. The meaning of -perm /000 will soon be "
1416 "changed to be consistent with -perm -000; that is, at the "
1417 "moment it matches no files but it will soon be changed to "
1418 "match all files."),
1422 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1428 parse_print (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1430 struct predicate
*our_pred
;
1435 our_pred
= insert_primary (entry
);
1436 /* -print has the side effect of printing. This prevents us
1437 from doing undesired multiple printing when the user has
1438 already specified -print. */
1439 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1440 our_pred
->need_stat
= our_pred
->need_type
= false;
1441 our_pred
->args
.printf_vec
.segment
= NULL
;
1442 our_pred
->args
.printf_vec
.stream
= stdout
;
1443 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(stdout
);
1444 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
1450 parse_print0 (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1452 struct predicate
*our_pred
;
1457 our_pred
= insert_primary (entry
);
1458 /* -print0 has the side effect of printing. This prevents us
1459 from doing undesired multiple printing when the user has
1460 already specified -print0. */
1461 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1462 our_pred
->need_stat
= our_pred
->need_type
= false;
1467 parse_printf (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1469 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1471 return insert_fprintf (stdout
, entry
, pred_fprintf
, argv
, arg_ptr
);
1475 parse_prune (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1477 struct predicate
*our_pred
;
1482 our_pred
= insert_primary (entry
);
1483 our_pred
->need_stat
= our_pred
->need_type
= false;
1484 /* -prune has a side effect that it does not descend into
1485 the current directory. */
1486 our_pred
->side_effects
= true;
1487 our_pred
->no_default_print
= false;
1492 parse_quit (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1494 struct predicate
*our_pred
= insert_primary (entry
);
1497 our_pred
->need_stat
= our_pred
->need_type
= false;
1498 our_pred
->side_effects
= true; /* Exiting is a side effect... */
1499 our_pred
->no_default_print
= false; /* Don't inhibit the default print, though. */
1505 parse_regextype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1507 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1510 /* collect the regex type name */
1511 options
.regex_options
= get_regex_type(argv
[*arg_ptr
]);
1519 parse_regex (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1521 return insert_regex (argv
, arg_ptr
, entry
, options
.regex_options
);
1525 insert_regex (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, int regex_options
)
1527 struct predicate
*our_pred
;
1528 struct re_pattern_buffer
*re
;
1529 const char *error_message
;
1531 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1533 our_pred
= insert_primary_withpred (entry
, pred_regex
);
1534 our_pred
->need_stat
= our_pred
->need_type
= false;
1535 re
= (struct re_pattern_buffer
*)
1536 xmalloc (sizeof (struct re_pattern_buffer
));
1537 our_pred
->args
.regex
= re
;
1538 re
->allocated
= 100;
1539 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1542 re_set_syntax(regex_options
);
1543 re
->syntax
= regex_options
;
1544 re
->translate
= NULL
;
1546 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1549 error (1, 0, "%s", error_message
);
1555 parse_size (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1557 struct predicate
*our_pred
;
1559 enum comparison_type c_type
;
1563 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1565 len
= strlen (argv
[*arg_ptr
]);
1567 error (1, 0, _("invalid null argument to -size"));
1568 switch (argv
[*arg_ptr
][len
- 1])
1572 argv
[*arg_ptr
][len
- 1] = '\0';
1577 argv
[*arg_ptr
][len
- 1] = '\0';
1582 argv
[*arg_ptr
][len
- 1] = '\0';
1585 case 'M': /* Megabytes */
1586 blksize
= 1024*1024;
1587 argv
[*arg_ptr
][len
- 1] = '\0';
1590 case 'G': /* Gigabytes */
1591 blksize
= 1024*1024*1024;
1592 argv
[*arg_ptr
][len
- 1] = '\0';
1597 argv
[*arg_ptr
][len
- 1] = '\0';
1613 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1615 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1617 our_pred
= insert_primary (entry
);
1618 our_pred
->args
.size
.kind
= c_type
;
1619 our_pred
->args
.size
.blocksize
= blksize
;
1620 our_pred
->args
.size
.size
= num
;
1627 parse_samefile (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1629 struct predicate
*our_pred
;
1632 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1634 if ((*options
.xstat
) (argv
[*arg_ptr
], &st
))
1635 error (1, errno
, "%s", argv
[*arg_ptr
]);
1637 our_pred
= insert_primary (entry
);
1638 our_pred
->args
.fileid
.ino
= st
.st_ino
;
1639 our_pred
->args
.fileid
.dev
= st
.st_dev
;
1640 our_pred
->need_type
= false;
1641 our_pred
->need_stat
= true;
1648 parse_show_control_chars (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1651 const char *errmsg
= _("The -show-control-chars option takes a single argument which "
1652 "must be 'literal' or 'safe'");
1654 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1656 error (1, errno
, "%s", errmsg
);
1661 arg
= argv
[*arg_ptr
];
1663 if (0 == strcmp("literal", arg
))
1665 options
.literal_control_chars
= true;
1667 else if (0 == strcmp("safe", arg
))
1669 options
.literal_control_chars
= false;
1673 error (1, errno
, "%s", errmsg
);
1676 (*arg_ptr
)++; /* consume the argument. */
1684 parse_true (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1686 struct predicate
*our_pred
;
1691 our_pred
= insert_primary (entry
);
1692 our_pred
->need_stat
= our_pred
->need_type
= false;
1697 insert_accesscheck (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1699 struct predicate
*our_pred
;
1702 our_pred
= insert_primary (entry
);
1703 our_pred
->need_stat
= our_pred
->need_type
= false;
1704 our_pred
->side_effects
= our_pred
->no_default_print
= false;
1709 parse_executable (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1711 return insert_accesscheck(entry
, argv
, arg_ptr
);
1715 parse_readable (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1717 return insert_accesscheck(entry
, argv
, arg_ptr
);
1721 parse_writable (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1723 return insert_accesscheck(entry
, argv
, arg_ptr
);
1727 parse_type (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1729 return insert_type (argv
, arg_ptr
, entry
, pred_type
);
1733 parse_uid (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1735 return insert_num (argv
, arg_ptr
, entry
);
1739 parse_used (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1741 struct predicate
*our_pred
;
1743 enum comparison_type c_type
;
1746 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1748 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1750 t
= num_days
* DAYSECS
;
1751 our_pred
= insert_primary (entry
);
1752 our_pred
->args
.info
.kind
= c_type
;
1753 our_pred
->args
.info
.negative
= t
< 0;
1754 our_pred
->args
.info
.l_val
= t
;
1760 parse_user (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1762 struct passwd
*cur_pwd
;
1763 struct predicate
*our_pred
;
1767 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1769 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1771 if (cur_pwd
!= NULL
)
1772 uid
= cur_pwd
->pw_uid
;
1775 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1776 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1778 uid
= atoi (argv
[*arg_ptr
]);
1780 our_pred
= insert_primary (entry
);
1781 our_pred
->args
.uid
= uid
;
1787 parse_version (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1789 extern char *version_string
;
1797 printf (_("GNU find version %s\n"), version_string
);
1798 printf (_("Features enabled: "));
1801 printf("CACHE_IDS ");
1809 printf("DEBUG_STAT ");
1812 #if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
1816 #if defined(O_NOFOLLOW)
1817 printf("O_NOFOLLOW(%s) ",
1818 (options
.open_nofollow_available
? "enabled" : "disabled"));
1821 #if defined(LEAF_OPTIMISATION)
1822 printf("LEAF_OPTIMISATION ");
1826 if (is_fts_enabled())
1834 /* For the moment, leave this as English in case someone wants
1835 to parse these strings. */
1844 parse_xdev (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1849 options
.stay_on_filesystem
= true;
1854 parse_ignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1859 options
.ignore_readdir_race
= true;
1864 parse_noignore_race (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1869 options
.ignore_readdir_race
= false;
1874 parse_warn (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1879 options
.warnings
= true;
1884 parse_xtype (const struct parser_table
* entry
, char **argv
, int *arg_ptr
)
1888 return insert_type (argv
, arg_ptr
, entry
, pred_xtype
);
1892 insert_type (char **argv
, int *arg_ptr
, const struct parser_table
*entry
, PRED_FUNC which_pred
)
1895 struct predicate
*our_pred
;
1897 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1898 || (strlen (argv
[*arg_ptr
]) != 1))
1900 switch (argv
[*arg_ptr
][0])
1902 case 'b': /* block special */
1903 type_cell
= S_IFBLK
;
1905 case 'c': /* character special */
1906 type_cell
= S_IFCHR
;
1908 case 'd': /* directory */
1909 type_cell
= S_IFDIR
;
1911 case 'f': /* regular file */
1912 type_cell
= S_IFREG
;
1915 case 'l': /* symbolic link */
1916 type_cell
= S_IFLNK
;
1920 case 'p': /* pipe */
1921 type_cell
= S_IFIFO
;
1925 case 's': /* socket */
1926 type_cell
= S_IFSOCK
;
1930 case 'D': /* Solaris door */
1931 type_cell
= S_IFDOOR
;
1934 default: /* None of the above ... nuke 'em. */
1937 our_pred
= insert_primary_withpred (entry
, which_pred
);
1939 /* Figure out if we will need to stat the file, because if we don't
1940 * need to follow symlinks, we can avoid a stat call by using
1941 * struct dirent.d_type.
1943 if (which_pred
== pred_xtype
)
1945 our_pred
->need_stat
= true;
1946 our_pred
->need_type
= false;
1950 our_pred
->need_stat
= false; /* struct dirent is enough */
1951 our_pred
->need_type
= true;
1953 our_pred
->args
.type
= type_cell
;
1954 (*arg_ptr
)++; /* Move on to next argument. */
1959 /* Return true if the file accessed via FP is a terminal.
1962 stream_is_tty(FILE *fp
)
1964 int fd
= fileno(fp
);
1967 return false; /* not a valid stream */
1971 return isatty(fd
) ? true : false;
1978 /* If true, we've determined that the current fprintf predicate
1979 uses stat information. */
1980 static boolean fprintf_stat_needed
;
1982 /* XXX: do we need to pass FUNC to this function? */
1984 insert_fprintf (FILE *fp
, const struct parser_table
*entry
, PRED_FUNC func
, char **argv
, int *arg_ptr
)
1986 char *format
; /* Beginning of unprocessed format string. */
1987 register char *scan
; /* Current address in scanning `format'. */
1988 register char *scan2
; /* Address inside of element being scanned. */
1989 struct segment
**segmentp
; /* Address of current segment. */
1990 struct predicate
*our_pred
;
1992 format
= argv
[(*arg_ptr
)++];
1994 fprintf_stat_needed
= false; /* Might be overridden later. */
1995 our_pred
= insert_primary_withpred (entry
, func
);
1996 our_pred
->side_effects
= our_pred
->no_default_print
= true;
1997 our_pred
->args
.printf_vec
.stream
= fp
;
1998 our_pred
->args
.printf_vec
.dest_is_tty
= stream_is_tty(fp
);
1999 our_pred
->args
.printf_vec
.quote_opts
= clone_quoting_options (NULL
);
2000 segmentp
= &our_pred
->args
.printf_vec
.segment
;
2003 for (scan
= format
; *scan
; scan
++)
2008 if (*scan2
>= '0' && *scan2
<= '7')
2012 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
2014 n
= 8 * n
+ *scan2
- '0';
2029 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
2030 our_pred
->need_stat
= fprintf_stat_needed
;
2048 /* *scan = '\\'; * it already is */
2052 _("warning: unrecognized escape `\\%c'"), *scan2
);
2057 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2059 format
= scan2
+ 1; /* Move past the escape. */
2060 scan
= scan2
; /* Incremented immediately by `for'. */
2062 else if (*scan
== '%')
2066 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
2072 /* Scan past flags, width and precision, to verify kind. */
2073 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
2075 while (ISDIGIT (*scan2
))
2078 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
2080 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2
))
2082 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2087 else if (strchr ("ACT", *scan2
) && scan2
[1])
2089 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
2090 *scan2
| (scan2
[1] << 8));
2097 /* An unrecognized % escape. Print the char after the %. */
2098 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
2100 segmentp
= make_segment (segmentp
, format
, scan
- format
,
2109 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
2110 our_pred
->need_type
= false;
2111 our_pred
->need_stat
= fprintf_stat_needed
;
2115 /* Create a new fprintf segment in *SEGMENT, with type KIND,
2116 from the text in FORMAT, which has length LEN.
2117 Return the address of the `next' pointer of the new segment. */
2119 static struct segment
**
2120 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
2124 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
2126 (*segment
)->kind
= kind
;
2127 (*segment
)->next
= NULL
;
2128 (*segment
)->text_len
= len
;
2130 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
2131 strncpy (fmt
, format
, len
);
2134 switch (kind
& 0xff)
2136 case KIND_PLAIN
: /* Plain text string, no % conversion. */
2137 case KIND_STOP
: /* Terminate argument, no newline. */
2140 case 'a': /* atime in `ctime' format */
2141 case 'A': /* atime in user-specified strftime format */
2142 case 'c': /* ctime in `ctime' format */
2143 case 'C': /* ctime in user-specified strftime format */
2144 case 'F': /* filesystem type */
2145 case 'g': /* group name */
2146 case 'i': /* inode number */
2147 case 'l': /* object of symlink */
2148 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
2149 case 's': /* size in bytes */
2150 case 't': /* mtime in `ctime' format */
2151 case 'T': /* mtime in user-specified strftime format */
2152 case 'u': /* user name */
2153 case 'y': /* file type */
2154 case 'Y': /* symlink pointed file type */
2155 fprintf_stat_needed
= true;
2157 case 'f': /* basename of path */
2158 case 'h': /* leading directories part of path */
2159 case 'H': /* ARGV element file was found under */
2160 case 'p': /* pathname */
2161 case 'P': /* pathname with ARGV element stripped */
2165 /* Numeric items that one might expect to honour
2166 * #, 0, + flags but which do not.
2168 case 'G': /* GID number */
2169 case 'U': /* UID number */
2170 case 'b': /* size in 512-byte blocks */
2171 case 'D': /* Filesystem device on which the file exits */
2172 case 'k': /* size in 1K blocks */
2173 case 'n': /* number of links */
2174 fprintf_stat_needed
= true;
2178 /* Numeric items that DO honour #, 0, + flags.
2180 case 'd': /* depth in search tree (0 = ARGV element) */
2184 case 'm': /* mode as octal number (perms only) */
2186 fprintf_stat_needed
= true;
2191 return &(*segment
)->next
;
2195 check_path_safety(const char *action
)
2197 const char *path
= getenv("PATH");
2199 s
= next_element(path
, 1);
2200 while ((s
= next_element ((char *) NULL
, 1)) != NULL
)
2202 if (0 == strcmp(s
, "."))
2204 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)"),
2211 /* handles both exec and ok predicate */
2212 #if defined(NEW_EXEC)
2213 /* handles both exec and ok predicate */
2215 new_insert_exec_ok (const char *action
,
2216 const struct parser_table
*entry
,
2220 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2221 int i
; /* Index into cmd args */
2222 int saw_braces
; /* True if previous arg was '{}'. */
2223 boolean allow_plus
; /* True if + is a valid terminator */
2224 int brace_count
; /* Number of instances of {}. */
2225 PRED_FUNC func
= entry
->pred_func
;
2227 struct predicate
*our_pred
;
2228 struct exec_val
*execp
; /* Pointer for efficiency. */
2230 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2233 our_pred
= insert_primary_withpred (entry
, func
);
2234 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2235 execp
= &our_pred
->args
.exec_vec
;
2237 if ((func
!= pred_okdir
) && (func
!= pred_ok
))
2240 execp
->close_stdin
= false;
2245 /* If find reads stdin (i.e. for -ok and similar), close stdin
2246 * in the child to prevent some script from consiming the output
2247 * intended for find.
2249 execp
->close_stdin
= true;
2253 if ((func
== pred_execdir
) || (func
== pred_okdir
))
2255 options
.ignore_readdir_race
= false;
2256 check_path_safety(action
);
2257 execp
->use_current_dir
= true;
2261 execp
->use_current_dir
= false;
2264 our_pred
->args
.exec_vec
.multiple
= 0;
2266 /* Count the number of args with path replacements, up until the ';'.
2267 * Also figure out if the command is terminated by ";" or by "+".
2270 for (end
= start
, saw_braces
=0, brace_count
=0;
2272 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2275 /* For -exec and -execdir, "{} +" can terminate the command. */
2277 && argv
[end
][0] == '+' && argv
[end
][1] == 0
2280 our_pred
->args
.exec_vec
.multiple
= 1;
2285 if (strstr (argv
[end
], "{}"))
2290 if (0 == end
&& (func
== pred_execdir
|| func
== pred_okdir
))
2292 /* The POSIX standard says that {} replacement should
2293 * occur even in the utility name. This is insecure
2294 * since it means we will be executing a command whose
2295 * name is chosen according to whatever find finds in
2296 * the filesystem. That can be influenced by an
2297 * attacker. Hence for -execdir and -okdir this is not
2298 * allowed. We can specify this as those options are
2299 * not defined by POSIX.
2301 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
2306 /* Fail if no command given or no semicolon found. */
2307 if ((end
== start
) || (argv
[end
] == NULL
))
2314 if (our_pred
->args
.exec_vec
.multiple
&& brace_count
> 1)
2318 if (func
== pred_execdir
)
2324 _("Only one instance of {} is supported with -exec%s ... +"),
2328 /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */
2329 bc_init_controlinfo(&execp
->ctl
);
2330 execp
->ctl
.exec_callback
= launch
;
2332 if (our_pred
->args
.exec_vec
.multiple
)
2334 /* "+" terminator, so we can just append our arguments after the
2335 * command and initial arguments.
2337 execp
->replace_vec
= NULL
;
2338 execp
->ctl
.replace_pat
= NULL
;
2339 execp
->ctl
.rplen
= 0;
2340 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2341 execp
->ctl
.args_per_exec
= 0; /* no limit */
2343 /* remember how many arguments there are */
2344 execp
->ctl
.initial_argc
= (end
-start
) - 1;
2346 /* execp->state = xmalloc(sizeof struct buildcmd_state); */
2347 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2349 /* Gather the initial arguments. Skip the {}. */
2350 for (i
=start
; i
<end
-1; ++i
)
2352 bc_push_arg(&execp
->ctl
, &execp
->state
,
2353 argv
[i
], strlen(argv
[i
])+1,
2360 /* Semicolon terminator - more than one {} is supported, so we
2361 * have to do brace-replacement.
2363 execp
->num_args
= end
- start
;
2365 execp
->ctl
.replace_pat
= "{}";
2366 execp
->ctl
.rplen
= strlen(execp
->ctl
.replace_pat
);
2367 execp
->ctl
.lines_per_exec
= 0; /* no limit */
2368 execp
->ctl
.args_per_exec
= 0; /* no limit */
2369 execp
->replace_vec
= xmalloc(sizeof(char*)*execp
->num_args
);
2372 /* execp->state = xmalloc(sizeof(*(execp->state))); */
2373 bc_init_state(&execp
->ctl
, &execp
->state
, execp
);
2375 /* Remember the (pre-replacement) arguments for later. */
2376 for (i
=0; i
<execp
->num_args
; ++i
)
2378 execp
->replace_vec
[i
] = argv
[i
+start
];
2382 if (argv
[end
] == NULL
)
2390 /* handles both exec and ok predicate */
2392 old_insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
2394 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
2395 int num_paths
; /* Number of args with path replacements. */
2396 int path_pos
; /* Index in array of path replacements. */
2397 int vec_pos
; /* Index in array of args. */
2398 struct predicate
*our_pred
;
2399 struct exec_val
*execp
; /* Pointer for efficiency. */
2401 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2404 /* Count the number of args with path replacements, up until the ';'. */
2406 for (end
= start
, num_paths
= 0;
2408 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2410 if (strstr (argv
[end
], "{}"))
2412 /* Fail if no command given or no semicolon found. */
2413 if ((end
== start
) || (argv
[end
] == NULL
))
2419 our_pred
= insert_primary (func
);
2420 our_pred
->side_effects
= our_pred
->no_default_print
= true;
2421 execp
= &our_pred
->args
.exec_vec
;
2422 execp
->usercontext
= our_pred
;
2423 execp
->use_current_dir
= false;
2425 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
2426 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
2427 /* Record the positions of all args, and the args with path replacements. */
2428 for (end
= start
, path_pos
= vec_pos
= 0;
2430 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
2435 execp
->paths
[path_pos
].count
= 0;
2436 for (p
= argv
[end
]; *p
; ++p
)
2437 if (p
[0] == '{' && p
[1] == '}')
2439 execp
->paths
[path_pos
].count
++;
2442 if (execp
->paths
[path_pos
].count
)
2444 execp
->paths
[path_pos
].offset
= vec_pos
;
2445 execp
->paths
[path_pos
].origarg
= argv
[end
];
2448 execp
->vec
[vec_pos
++] = argv
[end
];
2450 execp
->paths
[path_pos
].offset
= -1;
2451 execp
->vec
[vec_pos
] = NULL
;
2453 if (argv
[end
] == NULL
)
2464 insert_exec_ok (const char *action
, const struct parser_table
*entry
, char **argv
, int *arg_ptr
)
2466 #if defined(NEW_EXEC)
2467 return new_insert_exec_ok(action
, entry
, argv
, arg_ptr
);
2469 return old_insert_exec_ok(func
, argv
, arg_ptr
);
2475 /* Get a number of days and comparison type.
2476 STR is the ASCII representation.
2477 Set *NUM_DAYS to the number of days, taken as being from
2478 the current moment (or possibly midnight). Thus the sense of the
2479 comparison type appears to be reversed.
2480 Set *COMP_TYPE to the kind of comparison that is requested.
2482 Return true if all okay, false if input error.
2484 Used by -atime, -ctime and -mtime (parsers) to
2485 get the appropriate information for a time predicate processor. */
2488 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
2490 boolean r
= get_num (str
, num_days
, comp_type
);
2494 case COMP_LT
: *comp_type
= COMP_GT
; break;
2495 case COMP_GT
: *comp_type
= COMP_LT
; break;
2501 /* Insert a time predicate PRED.
2502 ARGV is a pointer to the argument array.
2503 ARG_PTR is a pointer to an index into the array, incremented if
2506 Return true if input is valid, false if not.
2508 A new predicate node is assigned, along with an argument node
2509 obtained with malloc.
2511 Used by -atime, -ctime, and -mtime parsers. */
2514 insert_time (char **argv
, int *arg_ptr
, const struct parser_table
* entry
, PRED_FUNC pred
)
2516 struct predicate
*our_pred
;
2518 enum comparison_type c_type
;
2521 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2523 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
2526 /* Figure out the timestamp value we are looking for. */
2527 t
= ( options
.cur_day_start
- num_days
* DAYSECS
2528 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2532 /* We introduce a scope in which 'val' can be declared, for the
2533 * benefit of compilers that are really C89 compilers
2534 * which support intmax_t because config.h #defines it
2536 intmax_t val
= ( (intmax_t)options
.cur_day_start
- num_days
* DAYSECS
2537 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
2540 /* Check for possibility of an overflow */
2541 if ( (intmax_t)t
!= val
)
2543 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
2547 our_pred
= insert_primary_withpred (entry
, pred
);
2548 our_pred
->args
.info
.kind
= c_type
;
2549 our_pred
->args
.info
.negative
= t
< 0;
2550 our_pred
->args
.info
.l_val
= t
;
2553 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2554 fprintf (stderr
, " type: %s %s ",
2555 (c_type
== COMP_GT
) ? "gt" :
2556 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2557 (c_type
== COMP_GT
) ? " >" :
2558 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
2559 t
= our_pred
->args
.info
.l_val
;
2560 fprintf (stderr
, "%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2561 if (c_type
== COMP_EQ
)
2563 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
2564 fprintf (stderr
, " < %ju %s",
2565 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
2566 our_pred
->args
.info
.l_val
-= DAYSECS
;
2572 /* Get a number with comparison information.
2573 The sense of the comparison information is 'normal'; that is,
2574 '+' looks for a count > than the number and '-' less than.
2576 STR is the ASCII representation of the number.
2577 Set *NUM to the number.
2578 Set *COMP_TYPE to the kind of comparison that is requested.
2580 Return true if all okay, false if input error. */
2583 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
2590 *comp_type
= COMP_GT
;
2594 *comp_type
= COMP_LT
;
2598 *comp_type
= COMP_EQ
;
2602 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
2605 /* Insert a number predicate.
2606 ARGV is a pointer to the argument array.
2607 *ARG_PTR is an index into ARGV, incremented if all went well.
2608 *PRED is the predicate processor to insert.
2610 Return true if input is valid, false if error.
2612 A new predicate node is assigned, along with an argument node
2613 obtained with malloc.
2615 Used by -inum and -links parsers. */
2618 insert_num (char **argv
, int *arg_ptr
, const struct parser_table
*entry
)
2620 struct predicate
*our_pred
;
2622 enum comparison_type c_type
;
2624 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2626 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2628 our_pred
= insert_primary (entry
);
2629 our_pred
->args
.info
.kind
= c_type
;
2630 our_pred
->args
.info
.l_val
= num
;
2633 fprintf (stderr
, "inserting %s\n", our_pred
->p_name
);
2634 fprintf (stderr
, " type: %s %s ",
2635 (c_type
== COMP_GT
) ? "gt" :
2636 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2637 (c_type
== COMP_GT
) ? " >" :
2638 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2639 fprintf (stderr
, "%ju\n", our_pred
->args
.info
.l_val
);
2645 open_output_file (char *path
)
2649 if (!strcmp (path
, "/dev/stderr"))
2651 else if (!strcmp (path
, "/dev/stdout"))
2653 f
= fopen_safer (path
, "w");
2655 error (1, errno
, "%s", path
);