autofs-5.1.3 - add amd mount type program mount support From: Ian Kent 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 --- 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);