aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>1998-03-27 05:37:41 +0000
committerH. Peter Anvin <hpa@zytor.com>1998-03-27 05:37:41 +0000
commitb85764b115b4cb3601c660613b094b2b042dcb0a (patch)
tree762e7ba86393ad293bf62f7763b22c7e06dcc690
parent416c8a6915ad2e45c98fd8a72a0deeb8adb5d1c1 (diff)
downloadautofs3-b85764b115b4cb3601c660613b094b2b042dcb0a.tar.gz
autofs3-b85764b115b4cb3601c660613b094b2b042dcb0a.tar.xz
autofs3-b85764b115b4cb3601c660613b094b2b042dcb0a.zip
Initial integration of rth's mount_autofs.
-rw-r--r--daemon/automount.c93
-rw-r--r--include/automount.h3
-rw-r--r--modules/Makefile6
-rw-r--r--modules/mount_autofs.c147
4 files changed, 231 insertions, 18 deletions
diff --git a/daemon/automount.c b/daemon/automount.c
index 2fb2c90..a7f9582 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -49,6 +49,7 @@ static char *pid_file = NULL; /* File in which to keep pid */
int kproto_version; /* Kernel protocol version used */
static int mounted = 0;
+static int submount = 0;
struct pending_mount {
pid_t pid; /* Which process is mounting for us */
@@ -73,6 +74,9 @@ volatile struct pending_mount *junk_mounts = NULL;
#define DEFAULT_TIMEOUT (5*60) /* 5 minutes */
#define CHECK_RATIO 4 /* exp_runfreq = exp_timeout/CHECK_RATIO */
+static void cleanup_exit(int exit_code);
+
+
static int umount_ent(char *root, char *name)
{
char path_buf[PATH_MAX];
@@ -132,16 +136,10 @@ static int umount_all(int force)
return left;
}
-static int umount_autofs(int force)
+static int do_umount_autofs(void)
{
int rv;
- if ( !mounted )
- return -1;
-
- if ( umount_all(force) && !force )
- return -1;
-
if (ap.ioctlfd >= 0) {
ioctl(ap.ioctlfd, AUTOFS_IOC_CATATONIC, 0);
close(ap.ioctlfd);
@@ -149,11 +147,63 @@ static int umount_autofs(int force)
if (ap.pipefd >= 0)
close(ap.pipefd);
rv = spawnl(LOG_ERR, _PATH_UMOUNT, _PATH_UMOUNT, ap.path, NULL);
+ if (rv == 0 && submount)
+ rmdir(ap.path);
+
free(ap.path);
mounted = 0;
return rv;
}
+static int umount_autofs(int force)
+{
+ if ( !mounted )
+ return -1;
+ if ( umount_all(force) && !force )
+ return -1;
+ return do_umount_autofs();
+}
+
+static void maybe_umount_autofs_and_exit(void)
+{
+ char path_buf[PATH_MAX];
+ struct stat st;
+ struct dirent *de;
+ DIR *dp;
+ int left;
+
+ /* If we are expiring, wait til next round to exit. */
+ if ( ap.exp_process )
+ return;
+
+ chdir("/");
+
+ dp = opendir(ap.path);
+ if ( !dp ) {
+ syslog(LOG_ERR, "maybe_umount_autofs: opendir: %m");
+ return;
+ }
+
+ left = 0;
+ while ( (de = readdir(dp)) != NULL ) {
+ if ( strcmp(de->d_name,".") && strcmp(de->d_name,"..") ) {
+ sprintf(path_buf, "%s/%s", ap.path, de->d_name);
+ if ( !lstat(path_buf,&st) ) {
+ if ( S_ISDIR(st.st_mode) ) {
+ if ( st.st_dev != ap.dev )
+ left++;
+ }
+ }
+ }
+ }
+ closedir(dp);
+
+ if (!left) {
+ if (do_umount_autofs() == 0)
+ cleanup_exit(0);
+ }
+}
+
static int mount_autofs(char *path)
{
int pipefd[2];
@@ -219,15 +269,20 @@ static int mount_autofs(char *path)
static void run_expire(void)
{
- pid_t f;
struct autofs_packet_expire pkt;
sigset_t s, olds;
+ pid_t f;
if ( ap.exp_process ) /* Another process is already expiring */
return; /* Try again next interval */
- if ( ioctl(ap.ioctlfd, AUTOFS_IOC_EXPIRE, &pkt) )
- return; /* Don't fork if there is nothing do expire */
+ if ( ioctl(ap.ioctlfd, AUTOFS_IOC_EXPIRE, &pkt) ) {
+ /* Don't fork if there is nothing do expire, but if we are a submount,
+ see if maybe we shouldn't exit. */
+ if (submount)
+ maybe_umount_autofs_and_exit();
+ return;
+ }
/* Temporarily block SIGCHLD and SIGALRM between forking and setting
ap.exp_process */
@@ -252,7 +307,7 @@ static void run_expire(void)
close(ap.pipefd);
syslog(LOG_DEBUG, "running expiration on path %s", ap.path);
-
+
do {
if ( pkt.hdr.type == autofs_ptype_expire ) {
if ( !umount_ent(ap.path,pkt.name) )
@@ -415,6 +470,8 @@ static void sig_child(int sig)
while ( (pid = waitpid(-1, &status, WNOHANG)) > 0 ) {
if ( pid == ap.exp_process ) {
ap.exp_process = 0;
+ if (submount)
+ maybe_umount_autofs_and_exit();
} else {
for ( mtp = &ap.mounts ; (mt = *mtp) ; mtp = &mt->next ) {
if ( mt->pid == pid ) {
@@ -465,14 +522,17 @@ static void become_daemon(void)
my_pid = getpid();
- /* Make our own process group for "magic" reason */
-
- if ( setpgrp() ) {
+ /* Make our own process group for "magic" reason: processes that share
+ our pgrp see the raw filesystem behine the magic. So if we are a
+ submount, don't change -- otherwise we won't be able to actually
+ perform the mount. */
+
+ if ( !submount && setpgrp() ) {
syslog(LOG_CRIT, "setpgrp: %m");
exit(1);
}
my_pgrp = getpgrp();
-
+
/* Redirect all our file descriptors to /dev/null */
if ( (nullfd = open("/dev/null", O_RDWR)) < 0 ) {
@@ -548,6 +608,7 @@ int main(int argc, char *argv[])
{"pid-file", 1, 0, 'p'},
{"timeout", 1, 0, 't'},
{"version", 0, 0, 'v'},
+ {"submount", 0, &submount, 1},
{0,0,0,0}
};
@@ -621,7 +682,7 @@ int main(int argc, char *argv[])
syslog(LOG_CRIT, "%s: mount failed!", path);
cleanup_exit(1);
}
-
+
/* The following signals cause a shutdown event to occur */
sa.sa_handler = sig_shutdown;
sigemptyset(&sa.sa_mask);
diff --git a/include/automount.h b/include/automount.h
index a590525..14f13c5 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -18,6 +18,9 @@
#ifndef _PATH_UMOUNT
#define _PATH_UMOUNT "/bin/umount"
#endif
+#ifndef _PATH_AUTOMOUNT
+#define _PATH_AUTOMOUNT "/usr/sbin/automount"
+#endif
#ifndef _PATH_E2FSCK
#define _PATH_E2FSCK "/sbin/fsck.ext2"
diff --git a/modules/Makefile b/modules/Makefile
index 3b5d849..694a8c9 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -7,11 +7,13 @@ include ../Makefile.rules
SRCS = lookup_yp.c lookup_file.c lookup_program.c \
parse_sun.c \
- mount_generic.c mount_ext2.c mount_nfs.c mount_smbfs.c mount_afs.c
+ mount_generic.c mount_ext2.c mount_nfs.c mount_smbfs.c \
+ mount_afs.c mount_autofs.c
MODS = lookup_yp.so lookup_file.so lookup_program.so \
parse_sun.so \
- mount_generic.so mount_ext2.so mount_nfs.so mount_smbfs.so mount_afs.so
+ mount_generic.so mount_ext2.so mount_nfs.so mount_smbfs.so \
+ mount_afs.so mount_autofs.so
ifdef HESIOD
SRCS += lookup_hesiod.c parse_hesiod.c
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
new file mode 100644
index 0000000..6ab439c
--- /dev/null
+++ b/modules/mount_autofs.c
@@ -0,0 +1,147 @@
+#ident "$Id$"
+/*
+ * mount_autofs.c
+ *
+ * Module for recursive autofs mounts.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <signal.h>
+#include <alloca.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#define MODULE_MOUNT
+#include "automount.h"
+
+#define MODPREFIX "mount(autofs): "
+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 *c_options,
+ void *context)
+{
+ char *fullpath;
+ const char **argv;
+ int argc, status;
+ struct stat sb, cb;
+ char *options, *p;
+
+ fullpath = alloca(strlen(root)+name_len+2);
+ if ( !fullpath ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ options = alloca(strlen(c_options)+1);
+ if ( !options ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ strcpy(options, c_options);
+
+ 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 "fullpath=%s what=%s options=%s",
+ fullpath, what, options);
+
+ /* Build our argument vector. */
+
+ argc = 5;
+ if ( options ) {
+ char *p = options;
+ do {
+ argc++;
+ } while ((p = strchr(p,',')) != NULL);
+ }
+ argv = (const char **) alloca((argc+1) * sizeof(char *));
+
+ argc = 0;
+ argv[argc++] = _PATH_AUTOMOUNT;
+ argv[argc++] = "--submount";
+ argv[argc++] = fullpath;
+ argv[argc++] = strcpy(alloca(strlen(what)+1), what);
+
+ if ( (p = strchr(argv[argc-1], ':')) == NULL ) {
+ syslog(LOG_NOTICE, MODPREFIX "%s missing script type on %s", name, what);
+ goto error;
+ }
+
+ argv[argc++] = p;
+
+ if ( options ) {
+ argv[argc++] = strtok(options, ",");
+ while ((argv[argc++] = strtok(NULL, ",")) != NULL)
+ continue;
+ }
+ argv[argc] = NULL;
+
+ /* Spawn a new daemon. */
+ status = spawnv(LOG_DEBUG, _PATH_AUTOMOUNT, argv);
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ syslog(LOG_NOTICE, MODPREFIX "sub automount returned status %d", status);
+ goto error;
+ }
+
+ /* We must wait a bit for it to get registered. We try three times, and
+ if it isn't ready after that, assume it has failed. This is a real
+ hack; we really should make --submount make the subprocess notify us. */
+
+ stat(root, &cb);
+ usleep(10000);
+
+ stat(fullpath, &sb);
+ if (cb.st_dev == sb.st_dev) {
+ int i;
+ /* First, to one second by tenths. */
+ for (i = 0; i < 10; ++i) {
+ usleep(100000);
+ stat(fullpath, &sb);
+ if (cb.st_dev != sb.st_dev)
+ goto ok;
+ }
+ /* Then to one minute by seconds. */
+ for (i = 1; i < 60; ++i) {
+ sleep(1);
+ stat(fullpath, &sb);
+ if (cb.st_dev != sb.st_dev)
+ goto ok;
+ }
+ syslog(LOG_NOTICE, MODPREFIX "timeout waiting for submount");
+ goto error;
+ }
+
+ok:
+ syslog(LOG_DEBUG, MODPREFIX "mounted %s on %s", what, fullpath);
+ return 0;
+
+error:
+ rmdir(fullpath);
+ syslog(LOG_NOTICE, MODPREFIX "failed to mount %s on %s", what, fullpath);
+ return 1;
+}
+
+int mount_done(void *context)
+{
+ return 0;
+}