When wd_sanity_check() fails, enumerate the mounted devices, rather than the mounted...
[findutils.git] / find / find.c
blob9525b8559a74dce5d5f3822635b3e44e3e503d00
1 /* find -- search for files in a directory hierarchy
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.*/
19 /* GNU find was written by Eric Decker <cire@cisco.com>,
20 with enhancements by David MacKenzie <djm@gnu.ai.mit.edu>,
21 Jay Plett <jay@silence.princeton.nj.us>,
22 and Tim Wood <axolotl!tim@toad.com>.
23 The idea for -print0 and xargs -0 came from
24 Dan Bernstein <brnstnd@kramden.acf.nyu.edu>. */
26 #include "defs.h"
28 #include <errno.h>
29 #include <assert.h>
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #else
35 #include <sys/file.h>
36 #endif
37 #include "../gnulib/lib/human.h"
38 #include "../gnulib/lib/canonicalize.h"
39 #include <modetype.h>
40 #include "../gnulib/lib/savedir.h"
42 #ifdef HAVE_LOCALE_H
43 #include <locale.h>
44 #endif
46 #if ENABLE_NLS
47 # include <libintl.h>
48 # define _(Text) gettext (Text)
49 #else
50 # define _(Text) Text
51 #define textdomain(Domain)
52 #define bindtextdomain(Package, Directory)
53 #endif
54 #ifdef gettext_noop
55 # define N_(String) gettext_noop (String)
56 #else
57 /* See locate.c for explanation as to why not use (String) */
58 # define N_(String) String
59 #endif
61 #define apply_predicate(pathname, stat_buf_ptr, node) \
62 (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
65 static void init_mounted_dev_list(void);
66 static void process_top_path PARAMS((char *pathname));
67 static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent));
68 static void process_dir PARAMS((char *pathname, char *name, int pathlen, struct stat *statp, char *parent));
69 #if 0
70 static boolean no_side_effects PARAMS((struct predicate *pred));
71 #endif
72 static boolean default_prints PARAMS((struct predicate *pred));
74 /* Name this program was run with. */
75 char *program_name;
77 /* All predicates for each path to process. */
78 struct predicate *predicates;
80 /* The last predicate allocated. */
81 struct predicate *last_pred;
83 /* The root of the evaluation tree. */
84 static struct predicate *eval_tree;
86 /* If true, process directory before contents. True unless -depth given. */
87 boolean do_dir_first;
89 /* If >=0, don't descend more than this many levels of subdirectories. */
90 int maxdepth;
92 /* If >=0, don't process files above this level. */
93 int mindepth;
95 /* Current depth; 0 means current path is a command line arg. */
96 int curdepth;
98 /* Output block size. */
99 int output_block_size;
101 /* Time at start of execution. */
102 time_t start_time;
104 /* Seconds between 00:00 1/1/70 and either one day before now
105 (the default), or the start of today (if -daystart is given). */
106 time_t cur_day_start;
108 /* If true, cur_day_start has been adjusted to the start of the day. */
109 boolean full_days;
111 /* If true, do not assume that files in directories with nlink == 2
112 are non-directories. */
113 boolean no_leaf_check;
115 /* If true, don't cross filesystem boundaries. */
116 boolean stay_on_filesystem;
118 /* If true, don't descend past current directory.
119 Can be set by -prune, -maxdepth, and -xdev/-mount. */
120 boolean stop_at_current_level;
122 /* The full path of the initial working directory, or "." if
123 STARTING_DESC is nonnegative. */
124 char const *starting_dir = ".";
126 /* A file descriptor open to the initial working directory.
127 Doing it this way allows us to work when the i.w.d. has
128 unreadable parents. */
129 int starting_desc;
131 /* The stat buffer of the initial working directory. */
132 struct stat starting_stat_buf;
134 /* If true, we have called stat on the current path. */
135 boolean have_stat;
137 /* The file being operated on, relative to the current directory.
138 Used for stat, readlink, remove, and opendir. */
139 char *rel_pathname;
141 /* Length of current path. */
142 int path_length;
144 /* true if following symlinks. Should be consistent with xstat. */
145 /* boolean dereference; */
146 enum SymlinkOption symlink_handling;
149 /* Pointer to the function used to stat files. */
150 int (*xstat) ();
152 /* Status value to return to system. */
153 int exit_status;
155 /* If true, we ignore the problem where we find that a directory entry
156 * no longer exists by the time we get around to processing it.
158 boolean ignore_readdir_race;
161 /* If true, we issue warning messages
163 boolean warnings;
166 enum TraversalDirection
168 TraversingUp,
169 TraversingDown
173 static int
174 following_links(void)
176 switch (symlink_handling)
178 case SYMLINK_ALWAYS_DEREF:
179 return 1;
180 case SYMLINK_DEREF_ARGSONLY:
181 return (curdepth == 0);
182 case SYMLINK_NEVER_DEREF:
183 return 0;
188 /* optionh_stat() implements the stat operation when the -H option is
189 * in effect.
191 * If the item to be examined is a command-line argument, we follow
192 * symbolic links. If the stat() call fails on the command-line item,
193 * we fall back on the properties of the symbolic link.
195 * If the item to be examined is not a command-line argument, we
196 * examine the link itself.
198 int
199 optionh_stat(const char *name, struct stat *p)
201 if (0 == curdepth)
203 /* This file is from the command line; deference the link (if it
204 * is a link).
206 if (0 == stat(name, p))
208 /* success */
209 return 0;
211 else
213 /* fallback - return the information for the link itself. */
214 return lstat(name, p);
217 else
219 /* Not a file on the command line; do not derefernce the link.
221 return lstat(name, p);
225 /* optionl_stat() implements the stat operation when the -L option is
226 * in effect. That option makes us examine the thing the symbolic
227 * link points to, not the symbolic link itself.
229 int
230 optionl_stat(const char *name, struct stat *p)
232 if (0 == stat(name, p))
234 return 0; /* normal case. */
236 else
238 return lstat(name, p); /* can't follow link, return the link itself. */
242 /* optionp_stat() implements the stat operation when the -P option is
243 * in effect (this is also the default). That option makes us examine
244 * the symbolic link itself, not the thing it points to.
246 int
247 optionp_stat(const char *name, struct stat *p)
249 return lstat(name, p);
252 #ifdef DEBUG_STAT
253 static int
254 debug_stat (const char *file, struct stat *bufp)
256 fprintf (stderr, "debug_stat (%s)\n", file);
257 switch (symlink_handling)
259 case SYMLINK_ALWAYS_DEREF:
260 return optionl_stat(file, bufp);
261 case SYMLINK_DEREF_ARGSONLY:
262 return optionh_stat(file, bufp);
263 case SYMLINK_NEVER_DEREF:
264 return optionp_stat(file, bufp);
267 #endif /* DEBUG_STAT */
269 void
270 set_follow_state(enum SymlinkOption opt)
272 switch (opt)
274 case SYMLINK_ALWAYS_DEREF: /* -L */
275 xstat = optionl_stat;
276 no_leaf_check = false;
277 break;
279 case SYMLINK_NEVER_DEREF: /* -P (default) */
280 xstat = optionp_stat;
281 /* Can't turn on no_leaf_check because the user might have specified
282 * -noleaf anyway
284 break;
286 case SYMLINK_DEREF_ARGSONLY: /* -H */
287 xstat = optionh_stat;
288 no_leaf_check = true;
291 /* For DBEUG_STAT, the choice is made at runtime within debug_stat()
292 * by checking the contents of the symlink_handling variable.
294 #if defined(DEBUG_STAT)
295 xstat = debug_stat;
296 #endif /* !DEBUG_STAT */
301 main (int argc, char **argv)
303 int i;
304 PFB parse_function; /* Pointer to the function which parses. */
305 struct predicate *cur_pred;
306 char *predicate_name; /* Name of predicate being parsed. */
307 int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
308 program_name = argv[0];
310 #ifdef HAVE_SETLOCALE
311 setlocale (LC_ALL, "");
312 #endif
313 bindtextdomain (PACKAGE, LOCALEDIR);
314 textdomain (PACKAGE);
316 if (isatty(0))
318 warnings = true;
320 else
322 warnings = false;
326 predicates = NULL;
327 last_pred = NULL;
328 do_dir_first = true;
329 maxdepth = mindepth = -1;
330 start_time = time (NULL);
331 cur_day_start = start_time - DAYSECS;
332 full_days = false;
333 no_leaf_check = false;
334 stay_on_filesystem = false;
335 ignore_readdir_race = false;
336 exit_status = 0;
338 #if defined(DEBUG_STAT)
339 xstat = debug_stat;
340 #endif /* !DEBUG_STAT */
342 #if 0
343 human_block_size (getenv ("FIND_BLOCK_SIZE"), 0, &output_block_size);
344 #else
345 if (getenv("POSIXLY_CORRECT"))
346 output_block_size = 512;
347 else
348 output_block_size = 1024;
350 if (getenv("FIND_BLOCK_SIZE"))
352 error (1, 0, _("The environment variable FIND_BLOCK_SIZE is not supported, the only thing that affects the block size is the POSIXLY_CORRECT environment variable"));
355 set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */
357 init_mounted_dev_list();
359 #endif
361 #ifdef DEBUG
362 printf ("cur_day_start = %s", ctime (&cur_day_start));
363 #endif /* DEBUG */
365 /* Check for -P, -H or -L options. */
366 for (i=1; (end_of_leading_options = i) < argc; ++i)
368 if (0 == strcmp("-H", argv[i]))
370 /* Meaning: dereference symbolic links on command line, but nowhere else. */
371 set_follow_state(SYMLINK_DEREF_ARGSONLY);
373 else if (0 == strcmp("-L", argv[i]))
375 /* Meaning: dereference all symbolic links. */
376 set_follow_state(SYMLINK_ALWAYS_DEREF);
378 else if (0 == strcmp("-P", argv[i]))
380 /* Meaning: never dereference symbolic links (default). */
381 set_follow_state(SYMLINK_NEVER_DEREF);
383 else if (0 == strcmp("--", argv[i]))
385 /* -- signifies the end of options. */
386 end_of_leading_options = i+1; /* Next time start with the next option */
387 break;
389 else
391 /* Hmm, must be one of
392 * (a) A path name
393 * (b) A predicate
395 end_of_leading_options = i; /* Next time start with this option */
396 break;
400 /* We are now processing the part of the "find" command line
401 * after the -H/-L options (if any).
404 /* fprintf(stderr, "rest: optind=%ld\n", (long)optind); */
406 /* Find where in ARGV the predicates begin. */
407 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
409 /* fprintf(stderr, "Looks like %s is not a predicate\n", argv[i]); */
410 /* Do nothing. */ ;
413 /* Enclose the expression in `( ... )' so a default -print will
414 apply to the whole expression. */
415 parse_open (argv, &argc);
416 /* Build the input order list. */
417 while (i < argc)
419 if (strchr ("-!(),", argv[i][0]) == NULL)
420 usage (_("paths must precede expression"));
421 predicate_name = argv[i];
422 parse_function = find_parser (predicate_name);
423 if (parse_function == NULL)
424 /* Command line option not recognized */
425 error (1, 0, _("invalid predicate `%s'"), predicate_name);
426 i++;
427 if (!(*parse_function) (argv, &i))
429 if (argv[i] == NULL)
430 /* Command line option requires an argument */
431 error (1, 0, _("missing argument to `%s'"), predicate_name);
432 else
433 error (1, 0, _("invalid argument `%s' to `%s'"),
434 argv[i], predicate_name);
437 if (predicates->pred_next == NULL)
439 /* No predicates that do something other than set a global variable
440 were given; remove the unneeded initial `(' and add `-print'. */
441 cur_pred = predicates;
442 predicates = last_pred = predicates->pred_next;
443 free ((char *) cur_pred);
444 parse_print (argv, &argc);
446 else if (!default_prints (predicates->pred_next))
448 /* One or more predicates that produce output were given;
449 remove the unneeded initial `('. */
450 cur_pred = predicates;
451 predicates = predicates->pred_next;
452 free ((char *) cur_pred);
454 else
456 /* `( user-supplied-expression ) -print'. */
457 parse_close (argv, &argc);
458 parse_print (argv, &argc);
461 #ifdef DEBUG
462 printf (_("Predicate List:\n"));
463 print_list (predicates);
464 #endif /* DEBUG */
466 /* Done parsing the predicates. Build the evaluation tree. */
467 cur_pred = predicates;
468 eval_tree = get_expr (&cur_pred, NO_PREC);
470 /* Check if we have any left-over predicates (this fixes
471 * Debian bug #185202).
473 if (cur_pred != NULL)
475 error (1, 0, _("unexpected extra predicate"));
478 #ifdef DEBUG
479 printf (_("Eval Tree:\n"));
480 print_tree (eval_tree, 0);
481 #endif /* DEBUG */
483 /* Rearrange the eval tree in optimal-predicate order. */
484 opt_expr (&eval_tree);
486 /* Determine the point, if any, at which to stat the file. */
487 mark_stat (eval_tree);
489 #ifdef DEBUG
490 printf (_("Optimized Eval Tree:\n"));
491 print_tree (eval_tree, 0);
492 #endif /* DEBUG */
494 starting_desc = open (".", O_RDONLY);
495 if (0 <= starting_desc && fchdir (starting_desc) != 0)
497 close (starting_desc);
498 starting_desc = -1;
500 if (starting_desc < 0)
502 starting_dir = xgetcwd ();
503 if (! starting_dir)
504 error (1, errno, _("cannot get current directory"));
506 if ((*xstat) (".", &starting_stat_buf) != 0)
507 error (1, errno, _("cannot get current directory"));
509 /* If no paths are given, default to ".". */
510 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
512 process_top_path (argv[i]);
515 /* If there were no path arguments, default to ".". */
516 if (i == end_of_leading_options)
519 * We use a temporary variable here because some actions modify
520 * the path temporarily. Hence if we use a string constant,
521 * we get a coredump. The best example of this is if we say
522 * "find -printf %H" (note, not "find . -printf %H").
524 char defaultpath[2] = ".";
525 process_top_path (defaultpath);
529 return exit_status;
533 static char *
534 specific_dirname(const char *dir)
536 char dirname[1024];
538 if (0 == strcmp(".", dir))
540 /* OK, what's '.'? */
541 if (NULL != getcwd(dirname, sizeof(dirname)))
543 return strdup(dirname);
545 else
547 return strdup(dir);
550 else
552 return canonicalize_filename_mode(dir, CAN_EXISTING);
559 #if 0
560 /* list_item_present: Search for NEEDLE in HAYSTACK.
562 * NEEDLE is a normal C string. HAYSTACK is a list of concatenated C strings,
563 * each with a terminating NUL. The last item in the list is identified by
564 * the fact that its terminating NUL is itself followed by a second NUL.
566 * This data structure does not lend itself to fast searching, but we only
567 * do this when wd_sanity_check() thinks that a filesystem might have been
568 * mounted or unmounted. That doesn't happen very often.
570 static int
571 list_item_present(const char *needle, const char *haystack)
573 if (NULL != haystack)
575 const char *s = haystack;
576 while (*s)
578 if (0 == strcmp(s, needle))
580 return 1;
582 else
584 s += strlen(s);
585 ++s; /* skip the first NUL. */
589 return 0;
592 static char *mount_points = NULL;
595 /* Initialise our idea of what the list of mount points is.
596 * this function is called exactly once.
598 static void
599 init_mount_point_list(void)
601 assert(NULL == mount_points);
602 mount_points = get_mounted_filesystems();
605 static void
606 refresh_mount_point_list(void)
608 if (mount_points)
610 free(mount_points);
611 mount_points = NULL;
613 init_mount_point_list();
616 /* Determine if a directory has recently had a filesystem
617 * mounted on it or unmounted from it.
619 static enum MountPointStateChange
620 get_mount_point_state(const char *dir)
622 int was_mounted, is_mounted;
624 was_mounted = list_item_present(dir, mount_points);
625 refresh_mount_point_list();
626 is_mounted = list_item_present(dir, mount_points);
628 if (was_mounted == is_mounted)
629 return MountPointStateUnchanged;
630 else if (is_mounted)
631 return MountPointRecentlyMounted;
632 else
633 return MountPointRecentlyUnmounted;
635 #endif
639 static dev_t *mounted_devices = NULL;
640 static size_t num_mounted_devices = 0u;
643 static void
644 init_mounted_dev_list()
646 assert(NULL == mounted_devices);
647 assert(0 == num_mounted_devices);
648 mounted_devices = get_mounted_devices(&num_mounted_devices);
651 static void
652 refresh_mounted_dev_list(void)
654 if (mounted_devices)
656 free(mounted_devices);
657 mounted_devices = 0;
659 num_mounted_devices = 0u;
660 init_mounted_dev_list();
664 /* Search for device DEV in the array LIST, which is of size N. */
665 static int
666 dev_present(dev_t dev, const dev_t *list, size_t n)
668 if (list)
670 while (n-- > 0u)
672 if ( (*list++) == dev )
673 return 1;
676 return 0;
679 enum MountPointStateChange
681 MountPointRecentlyMounted,
682 MountPointRecentlyUnmounted,
683 MountPointStateUnchanged
688 static enum MountPointStateChange
689 get_mount_state(dev_t newdev)
691 int new_is_present, new_was_present;
693 new_was_present = dev_present(newdev, mounted_devices, num_mounted_devices);
694 refresh_mounted_dev_list();
695 new_is_present = dev_present(newdev, mounted_devices, num_mounted_devices);
697 if (new_was_present == new_is_present)
698 return MountPointStateUnchanged;
699 else if (new_is_present)
700 return MountPointRecentlyMounted;
701 else
702 return MountPointRecentlyUnmounted;
707 /* Examine the results of the stat() of a directory from before we
708 * entered or left it, with the results of stat()ing it afterward. If
709 * these are different, the filesystem tree has been modified while we
710 * were traversing it. That might be an attempt to use a race
711 * condition to persuade find to do something it didn't intend
712 * (e.g. an attempt by an ordinary user to exploit the fact that root
713 * sometimes runs find on the whole filesystem). However, this can
714 * also happen if automount is running (certainly on Solaris). With
715 * automount, moving into a directory can cause a filesystem to be
716 * mounted there.
718 * To cope sensibly with this, we will raise an error if we see the
719 * device number change unless we are chdir()ing into a subdirectory,
720 * and the directory we moved into has been mounted or unmounted "recently".
721 * Here "recently" means since we started "find" or we last re-read
722 * the /etc/mnttab file.
724 * If the device number does not change but the inode does, that is a
725 * problem.
727 * If the device number and inode are both the same, we are happy.
729 * If a filesystem is (un)mounted as we chdir() into the directory, that
730 * may mean that we're now examining a section of the filesystem that might
731 * have been excluded from consideration (via -prune or -quit for example).
732 * Hence we print a warning message to indicate that the output of find
733 * might be inconsistent due to the change in the filesystem.
735 static void
736 wd_sanity_check(const char *thing_to_stat,
737 const char *program_name,
738 const char *what,
739 const struct stat *oldinfo,
740 struct stat *newinfo,
741 int parent,
742 int line_no,
743 enum TraversalDirection direction)
745 const char *fstype;
746 char *specific_what = NULL;
748 int isfatal = 1;
750 if ((*xstat) (".", newinfo) != 0)
751 error (1, errno, "%s", thing_to_stat);
753 if (oldinfo->st_dev != newinfo->st_dev)
755 specific_what = specific_dirname(what);
757 /* This condition is rare, so once we are here it is
758 * reasonable to perform an expensive computation to
759 * determine if we should continue or fail.
761 if (1 || TraversingDown == direction)
763 /* We stat()ed a directory, chdir()ed into it (we know this
764 * since direction is TraversingDown), stat()ed it again,
765 * and noticed that the device numbers are different. Check
766 * if the filesystem was recently mounted.
768 * If it was, it looks like chdir()ing into the directory
769 * caused a filesystem to be mounted. Maybe automount is
770 * running. Anyway, that's probably OK - but it happens
771 * only when we are moving downward.
773 * We also allow for the possibility that a similar thing
774 * has happened with the unmounting of a filesystem. This
775 * is much rarer, as it relies on an automounter timeout
776 * occurring at exactly the wrong moment.
778 enum MountPointStateChange transition = get_mount_state(newinfo->st_dev);
779 switch (transition)
781 case MountPointRecentlyUnmounted:
782 isfatal = 0;
783 error (0, 0,
784 _("Warning: filesystem %s has recently been unmounted."),
785 specific_what);
786 break;
788 case MountPointRecentlyMounted:
789 isfatal = 0;
790 error (0, 0,
791 _("Warning: filesystem %s has recently been mounted."),
792 specific_what);
793 break;
795 case MountPointStateUnchanged:
796 isfatal = 1;
797 break;
801 if (isfatal)
803 fstype = filesystem_type(thing_to_stat, ".", newinfo);
804 error (isfatal, 0,
805 _("%s%s changed during execution of %s (old device number %ld, new device number %ld, filesystem type is %s) [ref %ld]"),
806 specific_what,
807 parent ? "/.." : "",
808 program_name,
809 (long) oldinfo->st_dev,
810 (long) newinfo->st_dev,
811 fstype,
812 line_no);
814 else
816 /* Since the device has changed under us, the inode number
817 * will almost certainly also be different. However, we have
818 * already decided that this is not a problem. Hence we return
819 * without checking the inode number.
821 free(specific_what);
822 return;
826 /* Device number was the same, check if the inode has changed. */
827 if (oldinfo->st_ino != newinfo->st_ino)
829 specific_what = specific_dirname(what);
830 fstype = filesystem_type(thing_to_stat, ".", newinfo);
832 error (1, 0,
833 _("%s%s changed during execution of %s (old inode number %ld, new inode number %ld, filesystem type is %s) [ref %ld]"),
834 specific_what,
835 parent ? "/.." : "",
836 program_name,
837 (long) oldinfo->st_ino,
838 (long) newinfo->st_ino,
839 fstype,
840 line_no);
841 free(specific_what);
845 enum SafeChdirStatus
847 SafeChdirOK,
848 SafeChdirFailSymlink,
849 SafeChdirFailStat,
850 SafeChdirFailDefect
853 /* Safely perform a change in directory. */
854 static int
855 safely_chdir(const char *dest, enum TraversalDirection direction)
857 struct stat statbuf_dest, statbuf_arrived;
858 int rv=SafeChdirFailDefect, dotfd=-1;
859 char *name = NULL;
861 errno = 0;
862 dotfd = open(".", O_RDONLY);
863 if (dotfd >= 0)
865 /* Stat the directory we're going to. */
866 if (0 == (following_links() ? stat : lstat)(dest, &statbuf_dest))
868 #ifdef S_ISLNK
869 if (!following_links() && S_ISLNK(statbuf_dest.st_mode))
871 rv = SafeChdirFailSymlink;
872 goto fail;
874 #endif
875 chdir(dest);
877 else
879 rv = SafeChdirFailStat;
880 name = specific_dirname(dest);
881 goto fail;
884 else
888 fail:
889 if (errno)
891 if (NULL == name)
892 name = specific_dirname(".");
893 error(0, errno, "%s", name);
896 free(name);
897 name = NULL;
899 if (dotfd >= 0)
901 close(dotfd);
902 dotfd = -1;
904 return rv;
908 /* Safely go back to the starting directory. */
909 static void
910 chdir_back (void)
912 struct stat stat_buf;
914 if (starting_desc < 0)
916 if (chdir (starting_dir) != 0)
917 error (1, errno, "%s", starting_dir);
919 wd_sanity_check(starting_dir,
920 program_name, starting_dir,
921 &starting_stat_buf, &stat_buf, 0, __LINE__,
922 TraversingUp);
924 else
926 if (fchdir (starting_desc) != 0)
927 error (1, errno, "%s", starting_dir);
931 /* Descend PATHNAME, which is a command-line argument. */
933 static void
934 process_top_path (char *pathname)
936 struct stat stat_buf, cur_stat_buf;
938 curdepth = 0;
939 path_length = strlen (pathname);
941 /* We stat each pathname given on the command-line twice --
942 once here and once in process_path. It's not too bad, though,
943 since the kernel can read the stat information out of its inode
944 cache the second time. */
945 if ((*xstat) (pathname, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
947 if (chdir (pathname) < 0)
949 if (!ignore_readdir_race || (errno != ENOENT) )
951 error (0, errno, "%s", pathname);
952 exit_status = 1;
954 return;
957 /* Check that we are where we should be. */
958 wd_sanity_check(pathname, program_name,
959 ".",
960 &stat_buf, &cur_stat_buf, 0, __LINE__,
961 TraversingDown);
963 process_path (pathname, ".", false, ".");
964 chdir_back ();
966 else
967 process_path (pathname, pathname, false, ".");
970 /* Info on each directory in the current tree branch, to avoid
971 getting stuck in symbolic link loops. */
972 struct dir_id
974 ino_t ino;
975 dev_t dev;
977 static struct dir_id *dir_ids = NULL;
978 /* Entries allocated in `dir_ids'. */
979 static int dir_alloc = 0;
980 /* Index in `dir_ids' of directory currently being searched.
981 This is always the last valid entry. */
982 static int dir_curr = -1;
983 /* (Arbitrary) number of entries to grow `dir_ids' by. */
984 #define DIR_ALLOC_STEP 32
986 /* Recursively descend path PATHNAME, applying the predicates.
987 LEAF is true if PATHNAME is known to be in a directory that has no
988 more unexamined subdirectories, and therefore it is not a directory.
989 Knowing this allows us to avoid calling stat as long as possible for
990 leaf files.
992 NAME is PATHNAME relative to the current directory. We access NAME
993 but print PATHNAME.
995 PARENT is the path of the parent of NAME, relative to find's
996 starting directory.
998 Return nonzero iff PATHNAME is a directory. */
1000 static int
1001 process_path (char *pathname, char *name, boolean leaf, char *parent)
1003 struct stat stat_buf;
1004 static dev_t root_dev; /* Device ID of current argument pathname. */
1005 int i;
1007 /* Assume it is a non-directory initially. */
1008 stat_buf.st_mode = 0;
1010 rel_pathname = name;
1012 if (leaf)
1013 have_stat = false;
1014 else
1016 if ((*xstat) (name, &stat_buf) != 0)
1018 if (!ignore_readdir_race || (errno != ENOENT) )
1020 error (0, errno, "%s", pathname);
1021 exit_status = 1;
1023 return 0;
1025 have_stat = true;
1028 if (!S_ISDIR (stat_buf.st_mode))
1030 if (curdepth >= mindepth)
1031 apply_predicate (pathname, &stat_buf, eval_tree);
1032 return 0;
1035 /* From here on, we're working on a directory. */
1037 stop_at_current_level = maxdepth >= 0 && curdepth >= maxdepth;
1039 /* If we've already seen this directory on this branch,
1040 don't descend it again. */
1041 for (i = 0; i <= dir_curr; i++)
1042 if (stat_buf.st_ino == dir_ids[i].ino &&
1043 stat_buf.st_dev == dir_ids[i].dev)
1044 stop_at_current_level = true;
1046 if (dir_alloc <= ++dir_curr)
1048 dir_alloc += DIR_ALLOC_STEP;
1049 dir_ids = (struct dir_id *)
1050 xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id));
1052 dir_ids[dir_curr].ino = stat_buf.st_ino;
1053 dir_ids[dir_curr].dev = stat_buf.st_dev;
1055 if (stay_on_filesystem)
1057 if (curdepth == 0)
1058 root_dev = stat_buf.st_dev;
1059 else if (stat_buf.st_dev != root_dev)
1060 stop_at_current_level = true;
1063 if (do_dir_first && curdepth >= mindepth)
1064 apply_predicate (pathname, &stat_buf, eval_tree);
1066 #ifdef DEBUG
1067 fprintf(stderr, "pathname = %s, stop_at_current_level = %d\n",
1068 pathname, stop_at_current_level);
1069 #endif /* DEBUG */
1071 if (stop_at_current_level == false)
1072 /* Scan directory on disk. */
1073 process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
1075 if (do_dir_first == false && curdepth >= mindepth)
1077 rel_pathname = name;
1078 apply_predicate (pathname, &stat_buf, eval_tree);
1081 dir_curr--;
1083 return 1;
1086 /* Scan directory PATHNAME and recurse through process_path for each entry.
1088 PATHLEN is the length of PATHNAME.
1090 NAME is PATHNAME relative to the current directory.
1092 STATP is the results of *xstat on it.
1094 PARENT is the path of the parent of NAME, relative to find's
1095 starting directory. */
1097 static void
1098 process_dir (char *pathname, char *name, int pathlen, struct stat *statp, char *parent)
1100 char *name_space; /* Names of files in PATHNAME. */
1101 int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
1102 struct stat stat_buf;
1104 subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
1106 errno = 0;
1107 name_space = savedir (name);
1108 if (name_space == NULL)
1110 if (errno)
1112 error (0, errno, "%s", pathname);
1113 exit_status = 1;
1115 else
1116 error (1, 0, _("virtual memory exhausted"));
1118 else
1120 register char *namep; /* Current point in `name_space'. */
1121 char *cur_path; /* Full path of each file to process. */
1122 char *cur_name; /* Base name of each file to process. */
1123 unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
1124 register unsigned file_len; /* Length of each path to process. */
1125 register unsigned pathname_len; /* PATHLEN plus trailing '/'. */
1127 if (pathname[pathlen - 1] == '/')
1128 pathname_len = pathlen + 1; /* For '\0'; already have '/'. */
1129 else
1130 pathname_len = pathlen + 2; /* For '/' and '\0'. */
1131 cur_path_size = 0;
1132 cur_path = NULL;
1134 if (strcmp (name, ".") && chdir (name) < 0)
1136 error (0, errno, "%s", pathname);
1137 exit_status = 1;
1138 return;
1141 /* Check that we are where we should be. */
1142 if (1)
1144 struct stat tmp = {0};
1145 tmp.st_dev = dir_ids[dir_curr].dev;
1146 tmp.st_ino = dir_ids[dir_curr].ino;
1147 wd_sanity_check(pathname,
1148 program_name,
1149 ".",
1150 &tmp, &stat_buf, 0, __LINE__,
1151 TraversingDown);
1154 for (namep = name_space; *namep; namep += file_len - pathname_len + 1)
1156 /* Append this directory entry's name to the path being searched. */
1157 file_len = pathname_len + strlen (namep);
1158 if (file_len > cur_path_size)
1160 while (file_len > cur_path_size)
1161 cur_path_size += 1024;
1162 if (cur_path)
1163 free (cur_path);
1164 cur_path = xmalloc (cur_path_size);
1165 strcpy (cur_path, pathname);
1166 cur_path[pathname_len - 2] = '/';
1168 cur_name = cur_path + pathname_len - 1;
1169 strcpy (cur_name, namep);
1171 curdepth++;
1172 if (!no_leaf_check)
1173 /* Normal case optimization.
1174 On normal Unix filesystems, a directory that has no
1175 subdirectories has two links: its name, and ".". Any
1176 additional links are to the ".." entries of its
1177 subdirectories. Once we have processed as many
1178 subdirectories as there are additional links, we know
1179 that the rest of the entries are non-directories --
1180 in other words, leaf files. */
1181 subdirs_left -= process_path (cur_path, cur_name,
1182 subdirs_left == 0, pathname);
1183 else
1184 /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
1185 mounted, which don't have Unix-like directory link counts. */
1186 process_path (cur_path, cur_name, false, pathname);
1187 curdepth--;
1190 if (strcmp (name, "."))
1192 /* We could go back and do the next command-line arg
1193 instead, maybe using longjmp. */
1194 char const *dir;
1195 boolean deref;
1196 if (symlink_handling == SYMLINK_ALWAYS_DEREF)
1197 deref = true;
1198 else if (symlink_handling == SYMLINK_DEREF_ARGSONLY && (curdepth == 0))
1199 deref = true;
1200 else
1201 deref = false;
1203 if (!deref)
1204 dir = "..";
1205 else
1207 chdir_back ();
1208 dir = parent;
1211 if (chdir (dir) != 0)
1212 error (1, errno, "%s", parent);
1214 /* Check that we are where we should be. */
1215 if (1)
1217 struct stat tmp;
1218 int problem_is_with_parent;
1220 if (dir_curr > 0)
1222 tmp.st_dev = dir_ids[dir_curr-1].dev;
1223 tmp.st_ino = dir_ids[dir_curr-1].ino;
1225 else
1227 tmp.st_dev = starting_stat_buf.st_dev;
1228 tmp.st_ino = starting_stat_buf.st_ino;
1231 problem_is_with_parent = deref ? 1 : 0;
1232 wd_sanity_check(pathname,
1233 program_name,
1234 deref ? parent : starting_dir,
1235 &tmp, &stat_buf,
1236 problem_is_with_parent, __LINE__,
1237 TraversingUp);
1241 if (cur_path)
1242 free (cur_path);
1243 free (name_space);
1247 #if 0
1248 /* Return true if there are no side effects in any of the predicates in
1249 predicate list PRED, false if there are any. */
1251 static boolean
1252 no_side_effects (struct predicate *pred)
1254 while (pred != NULL)
1256 if (pred->side_effects)
1257 return (false);
1258 pred = pred->pred_next;
1260 return (true);
1262 #endif
1264 /* Return true if there are no predicates with no_default_print in
1265 predicate list PRED, false if there are any.
1266 Returns true if default print should be performed */
1268 static boolean
1269 default_prints (struct predicate *pred)
1271 while (pred != NULL)
1273 if (pred->no_default_print)
1274 return (false);
1275 pred = pred->pred_next;
1277 return (true);