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