diff options
author | H. Peter Anvin <hpa@zytor.com> | 2000-11-04 07:02:22 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2000-11-04 07:02:22 +0000 |
commit | ba547c0e908a601f30e863f011a9036736ef368b (patch) | |
tree | d608eae3a66b1a43e918607ef778c5c3afa929b2 | |
parent | c04e3aa83ca20d714c1deb6f7b6e0c113324e0ae (diff) | |
download | autofs3-ba547c0e908a601f30e863f011a9036736ef368b.tar.gz autofs3-ba547c0e908a601f30e863f011a9036736ef368b.tar.xz autofs3-ba547c0e908a601f30e863f011a9036736ef368b.zip |
Fix mount --bind; make failed mount --bind not cause trouble.
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | modules/mount_bind.c | 118 |
2 files changed, 106 insertions, 18 deletions
@@ -1,5 +1,11 @@ Since autofs-3.1.6: ------------------- +* Test for mount --bind at startup time, rather than allowing it to + fail. Resolves "test -d doesn't work" problems. +* Fixed silly typo in mount_bind. +* Bring canned linux/auto_fs.h header up to date; resolves compilation + problems with newer kernel headers installed. +* NOTE: util-linux-2.10p recommended for mount --bind to work properly! Since autofs-3.1.5: ------------------- diff --git a/modules/mount_bind.c b/modules/mount_bind.c index 5eb45b7..5a4580e 100644 --- a/modules/mount_bind.c +++ b/modules/mount_bind.c @@ -21,6 +21,8 @@ #include <unistd.h> #include <syslog.h> #include <string.h> +#include <limits.h> +#include <time.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> @@ -31,8 +33,82 @@ #define MODPREFIX "mount(bind): " int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */ +static int have_mount_bind = -1; /* -1 means: not tested yet */ + +/* This gives a conservative estimate for the number of hex digits it + may require to printf() type T. */ +#define HEXDIGITS(T) ((sizeof(T)*CHAR_BIT+3)/4) + +/* Test to see if "mount --bind" works properly or not */ +static int mount_bind_works_p(void) +{ + char testdir[32+HEXDIGITS(time_t)+HEXDIGITS(pid_t)]; + char dir1[40+HEXDIGITS(time_t)+HEXDIGITS(pid_t)]; + char dir2[40+HEXDIGITS(time_t)+HEXDIGITS(pid_t)]; + struct stat st1, st2; + pid_t mypid = getpid(); + int rv; + int bind_works = 0; /* Guilty until proven innocent */ + + syslog(LOG_DEBUG, MODPREFIX "Testing if \"mount --bind\" works correctly..."); + + /* Make a safe temporary directory */ + do { + sprintf(testdir, "/tmp/autofs-bind-%lx-%lx", + (unsigned long)time(NULL), (unsigned long)mypid); + rv = mkdir(testdir, 0700); + if ( rv && errno != EEXIST ) { + syslog(LOG_ERR, MODPREFIX "Cannot create temporary directory: %m"); + goto f0; + } + } while ( rv ); + + sprintf(dir1, "%s/dir1", testdir); + sprintf(dir2, "%s/dir2", testdir); + + if ( mkdir(dir1, 0700) ) + goto f1; + if ( mkdir(dir2, 0700) ) + goto f2; + + syslog(LOG_DEBUG, MODPREFIX "calling mount --bind %s %s", + dir1, dir2); + if ( spawnl(LOG_DEBUG, PATH_MOUNT, PATH_MOUNT, "--bind", + dir1, dir2, NULL) ) { + syslog(LOG_DEBUG, MODPREFIX "mount --bind failed"); + goto f3; + } + + /* mount --bind returned OK, now verify it did the right thing */ + if ( stat(dir1, &st1) || stat(dir2, &st2) ) { + syslog(LOG_DEBUG, MODPREFIX "Cannot stat temporary directories: %m"); + goto f4; + } + + /* If dir1 and dir2 are now the same directory, mount --bind worked */ + if ( st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino ) + bind_works = 1; + + /* Disassemble the test setup */ + f4: + /* umount the bind */ + spawnl(LOG_DEBUG, PATH_UMOUNT, PATH_UMOUNT, dir2, NULL); + f3: + rmdir(dir2); + f2: + rmdir(dir1); + f1: + rmdir(testdir); + f0: + return bind_works; +} + int mount_init(void **context) { + if ( have_mount_bind == -1 ) { + /* Need to figure out if mount --bind works or not */ + have_mount_bind = mount_bind_works_p(); + } return 0; } @@ -41,7 +117,7 @@ int mount_mount(const char *root, const char *name, int name_len, void *context) { char *fullpath; - int err; + int err = 0; fullpath = alloca(strlen(root)+name_len+2); if ( !fullpath ) { @@ -49,27 +125,33 @@ int mount_mount(const char *root, const char *name, int name_len, return 1; } sprintf(fullpath, "%s/%s", root, name); + + if ( have_mount_bind ) { + syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath); + if ( mkdir(fullpath, 0555) && errno != EEXIST ) { + syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name); + return 1; + } - syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath); - if ( mkdir(fullpath, 0555) && errno != EEXIST ) { - syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name); - return 1; + syslog(LOG_DEBUG, MODPREFIX "calling mount --bind %s %s", + what, fullpath); + err = spawnl(LOG_NOTICE, PATH_MOUNT, PATH_MOUNT, "--bind", + what, fullpath, NULL); + + if ( err ) { + if ( rmdir(fullpath) && errno == EBUSY ) { + return 0; + } else { + /* This shouldn't happen, but try anyway... */ + syslog(LOG_NOTICE, MODPREFIX "failed to mount --bind %s on %s, trying symlink", + what, fullpath); + } + } } - - syslog(LOG_DEBUG, MODPREFIX "calling mount --bind %s %s", - fstype, what, fullpath); - err = spawnl(LOG_NOTICE, PATH_MOUNT, PATH_MOUNT, "--bind", - what, fullpath, NULL); - - if ( err ) { - if ( rmdir(fullpath) && errno == EBUSY ) - return 0; - syslog(LOG_DEBUG, MODPREFIX "failed to mount --bind %s on %s, trying symlink", - what, fullpath); + if ( err || !have_mount_bind ) { if ( symlink(what, fullpath) && errno != EEXIST ) { - syslog(LOG_NOTICE, MODPREFIX "failed to create local mount %s -> %s", fullpath, what); - + syslog(LOG_NOTICE, MODPREFIX "failed to create symlink %s -> %s", fullpath, what); return 1; } else { syslog(LOG_DEBUG, MODPREFIX "symlinked %s -> %s", fullpath, what); |