summaryrefslogtreecommitdiff
path: root/find/defs.h
blob: 860069056d7fb51abee55318d1237bd248552910 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
/* defs.h -- data types and declarations.
   Copyright (C) 1990-2022 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/


#ifndef INC_DEFS_H
# define INC_DEFS_H 1

# if !defined ALREADY_INCLUDED_CONFIG_H
/*
 * Savannah bug #20128: if we include some system header and it
 * includes some other second system header, the second system header
 * may in fact turn out to be a file provided by gnulib.  For that
 * situation, we need to have already included <config.h> so that the
 * Gnulib files have access to the information probed by their
 * configure script fragments.  So <config.h> should be the first
 * thing included.
 */
#  error "<config.h> should be #included before defs.h, and indeed before any other header"
Please stop compiling the program now
# endif


# include <sys/types.h>

/* XXX: some of these includes probably don't belong in a common header file */
# include <sys/stat.h>
# include <stdio.h>		/* for FILE* */
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <time.h>
# include <limits.h>		/* for CHAR_BIT */
# include <stdbool.h>		/* for bool */
# include <stdint.h>		/* for uintmax_t */
# include <sys/stat.h> /* S_ISUID etc. */
# include <selinux/selinux.h>



# ifndef CHAR_BIT
#  define CHAR_BIT 8
# endif

# include <inttypes.h>

# include "regex.h"
# include "timespec.h"
# include "buildcmd.h"
# include "quotearg.h"
# include "sharefile.h"
# include "gcc-function-attributes.h"

int optionl_stat (const char *name, struct stat *p);
int optionp_stat (const char *name, struct stat *p);
int optionh_stat (const char *name, struct stat *p);
int debug_stat   (const char *file, struct stat *bufp);

void set_stat_placeholders (struct stat *p);
int get_statinfo (const char *pathname, const char *name, struct stat *p);


# define MODE_WXUSR	(S_IWUSR | S_IXUSR)
# define MODE_R		(S_IRUSR | S_IRGRP | S_IROTH)
# define MODE_RW		(S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
# define MODE_RWX	(S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
# define MODE_ALL	(S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)


struct predicate;
struct options;

/* Pointer to a predicate function. */
typedef bool (*PRED_FUNC)(const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr);

/* The number of seconds in a day. */
# define DAYSECS	    86400

/* Argument structures for predicates. */

enum comparison_type
{
  COMP_GT,
  COMP_LT,
  COMP_EQ
};

enum permissions_type
{
  PERM_AT_LEAST,
  PERM_ANY,
  PERM_EXACT
};

enum predicate_type
{
  NO_TYPE,
  PRIMARY_TYPE,
  UNI_OP,
  BI_OP,
  OPEN_PAREN,
  CLOSE_PAREN
};

enum predicate_precedence
{
  NO_PREC,
  COMMA_PREC,
  OR_PREC,
  AND_PREC,
  NEGATE_PREC,
  MAX_PREC
};

struct long_val
{
  enum comparison_type kind;
  bool negative;	 /* Defined only when representing time_t.  */
  uintmax_t l_val;
};

struct perm_val
{
  enum permissions_type kind;
  mode_t val[2];
};

/* samefile_file_id is used to support the -samefile test.
 */
struct samefile_file_id
{
  ino_t ino;
  dev_t dev;
  int   fd;
};

struct size_val
{
  enum comparison_type kind;
  int blocksize;
  uintmax_t size;
};

/* Supported file types for the -type/-xtype options.  */
enum file_type
  {
    FTYPE_BLK,
    FTYPE_CHR,
    FTYPE_DIR,
    FTYPE_REG,
# ifdef S_IFLNK
    FTYPE_LNK,
# endif
# ifdef S_IFIFO
    FTYPE_FIFO,
# endif
# ifdef S_IFSOCK
    FTYPE_SOCK,
# endif
# ifdef S_IFDOOR
    FTYPE_DOOR,
# endif
    FTYPE_COUNT
  };

enum xval
  {
    XVAL_ATIME, XVAL_BIRTHTIME, XVAL_CTIME, XVAL_MTIME, XVAL_TIME
  };

