Blob Blame History Raw
autofs-5.1.3 - add amd mount type program mount support

From: Ian Kent <raven@themaw.net>

Add support for the amd mount type "program" and its option "mount",
and its mutually exclusive options "umount" or "unmount" for specifying
the program to be used to perform the mount and optionally also the
umount.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG           |    1 
 README.amd-maps     |    6 +-
 include/parse_amd.h |    3 +
 lib/mounts.c        |   42 ++++++++++++++-
 modules/amd_parse.y |   36 +++++++++----
 modules/parse_amd.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 216 insertions(+), 15 deletions(-)

--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -281,6 +281,7 @@
 - add function umount_amd_ext_mount().
 - add function ext_mount_inuse().
 - add function construct_argv().
+- add amd mount type program mount support.
 
 25/07/2012 autofs-5.0.7
 =======================
--- autofs-5.0.7.orig/README.amd-maps
+++ autofs-5.0.7/README.amd-maps
@@ -146,9 +146,9 @@ always used for available map sources.
 
 The regex map key matching feature is not implemented.
 
-Mount types lustre, nfsx, jfs, program and direct haven't been
-implemented and other mount types that aren't implemented in amd are
-also not available.
+Mount types lustre, nfsx, jfs and direct haven't been implemented
+and other mount types that aren't implemented in amd are also not
+available.
 
 How to find out more
 --------------------
--- autofs-5.0.7.orig/include/parse_amd.h
+++ autofs-5.0.7/include/parse_amd.h
@@ -30,6 +30,7 @@
 #define AMD_MOUNT_TYPE_JFS	0x00000800
 #define AMD_MOUNT_TYPE_CACHEFS	0x00001000
 #define AMD_MOUNT_TYPE_CDFS	0x00002000
+#define AMD_MOUNT_TYPE_PROGRAM	0x00004000
 #define AMD_MOUNT_TYPE_MASK	0x0000ffff
 
 #define AMD_ENTRY_CUT		0x00010000
