autofs-5.0.3 - fix multi mount race.
From: Ian Kent <raven@themaw.net>
When using multi-mounts it is possible for a path walk to walk into
a mount tree before it is completely setup which leads to autofs
incorrectly failing to perform mounts.
For example, for the multi-mount
mm1
/om1 <server1>:/<path1>
/om2 <server2>:/<path2>
/om2/om21 <server3>:/<path3>
/om2/om22 <server3>:/<path4>
when a path walk hits mm1/om2 <serverr2>:/<path2> is mounted on top of
mm1/om2. If a path walk comes along before the multi-mount offsets for
mm1/om2 are setup it doesn't see that mm1/om2 is pending. This happens
because the lookup gets to mm1/om2, which is within the mm1 file system,
and is covered by a mount trigger mounted at mm1/om2, and the the trigger
itself is covered by the <server3>:/<path3> mount. So the walk follows
the stack up to the mount at <server3>:/<path3>, never seeing that the
trigger mm1/om2 is currently pending.
In the example above mm1/om2 could also be a submount.
To resolve this the mount tree needs to be created under a temporary
directory and moved into place once setup in one operation.
---
CHANGELOG | 1
daemon/automount.c | 32 +++-
daemon/direct.c | 40 ++---
daemon/indirect.c | 55 ++++--
daemon/lookup.c | 6 -
daemon/state.c | 2
include/automount.h | 12 +
include/master.h | 1
include/mounts.h | 4
lib/master.c | 20 +-
lib/mounts.c | 21 +-
modules/mount_autofs.c | 61 ++++---
modules/mount_bind.c | 43 +----
modules/mount_changer.c | 34 +---
modules/mount_ext2.c | 40 +----
modules/mount_generic.c | 40 +----
modules/mount_nfs.c | 41 +----
modules/parse_sun.c | 408 ++++++++++++++++++++++++++++++++++++-----------
18 files changed, 517 insertions(+), 344 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index ff44cc7..a7b41ec 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -29,6 +29,7 @@
- fix submount shutdown recovery handling.
- avoid stat of possibly dead mount points and limit time to wait for
umount during expire.
+- make mount of multi-mounts wuth a root offset atomic.
14/01/2008 autofs-5.0.3
-----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 5bd5f6d..5b6a561 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -489,7 +489,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
/* Lock the closest parent nesting point for umount */
cache_multi_lock(me->parent);
- if (umount_multi_triggers(ap, root, me, base)) {
+ if (umount_multi_triggers(ap, me, root, base)) {
warn(ap->logopt,
"some offset mounts still present under %s", path);
left++;
@@ -572,7 +572,7 @@ static int umount_all(struct autofs_point *ap, int force)
return left;
}
-int umount_autofs(struct autofs_point *ap, int force)
+int umount_autofs(struct autofs_point *ap, const char *root, int force)
{
int ret = 0;
@@ -589,7 +589,7 @@ int umount_autofs(struct autofs_point *ap, int force)
if (ap->type == LKP_INDIRECT) {
if (umount_all(ap, force) && !force)
return -1;
- ret = umount_autofs_indirect(ap);
+ ret = umount_autofs_indirect(ap, root);
} else
ret = umount_autofs_direct(ap);
@@ -754,7 +754,7 @@ out_free:
return ret;
}
-static int destroy_logpri_fifo(struct autofs_point *ap)
+int destroy_logpri_fifo(struct autofs_point *ap)
{
int ret = -1;
int fd = ap->logpri_fifo;
@@ -1056,7 +1056,7 @@ static int autofs_init_ap(struct autofs_point *ap)
return 0;
}
-static int mount_autofs(struct autofs_point *ap)
+static int mount_autofs(struct autofs_point *ap, const char *root)
{
int status = 0;
@@ -1066,7 +1066,7 @@ static int mount_autofs(struct autofs_point *ap)
if (ap->type == LKP_DIRECT)
status = mount_autofs_direct(ap);
else
- status = mount_autofs_indirect(ap);
+ status = mount_autofs_indirect(ap, root);
if (status < 0)
return -1;
@@ -1531,10 +1531,12 @@ void *handle_mounts(void *arg)
struct startup_cond *suc;
struct autofs_point *ap;
int cancel_state, status = 0;
+ char *root;
suc = (struct startup_cond *) arg;
ap = suc->ap;
+ root = strdup(suc->root);
pthread_cleanup_push(return_start_status, suc);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
@@ -1545,14 +1547,24 @@ void *handle_mounts(void *arg)
fatal(status);
}
- if (mount_autofs(ap) < 0) {
+ if (!root) {
+ crit(ap->logopt, "failed to alloc string root");
+ suc->status = 1;
+ pthread_setcancelstate(cancel_state, NULL);
+ pthread_exit(NULL);
+ }
+
+ if (mount_autofs(ap, root) < 0) {
crit(ap->logopt, "mount of %s failed!", ap->path);
suc->status = 1;
- umount_autofs(ap, 1);
+ umount_autofs(ap, root, 1);
+ free(root);
pthread_setcancelstate(cancel_state, NULL);
pthread_exit(NULL);
}
+ free(root);
+
if (ap->ghost && ap->type != LKP_DIRECT)
info(ap->logopt, "ghosting enabled");
@@ -1615,7 +1627,7 @@ void *handle_mounts(void *arg)
* to check for possible recovery.
*/
if (ap->type == LKP_DIRECT) {
- umount_autofs(ap, 1);
+ umount_autofs(ap, NULL, 1);
break;
}
@@ -1625,7 +1637,7 @@ void *handle_mounts(void *arg)
* so we can continue. This can happen if a lookup
* occurs while we're trying to umount.
*/
- ret = umount_autofs(ap, 1);
+ ret = umount_autofs(ap, NULL, 1);
if (!ret)
break;
diff --git a/daemon/direct.c b/daemon/direct.c
index 7fb78a3..34e882b 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -646,7 +646,7 @@ force_umount:
return rv;
}
-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
{
char buf[MAX_ERR_BUF];
struct mnt_params *mp;
@@ -654,6 +654,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
struct stat st;
int ioctlfd, cl_flags, status, ret;
const char *type, *map_name = NULL;
+ char mountpoint[PATH_MAX];
if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
if (ap->state != ST_READMAP)
@@ -695,8 +696,11 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
return MOUNT_OFFSET_OK;
}
+ strcpy(mountpoint, root);
+ strcat(mountpoint, offset);
+
/* In case the directory doesn't exist, try to mkdir it */
- if (mkdir_path(me->key, 0555) < 0) {
+ if (mkdir_path(mountpoint, 0555) < 0) {
if (errno == EEXIST) {
/*
* If the mount point directory is a real mount
@@ -705,7 +709,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
* the kernel NFS client.
*/
if (me->multi != me &&
- is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL))
+ is_mounted(_PATH_MOUNTED, mountpoint, MNTS_REAL))
return MOUNT_OFFSET_IGNORE;
/*
@@ -725,13 +729,13 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
debug(ap->logopt,
"can't create mount directory: %s, %s",
- me->key, estr);
+ mountpoint, estr);
return MOUNT_OFFSET_FAIL;
} else {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
crit(ap->logopt,
"failed to create mount directory: %s, %s",
- me->key, estr);
+ mountpoint, estr);
return MOUNT_OFFSET_FAIL;
}
} else {
@@ -741,7 +745,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
debug(ap->logopt,
"calling mount -t autofs " SLOPPY " -o %s automount %s",
- mp->options, me->key);
+ mp->options, mountpoint);
type = ap->entry->maps->type;
if (type && !strcmp(ap->entry->maps->type, "hosts")) {
@@ -753,22 +757,18 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
} else
map_name = me->mc->map->argv[0];
- ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options);
+ ret = mount(map_name, mountpoint, "autofs", MS_MGC_VAL, mp->options);
if (ret) {
- crit(ap->logopt, "failed to mount autofs path %s", me->key);
- goto out_err;
- }
-
- if (ret != 0) {
crit(ap->logopt,
- "failed to mount autofs offset trigger %s", me->key);
+ "failed to mount offset trigger %s at %s",
+ me->key, mountpoint);
goto out_err;
}
/* Root directory for ioctl()'s */
- ioctlfd = open(me->key, O_RDONLY);
+ ioctlfd = open(mountpoint, O_RDONLY);
if (ioctlfd < 0) {
- crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
+ crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
goto out_umount;
}
@@ -782,7 +782,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
ret = fstat(ioctlfd, &st);
if (ret == -1) {
error(ap->logopt,
- "failed to stat direct mount trigger %s", me->key);
+ "failed to stat direct mount trigger %s", mountpoint);
goto out_close;
}
@@ -790,17 +790,17 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
close(ioctlfd);
- debug(ap->logopt, "mounted trigger %s", me->key);
+ debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
return MOUNT_OFFSET_OK;
out_close:
close(ioctlfd);
out_umount:
- umount(me->key);
+ umount(mountpoint);
out_err:
- if (stat(me->key, &st) == 0 && me->dir_created)
- rmdir_path(ap, me->key, st.st_dev);
+ if (stat(mountpoint, &st) == 0 && me->dir_created)
+ rmdir_path(ap, mountpoint, st.st_dev);
return MOUNT_OFFSET_FAIL;
}
diff --git a/daemon/indirect.c b/daemon/indirect.c
index e832cd4..168d915 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -83,7 +83,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
return ret;
}
-static int do_mount_autofs_indirect(struct autofs_point *ap)
+static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
{
time_t timeout = ap->exp_timeout;
char *options = NULL;
@@ -109,11 +109,11 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
goto out_err;
/* In case the directory doesn't exist, try to mkdir it */
- if (mkdir_path(ap->path, 0555) < 0) {
+ if (mkdir_path(root, 0555) < 0) {
if (errno != EEXIST && errno != EROFS) {
crit(ap->logopt,
"failed to create autofs directory %s",
- ap->path);
+ root);
goto out_err;
}
/* If we recieve an error, and it's EEXIST or EROFS we know
@@ -134,9 +134,10 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
} else
map_name = ap->entry->maps->argv[0];
- ret = mount(map_name, ap->path, "autofs", MS_MGC_VAL, options);
+ ret = mount(map_name, root, "autofs", MS_MGC_VAL, options);
if (ret) {
- crit(ap->logopt, "failed to mount autofs path %s", ap->path);
+ crit(ap->logopt,
+ "failed to mount autofs path %s at %s", ap->path, root);
goto out_rmdir;
}
@@ -145,7 +146,7 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
options = NULL;
/* Root directory for ioctl()'s */
- ap->ioctlfd = open(ap->path, O_RDONLY);
+ ap->ioctlfd = open(root, O_RDONLY);
if (ap->ioctlfd < 0) {
crit(ap->logopt,
"failed to create ioctl fd for autofs path %s", ap->path);
@@ -163,13 +164,13 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
if (ap->exp_timeout)
info(ap->logopt,
- "mounted indirect mount on %s "
+ "mounted indirect mount for %s "
"with timeout %u, freq %u seconds", ap->path,
(unsigned int) ap->exp_timeout,
(unsigned int) ap->exp_runfreq);
else
info(ap->logopt,
- "mounted indirect mount on %s with timeouts disabled",
+ "mounted indirect mount for %s with timeouts disabled",
ap->path);
fstat(ap->ioctlfd, &st);
@@ -178,10 +179,10 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
return 0;
out_umount:
- umount(ap->path);
+ umount(root);
out_rmdir:
if (ap->dir_created)
- rmdir_path(ap, ap->path, ap->dev);
+ rmdir(root);
out_err:
if (options)
free(options);
@@ -193,7 +194,7 @@ out_err:
return -1;
}
-int mount_autofs_indirect(struct autofs_point *ap)
+int mount_autofs_indirect(struct autofs_point *ap, const char *root)
{
time_t now = time(NULL);
int status;
@@ -207,11 +208,11 @@ int mount_autofs_indirect(struct autofs_point *ap)
return -1;
}
- status = do_mount_autofs_indirect(ap);
+ status = do_mount_autofs_indirect(ap, root);
if (status < 0)
return -1;
- map = lookup_ghost(ap);
+ map = lookup_ghost(ap, root);
if (map & LKP_FAIL) {
if (map & LKP_DIRECT) {
error(ap->logopt,
@@ -230,7 +231,7 @@ int mount_autofs_indirect(struct autofs_point *ap)
return 0;
}
-static void close_mount_fds(struct autofs_point *ap)
+void close_mount_fds(struct autofs_point *ap)
{
/*
* Since submounts look after themselves the parent never knows
@@ -255,11 +256,17 @@ static void close_mount_fds(struct autofs_point *ap)
return;
}
-int umount_autofs_indirect(struct autofs_point *ap)
+int umount_autofs_indirect(struct autofs_point *ap, const char *root)
{
char buf[MAX_ERR_BUF];
+ char mountpoint[PATH_MAX + 1];
int ret, rv, retries;
+ if (root)
+ strcpy(mountpoint, root);
+ else
+ strcpy(mountpoint, ap->path);
+
/* If we are trying to shutdown make sure we can umount */
rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
if (rv == -1) {
@@ -284,7 +291,7 @@ int umount_autofs_indirect(struct autofs_point *ap)
sched_yield();
retries = UMOUNT_RETRIES;
- while ((rv = umount(ap->path)) == -1 && retries--) {
+ while ((rv = umount(mountpoint)) == -1 && retries--) {
struct timespec tm = {0, 200000000};
if (errno != EBUSY)
break;
@@ -296,13 +303,13 @@ int umount_autofs_indirect(struct autofs_point *ap)
case ENOENT:
case EINVAL:
error(ap->logopt,
- "mount point %s does not exist", ap->path);
+ "mount point %s does not exist", mountpoint);
close_mount_fds(ap);
return 0;
break;
case EBUSY:
debug(ap->logopt,
- "mount point %s is in use", ap->path);
+ "mount point %s is in use", mountpoint);
if (ap->state == ST_SHUTDOWN_FORCE) {
close_mount_fds(ap);
goto force_umount;
@@ -321,11 +328,11 @@ int umount_autofs_indirect(struct autofs_point *ap)
return 0;
}
#endif
- ap->ioctlfd = open(ap->path, O_RDONLY);
+ ap->ioctlfd = open(mountpoint, O_RDONLY);
if (ap->ioctlfd < 0) {
warn(ap->logopt,
"could not recover autofs path %s",
- ap->path);
+ mountpoint);
close_mount_fds(ap);
return 0;
}
@@ -355,12 +362,12 @@ int umount_autofs_indirect(struct autofs_point *ap)
force_umount:
if (rv != 0) {
warn(ap->logopt,
- "forcing umount of indirect mount %s", ap->path);
- rv = umount2(ap->path, MNT_DETACH);
+ "forcing umount of indirect mount %s", mountpoint);
+ rv = umount2(mountpoint, MNT_DETACH);
} else {
- info(ap->logopt, "umounted indirect mount %s", ap->path);
+ info(ap->logopt, "umounted indirect mount %s", mountpoint);
if (ap->submount)
- rm_unwanted(ap->logopt, ap->path, 1, ap->dev);
+ rm_unwanted(ap->logopt, mountpoint, 1, ap->dev);
}
return rv;
diff --git a/daemon/lookup.c b/daemon/lookup.c
index 85ac519..db3b636 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -565,7 +565,7 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
return 0;
}
-int lookup_ghost(struct autofs_point *ap)
+int lookup_ghost(struct autofs_point *ap, const char *root)
{
struct master_mapent *entry = ap->entry;
struct map_source *map;
@@ -611,12 +611,12 @@ int lookup_ghost(struct autofs_point *ap)
goto next;
}
- fullpath = alloca(strlen(me->key) + strlen(ap->path) + 3);
+ fullpath = alloca(strlen(me->key) + strlen(root) + 3);
if (!fullpath) {
warn(ap->logopt, "failed to allocate full path");
goto next;
}
- sprintf(fullpath, "%s/%s", ap->path, me->key);
+ sprintf(fullpath, "%s/%s", root, me->key);
ret = stat(fullpath, &st);
if (ret == -1 && errno != ENOENT) {
diff --git a/daemon/state.c b/daemon/state.c
index 122177c..0042a74 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -393,7 +393,7 @@ static void *do_readmap(void *arg)
if (ap->type == LKP_INDIRECT) {
lookup_prune_cache(ap, now);
- status = lookup_ghost(ap);
+ status = lookup_ghost(ap, ap->path);
} else {
struct mapent *me, *ne, *nested;
mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
diff --git a/include/automount.h b/include/automount.h
index 8ff24a7..61cdac6 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -230,7 +230,7 @@ int lookup_nss_read_master(struct master *master, time_t age);
int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age);
int lookup_enumerate(struct autofs_point *ap,
int (*fn)(struct autofs_point *,struct mapent *, int), time_t now);
-int lookup_ghost(struct autofs_point *ap);
+int lookup_ghost(struct autofs_point *ap, const char *root);
int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len);
void lookup_close_lookup(struct autofs_point *ap);
int lookup_prune_cache(struct autofs_point *ap, time_t age);
@@ -332,6 +332,7 @@ struct startup_cond {
pthread_mutex_t mutex;
pthread_cond_t cond;
struct autofs_point *ap;
+ char *root;
unsigned int done;
unsigned int status;
};
@@ -427,12 +428,13 @@ int do_expire(struct autofs_point *ap, const char *name, int namelen);
void *expire_proc_indirect(void *);
void *expire_proc_direct(void *);
int expire_offsets_direct(struct autofs_point *ap, struct mapent *me, int now);
-int mount_autofs_indirect(struct autofs_point *ap);
+int mount_autofs_indirect(struct autofs_point *ap, const char *root);
int mount_autofs_direct(struct autofs_point *ap);
-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me);
+int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset);
void submount_signal_parent(struct autofs_point *ap, unsigned int success);
-int umount_autofs(struct autofs_point *ap, int force);
-int umount_autofs_indirect(struct autofs_point *ap);
+void close_mount_fds(struct autofs_point *ap);
+int umount_autofs(struct autofs_point *ap, const char *root, int force);
+int umount_autofs_indirect(struct autofs_point *ap, const char *root);
int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me);
int umount_autofs_direct(struct autofs_point *ap);
int umount_autofs_offset(struct autofs_point *ap, struct mapent *me);
diff --git a/include/master.h b/include/master.h
index a397a75..e62c67b 100644
--- a/include/master.h
+++ b/include/master.h
@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *);
void master_source_current_wait(struct master_mapent *);
void master_source_current_signal(struct master_mapent *);
struct master_mapent *master_find_mapent(struct master *, const char *);
+struct autofs_point *__master_find_submount(struct autofs_point *, const char *);
struct autofs_point *master_find_submount(struct autofs_point *, const char *);
struct master_mapent *master_new_mapent(struct master *, const char *, time_t);
void master_add_mapent(struct master *, struct master_mapent *);
diff --git a/include/mounts.h b/include/mounts.h
index 7120351..ca4f9f3 100644
--- a/include/mounts.h
+++ b/include/mounts.h
@@ -85,7 +85,7 @@ int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char
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 *);
+int mount_multi_triggers(struct autofs_point *, struct mapent *, const char *, unsigned int, const char *);
+int umount_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
#endif
diff --git a/lib/master.c b/lib/master.c
index 71ba04a..d971ad6 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -602,27 +602,32 @@ struct master_mapent *master_find_mapent(struct master *master, const char *path
return NULL;
}
-struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
+struct autofs_point *__master_find_submount(struct autofs_point *ap, const char *path)
{
struct list_head *head, *p;
- mounts_mutex_lock(ap);
-
head = &ap->submounts;
list_for_each(p, head) {
struct autofs_point *submount;
submount = list_entry(p, struct autofs_point, mounts);
- if (!strcmp(submount->path, path)) {
- mounts_mutex_unlock(ap);
+ if (!strcmp(submount->path, path))
return submount;
- }
}
+ return NULL;
+}
+
+struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
+{
+ struct autofs_point *submount;
+
+ mounts_mutex_lock(ap);
+ submount = __master_find_submount(ap, path);
mounts_mutex_unlock(ap);
- return NULL;
+ return submount;
}
struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age)
@@ -955,6 +960,7 @@ static int master_do_mount(struct master_mapent *entry)
}
suc.ap = ap;
+ suc.root = ap->path;
suc.done = 0;
suc.status = 0;
diff --git a/lib/mounts.c b/lib/mounts.c
index d77a6b0..f6fc389 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -1105,7 +1105,8 @@ int umount_ent(struct autofs_point *ap, const char *path)
return rv;
}
-int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ const char *root, unsigned int start, const char *base)
{
char path[PATH_MAX + 1];
char *offset = path;
@@ -1113,17 +1114,13 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me,
struct list_head *pos = NULL;
unsigned int fs_path_len;
unsigned int mounted;
- int ret, start;
+ int ret;
- fs_path_len = strlen(root) + strlen(base);
+ fs_path_len = start + 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);
@@ -1137,9 +1134,9 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me,
if (!oe || !oe->mapent)
goto cont;
- debug(ap->logopt, "mount offset %s", oe->key);
+ debug(ap->logopt, "mount offset %s at %s", oe->key, root);
- ret = mount_autofs_offset(ap, oe);
+ ret = mount_autofs_offset(ap, oe, root, offset);
if (ret >= MOUNT_OFFSET_OK)
mounted++;
else {
@@ -1161,7 +1158,7 @@ cont:
return mounted;
}
-int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
{
char path[PATH_MAX + 1];
char *offset;
@@ -1198,7 +1195,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me
* nonstrict mount fail.
*/
oe_base = oe->key + strlen(root);
- left += umount_multi_triggers(ap, root, oe, oe_base);
+ left += umount_multi_triggers(ap, oe, root, oe_base);
if (oe->ioctlfd != -1)
left++;
@@ -1238,7 +1235,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me
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)
+ if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0)
warn(ap->logopt,
"failed to remount offset triggers");
return left++;
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index d6cbda8..8a7dd78 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -48,7 +48,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
{
struct startup_cond suc;
pthread_t thid;
- char *fullpath;
+ char *realpath, *mountpoint;
const char **argv;
int argc, status, ghost = ap->ghost;
time_t timeout = ap->exp_timeout;
@@ -60,32 +60,32 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
struct autofs_point *nap;
char buf[MAX_ERR_BUF];
char *options, *p;
- int ret;
-
- fullpath = alloca(strlen(root) + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- return 1;
- }
+ int len, ret;
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1)
- strcpy(fullpath, root);
- else if (*name == '/')
- strcpy(fullpath, name);
- else {
- strcpy(fullpath, root);
- strcat(fullpath, "/");
- strcat(fullpath, name);
- }
-
- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
- error(ap->logopt,
- MODPREFIX
- "warning: about to mount over %s, continuing",
- fullpath);
- return 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ realpath = alloca(strlen(ap->path) + name_len + 2);
+ mountpoint = alloca(len + 1);
+ strcpy(realpath, ap->path);
+ strcat(realpath, "/");
+ strcat(realpath, name);
+ len--;
+ strncpy(mountpoint, root, len);
+ mountpoint[len] = '\0';
+ } else if (*name == '/') {
+ realpath = alloca(name_len + 1);
+ mountpoint = alloca(len + 1);
+ strcpy(mountpoint, root);
+ strcpy(realpath, name);
+ } else {
+ realpath = alloca(len + name_len + 2);
+ mountpoint = alloca(len + name_len + 2);
+ strcpy(mountpoint, root);
+ strcat(mountpoint, "/");
+ strcpy(realpath, mountpoint);
+ strcat(mountpoint, name);
+ strcat(realpath, name);
}
options = NULL;
@@ -136,12 +136,12 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
}
debug(ap->logopt,
- MODPREFIX "fullpath=%s what=%s options=%s",
- fullpath, what, options);
+ MODPREFIX "mountpoint=%s what=%s options=%s",
+ mountpoint, what, options);
master = ap->entry->master;
- entry = master_new_mapent(master, fullpath, ap->entry->age);
+ entry = master_new_mapent(master, realpath, ap->entry->age);
if (!entry) {
error(ap->logopt,
MODPREFIX "failed to malloc master_mapent struct");
@@ -228,6 +228,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
}
suc.ap = nap;
+ suc.root = mountpoint;
suc.done = 0;
suc.status = 0;
@@ -235,7 +236,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
crit(ap->logopt,
MODPREFIX
"failed to create mount handler thread for %s",
- fullpath);
+ realpath);
handle_mounts_startup_cond_destroy(&suc);
mounts_mutex_unlock(ap);
master_free_map_source(source, 1);
@@ -256,7 +257,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
if (suc.status) {
crit(ap->logopt,
- MODPREFIX "failed to create submount for %s", fullpath);
+ MODPREFIX "failed to create submount for %s", realpath);
handle_mounts_startup_cond_destroy(&suc);
mounts_mutex_unlock(ap);
master_free_map_source(source, 1);
diff --git a/modules/mount_bind.c b/modules/mount_bind.c
index e4a04d0..396a3ca 100644
--- a/modules/mount_bind.c
+++ b/modules/mount_bind.c
@@ -74,34 +74,24 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
char *fullpath;
char buf[MAX_ERR_BUF];
int err;
- int i, rlen;
+ int i, len;
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1) {
- rlen = strlen(root);
- name_len = 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ fullpath = alloca(len);
+ len = snprintf(fullpath, len, "%s", root);
/* Direct mount name is absolute path so don't use root */
- } else if (*name == '/')
- rlen = 0;
- else
- rlen = strlen(root);
-
- fullpath = alloca(rlen + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- return 1;
+ } else if (*name == '/') {
+ fullpath = alloca(len + 1);
+ len = sprintf(fullpath, "%s", root);
+ } else {
+ fullpath = alloca(len + name_len + 2);
+ len = sprintf(fullpath, "%s/%s", root, name);
}
+ fullpath[len] = '\0';
- if (name_len) {
- if (rlen)
- sprintf(fullpath, "%s/%s", root, name);
- else
- sprintf(fullpath, "%s", name);
- } else
- sprintf(fullpath, "%s", root);
-
- i = strlen(fullpath);
+ i = len;
while (--i > 0 && fullpath[i] == '/')
fullpath[i] = '\0';
@@ -125,13 +115,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
if (!status)
existed = 0;
- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
- error(ap->logopt,
- MODPREFIX "warning: %s is already mounted",
- fullpath);
- return 0;
- }
-
debug(ap->logopt,
MODPREFIX
"calling mount --bind " SLOPPY " -o %s %s %s",
diff --git a/modules/mount_changer.c b/modules/mount_changer.c
index 08d9147..e838fcf 100644
--- a/modules/mount_changer.c
+++ b/modules/mount_changer.c
@@ -49,34 +49,24 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
char *fullpath;
char buf[MAX_ERR_BUF];
int err;
- int rlen, status, existed = 1;
+ int len, status, existed = 1;
fstype = "iso9660";
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1) {
- rlen = strlen(root);
- name_len = 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ fullpath = alloca(len);
+ len = snprintf(fullpath, len, "%s", root);
/* Direct mount name is absolute path so don't use root */
- } else if (*name == '/')
- rlen = 0;
- else
- rlen = strlen(root);
-
- fullpath = alloca(rlen + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- return 1;
+ } else if (*name == '/') {
+ fullpath = alloca(len + 1);
+ len = sprintf(fullpath, "%s", root);
+ } else {
+ fullpath = alloca(len + name_len + 2);
+ len = sprintf(fullpath, "%s/%s", root, name);
}
-
- if (name_len) {
- if (rlen)
- sprintf(fullpath, "%s/%s", root, name);
- else
- sprintf(fullpath, "%s", name);
- } else
- sprintf(fullpath, "%s", root);
+ fullpath[len] = '\0';
debug(ap->logopt, MODPREFIX "calling umount %s", what);
diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c
index 8cf9937..7589991 100644
--- a/modules/mount_ext2.c
+++ b/modules/mount_ext2.c
@@ -43,32 +43,22 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
const char *p, *p1;
int err, ro = 0;
const char *fsck_prog;
- int rlen, status, existed = 1;
+ int len, status, existed = 1;
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1) {
- rlen = strlen(root);
- name_len = 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ fullpath = alloca(len);
+ len = snprintf(fullpath, len, "%s", root);
/* Direct mount name is absolute path so don't use root */
- } else if (*name == '/')
- rlen = 0;
- else
- rlen = strlen(root);
-
- fullpath = alloca(rlen + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- return 1;
+ } else if (*name == '/') {
+ fullpath = alloca(len + 1);
+ len = sprintf(fullpath, "%s", root);
+ } else {
+ fullpath = alloca(len + name_len + 2);
+ len = sprintf(fullpath, "%s/%s", root, name);
}
-
- if (name_len) {
- if (rlen)
- sprintf(fullpath, "%s/%s", root, name);
- else
- sprintf(fullpath, "%s", name);
- } else
- sprintf(fullpath, "%s", root);
+ fullpath[len] = '\0';
debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
@@ -83,12 +73,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
if (!status)
existed = 0;
- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
- error(ap->logopt,
- MODPREFIX "warning: %s is already mounted", fullpath);
- return 0;
- }
-
if (options && options[0]) {
for (p = options; (p1 = strchr(p, ',')); p = p1)
if (!strncmp(p, "ro", p1 - p) && ++p1 - p == sizeof("ro"))
diff --git a/modules/mount_generic.c b/modules/mount_generic.c
index 85b4391..4b1213e 100644
--- a/modules/mount_generic.c
+++ b/modules/mount_generic.c
@@ -42,32 +42,22 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
char *fullpath;
char buf[MAX_ERR_BUF];
int err;
- int rlen, status, existed = 1;
+ int len, status, existed = 1;
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1) {
- rlen = strlen(root);
- name_len = 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ fullpath = alloca(len);
+ len = snprintf(fullpath, len, "%s", root);
/* Direct mount name is absolute path so don't use root */
- } else if (*name == '/')
- rlen = 0;
- else
- rlen = strlen(root);
-
- fullpath = alloca(rlen + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- return 1;
+ } else if (*name == '/') {
+ fullpath = alloca(len + 1);
+ len = sprintf(fullpath, "%s", root);
+ } else {
+ fullpath = alloca(len + name_len + 2);
+ len = sprintf(fullpath, "%s/%s", root, name);
}
-
- if (name_len) {
- if (rlen)
- sprintf(fullpath, "%s/%s", root, name);
- else
- sprintf(fullpath, "%s", name);
- } else
- sprintf(fullpath, "%s", root);
+ fullpath[len] = '\0';
debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
@@ -82,12 +72,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
if (!status)
existed = 0;
- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
- error(ap->logopt,
- MODPREFIX "warning: %s is already mounted", fullpath);
- return 0;
- }
-
if (options && options[0]) {
debug(ap->logopt,
MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index d7f42a7..0b253d8 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -64,7 +64,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
struct host *this, *hosts = NULL;
unsigned int vers;
char *nfsoptions = NULL;
- int len, rlen, status, err, existed = 1;
+ int len, status, err, existed = 1;
int nosymlink = 0;
int ro = 0; /* Set if mount bind should be read-only */
@@ -146,30 +146,18 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
/* Construct and perhaps create mount point directory */
/* Root offset of multi-mount */
- if (*name == '/' && name_len == 1) {
- rlen = strlen(root);
- name_len = 0;
+ len = strlen(root);
+ if (root[len - 1] == '/') {
+ fullpath = alloca(len);
+ len = snprintf(fullpath, len, "%s", root);
/* Direct mount name is absolute path so don't use root */
- } else if (*name == '/')
- rlen = 0;
- else
- rlen = strlen(root);
-
- fullpath = alloca(rlen + name_len + 2);
- if (!fullpath) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr(MODPREFIX "alloca: %s", estr);
- free_host_list(&hosts);
- return 1;
- }
-
- if (name_len) {
- if (rlen)
- len = sprintf(fullpath, "%s/%s", root, name);
- else
- len = sprintf(fullpath, "%s", name);
- } else
+ } else if (*name == '/') {
+ fullpath = alloca(len + 1);
len = sprintf(fullpath, "%s", root);
+ } else {
+ fullpath = alloca(len + name_len + 2);
+ len = sprintf(fullpath, "%s/%s", root, name);
+ }
fullpath[len] = '\0';
debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
@@ -189,13 +177,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
while (this) {
char *loc, *port_opt = NULL;
- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
- error(ap->logopt,
- MODPREFIX
- "warning: %s is already mounted", fullpath);
- break;
- }
-
/*
* If the "port" option is specified, then we don't want
* a bind mount. Use the "port" option if you want to
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index d839694..b548520 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -31,12 +31,18 @@
#include <sys/vfs.h>
#include <sys/utsname.h>
#include <netinet/in.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
#define MODULE_PARSE
#include "automount.h"
#define MODPREFIX "parse(sun): "
+#define MOUNT_MOVE_NONE 0x00
+#define MOUNT_MOVE_AUTOFS 0x01
+#define MOUNT_MOVE_OTHER 0x02
+
int parse_version = AUTOFS_PARSE_VERSION; /* Required by protocol */
static struct mount_mod *mount_nfs = NULL;
@@ -67,6 +73,7 @@ static struct parse_context default_context = {
1 /* Do slashify_colons */
};
+int destroy_logpri_fifo(struct autofs_point *ap);
static char *concat_options(char *left, char *right);
/* Free all storage associated with this context */
@@ -756,8 +763,10 @@ add_offset_entry(struct autofs_point *ap, const char *name,
p_len = strlen(path);
/* Trailing '/' causes us pain */
- if (p_len > 1 && path[p_len - 1] == '/')
- p_len--;
+ if (p_len > 1) {
+ while (p_len > 1 && path[p_len - 1] == '/')
+ p_len--;
+ }
m_key_len = m_root_len + p_len;
if (m_key_len > PATH_MAX) {
error(ap->logopt, MODPREFIX "multi mount key too long");
@@ -961,53 +970,318 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
return (p - ent);
}
-static int mount_subtree_offsets(struct autofs_point *ap, struct mapent_cache *mc, struct mapent *me)
+static int move_mount(struct autofs_point *ap,
+ const char *mm_tmp_root, const char *mm_root,
+ unsigned int move)
{
- struct mapent *mm;
- char *m_key;
- int ret, start;
- char *base, *m_root;
char buf[MAX_ERR_BUF];
+ int err;
- mm = me->multi;
+ if (move == MOUNT_MOVE_NONE)
+ return 1;
- if (!mm)
+ err = mkdir_path(mm_root, 0555);
+ if (err < 0 && errno != EEXIST) {
+ error(ap->logopt,
+ "failed to create move target mount point %s", mm_root);
return 0;
+ }
- cache_multi_lock(me->parent);
+ if (move == MOUNT_MOVE_AUTOFS)
+ err = mount(mm_tmp_root, mm_root, NULL, MS_MOVE, NULL);
+ else
+ err = spawn_mount(ap->logopt,
+ "--move", mm_tmp_root, mm_root, NULL);
+ if (err) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt,
+ "failed to move mount from %s to %s: %s",
+ mm_tmp_root, mm_root, estr);
+ return 0;
+ }
- m_key = mm->key;
+ debug(ap->logopt,
+ "moved mount tree from %s to %s", mm_tmp_root, mm_root);
- if (*m_key == '/') {
- m_root = m_key;
- start = strlen(m_key);
- } else {
- start = strlen(ap->path) + strlen(m_key) + 1;
- m_root = alloca(start + 1);
- if (!m_root) {
- char *estr;
- cache_multi_unlock(me->parent);
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
- error(ap->logopt, MODPREFIX "alloca: %s", estr);
- return -1;
+ return 1;
+}
+
+static void cleanup_multi_root(struct autofs_point *ap, const char *root,
+ const char *path, unsigned int move)
+{
+ if (move == MOUNT_MOVE_NONE)
+ return;
+
+ if (move == MOUNT_MOVE_OTHER)
+ spawn_umount(ap->logopt, root, NULL);
+ else {
+ struct autofs_point *submount;
+
+ mounts_mutex_lock(ap);
+ submount = __master_find_submount(ap, path);
+ if (!submount) {
+ mounts_mutex_unlock(ap);
+ return;
+ }
+
+ alarm_delete(submount);
+ st_remove_tasks(submount);
+ st_wait_state(submount, ST_READY);
+
+ submount->parent->submnt_count--;
+ list_del_init(&submount->mounts);
+
+ ioctl(submount->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+
+ mounts_mutex_unlock(ap);
+
+ if (submount->thid) {
+ pthread_cancel(submount->thid);
+ close_mount_fds(submount);
+ umount(root);
+ destroy_logpri_fifo(submount);
+ master_free_mapent_sources(submount->entry, 1);
+ master_free_mapent(ap->entry);
}
- strcpy(m_root, ap->path);
- strcat(m_root, "/");
- strcat(m_root, m_key);
}
+ return;
+}
- base = &me->key[start];
+static void cleanup_multi_triggers(struct autofs_point *ap,
+ struct mapent *me, const char *root, int start,
+ const char *base)
+{
+ char path[PATH_MAX + 1];
+ char offset[PATH_MAX + 1];
+ char *poffset = offset;
+ struct mapent *oe;
+ struct list_head *mm_root, *pos;
+ const char o_root[] = "/";
+ const char *mm_base;
+
+ mm_root = &me->multi->multi_list;
+
+ if (!base)
+ mm_base = o_root;
+ else
+ mm_base = base;
+
+ pos = NULL;
+
+ /* Make sure "none" of the offsets have an active mount. */
+ while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) {
+ oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list);
+ /* root offset is a special case */
+ if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+ continue;
+
+ strcpy(path, root);
+ strcat(path, poffset);
+ if (umount(path)) {
+ error(ap->logopt, "error recovering from mount fail");
+ error(ap->logopt, "cannot umount offset %s", path);
+ }
+ }
+
+ return;
+}
- ret = mount_multi_triggers(ap, m_root, me->multi, base);
- if (ret == -1) {
- cache_multi_unlock(me->parent);
- error(ap->logopt, MODPREFIX "failed to mount offset triggers");
- return -1;
+static int check_fstype_autofs_option(const char *options)
+{
+ char *tok, *tokbuf;
+ int found;
+
+ /*
+ * Look for fstype= in options and return true if
+ * the last occurrence is fstype=autofs.
+ */
+ found = 0;
+ tokbuf = alloca(strlen(options) + 2);
+ strcpy(tokbuf, options);
+ tok = strtok_r(tokbuf, ",", &tokbuf);
+ if (tok) {
+ do {
+ if (strstr(tok, "fstype=")) {
+ if (strstr(tok, "autofs"))
+ found = 1;
+ else
+ found = 0;
+ }
+ } while ((tok = strtok_r(NULL, ",", &tokbuf)));
}
- cache_multi_unlock(me->parent);
+ return found;
+}
- return ret;
+static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ const char *name, char *loc, char *options, void *ctxt)
+{
+ struct mapent *mm;
+ struct mapent *ro;
+ char t_dir[] = "/tmp/autoXXXXXX";
+ char *mm_root, *mm_base, *mm_key;
+ const char *mm_tmp_root, *target;
+ unsigned int mm_tmp_root_len;
+ int start, ret = 0, rv;
+ unsigned int move;
+
+ rv = 0;
+
+ if (!me || !me->multi) {
+ int loclen = strlen(loc);
+ int namelen = strlen(name);
+ const char *root = ap->path;
+
+ if (!strcmp(ap->path, "/-"))
+ root = name;
+
+ rv = sun_mount(ap, root, name, namelen, loc, loclen, options, ctxt);
+
+ goto done;
+ }
+
+ mm = me->multi;
+ mm_key = mm->key;
+ move = MOUNT_MOVE_NONE;
+
+ if (*mm_key == '/') {
+ mm_root = mm_key;
+ start = strlen(mm_key);
+ } else {
+ start = strlen(ap->path) + strlen(mm_key) + 1;
+ mm_root = alloca(start + 3);
+ strcpy(mm_root, ap->path);
+ strcat(mm_root, "/");
+ strcat(mm_root, mm_key);
+ }
+
+ mm_tmp_root = mkdtemp(t_dir);
+ if (!mm_tmp_root)
+ return 1;
+ mm_tmp_root_len = strlen(mm_tmp_root);
+
+ if (me == me->multi) {
+ /* name = NULL */
+ /* destination = mm_root */
+ target = mm_root;
+ mm_base = "/";
+
+ /* Mount root offset if it exists */
+ ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
+ if (ro) {
+ char *myoptions, *ro_loc, *tmp;
+ int namelen = name ? strlen(name) : 0;
+ const char *root;
+ int ro_len;
+
+ rv = parse_mapent(ro->mapent,
+ options, &myoptions, &ro_loc, ap->logopt);
+ if (!rv) {
+ warn(ap->logopt,
+ MODPREFIX "failed to parse root offset");
+ cache_delete_offset_list(me->mc, name);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+ ro_len = strlen(ro_loc);
+
+ move = MOUNT_MOVE_OTHER;
+ if (check_fstype_autofs_option(myoptions))
+ move = MOUNT_MOVE_AUTOFS;
+
+ root = mm_tmp_root;
+ tmp = alloca(mm_tmp_root_len + 1);
+ strcpy(tmp, mm_tmp_root);
+ tmp[mm_tmp_root_len] = '/';
+ tmp[mm_tmp_root_len + 1] = '\0';
+ root = tmp;
+
+ rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
+
+ free(myoptions);
+ free(ro_loc);
+ }
+
+ if (ro && rv == 0) {
+ ret = mount_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ if (ret == -1) {
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+ } else if (rv <= 0) {
+ move = MOUNT_MOVE_NONE;
+ ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
+ if (ret == -1) {
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+ }
+ } else {
+ int loclen = strlen(loc);
+ int namelen = strlen(name);
+
+ move = MOUNT_MOVE_OTHER;
+ if (check_fstype_autofs_option(options))
+ move = MOUNT_MOVE_AUTOFS;
+
+ /* name = mm_root + mm_base */
+ /* destination = mm_root + mm_base = name */
+ target = name;
+ mm_base = &me->key[start];
+
+ rv = sun_mount(ap, mm_tmp_root, name, namelen, loc, loclen, options, ctxt);
+ if (rv == 0) {
+ ret = mount_multi_triggers(ap, me->multi, mm_tmp_root, start, mm_base);
+ if (ret == -1) {
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+ } else if (rv < 0) {
+ move = MOUNT_MOVE_NONE;
+ ret = mount_multi_triggers(ap, me->multi, mm_root, start, mm_base);
+ if (ret == -1) {
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+ }
+ }
+
+ if (!move_mount(ap, mm_tmp_root, target, move)) {
+ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+ cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+ rmdir(mm_tmp_root);
+ return 1;
+ }
+
+ rmdir(mm_tmp_root);
+
+ /* Mount for base of tree failed */
+ if (rv > 0)
+ return rv;
+
+done:
+ /*
+ * Convert fail on nonstrict, non-empty multi-mount
+ * to success
+ */
+ if (rv < 0 && ret > 0)
+ rv = 0;
+
+ return rv;
}
/*
@@ -1029,7 +1303,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
char buf[MAX_ERR_BUF];
struct map_source *source;
struct mapent_cache *mc;
- struct mapent *me, *ro;
+ struct mapent *me = NULL;
char *pmapent, *options;
const char *p;
int mapent_len, rv = 0;
@@ -1154,7 +1428,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
char *m_root = NULL;
int m_root_len;
time_t age = time(NULL);
- int l, ret;
+ int l;
/* If name starts with "/" it's a direct mount */
if (*name == '/') {
@@ -1302,48 +1576,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
*/
cache_set_parents(me);
- /* Mount root offset if it exists */
- ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list);
- if (ro) {
- char *myoptions, *loc;
-
- rv = parse_mapent(ro->mapent,
- options, &myoptions, &loc, ap->logopt);
- if (!rv) {
- warn(ap->logopt,
- MODPREFIX "failed to mount root offset");
- cache_delete_offset_list(mc, name);
- cache_multi_unlock(me);
- cache_unlock(mc);
- free(options);
- pthread_setcancelstate(cur_state, NULL);
- return 1;
- }
-
- rv = sun_mount(ap, m_root,
- "/", 1, loc, strlen(loc), myoptions, ctxt);
-
- free(myoptions);
- free(loc);
- }
-
- ret = mount_multi_triggers(ap, m_root, me, "/");
- if (ret == -1) {
- warn(ap->logopt,
- MODPREFIX "failed to mount offset triggers");
- cache_multi_unlock(me);
- cache_unlock(mc);
- free(options);
- pthread_setcancelstate(cur_state, NULL);
- return 1;
- }
-
- /*
- * Convert fail on nonstrict, non-empty multi-mount
- * to success
- */
- if (rv < 0 && ret > 0)
- rv = 0;
+ rv = mount_subtree(ap, me, name, NULL, options, ctxt);
cache_multi_unlock(me);
cache_unlock(mc);
@@ -1461,24 +1694,15 @@ mount_it:
MODPREFIX "core of entry: options=%s, loc=%.*s",
options, loclen, loc);
- rv = sun_mount(ap, ap->path, name, name_len, loc, loclen, options, ctxt);
+ cache_readlock(mc);
+ cache_multi_lock(me);
+
+ rv = mount_subtree(ap, me, name, loc, options, ctxt);
free(loc);
free(options);
- /*
- * If it's a multi-mount insert the triggers
- * These are always direct mount triggers so root = ""
- */
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
- cache_readlock(mc);
- me = cache_lookup_distinct(mc, name);
- if (me) {
- int ret = mount_subtree_offsets(ap, mc, me);
- /* Convert fail on nonstrict, non-empty multi-mount to success */
- if (rv < 0 && ret > 0)
- rv = 0;
- }
+ cache_multi_unlock(me);
cache_unlock(mc);
pthread_setcancelstate(cur_state, NULL);
}