From 5768a03ddfb5e18b1682e339d6cdd24ff721c510 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker Date: Sun, 22 Aug 2021 18:41:17 +0200 Subject: [PATCH] oldfind: remove The FTS-based find is the default for a long time; oldfind has not been installed since 4.5.18 (2015), and was only just used in tests. * NEWS: Document the change. * doc/find-maint.texi (Factor Out Repeated Code): Remove mentioning of oldfind. * find/.gitignore (/oldfind): Remove entry. * find/Makefile.am (check_PROGRAMS): Remove. (oldfind_SOURCES): Remove. * find/defs.h (struct dir_id): Remove, it was only used in oldfind.c. (symlink_handling): Likewise. Adjust comments wrt oldfind otherwise. * find/oldfind.c: Remove. * find/testsuite/config/unix.exp: Remove the code to search for and to run tests with oldfind. * find/testsuite/find.posix/dotdotfiles.exp: Adjust comment. * po/POTFILES.in (find/oldfind.c): Remove entry. * tests/find/debug-missing-arg.sh: Remove run with oldfind. * tests/find/exec-plus-last-file.sh: Likewise. * tests/find/execdir-fd-leak.sh: Likewise. * tests/find/many-dir-entries-vs-OOM.sh: Likewise. * tests/find/name-lbracket-literal.sh: Likewise. * tests/find/printf_escape_c.sh: Likewise. * tests/find/printf_escapechars.sh: Likewise. * tests/find/printf_inode.sh: Likewise. * tests/find/refuse-noop.sh: Likewise. * tests/find/type_list.sh: Likewise. * tests/local.mk (built_programs): Remove oldfind from list. --- NEWS | 4 + doc/find-maint.texi | 5 +- find/.gitignore | 1 - find/Makefile.am | 7 +- find/defs.h | 14 +- find/oldfind.c | 1556 --------------------- find/testsuite/config/unix.exp | 29 +- find/testsuite/find.posix/dotdotfiles.exp | 2 +- po/POTFILES.in | 1 - tests/find/debug-missing-arg.sh | 12 +- tests/find/exec-plus-last-file.sh | 10 +- tests/find/execdir-fd-leak.sh | 12 +- tests/find/many-dir-entries-vs-OOM.sh | 22 +- tests/find/name-lbracket-literal.sh | 5 +- tests/find/printf_escape_c.sh | 17 +- tests/find/printf_escapechars.sh | 50 +- tests/find/printf_inode.sh | 12 +- tests/find/refuse-noop.sh | 18 +- tests/find/type_list.sh | 290 ++-- tests/local.mk | 2 +- 20 files changed, 223 insertions(+), 1846 deletions(-) delete mode 100644 find/oldfind.c diff --git a/NEWS b/NEWS index 17b08d4a..77bf365c 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,10 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) The output of 'find --help' now reads better. +** Changes to the build process + + The find version without FTS, oldfind, has been completely removed. It has + not been installed since 4.5.18 (2015), and was only still used in tests. * Noteworthy changes in release 4.8.0 (2020-01-09) [stable] diff --git a/doc/find-maint.texi b/doc/find-maint.texi index 647e6f5d..f033dc72 100644 --- a/doc/find-maint.texi +++ b/doc/find-maint.texi @@ -363,10 +363,7 @@ the nature of the input arguments which is in fact not true for the context of the now duplicated code. A good example of the use of refactoring in findutils is the -@code{collect_arg} function in @file{find/parser.c}. A less clear-cut -but larger example is the factoring out of code which would otherwise -have been duplicated between @file{find/oldfind.c} and -@code{find/ftsfind.c}. +@code{collect_arg} function in @file{find/parser.c}. The findutils test suite is comprehensive enough that refactoring code should not generally be a daunting prospect from a testing point of diff --git a/find/.gitignore b/find/.gitignore index 2ea5572d..d34536ca 100644 --- a/find/.gitignore +++ b/find/.gitignore @@ -4,4 +4,3 @@ /Makefile.in /find /libfindtools.a -/oldfind diff --git a/find/Makefile.am b/find/Makefile.am index f8d3bd95..c0779a0f 100644 --- a/find/Makefile.am +++ b/find/Makefile.am @@ -20,13 +20,10 @@ localedir = $(datadir)/locale noinst_LIBRARIES = libfindtools.a libfindtools_a_SOURCES = finddata.c fstype.c parser.c pred.c exec.c tree.c util.c sharefile.c print.c -# We always build two versions of find, one with fts (called "find"), -# one without (called "oldfind"). The oldfind binary is no longer -# installed. +# We only build the version of find with fts (called "find"), +# i.e., no longer the one called "oldfind". bin_PROGRAMS = find -check_PROGRAMS = oldfind find_SOURCES = ftsfind.c -oldfind_SOURCES = oldfind.c man_MANS = find.1 EXTRA_DIST = defs.h sharefile.h print.h $(man_MANS) diff --git a/find/defs.h b/find/defs.h index 1b02457d..cb519136 100644 --- a/find/defs.h +++ b/find/defs.h @@ -138,14 +138,6 @@ struct perm_val mode_t val[2]; }; -/* dir_id is used to support loop detection in oldfind.c - */ -struct dir_id -{ - ino_t ino; - dev_t dev; -}; - /* samefile_file_id is used to support the -samefile test. */ struct samefile_file_id @@ -346,14 +338,13 @@ struct predicate const struct parser_table* parser_entry; }; -/* oldfind.c, ftsfind.c */ +/* ftsfind.c */ bool is_fts_enabled(int *ftsoptions); /* find library function declarations. */ /* find global function declarations. */ -/* oldfind.c */ /* SymlinkOption represents the choice of * -P, -L or -P (default) on the command line. */ @@ -363,7 +354,6 @@ enum SymlinkOption SYMLINK_ALWAYS_DEREF, /* Option -L */ SYMLINK_DEREF_ARGSONLY /* Option -H */ }; -extern enum SymlinkOption symlink_handling; /* defined in oldfind.c. */ void set_follow_state (enum SymlinkOption opt); void cleanup(void); @@ -528,7 +518,7 @@ bool apply_predicate(const char *pathname, struct stat *stat_buf, struct predica # define pred_is(node, fn) ( ((node)->pred_func) == (fn) ) -/* oldfind.c. */ +/* util.c. */ int get_info (const char *pathname, struct stat *p, struct predicate *pred_ptr); bool following_links (void); bool digest_mode (mode_t *mode, const char *pathname, const char *name, struct stat *pstat, bool leaf); diff --git a/find/oldfind.c b/find/oldfind.c deleted file mode 100644 index 8456db59..00000000 --- a/find/oldfind.c +++ /dev/null @@ -1,1556 +0,0 @@ -/* find -- search for files in a directory hierarchy - Copyright (C) 1990-2021 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 . -*/ -/* GNU find was written by Eric Decker , - with enhancements by David MacKenzie , - Jay Plett , - and Tim Wood . - The idea for -print0 and xargs -0 came from - Dan Bernstein . - Improvements have been made by James Youngman . -*/ - -/* config.h must be included first. */ -#include - -/* system headers. */ -#include -#include -#include -#include - -/* gnulib headers. */ -#include "canonicalize.h" -#include "closein.h" -#include "dirent--.h" -#include "dirname.h" -#include "error.h" -#include "fcntl--.h" -#include "human.h" -#include "progname.h" -#include "save-cwd.h" -#include "xalloc.h" -#include "xgetcwd.h" - - -/* find headers. */ -#include "buildcmd.h" -#include "defs.h" -#include "die.h" -#include "fdleak.h" -#include "system.h" - -#undef STAT_MOUNTPOINTS - -#ifdef CLOSEDIR_VOID -/* Fake a return value. */ -# define CLOSEDIR(d) (closedir (d), 0) -#else -# define CLOSEDIR(d) closedir (d) -#endif - -enum -{ - NOT_AN_INODE_NUMBER = 0 -}; - -#ifdef D_INO_IN_DIRENT -# define D_INO(dp) (dp)->d_ino -#else -/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */ -# define D_INO(dp) NOT_AN_INODE_NUMBER -#endif - -#ifdef STAT_MOUNTPOINTS -static void init_mounted_dev_list (int mandatory); -#endif - -static void process_top_path (const char *pathname, mode_t mode, ino_t inum); -static int process_path (const char *pathname, const char *name, bool leaf, const char *parent, mode_t type, ino_t inum); -static void process_dir (const char *pathname, const char *name, int pathlen, const struct stat *statp, const char *parent); - -/* A file descriptor open to the initial working directory. - Doing it this way allows us to work when the i.w.d. has - unreadable parents. */ -extern int starting_desc; - -/* The stat buffer of the initial working directory. */ -static struct stat starting_stat_buf; - -enum ChdirSymlinkHandling - { - SymlinkHandleDefault, /* Normally the right choice */ - SymlinkFollowOk /* see comment in process_top_path() */ - }; - - -enum TraversalDirection - { - TraversingUp, - TraversingDown - }; - -enum WdSanityCheckFatality - { - FATAL_IF_SANITY_CHECK_FAILS, - RETRY_IF_SANITY_CHECK_FAILS, - NON_FATAL_IF_SANITY_CHECK_FAILS - }; - -#if defined HAVE_STRUCT_DIRENT_D_TYPE -/* Convert the value of struct dirent.d_type into a value for - * struct stat.st_mode (at least the file type bits), or zero - * if the type is DT_UNKNOWN or is a value we don't know about. - */ -static mode_t -type_to_mode (unsigned type) -{ - switch (type) - { -# ifdef DT_FIFO - case DT_FIFO: return S_IFIFO; -# endif -# ifdef DT_CHR - case DT_CHR: return S_IFCHR; -# endif -# ifdef DT_DIR - case DT_DIR: return S_IFDIR; -# endif -# ifdef DT_BLK - case DT_BLK: return S_IFBLK; -# endif -# ifdef DT_REG - case DT_REG: return S_IFREG; -# endif -# ifdef DT_LNK - case DT_LNK: return S_IFLNK; -# endif -# ifdef DT_SOCK - case DT_SOCK: return S_IFSOCK; -# endif - default: - return 0; /* Unknown. */ - } -} -#endif - - -/* CAUTION: this is the entry point for the oldfind executable, which is not the binary that - * will actually get installed. See ftsfind.c. */ -int -main (int argc, char **argv) -{ - int i; - int end_of_leading_options = 0; /* First arg after any -H/-L etc. */ - struct predicate *eval_tree; - - if (argv[0]) - set_program_name (argv[0]); - else - set_program_name ("find"); - - state.exit_status = 0; - - if (fd_leak_check_is_enabled ()) - { - remember_non_cloexec_fds (); - } - - record_initial_cwd (); - - state.already_issued_stat_error_msg = false; - state.shared_files = sharefile_init ("w"); - if (NULL == state.shared_files) - { - die (EXIT_FAILURE, errno, - _("Failed to initialize shared-file hash table")); - } - - /* Set the option defaults before we do the locale - * initialisation as check_nofollow () needs to be executed in the - * POSIX locale. - */ - set_option_defaults (&options); - -#ifdef HAVE_SETLOCALE - setlocale (LC_ALL, ""); -#endif - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - if (atexit (close_stdin)) - { - die (EXIT_FAILURE, errno, _("The atexit library function failed")); - } - - /* Check for -P, -H or -L options. */ - end_of_leading_options = process_leading_options (argc, argv); - - if (options.debug_options & DebugStat) - options.xstat = debug_stat; - - if (options.debug_options & DebugTime) - fprintf (stderr, "cur_day_start = %s", ctime (&options.cur_day_start.tv_sec)); - - /* state.cwd_dir_fd has to be initialized before we call build_expression_tree () - * because command-line parsing may lead us to stat some files. - */ - state.cwd_dir_fd = AT_FDCWD; - - /* We are now processing the part of the "find" command line - * after the -H/-L options (if any). - */ - eval_tree = build_expression_tree (argc, argv, end_of_leading_options); - - - /* safely_chdir () needs to check that it has ended up in the right place. - * To avoid bailing out when something gets automounted, it checks if - * the target directory appears to have had a directory mounted on it as - * we chdir ()ed. The problem with this is that in order to notice that - * a file system was mounted, we would need to lstat () all the mount points. - * That strategy loses if our machine is a client of a dead NFS server. - * - * Hence if safely_chdir () and wd_sanity_check () can manage without needing - * to know the mounted device list, we do that. - */ - if (!options.open_nofollow_available) - { -#ifdef STAT_MOUNTPOINTS - init_mounted_dev_list (0); -#endif - } - - - set_stat_placeholders (&starting_stat_buf); - if ((*options.xstat) (".", &starting_stat_buf) != 0) - die (EXIT_FAILURE, errno, _("cannot stat current directory")); - - /* If no paths are given, default to ".". */ - for (i = end_of_leading_options; i < argc && !looks_like_expression (argv[i], true); i++) - { - process_top_path (argv[i], 0, starting_stat_buf.st_ino); - } - - /* If there were no path arguments, default to ".". */ - if (i == end_of_leading_options) - { - /* - * We use a temporary variable here because some actions modify - * the path temporarily. Hence if we use a string constant, - * we get a coredump. The best example of this is if we say - * "find -printf %H" (note, not "find . -printf %H"). - */ - char defaultpath[2] = "."; - process_top_path (defaultpath, 0, starting_stat_buf.st_ino); - } - - /* If "-exec ... {} +" has been used, there may be some - * partially-full command lines which have been built, - * but which are not yet complete. Execute those now. - */ - show_success_rates (eval_tree); - cleanup (); - return state.exit_status; -} - -bool is_fts_enabled (int *ftsoptions) -{ - /* this version of find (i.e. this main ()) does not use fts. */ - *ftsoptions = 0; - return false; -} - - -static char * -specific_dirname (const char *dir) _GL_ATTRIBUTE_MALLOC; -static char * -specific_dirname (const char *dir) -{ - char dirbuf[1024]; - - if (0 == strcmp (".", dir)) - { - /* OK, what's '.'? */ - if (NULL != getcwd (dirbuf, sizeof (dirbuf))) - { - return strdup (dirbuf); - } - else - { - return strdup (dir); - } - } - else - { - char *result = canonicalize_filename_mode (dir, CAN_EXISTING); - if (NULL == result) - return strdup (dir); - else - return result; - } -} - - - -/* Return non-zero if FS is the name of a file system that is likely to - * be automounted - */ -static int -fs_likely_to_be_automounted (const char *fs) -{ - return ( (0==strcmp (fs, "nfs")) || (0==strcmp (fs, "autofs")) || (0==strcmp (fs, "subfs"))); -} - - - -#ifdef STAT_MOUNTPOINTS -static dev_t *mounted_devices = NULL; -static size_t num_mounted_devices = 0u; - - -static void -init_mounted_dev_list (int mandatory) -{ - assert (NULL == mounted_devices); - assert (0 == num_mounted_devices); - mounted_devices = get_mounted_devices (&num_mounted_devices); - if (mandatory && (NULL == mounted_devices)) - { - die (EXIT_FAILURE, 0, _("Cannot read list of mounted devices.")); - } -} - -static void -refresh_mounted_dev_list (void) -{ - if (mounted_devices) - { - free (mounted_devices); - mounted_devices = 0; - } - num_mounted_devices = 0u; - init_mounted_dev_list (1); -} - - -/* Search for device DEV in the array LIST, which is of size N. */ -static int -dev_present (dev_t dev, const dev_t *list, size_t n) -{ - if (list) - { - while (n-- > 0u) - { - if ( (*list++) == dev ) - return 1; - } - } - return 0; -} - -enum MountPointStateChange - { - MountPointRecentlyMounted, - MountPointRecentlyUnmounted, - MountPointStateUnchanged - }; - - - -static enum MountPointStateChange -get_mount_state (dev_t newdev) -{ - int new_is_present, new_was_present; - - new_was_present = dev_present (newdev, mounted_devices, num_mounted_devices); - refresh_mounted_dev_list (); - new_is_present = dev_present (newdev, mounted_devices, num_mounted_devices); - - if (new_was_present == new_is_present) - return MountPointStateUnchanged; - else if (new_is_present) - return MountPointRecentlyMounted; - else - return MountPointRecentlyUnmounted; -} - - - -/* We stat()ed a directory, chdir()ed into it (we know this - * since direction is TraversingDown), stat()ed it again, - * and noticed that the device numbers are different. Check - * if the file system was recently mounted. - * - * If it was, it looks like chdir()ing into the directory - * caused a file system to be mounted. Maybe automount is - * running. Anyway, that's probably OK - but it happens - * only when we are moving downward. - * - * We also allow for the possibility that a similar thing - * has happened with the unmounting of a file system. This - * is much rarer, as it relies on an automounter timeout - * occurring at exactly the wrong moment. - */ -static enum WdSanityCheckFatality -dirchange_is_fatal (const char *specific_what, - enum WdSanityCheckFatality isfatal, - int silent, - struct stat *newinfo) -{ - enum MountPointStateChange transition = get_mount_state (newinfo->st_dev); - switch (transition) - { - case MountPointRecentlyUnmounted: - isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS; - if (!silent) - { - error (0, 0, - _("WARNING: file system %s has recently been unmounted."), - safely_quote_err_filename (0, specific_what)); - } - break; - - case MountPointRecentlyMounted: - isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS; - if (!silent) - { - error (0, 0, - _("WARNING: file system %s has recently been mounted."), - safely_quote_err_filename (0, specific_what)); - } - break; - - case MountPointStateUnchanged: - /* leave isfatal as it is */ - break; - } - - return isfatal; -} - - -#endif - - - -/* Examine the results of the stat() of a directory from before we - * entered or left it, with the results of stat()ing it afterward. If - * these are different, the file system tree has been modified while we - * were traversing it. That might be an attempt to use a race - * condition to persuade find to do something it didn't intend - * (e.g. an attempt by an ordinary user to exploit the fact that root - * sometimes runs find on the whole file system). However, this can - * also happen if automount is running (certainly on Solaris). With - * automount, moving into a directory can cause a file system to be - * mounted there. - * - * To cope sensibly with this, we will raise an error if we see the - * device number change unless we are chdir()ing into a subdirectory, - * and the directory we moved into has been mounted or unmounted "recently". - * Here "recently" means since we started "find" or we last re-read - * the /etc/mnttab file. - * - * If the device number does not change but the inode does, that is a - * problem. - * - * If the device number and inode are both the same, we are happy. - * - * If a file system is (un)mounted as we chdir() into the directory, that - * may mean that we're now examining a section of the file system that might - * have been excluded from consideration (via -prune or -quit for example). - * Hence we print a warning message to indicate that the output of find - * might be inconsistent due to the change in the file system. - */ -static bool -wd_sanity_check (const char *thing_to_stat, - const char *progname, - const char *what, - dev_t old_dev, - ino_t old_ino, - struct stat *newinfo, - int parent, - int line_no, - enum TraversalDirection direction, - enum WdSanityCheckFatality isfatal, - bool *changed) /* output parameter */ -{ - const char *fstype; - char *specific_what = NULL; - int silent = 0; - const char *current_dir = "."; - - *changed = false; - - set_stat_placeholders (newinfo); - if ((*options.xstat) (current_dir, newinfo) != 0) - fatal_target_file_error (errno, thing_to_stat); - - if (old_dev != newinfo->st_dev) - { - *changed = true; - specific_what = specific_dirname (what); - fstype = filesystem_type (newinfo, current_dir); - silent = fs_likely_to_be_automounted (fstype); - - /* This condition is rare, so once we are here it is - * reasonable to perform an expensive computation to - * determine if we should continue or fail. - */ - if (TraversingDown == direction) - { -#ifdef STAT_MOUNTPOINTS - isfatal = dirchange_is_fatal (specific_what,isfatal,silent,newinfo); -#else - (void) silent; - isfatal = RETRY_IF_SANITY_CHECK_FAILS; -#endif - } - - switch (isfatal) - { - case FATAL_IF_SANITY_CHECK_FAILS: - { - fstype = filesystem_type (newinfo, current_dir); - die (EXIT_FAILURE, 0, - _("%s%s changed during execution of %s (old device number %ld, new device number %ld, file system type is %s) [ref %ld]"), - safely_quote_err_filename (0, specific_what), - parent ? "/.." : "", - safely_quote_err_filename (1, progname), - (long) old_dev, - (long) newinfo->st_dev, - fstype, - (long)line_no); - /*NOTREACHED*/ - return false; - } - - case NON_FATAL_IF_SANITY_CHECK_FAILS: - { - /* Since the device has changed under us, the inode number - * will almost certainly also be different. However, we have - * already decided that this is not a problem. Hence we return - * without checking the inode number. - */ - free (specific_what); - return true; - } - - case RETRY_IF_SANITY_CHECK_FAILS: - return false; - } - } - - /* Device number was the same, check if the inode has changed. */ - if (old_ino != newinfo->st_ino) - { - *changed = true; - specific_what = specific_dirname (what); - fstype = filesystem_type (newinfo, current_dir); - - error ((isfatal == FATAL_IF_SANITY_CHECK_FAILS) ? 1 : 0, - 0, /* no relevant errno value */ - _("%s%s changed during execution of %s " - "(old inode number %" PRIuMAX ", new inode number %" PRIuMAX - ", file system type is %s) [ref %ld]"), - safely_quote_err_filename (0, specific_what), - parent ? "/.." : "", - safely_quote_err_filename (1, progname), - (uintmax_t) old_ino, - (uintmax_t) newinfo->st_ino, - fstype, - (long)line_no); - free (specific_what); - return false; - } - - return true; -} - -enum SafeChdirStatus - { - SafeChdirOK, - SafeChdirFailSymlink, - SafeChdirFailNotDir, - SafeChdirFailStat, - SafeChdirFailWouldBeUnableToReturn, - SafeChdirFailChdirFailed, - SafeChdirFailNonexistent, - SafeChdirFailDestUnreadable - }; - -/* Safely perform a change in directory. We do this by calling - * lstat() on the subdirectory, using chdir() to move into it, and - * then lstat()ing ".". We compare the results of the two stat calls - * to see if they are consistent. If not, we sound the alarm. - * - * If following_links() is true, we do follow symbolic links. - */ -static enum SafeChdirStatus -safely_chdir_lstat (const char *dest, - enum TraversalDirection direction, - struct stat *statbuf_dest, - enum ChdirSymlinkHandling symlink_follow_option, - bool *did_stat) -{ - struct stat statbuf_arrived; - int rv, dotfd=-1; - int saved_errno; /* specific_dirname() changes errno. */ - bool rv_set = false; - bool statflag = false; - int tries = 0; - enum WdSanityCheckFatality isfatal = RETRY_IF_SANITY_CHECK_FAILS; - - saved_errno = errno = 0; - - dotfd = open_cloexec (".", O_RDONLY -#if defined O_LARGEFILE - |O_LARGEFILE -#endif - ); - - /* We jump back to here if wd_sanity_check() - * recoverably triggers an alert. - */ - retry: - ++tries; - - if (dotfd >= 0) - { - /* Stat the directory we're going to. */ - set_stat_placeholders (statbuf_dest); - if (0 == options.xstat (dest, statbuf_dest)) - { - statflag = true; - -#ifdef S_ISLNK - /* symlink_follow_option might be set to SymlinkFollowOk, which - * would allow us to chdir() into a symbolic link. This is - * only useful for the case where the directory we're - * chdir()ing into is the basename of a command line - * argument, for example where "foo/bar/baz" is specified on - * the command line. When -P is in effect (the default), - * baz will not be followed if it is a symlink, but if bar - * is a symlink, it _should_ be followed. Hence we need the - * ability to override the policy set by following_links(). - */ - if (!following_links () && S_ISLNK(statbuf_dest->st_mode)) - { - /* We're not supposed to be following links, but this is - * a link. Check symlink_follow_option to see if we should - * make a special exception. - */ - if (symlink_follow_option == SymlinkFollowOk) - { - /* We need to re-stat() the file so that the - * sanity check can pass. - */ - if (0 != stat (dest, statbuf_dest)) - { - rv = SafeChdirFailNonexistent; - rv_set = true; - saved_errno = errno; - goto fail; - } - statflag = true; - } - else - { - /* Not following symlinks, so the attempt to - * chdir() into a symlink should be prevented. - */ - rv = SafeChdirFailSymlink; - rv_set = true; - saved_errno = 0; /* silence the error message */ - goto fail; - } - } -#endif -#ifdef S_ISDIR - /* Although the immediately following chdir() would detect - * the fact that this is not a directory for us, this would - * result in an extra system call that fails. Anybody - * examining the system-call trace should ideally not be - * concerned that something is actually failing. - */ - if (!S_ISDIR(statbuf_dest->st_mode)) - { - rv = SafeChdirFailNotDir; - rv_set = true; - saved_errno = 0; /* silence the error message */ - goto fail; - } -#endif - - if (options.debug_options & DebugSearch) - fprintf (stderr, "safely_chdir(): chdir(\"%s\")\n", dest); - - if (0 == chdir (dest)) - { - /* check we ended up where we wanted to go */ - bool changed = false; - if (!wd_sanity_check (".", program_name, ".", - statbuf_dest->st_dev, - statbuf_dest->st_ino, - &statbuf_arrived, - 0, __LINE__, direction, - isfatal, - &changed)) - { - /* Only allow one failure. */ - if (RETRY_IF_SANITY_CHECK_FAILS == isfatal) - { - if (0 == fchdir (dotfd)) - { - isfatal = FATAL_IF_SANITY_CHECK_FAILS; - goto retry; - } - else - { - /* Failed to return to original directory, - * but we know that the current working - * directory is not the one that we intend - * to be in. Since fchdir() failed, we - * can't recover from this and so this error - * is fatal. - */ - die (EXIT_FAILURE, errno, - _("failed to return to parent directory")); - } - } - else - { - /* XXX: not sure what to use as an excuse here. */ - rv = SafeChdirFailNonexistent; - rv_set = true; - saved_errno = 0; - goto fail; - } - } - - close (dotfd); - return SafeChdirOK; - } - else - { - saved_errno = errno; - if (ENOENT == saved_errno) - { - rv = SafeChdirFailNonexistent; - rv_set = true; - if (options.ignore_readdir_race) - errno = 0; /* don't issue err msg */ - } - else if (ENOTDIR == saved_errno) - { - /* This can happen if the we stat a directory, - * and then file system activity changes it into - * a non-directory. - */ - saved_errno = 0; /* don't issue err msg */ - rv = SafeChdirFailNotDir; - rv_set = true; - } - else - { - rv = SafeChdirFailChdirFailed; - rv_set = true; - } - goto fail; - } - } - else - { - saved_errno = errno; - rv = SafeChdirFailStat; - rv_set = true; - - if ( (ENOENT == saved_errno) || (0 == state.curdepth)) - saved_errno = 0; /* don't issue err msg */ - goto fail; - } - } - else - { - /* We do not have read permissions on "." */ - rv = SafeChdirFailWouldBeUnableToReturn; - rv_set = true; - goto fail; - } - - /* This is the success path, so we clear errno. The caller probably - * won't be calling error() anyway. - */ - saved_errno = 0; - - /* We use the same exit path for success or failure. - * which has occurred is recorded in RV. - */ - fail: - /* We do not call error() as this would result in a duplicate error - * message when the caller does the same thing. - */ - if (saved_errno) - errno = saved_errno; - - if (dotfd >= 0) - { - close (dotfd); - dotfd = -1; - } - - *did_stat = statflag; - assert (rv_set); - return rv; -} - -/* Safely change working directory to the specified subdirectory. If - * we are not allowed to follow symbolic links, we use open() with - * O_NOFOLLOW, followed by fchdir(). This ensures that we don't - * follow symbolic links (of course, we do follow them if the -L - * option is in effect). - */ -static enum SafeChdirStatus -safely_chdir_nofollow (const char *dest, - enum TraversalDirection direction, - struct stat *statbuf_dest, - enum ChdirSymlinkHandling symlink_follow_option, - bool *did_stat) -{ - int extraflags, fd; - - (void) direction; - (void) statbuf_dest; - - extraflags = 0; - *did_stat = false; - - switch (symlink_follow_option) - { - case SymlinkFollowOk: - extraflags = 0; - break; - - case SymlinkHandleDefault: - if (following_links ()) - extraflags = 0; - else - extraflags = O_NOFOLLOW; /* ... which may still be 0. */ - break; - } - - errno = 0; - fd = open (dest, O_RDONLY -#if defined O_LARGEFILE - |O_LARGEFILE -#endif -#if defined O_CLOEXEC - |O_CLOEXEC -#endif - |extraflags); - if (fd < 0) - { - switch (errno) - { - case ELOOP: - return SafeChdirFailSymlink; /* This is why we use O_NOFOLLOW */ - case ENOENT: - return SafeChdirFailNonexistent; - default: - return SafeChdirFailDestUnreadable; - } - } - - errno = 0; - if (0 == fchdir (fd)) - { - close (fd); - return SafeChdirOK; - } - else - { - int saved_errno = errno; - close (fd); - errno = saved_errno; - - switch (errno) - { - case ENOTDIR: - return SafeChdirFailNotDir; - - case EACCES: - case EBADF: /* Shouldn't happen */ - case EINTR: - case EIO: - default: - return SafeChdirFailChdirFailed; - } - } -} - -static enum SafeChdirStatus -safely_chdir (const char *dest, - enum TraversalDirection direction, - struct stat *statbuf_dest, - enum ChdirSymlinkHandling symlink_follow_option, - bool *did_stat) -{ - enum SafeChdirStatus result; - - /* We're about to leave a directory. If there are any -execdir - * argument lists which have been built but have not yet been - * processed, do them now because they must be done in the same - * directory. - */ - complete_pending_execdirs (); - - /* gnulib defines O_NOFOLLOW to 0 if the OS doesn't have it. */ - options.open_nofollow_available = !!O_NOFOLLOW; - if (options.open_nofollow_available) - { - result = safely_chdir_nofollow (dest, direction, statbuf_dest, - symlink_follow_option, did_stat); - if (SafeChdirFailDestUnreadable != result) - { - return result; - } - else - { - /* Savannah bug #15384: fall through to use safely_chdir_lstat - * if the directory is not readable. - */ - /* Do nothing. */ - } - } - /* Even if O_NOFOLLOW is available, we may need to use the alternative - * method, since parent of the start point may be executable but not - * readable. - */ - return safely_chdir_lstat (dest, direction, statbuf_dest, - symlink_follow_option, did_stat); -} - - - -/* Safely go back to the starting directory. */ -static void -chdir_back (void) -{ - if (options.debug_options & DebugSearch) - fprintf (stderr, "chdir_back(): chdir to start point\n"); - - restore_cwd (initial_wd); -} - -/* Move to the parent of a given directory and then call a function, - * restoring the cwd. Don't bother changing directory if the - * specified directory is a child of "." or is the root directory. - */ -static void -at_top (const char *pathname, - mode_t mode, - ino_t inum, - struct stat *pstat, - void (*action)(const char *pathname, - const char *basename, - int mode, - ino_t inum, - struct stat *pstat)) -{ - int dirchange; - char *parent_dir = dir_name (pathname); - const char *base = last_component (pathname); - - state.curdepth = 0; - state.starting_path_length = strlen (pathname); - - if (0 == *base - || 0 == strcmp (parent_dir, ".")) - { - dirchange = 0; - base = pathname; - } - else - { - enum TraversalDirection direction; - enum SafeChdirStatus chdir_status; - struct stat st; - bool did_stat = false; - - dirchange = 1; - if (0 == strcmp (base, "..")) - direction = TraversingUp; - else - direction = TraversingDown; - - /* We pass SymlinkFollowOk to safely_chdir(), which allows it to - * chdir() into a symbolic link. This is only useful for the - * case where the directory we're chdir()ing into is the - * basename of a command line argument, for example where - * "foo/bar/baz" is specified on the command line. When -P is - * in effect (the default), baz will not be followed if it is a - * symlink, but if bar is a symlink, it _should_ be followed. - * Hence we need the ability to override the policy set by - * following_links(). - */ - chdir_status = safely_chdir (parent_dir, direction, &st, SymlinkFollowOk, &did_stat); - if (SafeChdirOK != chdir_status) - { - const char *what = (SafeChdirFailWouldBeUnableToReturn == chdir_status) ? "." : parent_dir; - if (errno) - error (0, errno, "%s", - safely_quote_err_filename (0, what)); - else - error (0, 0, _("Failed to safely change directory into %s"), - safely_quote_err_filename (0, parent_dir)); - - /* We can't process this command-line argument. */ - state.exit_status = 1; - return; - } - } - - free (parent_dir); - parent_dir = NULL; - - action (pathname, base, mode, inum, pstat); - - if (dirchange) - { - chdir_back (); - } -} - - -static void do_process_top_dir (const char *pathname, - const char *base, - int mode, - ino_t inum, - struct stat *pstat) -{ - (void) pstat; - - process_path (pathname, base, false, ".", mode, inum); - complete_pending_execdirs (); -} - -static void -do_process_predicate (const char *pathname, - const char *base, - int mode, - ino_t inum, - struct stat *pstat) -{ - (void) mode; - (void) inum; - state.rel_pathname = base; /* cwd_dir_fd was already set by safely_chdir */ - apply_predicate (pathname, pstat, get_eval_tree ()); -} - - - - -/* Descend PATHNAME, which is a command-line argument. - - Actions like -execdir assume that we are in the - parent directory of the file we're examining, - and on entry to this function our working directory - is whatever it was when find was invoked. Therefore - If PATHNAME is "." we just leave things as they are. - Otherwise, we figure out what the parent directory is, - and move to that. -*/ -static void -process_top_path (const char *pathname, mode_t mode, ino_t inum) -{ - at_top (pathname, mode, inum, NULL, do_process_top_dir); -} - - -/* Info on each directory in the current tree branch, to avoid - getting stuck in symbolic link loops. */ -static struct dir_id *dir_ids = NULL; -/* Entries allocated in `dir_ids'. */ -static int dir_alloc = 0; -/* Index in `dir_ids' of directory currently being searched. - This is always the last valid entry. */ -static int dir_curr = -1; -/* (Arbitrary) number of entries to grow `dir_ids' by. */ -#define DIR_ALLOC_STEP 32 - - - -/* We've detected a file system loop. This is caused by one of - * two things: - * - * 1. Option -L is in effect and we've hit a symbolic link that - * points to an ancestor. This is harmless. We won't traverse the - * symbolic link. - * - * 2. We have hit a real cycle in the directory hierarchy. In this - * case, we issue a diagnostic message (POSIX requires this) and we - * skip that directory entry. - */ -static void -issue_loop_warning (const char *name, const char *pathname, int level) -{ - struct stat stbuf_link; - if (lstat (name, &stbuf_link) != 0) - stbuf_link.st_mode = S_IFREG; - - if (S_ISLNK(stbuf_link.st_mode)) - { - error (0, 0, - _("Symbolic link %s is part of a loop in the directory hierarchy; we have already visited the directory to which it points."), - safely_quote_err_filename (0, pathname)); - /* XXX: POSIX appears to require that the exit status be non-zero if a - * diagnostic is issued. - */ - } - else - { - int distance = 1 + (dir_curr-level); - /* We have found an infinite loop. POSIX requires us to - * issue a diagnostic. Usually we won't get to here - * because when the leaf optimisation is on, it will cause - * the subdirectory to be skipped. If /a/b/c/d is a hard - * link to /a/b, then the link count of /a/b/c is 2, - * because the ".." entry of /b/b/c/d points to /a, not - * to /a/b/c. - */ - error (0, 0, - ngettext ( - "Filesystem loop detected; %s has the same device number and inode as " - "a directory which is %d level higher in the file system hierarchy", - "Filesystem loop detected; %s has the same device number and inode as " - "a directory which is %d levels higher in the file system hierarchy", - (long)distance), - safely_quote_err_filename (0, pathname), - distance); - } -} - - - -/* Recursively descend path PATHNAME, applying the predicates. - LEAF is true if PATHNAME is known to be in a directory that has no - more unexamined subdirectories, and therefore it is not a directory. - Knowing this allows us to avoid calling stat as long as possible for - leaf files. - - NAME is PATHNAME relative to the current directory. We access NAME - but print PATHNAME. - - PARENT is the path of the parent of NAME, relative to find's - starting directory. - - Return nonzero iff PATHNAME is a directory. */ - -static int -process_path (const char *pathname, const char *name, bool leaf, const char *parent, - mode_t mode, ino_t inum) -{ - struct stat stat_buf; - static dev_t root_dev; /* Device ID of current argument pathname. */ - int i; - struct predicate *eval_tree; - - eval_tree = get_eval_tree (); - /* Assume it is a non-directory initially. */ - stat_buf.st_mode = 0; - - /* The caller usually knows the inode number, either from readdir or - * a *stat call. We use that value (the caller passes 0 to indicate - * ignorance of the inode number). - */ - stat_buf.st_ino = inum; - - state.rel_pathname = name; - state.type = 0; - state.have_stat = false; - state.have_type = false; - state.already_issued_stat_error_msg = false; - - if (!digest_mode (&mode, pathname, name, &stat_buf, leaf)) - return 0; - - if (!S_ISDIR (state.type)) - { - if (state.curdepth >= options.mindepth) - apply_predicate (pathname, &stat_buf, eval_tree); - return 0; - } - - /* From here on, we're working on a directory. */ - - - /* Now we really need to stat the directory, even if we know the - * type, because we need information like struct stat.st_rdev. - */ - if (get_statinfo (pathname, name, &stat_buf) != 0) - return 0; - - state.have_stat = true; - mode = state.type = stat_buf.st_mode; /* use full info now that we have it. */ - state.stop_at_current_level = - options.maxdepth >= 0 - && state.curdepth >= options.maxdepth; - - /* If we've already seen this directory on this branch, - don't descend it again. */ - for (i = 0; i <= dir_curr; i++) - if (stat_buf.st_ino == dir_ids[i].ino && - stat_buf.st_dev == dir_ids[i].dev) - { - state.stop_at_current_level = true; - issue_loop_warning (name, pathname, i); - } - - if (dir_alloc <= ++dir_curr) - { - dir_alloc += DIR_ALLOC_STEP; - dir_ids = (struct dir_id *) - xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id)); - } - dir_ids[dir_curr].ino = stat_buf.st_ino; - dir_ids[dir_curr].dev = stat_buf.st_dev; - - if (options.stay_on_filesystem) - { - if (state.curdepth == 0) - root_dev = stat_buf.st_dev; - else if (stat_buf.st_dev != root_dev) - state.stop_at_current_level = true; - } - - if (options.do_dir_first && state.curdepth >= options.mindepth) - apply_predicate (pathname, &stat_buf, eval_tree); - - if (options.debug_options & DebugSearch) - fprintf (stderr, "pathname = %s, stop_at_current_level = %d\n", - pathname, state.stop_at_current_level); - - if (state.stop_at_current_level == false) - { - /* Scan directory on disk. */ - process_dir (pathname, name, strlen (pathname), &stat_buf, parent); - } - - if (options.do_dir_first == false && state.curdepth >= options.mindepth) - { - /* The fields in 'state' are now out of date. Correct them. - */ - if (!digest_mode (&mode, pathname, name, &stat_buf, leaf)) - return 0; - - if (0 == dir_curr) - { - at_top (pathname, mode, stat_buf.st_ino, &stat_buf, - do_process_predicate); - } - else - { - do_process_predicate (pathname, name, mode, stat_buf.st_ino, - &stat_buf); - } - } - - dir_curr--; - - return 1; -} - - -/* Scan directory PATHNAME and recurse through process_path for each entry. - - PATHLEN is the length of PATHNAME. - - NAME is PATHNAME relative to the current directory. - - STATP is the results of *options.xstat on it. - - PARENT is the path of the parent of NAME, relative to find's - starting directory. */ - -static void -process_dir (const char *pathname, const char *name, int pathlen, const struct stat *statp, const char *parent) -{ - int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */ - bool subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */ - struct stat stat_buf; - size_t dircount = 0u; - DIR *dirp; - - if (statp->st_nlink < 2) - { - subdirs_unreliable = true; - subdirs_left = 0; - } - else - { - subdirs_unreliable = false; /* not necessarily right */ - subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */ - } - - errno = 0; - dirp = opendir (name); - - if (dirp == NULL) - { - assert (errno != 0); - error (0, errno, "%s", safely_quote_err_filename (0, pathname)); - state.exit_status = 1; - } - else - { - char *cur_path; /* Full path of each file to process. */ - char *cur_name; /* Base name of each file to process. */ - unsigned cur_path_size; /* Bytes allocated for `cur_path'. */ - register unsigned file_len; /* Length of each path to process. */ - register unsigned pathname_len; /* PATHLEN plus trailing '/'. */ - bool did_stat = false; - - if (pathname[pathlen - 1] == '/') - pathname_len = pathlen + 1; /* For '\0'; already have '/'. */ - else - pathname_len = pathlen + 2; /* For '/' and '\0'. */ - cur_path_size = 0; - cur_path = NULL; - - /* We're about to leave the directory. If there are any - * -execdir argument lists which have been built but have not - * yet been processed, do them now because they must be done in - * the same directory. - */ - complete_pending_execdirs (); - - if (strcmp (name, ".")) - { - enum SafeChdirStatus status = safely_chdir (name, TraversingDown, &stat_buf, SymlinkHandleDefault, &did_stat); - switch (status) - { - case SafeChdirOK: - /* If there had been a change but wd_sanity_check() - * accepted it, we need to accept that on the - * way back up as well, so modify our record - * of what we think we should see later. - * If there was no change, the assignments are a no-op. - * - * However, before performing the assignment, we need to - * check that we have the stat information. If O_NOFOLLOW - * is available, safely_chdir() will not have needed to use - * stat(), and so stat_buf will just contain random data. - */ - if (!did_stat) - { - /* If there is a link we need to follow it. Hence - * the direct call to stat() not through (options.xstat) - */ - set_stat_placeholders (&stat_buf); - if (0 != stat (".", &stat_buf)) - break; /* skip the assignment. */ - } - dir_ids[dir_curr].dev = stat_buf.st_dev; - dir_ids[dir_curr].ino = stat_buf.st_ino; - - break; - - case SafeChdirFailWouldBeUnableToReturn: - error (0, errno, "."); - state.exit_status = 1; - break; - - case SafeChdirFailNonexistent: - case SafeChdirFailDestUnreadable: - case SafeChdirFailStat: - case SafeChdirFailNotDir: - case SafeChdirFailChdirFailed: - error (0, errno, "%s", - safely_quote_err_filename (0, pathname)); - state.exit_status = 1; - return; - - case SafeChdirFailSymlink: - error (0, 0, - _("warning: not following the symbolic link %s"), - safely_quote_err_filename (0, pathname)); - state.exit_status = 1; - return; - } - } - - while (1) - { - const char *namep; - mode_t mode = 0; - const struct dirent *dp; - - /* We reset errno here to distinguish between end-of-directory and an error */ - errno = 0; - dp = readdir (dirp); - if (NULL == dp) - { - if (errno) - { - /* an error occurred, but we are not yet at the end - of the directory stream. */ - error (0, errno, "%s", safely_quote_err_filename (0, pathname)); - continue; - } - else - { - break; /* End of the directory stream. */ - } - } - else - { - namep = dp->d_name; - /* Skip "", ".", and "..". "" is returned by at least one buggy - implementation: Solaris 2.4 readdir on NFS file systems. */ - if (!namep[0] || - (namep[0] == '.' && (namep[1] == 0 || - (namep[1] == '.' && namep[2] == 0)))) - continue; - } - -#if defined HAVE_STRUCT_DIRENT_D_TYPE - if (dp->d_type != DT_UNKNOWN) - mode = type_to_mode (dp->d_type); -#endif - - /* Append this directory entry's name to the path being searched. */ - file_len = pathname_len + strlen (namep); - if (file_len > cur_path_size) - { - cur_path_size = (file_len/1024 + 1) * 1024; - free (cur_path); - cur_path = xmalloc (cur_path_size); - strcpy (cur_path, pathname); - cur_path[pathname_len - 2] = '/'; - } - cur_name = cur_path + pathname_len - 1; - strcpy (cur_name, namep); - - state.curdepth++; - if (!options.no_leaf_check && !subdirs_unreliable) - { - if (mode && S_ISDIR(mode) && (subdirs_left == 0)) - { - /* This is a subdirectory, but the number of directories we - * have found now exceeds the number we would expect given - * the hard link count on the parent. This is likely to be - * a bug in the file system driver (e.g. Linux's - * /proc file system) or may just be a fact that the OS - * doesn't really handle hard links with Unix semantics. - * In the latter case, -noleaf should be used routinely. - */ - error (0, 0, _("WARNING: Hard link count is wrong for %s (saw only st_nlink=%" PRIuMAX " but we already saw %" PRIuMAX " subdirectories): this may be a bug in your file system driver. Automatically turning on find's -noleaf option. Earlier results may have failed to include directories that should have been searched."), - safely_quote_err_filename(0, pathname), - (uintmax_t) statp->st_nlink, - (uintmax_t) dircount); - state.exit_status = 1; /* We know the result is wrong, now */ - options.no_leaf_check = true; /* Don't make same - mistake again */ - subdirs_unreliable = 1; - subdirs_left = 1; /* band-aid for this iteration. */ - } - - /* Normal case optimization. On normal Unix - file systems, a directory that has no subdirectories - has two links: its name, and ".". Any additional - links are to the ".." entries of its subdirectories. - Once we have processed as many subdirectories as - there are additional links, we know that the rest of - the entries are non-directories -- in other words, - leaf files. */ - { - int count; - count = process_path (cur_path, cur_name, - subdirs_left == 0, pathname, - mode, D_INO(dp)); - subdirs_left -= count; - dircount += count; - } - } - else - { - /* There might be weird (e.g., CD-ROM or MS-DOS) file systems - mounted, which don't have Unix-like directory link counts. */ - process_path (cur_path, cur_name, false, pathname, mode, - D_INO(dp)); - } - - state.curdepth--; - } - - - /* We're about to leave the directory. If there are any - * -execdir argument lists which have been built but have not - * yet been processed, do them now because they must be done in - * the same directory. - */ - complete_pending_execdirs (); - - if (strcmp (name, ".")) - { - enum SafeChdirStatus status; - - /* We could go back and do the next command-line arg - instead, maybe using longjmp. */ - char const *dir; - bool deref = following_links () ? true : false; - - if ( (state.curdepth>0) && !deref) - dir = ".."; - else - { - chdir_back (); - dir = parent; - } - - did_stat = false; - status = safely_chdir (dir, TraversingUp, &stat_buf, SymlinkHandleDefault, &did_stat); - switch (status) - { - case SafeChdirOK: - break; - - case SafeChdirFailWouldBeUnableToReturn: - die (EXIT_FAILURE, errno, "."); - return; - - case SafeChdirFailNonexistent: - case SafeChdirFailDestUnreadable: - case SafeChdirFailStat: - case SafeChdirFailSymlink: - case SafeChdirFailNotDir: - case SafeChdirFailChdirFailed: - die (EXIT_FAILURE, errno, - "%s", safely_quote_err_filename (0, pathname)); - return; - } - } - - free (cur_path); - CLOSEDIR (dirp); - } - - if (subdirs_unreliable) - { - /* Make sure we hasn't used the variable subdirs_left if we knew - * we shouldn't do so. - */ - assert (0 == subdirs_left || options.no_leaf_check); - } -} diff --git a/find/testsuite/config/unix.exp b/find/testsuite/config/unix.exp index d9211843..a879c896 100644 --- a/find/testsuite/config/unix.exp +++ b/find/testsuite/config/unix.exp @@ -20,39 +20,28 @@ # written by Rob Savoye . -global OLDFIND global FTSFIND verbose "base_dir is $base_dir" 2 global env; set env(GNU_FINDUTILS_FD_LEAK_CHECK) "1" -# look for OLDFIND and FTSFIND -if { ![info exists OLDFIND] || ![info exists FTSFIND] } { - verbose "Searching for oldfind" +# look for FTSFIND +if { ![info exists FTSFIND] } { + verbose "Searching for find" set dir "$base_dir/.." set objfile "ftsfind.o" if ![file exists "$dir/$objfile"] then { error "dir is $dir, but I cannot see $objfile in that directory" } - set OLDFIND [findfile $dir/oldfind $dir/oldfind [transform oldfind]] set FTSFIND [findfile $dir/find $dir/find [transform find ]] } verbose "ftsfind is at $FTSFIND" 2 -verbose "oldfind is at $OLDFIND" 2 - -if { [ string equal $FTSFIND $OLDFIND ] } { - error "OLDFIND and FTSFIND are set to $FTSFIND, which can't be right" -} if [file exists $FTSFIND] then { - if [file exists $OLDFIND] then { - verbose "FTSFIND=$FTSFIND and OLDFIND=$OLDFIND both exist." 2 - } else { - error "OLDFIND=$OLDFIND, but that program does not exist" - } + verbose "FTSFIND=$FTSFIND exists." 2 } else { error "FTSFIND=$FTSFIND, but that program does not exist (base_dir is $base_dir)" } @@ -198,10 +187,8 @@ proc optimisation_levels_to_test {} { } proc find_start { passfail options {infile ""} {output ""} {setup ""}} { - global OLDFIND global FTSFIND global FINDFLAGS - global SKIP_OLD global SKIP_NEW if {$infile != ""} then { @@ -214,18 +201,10 @@ proc find_start { passfail options {infile ""} {output ""} {setup ""}} { error "$FTSFIND, program does not exist" exit 1 } - if {[which $OLDFIND] == 0} then { - error "$OLDFIND, program does not exist" - exit 1 - } # Now run the test with each binary, once with each optimisation level. foreach optlevel [optimisation_levels_to_test] { set flags "$FINDFLAGS -O$optlevel" - if { ![info exists SKIP_OLD] || ! $SKIP_OLD } { - eval $setup - do_find_start old-O$optlevel $OLDFIND $flags $passfail $options $infile $output - } if { ![info exists SKIP_NEW] || !$SKIP_NEW } { eval $setup do_find_start new-O$optlevel $FTSFIND $flags $passfail $options $infile $output diff --git a/find/testsuite/find.posix/dotdotfiles.exp b/find/testsuite/find.posix/dotdotfiles.exp index 80df7c6c..9a45ea24 100644 --- a/find/testsuite/find.posix/dotdotfiles.exp +++ b/find/testsuite/find.posix/dotdotfiles.exp @@ -1,6 +1,6 @@ # Test entries starting with "..", e.g. "..tmp". # Commit v4.5.10-95-ga29e61b introduced a regression -# which made oldfind(1) skip such entries. +# which made (no longer built) oldfind(1) skip such entries. # This is Savannah bug #45090. exec rm -rf tmp exec mkdir tmp tmp/..tmp diff --git a/po/POTFILES.in b/po/POTFILES.in index 813b708c..ea323a92 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -9,7 +9,6 @@ find/exec.c find/fstype.c find/ftsfind.c -find/oldfind.c find/parser.c find/pred.c find/print.c diff --git a/tests/find/debug-missing-arg.sh b/tests/find/debug-missing-arg.sh index ce8dffaf..776f295d 100755 --- a/tests/find/debug-missing-arg.sh +++ b/tests/find/debug-missing-arg.sh @@ -19,14 +19,10 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find -# Exercise both find executables. -for exe in find oldfind; do - rm -f out err || framework_failure_ - returns_ 1 "$exe" -D >/dev/null 2> err || fail=1 - grep -F "find: Missing argument after the -D option." err \ - || { cat err; fail=1; } -done +returns_ 1 find -D >/dev/null 2> err || fail=1 +grep -F "find: Missing argument after the -D option." err \ + || { cat err; fail=1; } Exit $fail diff --git a/tests/find/exec-plus-last-file.sh b/tests/find/exec-plus-last-file.sh index 596f544b..e9001b64 100755 --- a/tests/find/exec-plus-last-file.sh +++ b/tests/find/exec-plus-last-file.sh @@ -21,7 +21,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # Require seq(1) for this test - which may not be available # on some systems, e.g on some *BSDs. @@ -57,10 +57,8 @@ mkdir "$DIR" \ || framework_failure_ -for exe in find oldfind; do - "$exe" "$DIR" -type f -exec "$CMD" '{}' + > out || fail=1 - LC_ALL=C sort out > out2 || fail=1 - compare exp out2 || fail=1 -done +find "$DIR" -type f -exec "$CMD" '{}' + > out || fail=1 +LC_ALL=C sort out > out2 || fail=1 +compare exp out2 || fail=1 Exit $fail diff --git a/tests/find/execdir-fd-leak.sh b/tests/find/execdir-fd-leak.sh index 4fbf0a5c..2b680f5e 100755 --- a/tests/find/execdir-fd-leak.sh +++ b/tests/find/execdir-fd-leak.sh @@ -19,7 +19,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # seq is not required by POSIX, so we have manual lists of number here instead. three_to_thirty_five="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" @@ -55,12 +55,10 @@ make_test_data() { make_test_data \ || framework_failure_ "failed to set up the test" -for exe in find oldfind; do - ( ulimit -n 30 && \ - ${exe} . -type f -execdir cat '{}' \; >/dev/null; \ - ) \ - || { echo "Option -execdir of ${exe} leaks file descriptors" >&2 ; \ +( ulimit -n 30 && \ + find . -type f -execdir cat '{}' \; >/dev/null; \ +) \ + || { echo "Option -execdir leaks file descriptors" >&2 ; \ fail=1 ; } -done Exit $fail diff --git a/tests/find/many-dir-entries-vs-OOM.sh b/tests/find/many-dir-entries-vs-OOM.sh index 8ab343f7..d2edb253 100755 --- a/tests/find/many-dir-entries-vs-OOM.sh +++ b/tests/find/many-dir-entries-vs-OOM.sh @@ -19,7 +19,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # Mark as expensive. expensive_ @@ -77,18 +77,12 @@ cd .. # Create a small directory as reference to determine lower ulimit. mkdir dir2 && touch dir2/a dir2/b dir2/c || framework_failure_ -# We don't check oldfind, as it uses savedir, meaning that -# it stores all the directory entries. Hence the excessive -# memory consumption bug applies to oldfind even though it is -# not using fts. -for exe in find oldfind; do - # Determine memory consumption for the trivial case. - vm="$(get_min_ulimit_v_ ${exe} dir2 -fprint dummy)" \ - || skip_ "this shell lacks ulimit support" - - # Allow 35MiB more memory than above. - ( ulimit -v $(($vm + 35000)) && ${exe} dir >/dev/null ) \ - || { echo "${exe}: memory consumption is too high" >&2; fail=1; } -done +# Determine memory consumption for the trivial case. +vm="$(get_min_ulimit_v_ find dir2 -fprint dummy)" \ + || skip_ "this shell lacks ulimit support" + +# Allow 35MiB more memory than above. +( ulimit -v $(($vm + 35000)) && find dir >/dev/null ) \ + || { echo "memory consumption is too high" >&2; fail=1; } Exit $fail diff --git a/tests/find/name-lbracket-literal.sh b/tests/find/name-lbracket-literal.sh index 9f5583d2..b3a6be58 100755 --- a/tests/find/name-lbracket-literal.sh +++ b/tests/find/name-lbracket-literal.sh @@ -18,7 +18,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # Prepare a file named '['. touch '[' || framework_failure_ @@ -27,7 +27,4 @@ echo './[' > exp || framework_failure_ find -name '[' -print > out || fail=1 compare exp out || fail=1 -oldfind -name '[' -print > out2 || fail=1 -compare exp out2 || fail=1 - Exit $fail diff --git a/tests/find/printf_escape_c.sh b/tests/find/printf_escape_c.sh index 6a938a2d..530ac7b8 100755 --- a/tests/find/printf_escape_c.sh +++ b/tests/find/printf_escape_c.sh @@ -17,19 +17,16 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find echo 'hello^.^world' > exp || framework_failure_ -for executable in oldfind find; do - rm -f out || framework_failure_ - $executable . -maxdepth 0 \ - -printf 'hello^\cthere' \ - -exec printf %s {} \; \ - -printf '^world\n' \ - > out || fail=1 +find . -maxdepth 0 \ + -printf 'hello^\cthere' \ + -exec printf %s {} \; \ + -printf '^world\n' \ + > out || fail=1 - compare exp out || fail=1 -done +compare exp out || fail=1 Exit $fail diff --git a/tests/find/printf_escapechars.sh b/tests/find/printf_escapechars.sh index 8d6dcebe..55900e59 100755 --- a/tests/find/printf_escapechars.sh +++ b/tests/find/printf_escapechars.sh @@ -17,7 +17,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # Check for working od(1). echo test | od -c >/dev/null \ @@ -54,33 +54,29 @@ _EOD_ # Prepare expected stderr. echo "warning: unrecognized escape" > experr || framework_failure_ -for executable in oldfind find; do - rm -f out* err* || framework_failure_ +find . -maxdepth 0 \ + -printf 'OCTAL1: \1\n' \ + -printf 'OCTAL2: \02\n' \ + -printf 'OCTAL3: \003\n' \ + -printf 'OCTAL4: \0044\n' \ + -printf 'OCTAL8: \0028\n' \ + -printf 'BEL: \a\n' \ + -printf 'CR: \r\n' \ + -printf 'FF: \f\n' \ + -printf 'TAB: \t\n' \ + -printf 'VTAB: \v\n' \ + -printf 'BS: \b\n' \ + -printf 'BACKSLASH: \\\n' \ + -printf 'UNKNOWN: \z\n' \ + > out 2> err || fail=1 - $executable . -maxdepth 0 \ - -printf 'OCTAL1: \1\n' \ - -printf 'OCTAL2: \02\n' \ - -printf 'OCTAL3: \003\n' \ - -printf 'OCTAL4: \0044\n' \ - -printf 'OCTAL8: \0028\n' \ - -printf 'BEL: \a\n' \ - -printf 'CR: \r\n' \ - -printf 'FF: \f\n' \ - -printf 'TAB: \t\n' \ - -printf 'VTAB: \v\n' \ - -printf 'BS: \b\n' \ - -printf 'BACKSLASH: \\\n' \ - -printf 'UNKNOWN: \z\n' \ - > out 2> err || fail=1 +# Some 'od' implementations (e.g. on the *BSDs) produce different indentation +# and trailing spaces, therefore squeeze the former and remove the latter. +od -t o1 < out | sed 's/ */ /g; s/ *$//;' > out2 || framework_failure_ +compare expout out2 || fail=1 - # Some 'od' implementations (e.g. on the *BSDs) produce different indentation - # and trailing spaces, therefore squeeze the former and remove the latter. - od -t o1 < out | sed 's/ */ /g; s/ *$//;' > out2 || framework_failure_ - compare expout out2 || fail=1 - - sed 's/^.*\(warning: unrecognized escape\) .*$/\1/' err > err2 \ - || framework_failure_ - compare experr err2 || fail=1 -done +sed 's/^.*\(warning: unrecognized escape\) .*$/\1/' err > err2 \ + || framework_failure_ +compare experr err2 || fail=1 Exit $fail diff --git a/tests/find/printf_inode.sh b/tests/find/printf_inode.sh index 53925d2b..40e918ff 100755 --- a/tests/find/printf_inode.sh +++ b/tests/find/printf_inode.sh @@ -17,7 +17,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find make_canonical() { sed -e ' @@ -33,11 +33,9 @@ make_canonical() { # Let ls(1) create the expected output. ls -i file | make_canonical > exp || framework_failure_ -for executable in oldfind find; do - rm -f out out2 - $executable file -printf '%i_%p\n' > out || fail=1 - make_canonical < out > out2 || framework_failure_ - compare exp out2 || fail=1 -done +rm -f out out2 +find file -printf '%i_%p\n' > out || fail=1 +make_canonical < out > out2 || framework_failure_ +compare exp out2 || fail=1 Exit $fail diff --git a/tests/find/refuse-noop.sh b/tests/find/refuse-noop.sh index d896ee26..a2a1a53f 100755 --- a/tests/find/refuse-noop.sh +++ b/tests/find/refuse-noop.sh @@ -19,18 +19,16 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # Exercise both the previous name of the pseudo-option '-noop', -# and the now renamed '---noop' option for both find executables. -for exe in find oldfind; do - for opt in 'noop' '--noop'; do - rm -f out err || framework_failure_ - returns_ 1 "$exe" "-${opt}" > out 2> err || fail=1 - compare /dev/null out || fail=1 - grep "find: unknown predicate .-${opt}." err \ - || { cat err; fail=1; } - done +# and the now renamed '---noop' option. +for opt in 'noop' '--noop'; do + rm -f out err || framework_failure_ + returns_ 1 find "-${opt}" > out 2> err || fail=1 + compare /dev/null out || fail=1 + grep "find: unknown predicate .-${opt}." err \ + || { cat err; fail=1; } done Exit $fail diff --git a/tests/find/type_list.sh b/tests/find/type_list.sh index 06c5c8b4..0165806d 100755 --- a/tests/find/type_list.sh +++ b/tests/find/type_list.sh @@ -18,7 +18,7 @@ # along with this program. If not, see . . "${srcdir=.}/tests/init.sh"; fu_path_prepend_ -print_ver_ find oldfind +print_ver_ find # This test is in 'all_root_tests' to get better coverage for file types a # regular user cannot create. Still, it is run during 'make check' as well. @@ -116,175 +116,171 @@ make_test_data dir \ find dir -mindepth 1 -ls fail=0 -for exe in find oldfind; do - - # Negative tests first. Expect the output to be empty. - > exp - - # Ensure empty type arguments are rejected. - returns_ 1 "${exe}" dir -mindepth 1 -type '' > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Arguments to -type should contain at least one letter' err \ - || { cat err; fail=1; } - - returns_ 1 "${exe}" dir -mindepth 1 -xtype '' > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Arguments to -xtype should contain at least one letter' err \ - || { cat err; fail=1; } - - # Ensure non-separated type arguments are rejected. - returns_ 1 "${exe}" dir -mindepth 1 -type fd > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Must separate multiple arguments to -type' err \ - || { cat err; fail=1; } - - returns_ 1 "${exe}" dir -mindepth 1 -xtype fd > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Must separate multiple arguments to -xtype' err \ - || { cat err; fail=1; } - - # Ensure unterminated type list arguments are rejected. - returns_ 1 "${exe}" dir -mindepth 1 -type f, > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Last file type in list argument to -type is missing' err \ - || { cat err; fail=1; } - - returns_ 1 "${exe}" dir -mindepth 1 -xtype f, > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Last file type in list argument to -xtype is missing' err \ - || { cat err; fail=1; } - - # Ensure duplicate entries in the type list arguments are rejected. - returns_ 1 "${exe}" dir -mindepth 1 -type f,f > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Duplicate file type .* in the argument list to -type' err \ - || { cat err; fail=1; } - - returns_ 1 "${exe}" dir -mindepth 1 -xtype f,f > out 2> err || fail=1 - compare exp out || fail=1 - grep 'Duplicate file type .* in the argument list to -xtype' err \ - || { cat err; fail=1; } - - # Continue with positive tests. - # Files only - grep -e '/reg$' all > exp - "${exe}" dir -type f > out || fail=1 + +# Negative tests first. Expect the output to be empty. +> exp + +# Ensure empty type arguments are rejected. +returns_ 1 find dir -mindepth 1 -type '' > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Arguments to -type should contain at least one letter' err \ + || { cat err; fail=1; } + +returns_ 1 find dir -mindepth 1 -xtype '' > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Arguments to -xtype should contain at least one letter' err \ + || { cat err; fail=1; } + +# Ensure non-separated type arguments are rejected. +returns_ 1 find dir -mindepth 1 -type fd > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Must separate multiple arguments to -type' err \ + || { cat err; fail=1; } + +returns_ 1 find dir -mindepth 1 -xtype fd > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Must separate multiple arguments to -xtype' err \ + || { cat err; fail=1; } + +# Ensure unterminated type list arguments are rejected. +returns_ 1 find dir -mindepth 1 -type f, > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Last file type in list argument to -type is missing' err \ + || { cat err; fail=1; } + +returns_ 1 find dir -mindepth 1 -xtype f, > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Last file type in list argument to -xtype is missing' err \ + || { cat err; fail=1; } + +# Ensure duplicate entries in the type list arguments are rejected. +returns_ 1 find dir -mindepth 1 -type f,f > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Duplicate file type .* in the argument list to -type' err \ + || { cat err; fail=1; } + +returns_ 1 find dir -mindepth 1 -xtype f,f > out 2> err || fail=1 +compare exp out || fail=1 +grep 'Duplicate file type .* in the argument list to -xtype' err \ + || { cat err; fail=1; } + +# Continue with positive tests. +# Files only +grep -e '/reg$' all > exp +find dir -type f > out || fail=1 +sort -o out out +compare exp out || fail=1; + +# Symbolic links only. +if [ $HAVE_LINK = 1 ]; then + grep -e 'link$' all > exp + find dir -type l > out || fail=1 sort -o out out compare exp out || fail=1; - # Symbolic links only. - if [ $HAVE_LINK = 1 ]; then - - grep -e 'link$' all > exp - "${exe}" dir -type l > out || fail=1 - sort -o out out - compare exp out || fail=1; - - grep -e 'dangling-link$' all > exp - "${exe}" dir -xtype l > out || fail=1 - sort -o out out - compare exp out || fail=1; - fi - - # Files and directories. - grep -e '/reg$' -e '/dir$' all > exp - "${exe}" dir -mindepth 1 -type f,d > out || fail=1 + grep -e 'dangling-link$' all > exp + find dir -xtype l > out || fail=1 sort -o out out compare exp out || fail=1; - - grep -e '/reg' -e '/dir' all > exp - "${exe}" dir -mindepth 1 -xtype f,d > out || fail=1 +fi + +# Files and directories. +grep -e '/reg$' -e '/dir$' all > exp +find dir -mindepth 1 -type f,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +grep -e '/reg' -e '/dir' all > exp +find dir -mindepth 1 -xtype f,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +# Block devices. +grep -e '/reg$' -e '/dir$' -e '/blk$' all > exp +find dir -mindepth 1 -type b,f,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +grep -e '/reg' -e '/dir' -e '/blk' all > exp +find dir -mindepth 1 -xtype b,f,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +# Character devices. +grep -e '/reg$' -e '/dir$' -e '/chr$' all > exp +find dir -mindepth 1 -type f,c,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +grep -e '/reg' -e '/dir' -e '/chr' all > exp +find dir -mindepth 1 -xtype f,c,d > out || fail=1 +sort -o out out +compare exp out || fail=1; + +# FIFOs. +if [ $HAVE_FIFO = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/fifo$' all > exp + find dir -mindepth 1 -type f,d,p > out || fail=1 sort -o out out compare exp out || fail=1; - # Block devices. - grep -e '/reg$' -e '/dir$' -e '/blk$' all > exp - "${exe}" dir -mindepth 1 -type b,f,d > out || fail=1 + grep -e '/reg' -e '/dir' -e '/fifo' all > exp + find dir -mindepth 1 -xtype f,d,p > out || fail=1 sort -o out out compare exp out || fail=1; +fi - grep -e '/reg' -e '/dir' -e '/blk' all > exp - "${exe}" dir -mindepth 1 -xtype b,f,d > out || fail=1 +# Sockets. +if [ $HAVE_SOCK = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/sock$' all > exp + find dir -mindepth 1 -type f,d,s > out || fail=1 sort -o out out compare exp out || fail=1; - # Character devices. - grep -e '/reg$' -e '/dir$' -e '/chr$' all > exp - "${exe}" dir -mindepth 1 -type f,c,d > out || fail=1 + grep -e '/reg' -e '/dir' -e '/sock' all > exp + find dir -mindepth 1 -xtype f,d,s > out || fail=1 sort -o out out compare exp out || fail=1; +fi - grep -e '/reg' -e '/dir' -e '/chr' all > exp - "${exe}" dir -mindepth 1 -xtype f,c,d > out || fail=1 +# Symbolic links. +if [ $HAVE_LINK = 1 ]; then + grep -e '/reg$' -e 'link$' all > exp + find dir -mindepth 1 -type f,l > out || fail=1 sort -o out out compare exp out || fail=1; - # FIFOs. - if [ $HAVE_FIFO = 1 ]; then - grep -e '/reg$' -e '/dir$' -e '/fifo$' all > exp - "${exe}" dir -mindepth 1 -type f,d,p > out || fail=1 - sort -o out out - compare exp out || fail=1; - - grep -e '/reg' -e '/dir' -e '/fifo' all > exp - "${exe}" dir -mindepth 1 -xtype f,d,p > out || fail=1 - sort -o out out - compare exp out || fail=1; - fi - - # Sockets. - if [ $HAVE_SOCK = 1 ]; then - grep -e '/reg$' -e '/dir$' -e '/sock$' all > exp - "${exe}" dir -mindepth 1 -type f,d,s > out || fail=1 - sort -o out out - compare exp out || fail=1; - - grep -e '/reg' -e '/dir' -e '/sock' all > exp - "${exe}" dir -mindepth 1 -xtype f,d,s > out || fail=1 - sort -o out out - compare exp out || fail=1; - fi - - # Symbolic links. - if [ $HAVE_LINK = 1 ]; then - - grep -e '/reg$' -e 'link$' all > exp - "${exe}" dir -mindepth 1 -type f,l > out || fail=1 - sort -o out out - compare exp out || fail=1; - - grep -e '/reg' -e 'dangling-link$' all > exp - "${exe}" dir -mindepth 1 -xtype f,l > out || fail=1 - sort -o out out - compare exp out || fail=1; - fi - - # -xtype: all but the dangling symlink. - t='f,d,b,c' - [ $HAVE_FIFO = 1 ] && t="$t,p" - [ $HAVE_SOCK = 1 ] && t="$t,s" - [ $HAVE_DOOR = 1 ] && t="$t,D" - grep -v 'dangling-link$' all > exp - "${exe}" dir -mindepth 1 -xtype "$t" > out || fail=1 + grep -e '/reg' -e 'dangling-link$' all > exp + find dir -mindepth 1 -xtype f,l > out || fail=1 sort -o out out compare exp out || fail=1; - - # negation - if [ $HAVE_LINK = 1 ]; then - "${exe}" dir -mindepth 1 -not -xtype l > out || fail=1 - sort -o out out - compare exp out || fail=1; - fi - - # Finally: full list - [ $HAVE_LINK = 1 ] && t="$t,l" - "${exe}" dir -mindepth 1 -type "$t" > out || fail=1 +fi + +# -xtype: all but the dangling symlink. +t='f,d,b,c' +[ $HAVE_FIFO = 1 ] && t="$t,p" +[ $HAVE_SOCK = 1 ] && t="$t,s" +[ $HAVE_DOOR = 1 ] && t="$t,D" +grep -v 'dangling-link$' all > exp +find dir -mindepth 1 -xtype "$t" > out || fail=1 +sort -o out out +compare exp out || fail=1; + +# negation +if [ $HAVE_LINK = 1 ]; then + find dir -mindepth 1 -not -xtype l > out || fail=1 sort -o out out - compare all out || fail=1; + compare exp out || fail=1; +fi - "${exe}" dir -mindepth 1 -xtype "$t" > out || fail=1 - sort -o out out - compare all out || fail=1; -done +# Finally: full list +[ $HAVE_LINK = 1 ] && t="$t,l" +find dir -mindepth 1 -type "$t" > out || fail=1 +sort -o out out +compare all out || fail=1; + +find dir -mindepth 1 -xtype "$t" > out || fail=1 +sort -o out out +compare all out || fail=1; Exit $fail diff --git a/tests/local.mk b/tests/local.mk index 5b5a0e64..17efc591 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -15,7 +15,7 @@ ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . -built_programs = find oldfind xargs frcode locate updatedb +built_programs = find xargs frcode locate updatedb # Indirections required so that we'll still be able to know the # complete list of our tests even if the user overrides TESTS -- 2.33.0