@@ -60,6 +61,8 @@ struct amd_entry {
 	char *addopts;
 	char *remopts;
 	char *sublink;
+	char *mount;
+	char *umount;
 	struct selector *selector;
 	struct list_head list;
 	struct list_head entries;
--- autofs-5.0.7.orig/lib/mounts.c
+++ autofs-5.0.7/lib/mounts.c
@@ -2056,6 +2056,46 @@ int umount_amd_ext_mount(struct autofs_p
 {
 	int rv = 1;
 
+	if (entry->umount) {
+		char *prog, *str;
+		char **argv;
+		int argc = -1;
+
+		str = strdup(entry->umount);
+		if (!str)
+			goto out;
+
+		prog = NULL;
+		argv = NULL;
+
+		argc = construct_argv(str, &prog, &argv);
+		if (argc == -1) {
+			free(str);
+			goto out;
+		}
+
+		if (!ext_mount_remove(&entry->ext_mount, entry->fs)) {
+			rv =0;
+			goto out;
+		}
+
+		rv = spawnv(ap->logopt, prog, (const char * const *) argv);
+		if (rv == -1 || (WIFEXITED(rv) && WEXITSTATUS(rv)))
+			error(ap->logopt,
+			     "failed to umount program mount at %s", entry->fs);
+		else {
+			rv = 0;
+			debug(ap->logopt,
+			      "umounted program mount at %s", entry->fs);
+			rmdir_path(ap, entry->fs, ap->dev);
+		}
+
+		free_argv(argc, (const char **) argv);
+		free(str);
+
+		goto out;
+	}
+
 	if (ext_mount_remove(&entry->ext_mount, entry->fs)) {
 		rv = umount_ent(ap, entry->fs);
 		if (rv)
@@ -2065,7 +2105,7 @@ int umount_amd_ext_mount(struct autofs_p
 			debug(ap->logopt,
 			      "umounted external mount %s", entry->fs);
 	}
-
+out:
 	return rv;
 }
 
--- autofs-5.0.7.orig/modules/amd_parse.y
+++ autofs-5.0.7/modules/amd_parse.y
@@ -347,13 +347,18 @@ option_assignment: MAP_OPTION OPTION_ASS
 			amd_set_value(&entry.rfs, fs_opt_val);
 		else if (!strcmp($1, "dev"))
 			amd_set_value(&entry.dev, fs_opt_val);
-		else if (!strcmp($1, "mount") ||
-			 !strcmp($1, "unmount") ||
+		else if (!strcmp($1, "mount"))
+			amd_set_value(&entry.mount, fs_opt_val);
+		else if (!strcmp($1, "unmount") ||
 			 !strcmp($1, "umount")) {
-			amd_info("file system type program is not "
-				 "yet implemented, option ignored");
-			free(fs_opt_val);
-			YYABORT;
+			if (entry.umount) {
+				sprintf(msg_buf,
+				    "unmount or umount may only be used once");
+				amd_info(msg_buf);
+				free(fs_opt_val);
+				YYABORT;
+			}
+			entry.umount = fs_opt_val;
 		} else if (!strcmp($1, "delay") ||
 			   !strcmp($1, "cachedir")) {
 			sprintf(msg_buf, "option %s is not used by autofs", $1);
@@ -381,7 +386,14 @@ option_assignment: MAP_OPTION OPTION_ASS
 			amd_set_value(&entry.rfs, empty);
 		else if (!strcmp($1, "dev"))
 			amd_set_value(&entry.dev, empty);
-		else {
+		else if (!strcmp($1, "mount")) {
+			amd_set_value(&entry.mount, NULL);
+			free(empty);
+		} else if (!strcmp($1, "umount") ||
+			   !strcmp($1, "unmount")) {
+			amd_set_value(&entry.umount, NULL);
+			free(empty);
+		} else {
 			amd_notify($1);
 			free(empty);
 			YYABORT;
@@ -426,8 +438,7 @@ option_assignment: MAP_OPTION OPTION_ASS
 options: OPTION
 	{
 		if (!strcmp($1, "fullybrowsable") ||
-		    !strcmp($1, "nounmount") ||
-		    !strcmp($1, "unmount")) {
+		    !strcmp($1, "nounmount")) {
 			sprintf(msg_buf, "option %s is not currently "
 					 "implemented, ignored", $1);
 			amd_info(msg_buf);
@@ -496,7 +507,9 @@ static int match_map_option_fs_type(char
 		   !strcmp(fs_type, "ext3") ||
 		   !strcmp(fs_type, "ext4"))
 		entry.flags |= AMD_MOUNT_TYPE_EXT;
-	} else if (!strcmp(fs_type, "ufs")) {
+	else if (!strcmp(fs_type, "program"))
+		entry.flags |= AMD_MOUNT_TYPE_PROGRAM;
+	else if (!strcmp(fs_type, "ufs")) {
 		entry.flags |= AMD_MOUNT_TYPE_UFS;
 		entry.type = conf_amd_get_linux_ufs_mount_type();
 		if (!entry.type) {
@@ -520,7 +533,6 @@ static int match_map_option_fs_type(char
 		fs_type = NULL;
 	} else if (!strcmp(fs_type, "jfs") ||
 		   !strcmp(fs_type, "nfsx") ||
-		   !strcmp(fs_type, "program") ||
 		   !strcmp(fs_type, "lustre") ||
 		   !strcmp(fs_type, "direct")) {
 		sprintf(msg_buf, "file system type %s is "
@@ -880,6 +892,8 @@ static int add_location(void)
 	new->addopts = entry.addopts;
 	new->remopts = entry.remopts;
 	new->sublink = entry.sublink;
+	new->mount = entry.mount;
+	new->umount = entry.umount;
 	new->selector = entry.selector;
 	list_add_tail(&new->list, entries);
 	memset(&entry, 0, sizeof(struct amd_entry));
--- autofs-5.0.7.orig/modules/parse_amd.c
+++ autofs-5.0.7/modules/parse_amd.c
@@ -790,6 +790,35 @@ next:
 		sv = macro_addvar(sv, "remopts", 7, entry->remopts);
 	}
 
+	if (entry->mount) {
+		if (!expand_selectors(ap, entry->mount, &expand, sv)) {
+			free(entry->mount);
+			if (entry->umount)
+				free(entry->umount);
+			entry->mount = NULL;
+			entry->umount = NULL;
+			goto done;
+		}
+		debug(logopt, MODPREFIX
+		      "mount expand(\"%s\") -> %s", entry->mount, expand);
+		free(entry->mount);
+		entry->mount = expand;
+		sv = macro_addvar(sv, "mount", 5, entry->mount);
+	}
+
+	if (entry->umount) {
+		if (!expand_selectors(ap, entry->umount, &expand, sv)) {
+			free(entry->umount);
+			entry->umount = NULL;
+			goto done;
+		}
+		debug(logopt, MODPREFIX
+		      "umount expand(\"%s\") -> %s", entry->umount, expand);
+		free(entry->umount);
+		entry->umount = expand;
+		sv = macro_addvar(sv, "umount", 5, entry->umount);
+	}
+done:
 	return sv;
 }
 
@@ -1224,6 +1253,91 @@ out:
 	return ret;
 }
 
+static int do_program_mount(struct autofs_point *ap,
+			    struct amd_entry *entry, const char *name)
+{
+	char *prog, *str;
+	char **argv;
+	int argc = -1;
+	int rv = 1;
+
+	str = strdup(entry->mount);
+	if (!str)
+		goto out;
+
+	prog = NULL;
+	argv = NULL;
+
+	argc = construct_argv(str, &prog, &argv);
+	if (argc == -1) {
+		error(ap->logopt, MODPREFIX
+		      "%s: error creating mount arguments", entry->type);
+		free(str);
+		goto out;
+	}
+
+	/* The am-utils documentation doesn't actually say that the
+	 * mount (and umount, if given) command need to use ${fs} as
+	 * the mount point in the command.
+	 *
+	 * For program mounts there's no way to know what the mount
+	 * point is so ${fs} must be used in the mount (and umount,
+	 * if given) in order to create the mount point directory
+	 * before executing the mount command and removing it at
+	 * umount.
+	 */
+	if (ext_mount_inuse(entry->fs)) {
+		rv = 0;
+		ext_mount_add(&entry->ext_mount, entry->fs, 1);
+	} else {
+		rv = mkdir_path(entry->fs, 0555);
+		if (rv && errno != EEXIST) {
+			char *buf[MAX_ERR_BUF];
+			char * estr;
+
+			estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(ap->logopt,
+			      MODPREFIX "%s: mkdir_path %s failed: %s",
+			      entry->type, entry->fs, estr);
+			goto do_free;
+		}
+
+		rv = spawnv(ap->logopt, prog, (const char * const *) argv);
+		if (WIFEXITED(rv) && !WEXITSTATUS(rv)) {
+			rv = 0;
+			ext_mount_add(&entry->ext_mount, entry->fs, 1);
+			debug(ap->logopt, MODPREFIX
+			      "%s: mounted %s", entry->type, entry->fs);
+		} else {
+			if (!ext_mount_inuse(entry->fs))
+				rmdir_path(ap, entry->fs, ap->dev);
+			error(ap->logopt, MODPREFIX
+			     "%s: failed to mount using: %s",
+			     entry->type, entry->mount);
+		}
+	}
+do_free:
+	free_argv(argc, (const char **) argv);
+	free(str);
+
+	if (rv)
+		goto out;
+
+	rv = do_link_mount(ap, name, entry, 0);
+	if (!rv)
+		goto out;
+
+	if (umount_amd_ext_mount(ap, entry)) {
+		if (!ext_mount_inuse(entry->fs))
+			rmdir_path(ap, entry->fs, ap->dev);
+		debug(ap->logopt, MODPREFIX
+		      "%s: failed to umount external mount at %s",
+		      entry->type, entry->fs);
+	}
+out:
+	return rv;
+}
+
 static unsigned int validate_auto_options(unsigned int logopt,
 					  struct amd_entry *entry)
 {
@@ -1350,6 +1464,29 @@ static unsigned int validate_host_option
 	return 1;
 }
 
+static unsigned int validate_program_options(unsigned int logopt,
+					     struct amd_entry *entry)
+{
+	/*
+	 * entry->mount will be NULL if there is a problem expanding
+	 * ${} macros in expandamdent().
+	 */
+	if (!entry->mount) {
+		error(logopt, MODPREFIX
+		      "%s: mount program invalid or not set", entry->type);
+		return 0;
+	}
+
+	if (!entry->fs && !*entry->fs) {
+		error(logopt, MODPREFIX
+		    "%s: ${fs} must be used as the mount point but is not set",
+		    entry->type);
+		return 0;
+	}
+
+	return 1;
+}
+
 static int amd_mount(struct autofs_point *ap, const char *name,
 		     struct amd_entry *entry, struct map_source *source,
 		     struct substvar *sv, unsigned int flags,
@@ -1415,6 +1552,12 @@ static int amd_mount(struct autofs_point
 		ret = do_host_mount(ap, name, entry, source, flags);
 		break;
 
+	case AMD_MOUNT_TYPE_PROGRAM:
+		if (!validate_program_options(ap->logopt, entry))
+			return 1;
+		ret = do_program_mount(ap, entry, name);
+		break;
+
 	default:
 		info(ap->logopt,
 		     MODPREFIX "unkown file system type %x", fstype);