aboutsummaryrefslogtreecommitdiffstats
path: root/modules/mount_autofs.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mount_autofs.c')
-rw-r--r--modules/mount_autofs.c147
1 files changed, 147 insertions, 0 deletions
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;
+}