struct time_val
{
  enum xval            xval;
  enum comparison_type kind;
  struct timespec      ts;
};


struct exec_val
{
  bool multiple;		/* -exec {} \+ denotes multiple argument. */
  struct buildcmd_control ctl;
  struct buildcmd_state   state;
  char **replace_vec;		/* Command arguments (for ";" style) */
  int num_args;
  bool close_stdin;		/* If true, close stdin in the child. */
  struct saved_cwd *wd_for_exec; /* What directory to perform the exec in. */
  int last_child_status;	/* Status of the most recent child. */
};

/* The format string for a -printf or -fprintf is chopped into one or
   more `struct segment', linked together into a list.
   Each stretch of plain text is a segment, and
   each \c and `%' conversion is a segment. */

/* Special values for the `kind' field of `struct segment'. */
enum SegmentKind
  {
    KIND_PLAIN=0,		/* Segment containing just plain text. */
    KIND_STOP=1,		/* \c -- stop printing and flush output. */
    KIND_FORMAT,		/* Regular format */
  };

struct segment
{
  enum SegmentKind segkind;     /* KIND_FORMAT, KIND_PLAIN, KIND_STOP */
  char format_char[2];		/* Format chars if kind is KIND_FORMAT */
  char *text;			/* Plain text or `%' format string. */
  int text_len;			/* Length of `text'. */
  struct segment *next;		/* Next segment for this predicate. */
};

struct format_val
{
  struct segment *segment;	/* Linked list of segments. */
  FILE *stream;			/* Output stream to print on. */
  const char *filename;		/* We need the filename for error messages. */
  bool dest_is_tty;		/* True if the destination is a terminal. */
  struct quoting_options *quote_opts;
};

/* Profiling information for a predicate */
struct predicate_performance_info
{
  unsigned long visits;
  unsigned long successes;
};

/* evaluation cost of a predicate */
enum EvaluationCost
{
  NeedsNothing,
  NeedsInodeNumber,
  NeedsType,
  NeedsStatInfo,
  NeedsLinkName,
  NeedsAccessInfo,
  NeedsSyncDiskHit,
  NeedsEventualExec,
  NeedsImmediateExec,
  NeedsUserInteraction,
  NeedsUnknown,
  NumEvaluationCosts
};

struct predicate
{
  /* Pointer to the function that implements this predicate.  */
  PRED_FUNC pred_func;

  /* Used for debugging */
  const char *p_name;

  /* The type of this node.  There are two kinds.  The first is real
     predicates ("primaries") such as -perm, -print, or -exec.  The
     other kind is operators for combining predicates. */
  enum predicate_type p_type;

  /* The precedence of this node.  Only has meaning for operators. */
  enum predicate_precedence p_prec;

  /* True if this predicate node produces side effects.
     If side_effects are produced
     then optimization will not be performed */
  bool side_effects;

  /* True if this predicate node requires default print be turned off. */
  bool no_default_print;

  /* True if this predicate node requires a stat system call to execute. */
  bool need_stat;

  /* True if this predicate node requires knowledge of the file type. */
  bool need_type;

  /* True if this predicate node requires knowledge of the inode number. */
  bool need_inum;

  enum EvaluationCost p_cost;

  /* est_success_rate is a number between 0.0 and 1.0 */
  float est_success_rate;

  /* True if this predicate should display control characters literally */
  bool literal_control_chars;

  /* True if this predicate didn't originate from the user. */
  bool artificial;

  /* The raw text of the argument of this predicate. */
  const char *arg_text;

  /* Information needed by the predicate processor.
     Next to each member are listed the predicates that use it. */
  union
  {
    const char *str;		/* fstype [i]lname [i]name [i]path */
    struct re_pattern_buffer *regex; /* regex */
    struct exec_val exec_vec;	/* exec ok */
    struct long_val numinfo;	/* gid inum links  uid */
    struct size_val size;	/* size */
    uid_t uid;			/* user */
    gid_t gid;			/* group */
    struct time_val reftime;	/* newer newerXY anewer cnewer mtime atime ctime mmin amin cmin */
    struct perm_val perm;	/* perm */
    struct samefile_file_id samefileid; /* samefile */
    bool types[FTYPE_COUNT];	/* file type(s) */
    struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */
    char *scontext; /* security context */
  } args;

