From 1c68907c32fdd3cf965bc4fe05d6cd098954f72f Mon Sep 17 00:00:00 2001 From: jay Date: Wed, 24 Nov 2004 11:56:14 +0000 Subject: [PATCH] When wd_sanity_check() fails, enumerate the mounted devices, rather than the mounted filesystem names --- find/defs.h | 1 + find/find.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- find/fstype.c | 110 +++++++++++++++++++++++++++++-- 3 files changed, 282 insertions(+), 32 deletions(-) diff --git a/find/defs.h b/find/defs.h index 1e2ffdf..a984e80 100644 --- a/find/defs.h +++ b/find/defs.h @@ -345,6 +345,7 @@ void set_follow_state PARAMS((enum SymlinkOption opt)); /* fstype.c */ char *filesystem_type PARAMS((const char *path, const char *relpath, const struct stat *statp)); char * get_mounted_filesystems (void); +dev_t * get_mounted_devices PARAMS((size_t *)); /* parser.c */ PFB find_parser PARAMS((char *search_name)); diff --git a/find/find.c b/find/find.c index 3789848..9525b85 100644 --- a/find/find.c +++ b/find/find.c @@ -62,7 +62,7 @@ (*(node)->pred_func)((pathname), (stat_buf_ptr), (node)) -static void init_mount_point_list(void); +static void init_mounted_dev_list(void); static void process_top_path PARAMS((char *pathname)); static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent)); static void process_dir PARAMS((char *pathname, char *name, int pathlen, struct stat *statp, char *parent)); @@ -170,6 +170,21 @@ enum TraversalDirection }; +static int +following_links(void) +{ + switch (symlink_handling) + { + case SYMLINK_ALWAYS_DEREF: + return 1; + case SYMLINK_DEREF_ARGSONLY: + return (curdepth == 0); + case SYMLINK_NEVER_DEREF: + return 0; + } +} + + /* optionh_stat() implements the stat operation when the -H option is * in effect. * @@ -339,7 +354,7 @@ main (int argc, char **argv) set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */ - init_mount_point_list(); + init_mounted_dev_list(); #endif @@ -538,25 +553,10 @@ specific_dirname(const char *dir) } } -enum MountPointStateChange - { - MountPointRecentlyMounted, - MountPointRecentlyUnmounted, - MountPointStateUnchanged - }; -static char *mount_points = NULL; -/* Initialise our idea of what the list of mount points is. - * this function is called exactly once. - */ -static void -init_mount_point_list(void) -{ - assert(NULL == mount_points); - mount_points = get_mounted_filesystems(); -} +#if 0 /* list_item_present: Search for NEEDLE in HAYSTACK. * * NEEDLE is a normal C string. HAYSTACK is a list of concatenated C strings, @@ -589,6 +589,29 @@ list_item_present(const char *needle, const char *haystack) return 0; } +static char *mount_points = NULL; + + +/* Initialise our idea of what the list of mount points is. + * this function is called exactly once. + */ +static void +init_mount_point_list(void) +{ + assert(NULL == mount_points); + mount_points = get_mounted_filesystems(); +} + +static void +refresh_mount_point_list(void) +{ + if (mount_points) + { + free(mount_points); + mount_points = NULL; + } + init_mount_point_list(); +} /* Determine if a directory has recently had a filesystem * mounted on it or unmounted from it. @@ -599,13 +622,7 @@ get_mount_point_state(const char *dir) int was_mounted, is_mounted; was_mounted = list_item_present(dir, mount_points); - - if (mount_points) - { - free(mount_points); - } - mount_points = get_mounted_filesystems(); - + refresh_mount_point_list(); is_mounted = list_item_present(dir, mount_points); if (was_mounted == is_mounted) @@ -615,6 +632,76 @@ get_mount_point_state(const char *dir) else return MountPointRecentlyUnmounted; } +#endif + + + +static dev_t *mounted_devices = NULL; +static size_t num_mounted_devices = 0u; + + +static void +init_mounted_dev_list() +{ + assert(NULL == mounted_devices); + assert(0 == num_mounted_devices); + mounted_devices = get_mounted_devices(&num_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(); +} + + +/* 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; +} + /* Examine the results of the stat() of a directory from before we @@ -671,7 +758,7 @@ wd_sanity_check(const char *thing_to_stat, * reasonable to perform an expensive computation to * determine if we should continue or fail. */ - if (TraversingDown == direction) + if (1 || TraversingDown == direction) { /* We stat()ed a directory, chdir()ed into it (we know this * since direction is TraversingDown), stat()ed it again, @@ -688,7 +775,7 @@ wd_sanity_check(const char *thing_to_stat, * is much rarer, as it relies on an automounter timeout * occurring at exactly the wrong moment. */ - enum MountPointStateChange transition = get_mount_point_state(specific_what); + enum MountPointStateChange transition = get_mount_state(newinfo->st_dev); switch (transition) { case MountPointRecentlyUnmounted: @@ -754,6 +841,68 @@ wd_sanity_check(const char *thing_to_stat, free(specific_what); } } + +enum SafeChdirStatus + { + SafeChdirOK, + SafeChdirFailSymlink, + SafeChdirFailStat, + SafeChdirFailDefect + }; + +/* Safely perform a change in directory. */ +static int +safely_chdir(const char *dest, enum TraversalDirection direction) +{ + struct stat statbuf_dest, statbuf_arrived; + int rv=SafeChdirFailDefect, dotfd=-1; + char *name = NULL; + + errno = 0; + dotfd = open(".", O_RDONLY); + if (dotfd >= 0) + { + /* Stat the directory we're going to. */ + if (0 == (following_links() ? stat : lstat)(dest, &statbuf_dest)) + { +#ifdef S_ISLNK + if (!following_links() && S_ISLNK(statbuf_dest.st_mode)) + { + rv = SafeChdirFailSymlink; + goto fail; + } +#endif + chdir(dest); + } + else + { + rv = SafeChdirFailStat; + name = specific_dirname(dest); + goto fail; + } + } + else + { + } + + fail: + if (errno) + { + if (NULL == name) + name = specific_dirname("."); + error(0, errno, "%s", name); + } + + free(name); + name = NULL; + + if (dotfd >= 0) + { + close(dotfd); + dotfd = -1; + } + return rv; +} /* Safely go back to the starting directory. */ diff --git a/find/fstype.c b/find/fstype.c index db1cc60..6f156a2 100644 --- a/find/fstype.c +++ b/find/fstype.c @@ -19,17 +19,31 @@ /* Written by David MacKenzie . */ -#include "defs.h" - -#include "../gnulib/lib/dirname.h" -#include "modetype.h" +#include #include +#include + +#ifdef HAVE_SYS_MNTIO_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif + +#if defined(MNTIOC_NMNTS) && defined(MNTIOC_GETDEVLIST) +#define USE_MNTIOC_GETDEVLIST 1 +#endif + + #ifdef STDC_HEADERS #include #else extern int errno; #endif -#include + +#include "defs.h" +#include "../gnulib/lib/dirname.h" +#include "modetype.h" /* Need declaration of function `xstrtoumax' */ #include "../gnulib/lib/xstrtol.h" @@ -541,3 +555,89 @@ get_mounted_filesystems (void) return NULL; /* No getmntent(). */ } #endif + +#ifdef USE_MNTIOC_GETDEVLIST + +dev_t* +get_mounted_devices (size_t *n) +{ + dev_t *result = NULL; + int i, fd; + + /* Yes, we really are issuing an ioctl() against a vanilla file in order to + * find out what's in it. + */ + if ( (fd = open(MOUNTED, O_RDONLY)) >= 0) + { + int nmnts = -1; + if (0 == ioctl(fd, MNTIOC_NMNTS, &nmnts)) + { + uint32_t * devlist = (uint32_t*) xcalloc(2 * nmnts, sizeof(uint32_t)); + result = xcalloc(nmnts, sizeof(dev_t)); + + if (0 == ioctl(fd, MNTIOC_GETDEVLIST, devlist)) + { + printf("fd=%d nmnts=%d\n", fd, nmnts); + for (i = 0; i < nmnts; ++i) + { + result[i] = makedev(devlist[2*i], devlist[2*i+1]); + } + free(devlist); + *n = nmnts; + return result; + } + } + } + error (1, errno, "%s", MOUNTED); + /*NOTREAHED*/ + return 0; +} + +#else +dev_t * +get_mounted_devices (size_t *n) +{ + char *mountpoints = get_mounted_filesystems(); + dev_t *result; + size_t alloc_size = 0u; + size_t used; + + used = 0u; + result = NULL; + if (mountpoints) + { + const char *mountpoint = mountpoints; + while (*mountpoint) + { + struct stat st; + if (0 == lstat(mountpoint, &st)) + { + result = extendbuf(result, sizeof(dev_t)*(used+1), &alloc_size); + result[used] = st.st_dev; + ++used; + } + else + { + if (errno == ENOENT || errno == EACCES) + { + /* ignore, carry on with the next. */ + } + else + { + error (1, errno, "%s", mountpoint); + } + } + mountpoint += strlen(mountpoint); + ++mountpoint; /* skip the terminating NUL to find next entry. */ + } + + if (NULL != result) + result = xrealloc(result, sizeof(dev_t)*used); + } + + *n = used; + return result; +} +#endif + + -- 2.11.4.GIT