summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2000-06-01 19:29:31 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2000-06-01 19:29:31 (GMT)
commit30cd6e1dff5bb0fb49415aae820b731dcb97d83c (patch)
tree30f3f253b5d99a16879f1b5a6efa36574b219bc9
parent58ce3bea37f11479b1bfbc7b77eab37dc1b621f7 (diff)
downloadautofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.zip
autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.tar.gz
autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.tar.bz2
autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.tar.xz
Support "bind" mounts: local loopback mounts without using symlinks.
-rw-r--r--NEWS7
-rw-r--r--daemon/mount.c2
-rw-r--r--modules/Makefile4
-rw-r--r--modules/mount_bind.c94
-rw-r--r--modules/mount_nfs.c179
5 files changed, 190 insertions, 96 deletions
diff --git a/NEWS b/NEWS
index 5c83bd7..54a4e82 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+Since autofs-3.1.4:
+-------------------
+* Support "bind" mounts introduced in linux-2.3.99-pre7.7 instead of
+ using symlinks. If you are using a version of the Linux kernel
+ which supports "bind" mounts, you will no longer see symlinks when
+ mounting local filesystems.
+
Since autofs-3.1.3:
-------------------
* Merge in documentation changes from RedHat RPM.
diff --git a/daemon/mount.c b/daemon/mount.c
index 1978463..11d5dbd 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -26,7 +26,7 @@
/* These filesystems are known not to work with the "generic" module */
/* Note: starting with Samba 2.0.6, smbfs is handled generically. */
static char *not_generic[] = { "nfs", "ncpfs", "userfs", "afs",
- "autofs", "changer", NULL };
+ "autofs", "changer", "bind", NULL };
int do_mount(const char *root, const char *name, int name_len,
const char *what, const char *fstype, const char *options)
diff --git a/modules/Makefile b/modules/Makefile
index 20980f8..5d398a1 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -10,13 +10,13 @@ SRCS := lookup_yp.c lookup_file.c lookup_program.c lookup_userhome.c \
lookup_multi.c \
parse_sun.c \
mount_generic.c mount_nfs.c mount_afs.c mount_autofs.c \
- mount_changer.c
+ mount_changer.c mount_bind.c
MODS := lookup_yp.so lookup_file.so lookup_program.so lookup_userhome.so \
lookup_multi.so \
parse_sun.so \
mount_generic.so mount_nfs.so mount_afs.so mount_autofs.so \
- mount_changer.so
+ mount_changer.so mount_bind.so
ifeq ($(EXT2FS), 1)
SRCS += mount_ext2.c
diff --git a/modules/mount_bind.c b/modules/mount_bind.c
new file mode 100644
index 0000000..18ed071
--- /dev/null
+++ b/modules/mount_bind.c
@@ -0,0 +1,94 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * mount_bind.c - module to mount a local filesystem if possible;
+ * otherwise create a symlink.
+ *
+ * Copyright 2000 Transmeta Corporation - All Rights Reserved
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MODULE_MOUNT
+#include "automount.h"
+
+#define MODPREFIX "mount(bind): "
+int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
+
+int mount_init(void **context)
+{
+ return 0;
+}
+
+int mount_mount(const char *root, const char *name, int name_len,
+ const char *what, const char *fstype, const char *options,
+ void *context)
+{
+ char *fullpath;
+ int err;
+
+ fullpath = alloca(strlen(root)+name_len+2);
+ if ( !fullpath ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ 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;
+ }
+
+ if ( options ) {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
+ fstype, options, what, fullpath);
+ err = spawnl(LOG_NOTICE, PATH_MOUNT, PATH_MOUNT, "-t", fstype,
+ SLOPPYOPT "-o", options, what, fullpath, NULL);
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t %s %s %s",
+ fstype, what, fullpath);
+ err = spawnl(LOG_NOTICE, PATH_MOUNT, PATH_MOUNT, "-t", fstype,
+ what, fullpath, NULL);
+ }
+ if ( err ) {
+ if ( rmdir(fullpath) && errno == EBUSY )
+ return 0;
+
+ syslog(LOG_DEBUG, MODPREFIX "failed to mount %s (type %s) on %s, trying symlink",
+ what, fstype, fullpath);
+ if ( symlink(what, fullpath) && errno != EEXIST ) {
+ syslog(LOG_NOTICE, MODPREFIX "failed to create local mount %s -> %s", fullpath, what);
+
+ return 1;
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "symlinked %s -> %s", fullpath, what);
+ return 0;
+ }
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "mounted %s type %s on %s",
+ what, fstype, fullpath);
+ return 0;
+ }
+}
+
+int mount_done(void *context)
+{
+ return 0;
+}
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 1996972..e1d9e6b 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -4,7 +4,7 @@
* mount_nfs.c - Module for Linux automountd to mount an NFS filesystem,
* with fallback to symlinking if the path is local
*
- * Copyright 1997 Transmeta Corporation - All Rights Reserved
+ * Copyright 1997-2000 Transmeta Corporation - All Rights Reserved
*
* 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
@@ -37,6 +37,8 @@ int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
static int udpproto;
static short port_discard;
+static struct mount_mod *mount_bind = NULL;
+
int mount_init(void **context)
{
struct protoent *udp;
@@ -51,14 +53,18 @@ int mount_init(void **context)
else
port_discard = htons(9); /* 9 is the standard discard port */
- return 0;
+ /* Make sure we have the local mount method available */
+ if ( !mount_bind )
+ mount_bind = open_mount("bind", MODPREFIX);
+
+ return !mount_bind;
}
int mount_mount(const char *root, const char *name, int name_len,
const char *what, const char *fstype,
const char *options, void *context)
{
- char *colon, **haddr, *fullpath;
+ char *colon, *localname, **haddr, *fullpath;
char *whatstr, *hostname, *comma, *paren;
struct hostent *he;
struct sockaddr_in saddr, laddr;
@@ -74,106 +80,93 @@ int mount_mount(const char *root, const char *name, int name_len,
colon = strchr(whatstr, ':');
if ( !colon ) {
- /* No colon, take this as a symlink (local) entry */
- syslog(LOG_DEBUG, MODPREFIX "entry %s -> %s: no colon, assume local",
- name, whatstr);
- chdir(root);
- err = symlink(whatstr, name);
- if ( err && errno == EEXIST )
- err = 0;
- if ( err )
- syslog(LOG_NOTICE, MODPREFIX "symlink %s: %m", name);
- chdir("/");
- return err ? 1 : 0;
- }
-
- *colon = '\0';
-
- /* The host part may actually be a comma-separated list of hosts with
- parenthesized weights. We want to check each host, ignoring any
- weights, until we either find the localhost or reach the end of the
- list. */
- local = 0;
- hostname = whatstr;
- do {
- comma = strchr(hostname, ',');
- if ( comma )
- *comma = '\0';
-
- paren = strchr(hostname, '(');
- if ( paren )
- *paren = '\0';
-
- if ( !(he = gethostbyname(hostname)) ) {
- syslog(LOG_NOTICE, MODPREFIX "entry %s: host %s: lookup failure",
- name, hostname);
- return 1; /* No such host */
- }
-
- /* Probe to see if we are the local host. Open a UDP socket and see
- if the local address is the same as the remote one */
-
- for ( haddr = he->h_addr_list ; *haddr ; haddr++ ) {
- sock = socket(AF_INET, SOCK_DGRAM, udpproto);
- if ( sock < 0 ) {
- syslog(LOG_ERR, MODPREFIX "socket: %m");
- return 1;
+ /* No colon, take this as a bind (local) entry */
+ local = 1;
+ localname = whatstr;
+ } else {
+ *colon = '\0';
+
+ /* The host part may actually be a comma-separated list of hosts with
+ parenthesized weights. We want to check each host, ignoring any
+ weights, until we either find the localhost or reach the end of the
+ list. */
+ local = 0;
+ localname = colon+1;
+ hostname = whatstr;
+ do {
+ comma = strchr(hostname, ',');
+ if ( comma )
+ *comma = '\0';
+
+ paren = strchr(hostname, '(');
+ if ( paren )
+ *paren = '\0';
+
+ if ( !(he = gethostbyname(hostname)) ) {
+ syslog(LOG_NOTICE, MODPREFIX "entry %s: host %s: lookup failure",
+ name, hostname);
+ return 1; /* No such host */
}
- saddr.sin_family = AF_INET;
- memcpy(&saddr.sin_addr, *haddr, he->h_length);
- saddr.sin_port = port_discard;
- len = sizeof(laddr);
-
- if ( connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
- continue; /* Assume it wasn't local */
-
- if ( getsockname(sock, (struct sockaddr *) &laddr, &len) < 0 ) {
- syslog(LOG_ERR, MODPREFIX "getsockname failed for %s: %m", name);
+ /* Probe to see if we are the local host. Open a UDP socket and see
+ if the local address is the same as the remote one */
+
+ for ( haddr = he->h_addr_list ; *haddr ; haddr++ ) {
+ sock = socket(AF_INET, SOCK_DGRAM, udpproto);
+ if ( sock < 0 ) {
+ syslog(LOG_ERR, MODPREFIX "socket: %m");
+ return 1;
+ }
+ saddr.sin_family = AF_INET;
+ memcpy(&saddr.sin_addr, *haddr, he->h_length);
+ saddr.sin_port = port_discard;
+
+ len = sizeof(laddr);
+
+ if ( connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
+ continue; /* Assume it wasn't local */
+
+ if ( getsockname(sock, (struct sockaddr *) &laddr, &len) < 0 ) {
+ syslog(LOG_ERR, MODPREFIX "getsockname failed for %s: %m", name);
+ close(sock);
+ return 1;
+ }
close(sock);
- return 1;
+
+ if ( !memcmp(&saddr.sin_addr,&laddr.sin_addr,he->h_length) ) {
+ local = 1;
+ break;
+ }
}
- close(sock);
- if ( !memcmp(&saddr.sin_addr,&laddr.sin_addr,he->h_length) ) {
- local = 1;
- break;
+ if ( paren )
+ *paren = '(';
+
+ if ( comma ) {
+ *comma = ',';
+ hostname = comma + 1;
+ } else {
+ hostname += strlen(hostname);
}
- }
+ } while (*hostname && !local);
+ }
- if ( paren )
- *paren = '(';
+ fullpath = alloca(strlen(root)+name_len+2);
+ if ( !fullpath ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ if ( local ) {
+ /* Local host -- do a "bind" */
- if ( comma ) {
- *comma = ',';
- hostname = comma + 1;
- } else {
- hostname += strlen(hostname);
- }
- } while (*hostname && !local);
+ syslog(LOG_DEBUG, MODPREFIX "%s is local, doing bind", name);
- if ( local ) {
- /* Local host -- do a symlink */
-
- syslog(LOG_DEBUG, MODPREFIX "%s is local, symlinking", name);
- chdir(root);
- err = symlink(colon+1, name);
- if ( err && errno == EEXIST )
- err = 0;
- if ( err )
- syslog(LOG_NOTICE, MODPREFIX "symlink %s: %m", name);
- chdir("/");
- return err ? 1 : 0;
+ return mount_bind->mount_mount(root,name,name_len,localname,"bind",NULL,mount_bind->context);
} else {
- /* Not a local host - do a mount */
+ /* Not a local host - do an NFS mount */
- fullpath = alloca(strlen(root)+name_len+2);
- if ( !fullpath ) {
- syslog(LOG_ERR, MODPREFIX "alloca: %m");
- return 1;
- }
- sprintf(fullpath, "%s/%s", root, name);
-
*colon = ':';
syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath);
if ( mkdir(fullpath, 0555) && errno != EEXIST ) {
@@ -205,5 +198,5 @@ int mount_mount(const char *root, const char *name, int name_len,
int mount_done(void *context)
{
- return 0;
+ return mount_bind->mount_done(mount_bind->context);
}