  /* The next predicate in the user input sequence,
     which represents the order in which the user supplied the
     predicates on the command line. */
  struct predicate *pred_next;

  /* The right and left branches from this node in the expression
     tree, which represents the order in which the nodes should be
     processed. */
  struct predicate *pred_left;
  struct predicate *pred_right;

  struct predicate_performance_info perf;

  const struct parser_table* parser_entry;
};

/* ftsfind.c */
bool is_fts_enabled(int *ftsoptions);

/* find library function declarations.  */

/* find global function declarations.  */

/* SymlinkOption represents the choice of
 * -P, -L or -P (default) on the command line.
 */
enum SymlinkOption
  {
    SYMLINK_NEVER_DEREF,	/* Option -P */
    SYMLINK_ALWAYS_DEREF,	/* Option -L */
    SYMLINK_DEREF_ARGSONLY	/* Option -H */
  };

void set_follow_state (enum SymlinkOption opt);
void cleanup(void);

/* fstype.c */
char *filesystem_type (const struct stat *statp, const char *path);
bool is_used_fs_type(const char *name);
dev_t * get_mounted_devices (size_t *);



enum arg_type
  {
    ARG_OPTION,			/* regular options like -maxdepth */
    ARG_NOOP,			/* does nothing, returns true, internal use only */
    ARG_POSITIONAL_OPTION,	/* options whose position is important (-follow) */
    ARG_TEST,			/* a like -name */
    ARG_SPECIAL_PARSE,		/* complex to parse, don't eat the test name before calling parse_xx(). */
    ARG_PUNCTUATION,		/* like -o or ( */
    ARG_ACTION			/* like -print */
  };


struct parser_table;
/* Pointer to a parser function. */
typedef bool (*PARSE_FUNC)(const struct parser_table *p,
			   char *argv[], int *arg_ptr);
struct parser_table
{
  enum arg_type type;
  const char *parser_name;
  PARSE_FUNC parser_func;
  PRED_FUNC    pred_func;
};

/* parser.c */
const struct parser_table* find_parser (const char *search_name);
bool parse_print (const struct parser_table*, char *argv[], int *arg_ptr);
void pred_sanity_check (const struct predicate *predicates);
void check_option_combinations (const struct predicate *p);
void parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates);
void parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates);
bool parse_openparen  (const struct parser_table* entry, char *argv[], int *arg_ptr);
bool parse_closeparen (const struct parser_table* entry, char *argv[], int *arg_ptr);

/* pred.c */

typedef bool PREDICATEFUNCTION(const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr);

PREDICATEFUNCTION pred_amin;
PREDICATEFUNCTION pred_and;
PREDICATEFUNCTION pred_anewer;
PREDICATEFUNCTION pred_atime;
PREDICATEFUNCTION pred_closeparen;
PREDICATEFUNCTION pred_cmin;
PREDICATEFUNCTION pred_cnewer;
PREDICATEFUNCTION pred_comma;
PREDICATEFUNCTION pred_ctime;
PREDICATEFUNCTION pred_delete;
PREDICATEFUNCTION pred_empty;
PREDICATEFUNCTION pred_exec;
PREDICATEFUNCTION pred_execdir;
PREDICATEFUNCTION pred_executable;
PREDICATEFUNCTION pred_false;
PREDICATEFUNCTION pred_fls;
PREDICATEFUNCTION pred_fprint;
PREDICATEFUNCTION pred_fprint0;
PREDICATEFUNCTION pred_fprintf;
PREDICATEFUNCTION pred_fstype;
PREDICATEFUNCTION pred_gid;
PREDICATEFUNCTION pred_group;
PREDICATEFUNCTION pred_ilname;
PREDICATEFUNCTION pred_iname;
PREDICATEFUNCTION pred_inum;
PREDICATEFUNCTION pred_ipath;
PREDICATEFUNCTION pred_links;
PREDICATEFUNCTION pred_lname;
PREDICATEFUNCTION pred_ls;
PREDICATEFUNCTION pred_mmin;
PREDICATEFUNCTION pred_mtime;
PREDICATEFUNCTION pred_name;
PREDICATEFUNCTION pred_negate;
PREDICATEFUNCTION pred_newer;
PREDICATEFUNCTION pred_newerXY;
PREDICATEFUNCTION pred_nogroup;
PREDICATEFUNCTION pred_nouser;
PREDICATEFUNCTION pred_ok;
PREDICATEFUNCTION pred_okdir;
PREDICATEFUNCTION pred_openparen;
PREDICATEFUNCTION pred_or;
PREDICATEFUNCTION pred_path;
PREDICATEFUNCTION pred_perm;
PREDICATEFUNCTION pred_print;
PREDICATEFUNCTION pred_print0;
PREDICATEFUNCTION pred_prune;
PREDICATEFUNCTION pred_readable;
PREDICATEFUNCTION pred_regex;
PREDICATEFUNCTION pred_samefile;
PREDICATEFUNCTION pred_size;
PREDICATEFUNCTION pred_true;
PREDICATEFUNCTION pred_type;
PREDICATEFUNCTION pred_uid;
PREDICATEFUNCTION pred_used;
PREDICATEFUNCTION pred_user;
PREDICATEFUNCTION pred_writable;
PREDICATEFUNCTION pred_xtype;
PREDICATEFUNCTION pred_context;

