autofs-5.0.3 - refactor mount request vars From: Ian Kent There is code duplication between the direct and indirect mount modules that sets up the variables available to maps. This patch reorganizes and moves that code to a common location. Signed-off-by: Ian Kent --- daemon/direct.c | 131 ---------------- daemon/indirect.c | 131 ---------------- include/automount.h | 56 ------- include/mounts.h | 91 +++++++++++ include/parse_subs.h | 3 lib/mounts.c | 410 ++++++++++++++++++++++++++++++++++++++++++++------ lib/parse_subs.c | 230 ---------------------------- 7 files changed, 458 insertions(+), 594 deletions(-) create mode 100644 include/mounts.h diff --git a/daemon/direct.c b/daemon/direct.c index 072ef97..a3869a5 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -35,8 +35,6 @@ #include #include #include -#include -#include #include "automount.h" @@ -1237,15 +1235,6 @@ static void *do_mount_direct(void *arg) { struct pending_args *args, mt; struct autofs_point *ap; - struct passwd pw; - struct passwd *ppw = &pw; - struct passwd **pppw = &ppw; - struct group gr; - struct group *pgr; - struct group **ppgr; - char *pw_tmp, *gr_tmp; - struct thread_stdenv_vars *tsv; - int tmplen, grplen; struct stat st; int status, state; @@ -1291,126 +1280,8 @@ static void *do_mount_direct(void *arg) info(ap->logopt, "attempting to mount entry %s", mt.name); - /* - * Setup thread specific data values for macro - * substution in map entries during the mount. - * Best effort only as it must go ahead. - */ - - tsv = malloc(sizeof(struct thread_stdenv_vars)); - if (!tsv) - goto cont; - - tsv->uid = mt.uid; - tsv->gid = mt.gid; - - /* Try to get passwd info */ - - tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getpwuid_r"); - free(tsv); - goto cont; - } - - pw_tmp = malloc(tmplen + 1); - if (!pw_tmp) { - error(ap->logopt, "failed to malloc buffer for getpwuid_r"); - free(tsv); - goto cont; - } - - status = getpwuid_r(tsv->uid, ppw, pw_tmp, tmplen, pppw); - if (status || !ppw) { - error(ap->logopt, "failed to get passwd info from getpwuid_r"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->user = strdup(pw.pw_name); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for user"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->home = strdup(pw.pw_dir); - if (!tsv->home) { - error(ap->logopt, "failed to malloc buffer for home"); - free(pw_tmp); - free(tsv->user); - free(tsv); - goto cont; - } - - free(pw_tmp); - - /* Try to get group info */ - - grplen = sysconf(_SC_GETGR_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - - gr_tmp = NULL; - tmplen = grplen; - while (1) { - char *tmp = realloc(gr_tmp, tmplen + 1); - if (!tmp) { - error(ap->logopt, "failed to malloc buffer for getgrgid_r"); - if (gr_tmp) - free(gr_tmp); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - gr_tmp = tmp; - pgr = &gr; - ppgr = &pgr; - status = getgrgid_r(tsv->gid, pgr, gr_tmp, tmplen, ppgr); - if (status != ERANGE) - break; - tmplen += grplen; - } - - if (status || !pgr) { - error(ap->logopt, "failed to get group info from getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - tsv->group = strdup(gr.gr_name); - if (!tsv->group) { - error(ap->logopt, "failed to malloc buffer for group"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - free(gr_tmp); - - status = pthread_setspecific(key_thread_stdenv_vars, tsv); - if (status) { - error(ap->logopt, "failed to set stdenv thread var"); - free(tsv->group); - free(tsv->user); - free(tsv->home); - free(tsv); - } + set_tsd_user_vars(ap->logopt, mt.uid, mt.gid); -cont: status = lookup_nss_mount(ap, NULL, mt.name, mt.len); /* * Direct mounts are always a single mount. If it fails there's diff --git a/daemon/indirect.c b/daemon/indirect.c index ccdd8bf..3922f3f 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include "automount.h" @@ -672,15 +670,7 @@ static void *do_mount_indirect(void *arg) struct autofs_point *ap; char buf[PATH_MAX + 1]; struct stat st; - struct passwd pw; - struct passwd *ppw = &pw; - struct passwd **pppw = &ppw; - struct group gr; - struct group *pgr; - struct group **ppgr; - char *pw_tmp, *gr_tmp; - struct thread_stdenv_vars *tsv; - int len, tmplen, grplen, status, state; + int len, status, state; args = (struct pending_args *) arg; @@ -722,125 +712,8 @@ static void *do_mount_indirect(void *arg) info(ap->logopt, "attempting to mount entry %s", buf); - /* - * Setup thread specific data values for macro - * substution in map entries during the mount. - * Best effort only as it must go ahead. - */ - - tsv = malloc(sizeof(struct thread_stdenv_vars)); - if (!tsv) - goto cont; - - tsv->uid = mt.uid; - tsv->gid = mt.gid; - - /* Try to get passwd info */ - - tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getpwuid_r"); - free(tsv); - goto cont; - } - - pw_tmp = malloc(tmplen + 1); - if (!pw_tmp) { - error(ap->logopt, "failed to malloc buffer for getpwuid_r"); - free(tsv); - goto cont; - } - - status = getpwuid_r(tsv->uid, ppw, pw_tmp, tmplen, pppw); - if (status || !ppw) { - error(ap->logopt, "failed to get passwd info from getpwuid_r"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->user = strdup(pw.pw_name); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for user"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->home = strdup(pw.pw_dir); - if (!tsv->home) { - error(ap->logopt, "failed to malloc buffer for home"); - free(pw_tmp); - free(tsv->user); - free(tsv); - goto cont; - } + set_tsd_user_vars(ap->logopt, mt.uid, mt.gid); - free(pw_tmp); - - /* Try to get group info */ - - grplen = sysconf(_SC_GETGR_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - - gr_tmp = NULL; - tmplen = grplen; - while (1) { - char *tmp = realloc(gr_tmp, tmplen + 1); - if (!tmp) { - error(ap->logopt, "failed to malloc buffer for getgrgid_r"); - if (gr_tmp) - free(gr_tmp); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - gr_tmp = tmp; - pgr = &gr; - ppgr = &pgr; - status = getgrgid_r(tsv->gid, pgr, gr_tmp, tmplen, ppgr); - if (status != ERANGE) - break; - tmplen += grplen; - } - - if (status || !pgr) { - error(ap->logopt, "failed to get group info from getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - tsv->group = strdup(gr.gr_name); - if (!tsv->group) { - error(ap->logopt, "failed to malloc buffer for group"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - free(gr_tmp); - - status = pthread_setspecific(key_thread_stdenv_vars, tsv); - if (status) { - error(ap->logopt, "failed to set stdenv thread var"); - free(tsv->group); - free(tsv->user); - free(tsv->home); - free(tsv); - } -cont: status = lookup_nss_mount(ap, NULL, mt.name, mt.len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) { diff --git a/include/automount.h b/include/automount.h index 72e2457..da1bf8f 100644 --- a/include/automount.h +++ b/include/automount.h @@ -28,6 +28,7 @@ #include "macros.h" #include "log.h" #include "rpc_subs.h" +#include "mounts.h" #include "parse_subs.h" #ifdef WITH_DMALLOC @@ -323,61 +324,6 @@ int cat_path(char *buf, size_t len, const char *dir, const char *base); int ncat_path(char *buf, size_t len, const char *dir, const char *base, size_t blen); -/* mount table utilities */ - -#define MNTS_ALL 0x0001 -#define MNTS_REAL 0x0002 -#define MNTS_AUTOFS 0x0004 - -struct mnt_list { - char *path; - char *fs_name; - char *fs_type; - char *opts; - pid_t owner; - /* - * List operations ie. get_mnt_list. - */ - struct mnt_list *next; - /* - * Tree operations ie. tree_make_tree, - * tree_get_mnt_list etc. - */ - struct mnt_list *left; - struct mnt_list *right; - struct list_head self; - struct list_head list; - struct list_head entries; - struct list_head sublist; - /* - * Offset mount handling ie. add_ordered_list - * and get_offset. - */ - struct list_head ordered; -}; - -unsigned int query_kproto_ver(void); -unsigned int get_kver_major(void); -unsigned int get_kver_minor(void); -char *make_options_string(char *path, int kernel_pipefd, char *extra); -char *make_mnt_name_string(char *path); -struct mnt_list *get_mnt_list(const char *table, const char *path, int include); -struct mnt_list *reverse_mnt_list(struct mnt_list *list); -void free_mnt_list(struct mnt_list *list); -int contained_in_local_fs(const char *path); -int is_mounted(const char *table, const char *path, unsigned int type); -int has_fstab_option(const char *opt); -char *find_mnt_ino(const char *table, dev_t dev, ino_t ino); -char *get_offset(const char *prefix, char *offset, - struct list_head *head, struct list_head **pos); -void add_ordered_list(struct mnt_list *ent, struct list_head *head); -void tree_free_mnt_tree(struct mnt_list *tree); -struct mnt_list *tree_make_mnt_tree(const char *table, const char *path); -int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include); -int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include); -int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path); -int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type); - /* Core automount definitions */ #define MNT_DETACH 0x00000002 /* Just detach from the tree */ diff --git a/include/mounts.h b/include/mounts.h new file mode 100644 index 0000000..7120351 --- /dev/null +++ b/include/mounts.h @@ -0,0 +1,91 @@ +/* ----------------------------------------------------------------------- * + * + * mounts.h - header file for mount utilities module. + * + * Copyright 2008 Red Hat, Inc. All rights reserved. + * Copyright 2004-2006 Ian Kent - 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. + * + * ----------------------------------------------------------------------- */ + +#ifndef MOUNTS_H +#define MOUNTS_H + +#define AUTOFS_TYPE_ANY 0x0000 +#define AUTOFS_TYPE_INDIRECT 0x0001 +#define AUTOFS_TYPE_DIRECT 0x0002 +#define AUTOFS_TYPE_OFFSET 0x0004 + +#define MNTS_ALL 0x0001 +#define MNTS_REAL 0x0002 +#define MNTS_AUTOFS 0x0004 + +#define REMOUNT_SUCCESS 0x0000 +#define REMOUNT_OPEN_FAIL 0x0001 +#define REMOUNT_STAT_FAIL 0x0002 +#define REMOUNT_READ_MAP 0x0004 + +extern const unsigned int indirect; +extern const unsigned int direct; +extern const unsigned int offset; + +struct mapent; + +struct mnt_list { + char *path; + char *fs_name; + char *fs_type; + char *opts; + pid_t owner; + /* + * List operations ie. get_mnt_list. + */ + struct mnt_list *next; + /* + * Tree operations ie. tree_make_tree, + * tree_get_mnt_list etc. + */ + struct mnt_list *left; + struct mnt_list *right; + struct list_head self; + struct list_head list; + struct list_head entries; + struct list_head sublist; + /* + * Offset mount handling ie. add_ordered_list + * and get_offset. + */ + struct list_head ordered; +}; + +unsigned int query_kproto_ver(void); +unsigned int get_kver_major(void); +unsigned int get_kver_minor(void); +char *make_options_string(char *path, int kernel_pipefd, const char *extra); +char *make_mnt_name_string(char *path); +struct mnt_list *get_mnt_list(const char *table, const char *path, int include); +struct mnt_list *reverse_mnt_list(struct mnt_list *list); +void free_mnt_list(struct mnt_list *list); +int contained_in_local_fs(const char *path); +int is_mounted(const char *table, const char *path, unsigned int type); +int has_fstab_option(const char *opt); +char *get_offset(const char *prefix, char *offset, + struct list_head *head, struct list_head **pos); +void add_ordered_list(struct mnt_list *ent, struct list_head *head); +void tree_free_mnt_tree(struct mnt_list *tree); +struct mnt_list *tree_make_mnt_tree(const char *table, const char *path); +int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include); +int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include); +int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path); +int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type); +void set_tsd_user_vars(unsigned int, uid_t, gid_t); +int umount_ent(struct autofs_point *, const char *); +int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); +int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); + +#endif diff --git a/include/parse_subs.h b/include/parse_subs.h index 10c6083..643ad68 100644 --- a/include/parse_subs.h +++ b/include/parse_subs.h @@ -27,8 +27,5 @@ int strmcmp(const char *, const char *, int); char *dequote(const char *, int, unsigned int); int span_space(const char *, unsigned int); char *sanitize_path(const char *, int, unsigned int, unsigned int); -int umount_ent(struct autofs_point *, const char *); -int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); -int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); #endif diff --git a/lib/mounts.c b/lib/mounts.c index b987fbb..a4bf86c 100644 --- a/lib/mounts.c +++ b/lib/mounts.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * mounts.c - module for Linux automount mount table lookup functions + * mounts.c - module for mount utilities. * * Copyright 2002-2005 Ian Kent - All Rights Reserved * @@ -23,12 +23,21 @@ #include #include #include +#include +#include +#include +#include #include "automount.h" #define MAX_OPTIONS_LEN 80 #define MAX_MNT_NAME_LEN 30 +const unsigned int indirect = AUTOFS_TYPE_INDIRECT; +const unsigned int direct = AUTOFS_TYPE_DIRECT; +const unsigned int offset = AUTOFS_TYPE_OFFSET; +const unsigned int type_count = 3; + static const char options_template[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d"; static const char options_template_extra[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d,%s"; static const char mnt_name_template[] = "automount(pid%u)"; @@ -119,7 +128,7 @@ unsigned int get_kver_minor(void) /* * Make common autofs mount options string */ -char *make_options_string(char *path, int pipefd, char *extra) +char *make_options_string(char *path, int pipefd, const char *extra) { char *options; int len; @@ -462,51 +471,6 @@ int has_fstab_option(const char *opt) return ret; } -char *find_mnt_ino(const char *table, dev_t dev, ino_t ino) -{ - struct mntent mnt_wrk; - struct mntent *mnt; - char buf[PATH_MAX * 3]; - char *path = NULL; - unsigned long l_dev = (unsigned long) dev; - unsigned long l_ino = (unsigned long) ino; - FILE *tab; - - tab = setmntent(table, "r"); - if (!tab) { - char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1); - logerr("setmntent: %s", estr); - return 0; - } - - while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) { - char *p_dev, *p_ino; - unsigned long m_dev, m_ino; - - if (strcmp(mnt->mnt_type, "autofs")) - continue; - - p_dev = strstr(mnt->mnt_opts, "dev="); - if (!p_dev) - continue; - sscanf(p_dev, "dev=%lu", &m_dev); - if (m_dev != l_dev) - continue; - - p_ino = strstr(mnt->mnt_opts, "ino="); - if (!p_ino) - continue; - sscanf(p_ino, "ino=%lu", &m_ino); - if (m_ino == l_ino) { - path = strdup(mnt->mnt_dir); - break; - } - } - endmntent(tab); - - return path; -} - char *get_offset(const char *prefix, char *offset, struct list_head *head, struct list_head **pos) { @@ -982,3 +946,355 @@ int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type) return mounted; } +void set_tsd_user_vars(unsigned int logopt, uid_t uid, gid_t gid) +{ + struct thread_stdenv_vars *tsv; + struct passwd pw; + struct passwd *ppw = &pw; + struct passwd **pppw = &ppw; + struct group gr; + struct group *pgr; + struct group **ppgr; + char *pw_tmp, *gr_tmp; + int status, tmplen, grplen; + + /* + * Setup thread specific data values for macro + * substution in map entries during the mount. + * Best effort only as it must go ahead. + */ + + tsv = malloc(sizeof(struct thread_stdenv_vars)); + if (!tsv) { + error(logopt, "failed alloc tsv storage"); + return; + } + + tsv->uid = uid; + tsv->gid = gid; + + /* Try to get passwd info */ + + tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (tmplen < 0) { + error(logopt, "failed to get buffer size for getpwuid_r"); + goto free_tsv; + } + + pw_tmp = malloc(tmplen + 1); + if (!pw_tmp) { + error(logopt, "failed to malloc buffer for getpwuid_r"); + goto free_tsv; + } + + status = getpwuid_r(uid, ppw, pw_tmp, tmplen, pppw); + if (status || !ppw) { + error(logopt, "failed to get passwd info from getpwuid_r"); + free(pw_tmp); + goto free_tsv; + } + + tsv->user = strdup(pw.pw_name); + if (!tsv->user) { + error(logopt, "failed to malloc buffer for user"); + free(pw_tmp); + goto free_tsv; + } + + tsv->home = strdup(pw.pw_dir); + if (!tsv->home) { + error(logopt, "failed to malloc buffer for home"); + free(pw_tmp); + goto free_tsv_user; + } + + free(pw_tmp); + + /* Try to get group info */ + + grplen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (tmplen < 0) { + error(logopt, "failed to get buffer size for getgrgid_r"); + goto free_tsv_home; + } + + gr_tmp = NULL; + tmplen = grplen; + while (1) { + char *tmp = realloc(gr_tmp, tmplen + 1); + if (!tmp) { + error(logopt, "failed to malloc buffer for getgrgid_r"); + if (gr_tmp) + free(gr_tmp); + goto free_tsv_home; + } + gr_tmp = tmp; + pgr = &gr; + ppgr = &pgr; + status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr); + if (status != ERANGE) + break; + tmplen += grplen; + } + + if (status || !pgr) { + error(logopt, "failed to get group info from getgrgid_r"); + free(gr_tmp); + goto free_tsv_home; + } + + tsv->group = strdup(gr.gr_name); + if (!tsv->group) { + error(logopt, "failed to malloc buffer for group"); + free(gr_tmp); + goto free_tsv_home; + } + + free(gr_tmp); + + status = pthread_setspecific(key_thread_stdenv_vars, tsv); + if (status) { + error(logopt, "failed to set stdenv thread var"); + goto free_tsv_group; + } + + return; + +free_tsv_group: + free(tsv->group); +free_tsv_home: + free(tsv->home); +free_tsv_user: + free(tsv->user); +free_tsv: + free(tsv); + return; +} + +int umount_ent(struct autofs_point *ap, const char *path) +{ + struct stat st; + struct statfs fs; + int sav_errno; + int status, is_smbfs = 0; + int ret, rv = 1; + + ret = statfs(path, &fs); + if (ret == -1) { + warn(ap->logopt, "could not stat fs of %s", path); + is_smbfs = 0; + } else { + int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER; + int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC; + is_smbfs = (cifsfs | smbfs) ? 1 : 0; + } + + status = lstat(path, &st); + sav_errno = errno; + + if (status < 0) + warn(ap->logopt, "lstat of %s failed with %d", path, status); + + /* + * lstat failed and we're an smbfs fs returning an error that is not + * EIO or EBADSLT or the lstat failed so it's a bad path. Return + * a fail. + * + * EIO appears to correspond to an smb mount that has gone away + * and EBADSLT relates to CD changer not responding. + */ + if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) { + rv = spawn_umount(ap->logopt, path, NULL); + } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) { + rv = spawn_umount(ap->logopt, path, NULL); + } + + /* We are doing a forced shutcwdown down so unlink busy mounts */ + if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) { + ret = stat(path, &st); + if (ret == -1 && errno == ENOENT) { + warn(ap->logopt, "mount point does not exist"); + return 0; + } + + if (ret == 0 && !S_ISDIR(st.st_mode)) { + warn(ap->logopt, "mount point is not a directory"); + return 0; + } + + if (ap->state == ST_SHUTDOWN_FORCE) { + info(ap->logopt, "forcing umount of %s", path); + rv = spawn_umount(ap->logopt, "-l", path, NULL); + } + + /* + * Verify that we actually unmounted the thing. This is a + * belt and suspenders approach to not eating user data. + * We have seen cases where umount succeeds, but there is + * still a file system mounted on the mount point. How + * this happens has not yet been determined, but we want to + * make sure to return failure here, if that is the case, + * so that we do not try to call rmdir_path on the + * directory. + */ + if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { + crit(ap->logopt, + "the umount binary reported that %s was " + "unmounted, but there is still something " + "mounted on this path.", path); + rv = -1; + } + } + + return rv; +} + +int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) +{ + char path[PATH_MAX + 1]; + char *offset = path; + struct mapent *oe; + struct list_head *pos = NULL; + unsigned int fs_path_len; + unsigned int mounted; + int ret, start; + + fs_path_len = strlen(root) + strlen(base); + if (fs_path_len > PATH_MAX) + return -1; + + strcpy(path, root); + strcat(path, base); + + mounted = 0; + start = strlen(root); + offset = cache_get_offset(base, offset, start, &me->multi_list, &pos); + while (offset) { + int plen = fs_path_len + strlen(offset); + + if (plen > PATH_MAX) { + warn(ap->logopt, "path loo long"); + goto cont; + } + + oe = cache_lookup_offset(base, offset, start, &me->multi_list); + if (!oe || !oe->mapent) + goto cont; + + debug(ap->logopt, "mount offset %s", oe->key); + + ret = mount_autofs_offset(ap, oe); + if (ret >= MOUNT_OFFSET_OK) + mounted++; + else { + if (ret != MOUNT_OFFSET_IGNORE) + warn(ap->logopt, "failed to mount offset"); + else { + debug(ap->logopt, + "ignoring \"nohide\" trigger %s", + oe->key); + free(oe->mapent); + oe->mapent = NULL; + } + } +cont: + offset = cache_get_offset(base, + offset, start, &me->multi_list, &pos); + } + + return mounted; +} + +int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) +{ + char path[PATH_MAX + 1]; + char *offset; + struct mapent *oe; + struct list_head *mm_root, *pos; + const char o_root[] = "/"; + const char *mm_base; + int left, start; + + left = 0; + start = strlen(root); + + mm_root = &me->multi->multi_list; + + if (!base) + mm_base = o_root; + else + mm_base = base; + + pos = NULL; + offset = path; + + /* Make sure "none" of the offsets have an active mount. */ + while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { + char *oe_base; + + oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); + /* root offset is a special case */ + if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) + continue; + + /* + * Check for and umount subtree offsets resulting from + * nonstrict mount fail. + */ + oe_base = oe->key + strlen(root); + left += umount_multi_triggers(ap, root, oe, oe_base); + + if (oe->ioctlfd != -1) + left++; + } + + if (left) + return left; + + pos = NULL; + offset = path; + + /* Make sure "none" of the offsets have an active mount. */ + while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { + oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); + /* root offset is a special case */ + if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) + continue; + + debug(ap->logopt, "umount offset %s", oe->key); + + if (umount_autofs_offset(ap, oe)) { + warn(ap->logopt, "failed to umount offset"); + left++; + } + } + + if (!left && me->multi == me) { + struct mapent_cache *mc = me->mc; + int status; + + /* + * Special case. + * If we can't umount the root container then we can't + * delete the offsets from the cache and we need to put + * the offset triggers back. + */ + if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) { + info(ap->logopt, "unmounting dir = %s", root); + if (umount_ent(ap, root)) { + if (mount_multi_triggers(ap, root, me, "/") < 0) + warn(ap->logopt, + "failed to remount offset triggers"); + return left++; + } + } + + /* We're done - clean out the offsets */ + status = cache_delete_offset_list(mc, me->key); + if (status != CHE_OK) + warn(ap->logopt, "couldn't delete offset list"); + } + + return left; +} + diff --git a/lib/parse_subs.c b/lib/parse_subs.c index 27cb0fc..3a04dd6 100644 --- a/lib/parse_subs.c +++ b/lib/parse_subs.c @@ -18,10 +18,7 @@ #include #include #include -#include -#include #include -#include #include "automount.h" /* @@ -304,230 +301,3 @@ char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned i return s_path; } -int umount_ent(struct autofs_point *ap, const char *path) -{ - struct stat st; - struct statfs fs; - int sav_errno; - int status, is_smbfs = 0; - int ret, rv = 1; - - ret = statfs(path, &fs); - if (ret == -1) { - warn(ap->logopt, "could not stat fs of %s", path); - is_smbfs = 0; - } else { - int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER; - int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC; - is_smbfs = (cifsfs | smbfs) ? 1 : 0; - } - - status = lstat(path, &st); - sav_errno = errno; - - if (status < 0) - warn(ap->logopt, "lstat of %s failed with %d", path, status); - - /* - * lstat failed and we're an smbfs fs returning an error that is not - * EIO or EBADSLT or the lstat failed so it's a bad path. Return - * a fail. - * - * EIO appears to correspond to an smb mount that has gone away - * and EBADSLT relates to CD changer not responding. - */ - if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) { - rv = spawn_umount(ap->logopt, path, NULL); - } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) { - rv = spawn_umount(ap->logopt, path, NULL); - } - - /* We are doing a forced shutcwdown down so unlink busy mounts */ - if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) { - ret = stat(path, &st); - if (ret == -1 && errno == ENOENT) { - warn(ap->logopt, "mount point does not exist"); - return 0; - } - - if (ret == 0 && !S_ISDIR(st.st_mode)) { - warn(ap->logopt, "mount point is not a directory"); - return 0; - } - - if (ap->state == ST_SHUTDOWN_FORCE) { - info(ap->logopt, "forcing umount of %s", path); - rv = spawn_umount(ap->logopt, "-l", path, NULL); - } - - /* - * Verify that we actually unmounted the thing. This is a - * belt and suspenders approach to not eating user data. - * We have seen cases where umount succeeds, but there is - * still a file system mounted on the mount point. How - * this happens has not yet been determined, but we want to - * make sure to return failure here, if that is the case, - * so that we do not try to call rmdir_path on the - * directory. - */ - if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { - crit(ap->logopt, - "the umount binary reported that %s was " - "unmounted, but there is still something " - "mounted on this path.", path); - rv = -1; - } - } - - return rv; -} - -int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) -{ - char path[PATH_MAX + 1]; - char *offset = path; - struct mapent *oe; - struct list_head *pos = NULL; - unsigned int fs_path_len; - unsigned int mounted; - int ret, start; - - fs_path_len = strlen(root) + strlen(base); - if (fs_path_len > PATH_MAX) - return -1; - - strcpy(path, root); - strcat(path, base); - - mounted = 0; - start = strlen(root); - offset = cache_get_offset(base, offset, start, &me->multi_list, &pos); - while (offset) { - int plen = fs_path_len + strlen(offset); - - if (plen > PATH_MAX) { - warn(ap->logopt, "path loo long"); - goto cont; - } - - oe = cache_lookup_offset(base, offset, start, &me->multi_list); - if (!oe || !oe->mapent) - goto cont; - - debug(ap->logopt, "mount offset %s", oe->key); - - ret = mount_autofs_offset(ap, oe); - if (ret >= MOUNT_OFFSET_OK) - mounted++; - else { - if (ret != MOUNT_OFFSET_IGNORE) - warn(ap->logopt, "failed to mount offset"); - else { - debug(ap->logopt, - "ignoring \"nohide\" trigger %s", - oe->key); - free(oe->mapent); - oe->mapent = NULL; - } - } -cont: - offset = cache_get_offset(base, - offset, start, &me->multi_list, &pos); - } - - return mounted; -} - -int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) -{ - char path[PATH_MAX + 1]; - char *offset; - struct mapent *oe; - struct list_head *mm_root, *pos; - const char o_root[] = "/"; - const char *mm_base; - int left, start; - - left = 0; - start = strlen(root); - - mm_root = &me->multi->multi_list; - - if (!base) - mm_base = o_root; - else - mm_base = base; - - pos = NULL; - offset = path; - - /* Make sure "none" of the offsets have an active mount. */ - while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { - char *oe_base; - - oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); - /* root offset is a special case */ - if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) - continue; - - /* - * Check for and umount subtree offsets resulting from - * nonstrict mount fail. - */ - oe_base = oe->key + strlen(root); - left += umount_multi_triggers(ap, root, oe, oe_base); - - if (oe->ioctlfd != -1) - left++; - } - - if (left) - return left; - - pos = NULL; - offset = path; - - /* Make sure "none" of the offsets have an active mount. */ - while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { - oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); - /* root offset is a special case */ - if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) - continue; - - debug(ap->logopt, "umount offset %s", oe->key); - - if (umount_autofs_offset(ap, oe)) { - warn(ap->logopt, "failed to umount offset"); - left++; - } - } - - if (!left && me->multi == me) { - struct mapent_cache *mc = me->mc; - int status; - - /* - * Special case. - * If we can't umount the root container then we can't - * delete the offsets from the cache and we need to put - * the offset triggers back. - */ - if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) { - info(ap->logopt, "unmounting dir = %s", root); - if (umount_ent(ap, root)) { - if (mount_multi_triggers(ap, root, me, "/") < 0) - warn(ap->logopt, - "failed to remount offset triggers"); - return left++; - } - } - - /* We're done - clean out the offsets */ - status = cache_delete_offset_list(mc, me->key); - if (status != CHE_OK) - warn(ap->logopt, "couldn't delete offset list"); - } - - return left; -} -