aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2000-11-04 07:02:22 +0000
committerH. Peter Anvin <hpa@zytor.com>2000-11-04 07:02:22 +0000
commitba547c0e908a601f30e863f011a9036736ef368b (patch)
treed608eae3a66b1a43e918607ef778c5c3afa929b2
parentc04e3aa83ca20d714c1deb6f7b6e0c113324e0ae (diff)
downloadautofs3-ba547c0e908a601f30e863f011a9036736ef368b.tar.gz
autofs3-ba547c0e908a601f30e863f011a9036736ef368b.tar.xz
autofs3-ba547c0e908a601f30e863f011a9036736ef368b.zip
Fix mount --bind; make failed mount --bind not cause trouble.
-rw-r--r--NEWS6
-rw-r--r--modules/mount_bind.c118
2 files changed, 106 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index 78aa24f..bc91641 100644
--- a/NEWS
+++ b/NEWS
@@ -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);