bool pred_quit (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
  _GL_ATTRIBUTE_NORETURN;



char *find_pred_name (PRED_FUNC pred_func);


void print_predicate (FILE *fp, const struct predicate *p);
void print_tree (FILE*, struct predicate *node, int indent);
void print_list (FILE*, struct predicate *node);
void print_optlist (FILE *fp, const struct predicate *node);
void show_success_rates(const struct predicate *node);


/* tree.c */
bool matches_start_point(const char * glob, bool foldcase);
struct predicate * build_expression_tree (int argc, char *argv[], int end_of_leading_options);
struct predicate * get_eval_tree (void);
struct predicate *get_new_pred_noarg (const struct parser_table *entry);
struct predicate *get_new_pred (const struct parser_table *entry);
struct predicate *get_new_pred_chk_op (const struct parser_table *entry,
					      const char *arg);
float  calculate_derived_rates (struct predicate *p);

/* util.c */
struct predicate *insert_primary (const struct parser_table *entry, const char *arg);
struct predicate *insert_primary_noarg (const struct parser_table *entry);
struct predicate *insert_primary_withpred (const struct parser_table *entry, PRED_FUNC fptr, const char *arg);
void usage (int status) _GL_ATTRIBUTE_NORETURN;
extern bool check_nofollow(void);
void complete_pending_execs(struct predicate *p);
void complete_pending_execdirs (void);
const char *safely_quote_err_filename (int n, char const *arg);
void record_initial_cwd (void);
bool is_exec_in_local_dir(const PRED_FUNC pred_func);

void fatal_target_file_error (int errno_value, const char *name) _GL_ATTRIBUTE_NORETURN;
void fatal_nontarget_file_error (int errno_value, const char *name) _GL_ATTRIBUTE_NORETURN;
void nonfatal_target_file_error (int errno_value, const char *name);
void nonfatal_nontarget_file_error (int errno_value, const char *name);


int process_leading_options (int argc, char *argv[]);
void set_option_defaults (struct options *p);

# if 0
#  define apply_predicate(pathname, stat_buf_ptr, node)	\
  (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
# else
bool apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p);
# endif

# define pred_is(node, fn) ( ((node)->pred_func) == (fn) )


/* util.c. */
bool following_links (void);
bool digest_mode (mode_t *mode, const char *pathname, const char *name, struct stat *pstat, bool leaf);
bool default_prints (struct predicate *pred);
bool looks_like_expression (const char *arg, bool leading);


enum DebugOption
  {
    DebugNone             = 0,
    DebugExpressionTree   = 1 << 0,
    DebugStat             = 1 << 1,
    DebugSearch           = 1 << 2,
    DebugTreeOpt          = 1 << 3,
    DebugHelp             = 1 << 4,
    DebugExec             = 1 << 5,
    DebugSuccessRates     = 1 << 6,
    DebugTime             = 1 << 7,

    DebugAll              = ~DebugNone & ~DebugHelp, /* all but help */
  };

struct options
{
  /* If true, process directory before contents.  True unless -depth given. */
  bool do_dir_first;
  /* If true, -depth was EXPLICITLY set (as opposed to having been turned
   * on by -delete, for example).
   */
   bool explicit_depth;

  /* If >=0, don't descend more than this many levels of subdirectories. */
  int maxdepth;

  /* If >=0, don't process files above this level. */
  int mindepth;

  /* If true, do not assume that files in directories with nlink == 2
     are non-directories. */
  bool no_leaf_check;

  /* If true, don't cross filesystem boundaries. */
  bool stay_on_filesystem;

  /* If true, we ignore the problem where we find that a directory entry
   * no longer exists by the time we get around to processing it.
   */
  bool ignore_readdir_race;

  /* If true, pass control characters through.  If false, escape them
   * or turn them into harmless things.
   */
  bool literal_control_chars;

  /* If true, we issue warning messages
   */
  bool warnings;

  /* If true, avoid POSIX-incompatible behaviours
   * (this functionality is currently incomplete
   * and at the moment affects mainly warning messages).
   */
  bool posixly_correct;

  struct timespec      start_time;		/* Time at start of execution.  */

  /* Either one day before now (the default), or the start of today (if -daystart is given). */
  struct timespec      cur_day_start;

  /* If true, cur_day_start has been adjusted to the start of the day. */
  bool full_days;

  int output_block_size;	/* Output block size.  */

  /* bitmask for debug options */
  unsigned long debug_options;

  enum SymlinkOption symlink_handling;


  /* Pointer to the function used to stat files. */
  int (*xstat) (const char *name, struct stat *statbuf);


  /* Indicate if we can implement safely_chdir() using the O_NOFOLLOW
   * flag to open(2).
   */
  bool open_nofollow_available;

  /* The variety of regular expression that we support.
   * The default is POSIX Basic Regular Expressions, but this
   * can be changed with the positional option, -regextype.
   */
  int regex_options;

  /* function used to get file context */
  int (*x_getfilecon) (int, const char *, char **);

  /* Optimisation level.  One is the default.
   */
  unsigned short optimisation_level;


  /* How should we quote filenames in error messages and so forth?
   */
  enum quoting_style err_quoting_style;

  /* Read starting points from FILE (instead of argv).  */
  const char *files0_from;

  /* True if actions like -ok, -okdir need a user confirmation via stdin.  */
  bool ok_prompt_stdin;
};


struct state
{
  /* Current depth; 0 means current path is a command line arg. */
  int curdepth;

  /* If true, we have called stat on the current path. */
  bool have_stat;

  /* If true, we know the type of the current path. */
  bool have_type;
  mode_t type;			/* this is the actual type */

  /* The file being operated on, relative to the current directory.
     Used for stat, readlink, remove, and opendir.  */
  const char *rel_pathname;

  /* The directory fd to which rel_pathname is relative.  This is relevant
   * when we're navigating the hierarchy with fts() and using FTS_CWDFD.
   */
  int cwd_dir_fd;

  /* Length of starting path. */
  int starting_path_length;

  /* If true, don't descend past current directory.
     Can be set by -prune, -maxdepth, and -xdev/-mount. */
  bool stop_at_current_level;

  /* Status value to return to system. */
  int exit_status;

  /* True if there are any execdirs.  This saves us a pair of fchdir()
   * calls for every directory we leave if it is false.  This is just
   * an optimisation.  Set to true if you want to be conservative.
   */
  bool execdirs_outstanding;

  /* Shared files, opened via the interface in sharefile.h. */
  sharefile_handle shared_files;

  /* Avoid multiple error messages for the same file. */
  bool already_issued_stat_error_msg;
};

/* exec.c */
bool impl_pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr);
int launch (struct buildcmd_control *ctl, void *usercontext, int argc, char **argv);

/* finddata.c */
extern struct options options;
extern struct state state;
extern struct saved_cwd *initial_wd;

#endif