diff options
author | H. Peter Anvin <hpa@zytor.com> | 2000-06-01 19:29:31 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2000-06-01 19:29:31 +0000 |
commit | 30cd6e1dff5bb0fb49415aae820b731dcb97d83c (patch) | |
tree | 30f3f253b5d99a16879f1b5a6efa36574b219bc9 | |
parent | 58ce3bea37f11479b1bfbc7b77eab37dc1b621f7 (diff) | |
download | autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.tar.gz autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.tar.xz autofs3-30cd6e1dff5bb0fb49415aae820b731dcb97d83c.zip |
Support "bind" mounts: local loopback mounts without using symlinks.
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | daemon/mount.c | 2 | ||||
-rw-r--r-- | modules/Makefile | 4 | ||||
-rw-r--r-- | modules/mount_bind.c | 94 | ||||
-rw-r--r-- | modules/mount_nfs.c | 179 |
5 files changed, 190 insertions, 96 deletions
@@ -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); } |