|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* indirect.c - Linux automounter indirect mount handling
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 1997 Transmeta Corporation - All Rights Reserved
|
|
Packit |
8480eb |
* Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
|
|
Packit |
8480eb |
* Copyright 2001-2005 Ian Kent <raven@themaw.net>
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8480eb |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8480eb |
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
|
Packit |
8480eb |
* USA; either version 2 of the License, or (at your option) any later
|
|
Packit |
8480eb |
* version.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8480eb |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8480eb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8480eb |
* GNU General Public License for more details.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <dirent.h>
|
|
Packit |
8480eb |
#include <libgen.h>
|
|
Packit |
8480eb |
#include <signal.h>
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
#include <stdlib.h>
|
|
Packit |
8480eb |
#include <string.h>
|
|
Packit |
8480eb |
#include <sys/ioctl.h>
|
|
Packit |
8480eb |
#include <sys/types.h>
|
|
Packit |
8480eb |
#include <sys/wait.h>
|
|
Packit |
8480eb |
#include <sys/stat.h>
|
|
Packit |
8480eb |
#include <sys/time.h>
|
|
Packit |
8480eb |
#include <sys/mount.h>
|
|
Packit |
8480eb |
#include <sys/vfs.h>
|
|
Packit |
8480eb |
#include <sched.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define INCLUDE_PENDING_FUNCTIONS
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Attribute to create detached thread */
|
|
Packit |
8480eb |
extern pthread_attr_t th_attr_detached;
|
|
Packit |
8480eb |
|
|
Packit Service |
71cd40 |
static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
|
|
Packit Service |
71cd40 |
{
|
|
Packit Service |
71cd40 |
struct mnt_list *this;
|
|
Packit Service |
71cd40 |
int rv, ret;
|
|
Packit Service |
71cd40 |
pid_t pgrp = getpgrp();
|
|
Packit Service |
71cd40 |
char spgrp[20];
|
|
Packit Service |
71cd40 |
|
|
Packit Service |
71cd40 |
sprintf(spgrp, "pgrp=%d", pgrp);
|
|
Packit Service |
71cd40 |
|
|
Packit Service |
71cd40 |
ret = 1;
|
|
Packit Service |
71cd40 |
this = mnts;
|
|
Packit Service |
71cd40 |
while (this) {
|
|
Packit Service |
71cd40 |
if (strstr(this->opts, spgrp)) {
|
|
Packit Service |
71cd40 |
this = this->next;
|
|
Packit Service |
71cd40 |
continue;
|
|
Packit Service |
71cd40 |
}
|
|
Packit Service |
71cd40 |
|
|
Packit Service |
71cd40 |
if (strcmp(this->fs_type, "autofs"))
|
|
Packit Service |
71cd40 |
rv = spawn_umount(ap->logopt, "-l", this->path, NULL);
|
|
Packit Service |
71cd40 |
else
|
|
Packit Service |
71cd40 |
rv = umount2(this->path, MNT_DETACH);
|
|
Packit Service |
71cd40 |
if (rv == -1) {
|
|
Packit Service |
71cd40 |
debug(ap->logopt,
|
|
Packit Service |
71cd40 |
"can't unlink %s from mount tree", this->path);
|
|
Packit Service |
71cd40 |
|
|
Packit Service |
71cd40 |
switch (errno) {
|
|
Packit Service |
71cd40 |
case EINVAL:
|
|
Packit Service |
71cd40 |
warn(ap->logopt,
|
|
Packit Service |
71cd40 |
"bad superblock or not mounted");
|
|
Packit Service |
71cd40 |
break;
|
|
Packit Service |
71cd40 |
|
|
Packit Service |
71cd40 |
case ENOENT:
|
|
Packit Service |
71cd40 |
case EFAULT:
|
|
Packit Service |
71cd40 |
ret = 0;
|
|
Packit Service |
71cd40 |
warn(ap->logopt, "bad path for mount");
|
|
Packit Service |
71cd40 |
break;
|
|
Packit Service |
71cd40 |
}
|
|
Packit Service |
71cd40 |
}
|
|
Packit Service |
71cd40 |
this = this->next;
|
|
Packit Service |
71cd40 |
}
|
|
Packit Service |
71cd40 |
return ret;
|
|
Packit Service |
71cd40 |
}
|
|
Packit Service |
71cd40 |
|
|
Packit |
8480eb |
static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
const char *str_indirect = mount_type_str(t_indirect);
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
time_t timeout = get_exp_timeout(ap, ap->entry->maps);
|
|
Packit |
8480eb |
char *options = NULL;
|
|
Packit |
8480eb |
const char *hosts_map_name = "-hosts";
|
|
Packit |
8480eb |
const char *map_name = hosts_map_name;
|
|
Packit |
8480eb |
const char *type;
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit Service |
71cd40 |
struct mnt_list *mnts;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
int err;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If the map is being shared the exp_timeout can't be inherited
|
|
Packit |
8480eb |
* from the map source since it may be different so the autofs
|
|
Packit |
8480eb |
* point exp_runfreq must have already been set.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (ap->entry->maps->ref <= 1)
|
|
Packit |
8480eb |
ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ops->version && !do_force_unlink) {
|
|
Packit |
8480eb |
ap->flags |= MOUNT_FLAG_REMOUNT;
|
|
Packit |
8480eb |
ret = try_remount(ap, NULL, t_indirect);
|
|
Packit |
8480eb |
ap->flags &= ~MOUNT_FLAG_REMOUNT;
|
|
Packit |
8480eb |
if (ret == 1)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
} else {
|
|
Packit Service |
71cd40 |
mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
|
|
Packit Service |
71cd40 |
if (mnts) {
|
|
Packit Service |
71cd40 |
ret = unlink_mount_tree(ap, mnts);
|
|
Packit Service |
71cd40 |
free_mnt_list(mnts);
|
|
Packit Service |
71cd40 |
if (!ret) {
|
|
Packit Service |
71cd40 |
error(ap->logopt,
|
|
Packit Service |
71cd40 |
"already mounted as other than autofs "
|
|
Packit Service |
71cd40 |
"or failed to unlink entry in tree");
|
|
Packit Service |
71cd40 |
goto out_err;
|
|
Packit Service |
71cd40 |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
71cd40 |
options = make_options_string(ap->path, ap->kpipefd, str_indirect);
|
|
Packit |
8480eb |
if (!options) {
|
|
Packit |
8480eb |
error(ap->logopt, "options string error");
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* In case the directory doesn't exist, try to mkdir it */
|
|
Packit Service |
71cd40 |
if (mkdir_path(root, 0555) < 0) {
|
|
Packit |
8480eb |
if (errno != EEXIST && errno != EROFS) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
"failed to create autofs directory %s",
|
|
Packit |
8480eb |
root);
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
/* If we recieve an error, and it's EEXIST or EROFS we know
|
|
Packit |
8480eb |
the directory was not created. */
|
|
Packit |
8480eb |
ap->flags &= ~MOUNT_FLAG_DIR_CREATED;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
/* No errors so the directory was successfully created */
|
|
Packit |
8480eb |
ap->flags |= MOUNT_FLAG_DIR_CREATED;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
type = ap->entry->maps->type;
|
|
Packit |
8480eb |
if (!type || strcmp(ap->entry->maps->type, "hosts"))
|
|
Packit |
8480eb |
map_name = ap->entry->maps->argv[0];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = mount(map_name, root, "autofs", MS_MGC_VAL, options);
|
|
Packit |
8480eb |
if (ret) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
"failed to mount autofs path %s at %s", ap->path, root);
|
|
Packit |
8480eb |
goto out_rmdir;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(options);
|
|
Packit |
8480eb |
options = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = stat(root, &st);
|
|
Packit |
8480eb |
if (ret == -1) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
"failed to stat mount for autofs path %s", ap->path);
|
|
Packit |
8480eb |
goto out_umount;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ap->mode && (err = chmod(root, ap->mode)))
|
|
Packit |
8480eb |
warn(ap->logopt, "failed to change mode of %s", ap->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ops->open(ap->logopt, &ap->ioctlfd, st.st_dev, root)) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
"failed to create ioctl fd for autofs path %s", ap->path);
|
|
Packit |
8480eb |
goto out_umount;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ap->dev = st.st_dev; /* Device number for mount point checks */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ops->timeout(ap->logopt, ap->ioctlfd, timeout);
|
|
Packit |
8480eb |
if (ap->logopt & LOGOPT_DEBUG)
|
|
Packit |
8480eb |
notify_mount_result(ap, root, timeout, str_indirect);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
notify_mount_result(ap, ap->path, timeout, str_indirect);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
out_umount:
|
|
Packit |
8480eb |
umount(root);
|
|
Packit |
8480eb |
out_rmdir:
|
|
Packit |
8480eb |
if (ap->flags & MOUNT_FLAG_DIR_CREATED)
|
|
Packit |
8480eb |
rmdir(root);
|
|
Packit |
8480eb |
out_err:
|
|
Packit |
8480eb |
if (options)
|
|
Packit |
8480eb |
free(options);
|
|
Packit |
8480eb |
close(ap->state_pipe[0]);
|
|
Packit |
8480eb |
close(ap->state_pipe[1]);
|
|
Packit |
8480eb |
close(ap->pipefd);
|
|
Packit |
8480eb |
close(ap->kpipefd);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_autofs_indirect(struct autofs_point *ap, const char *root)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
time_t now = monotonic_time(NULL);
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
int map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* TODO: read map, determine map type is OK */
|
|
Packit |
8480eb |
if (lookup_nss_read_map(ap, NULL, now))
|
|
Packit |
8480eb |
lookup_prune_cache(ap, now);
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
error(ap->logopt, "failed to read map for %s", ap->path);
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = do_mount_autofs_indirect(ap, root);
|
|
Packit |
8480eb |
if (status < 0)
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = lookup_ghost(ap, root);
|
|
Packit |
8480eb |
if (map & LKP_FAIL) {
|
|
Packit |
8480eb |
if (map & LKP_DIRECT) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"bad map format,found direct, "
|
|
Packit |
8480eb |
"expected indirect exiting");
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
error(ap->logopt, "failed to load map, exiting");
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
/* TODO: Process cleanup ?? */
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (map & LKP_NOTSUP)
|
|
Packit |
8480eb |
ap->flags &= ~MOUNT_FLAG_GHOST;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void close_mount_fds(struct autofs_point *ap)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Since submounts look after themselves the parent never knows
|
|
Packit |
8480eb |
* it needs to close the ioctlfd for offset mounts so we have
|
|
Packit |
8480eb |
* to do it here. If the cache entry isn't found then there aren't
|
|
Packit |
8480eb |
* any offset mounts.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (ap->submount)
|
|
Packit |
8480eb |
lookup_source_close_ioctlfd(ap->parent, ap->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
close(ap->state_pipe[0]);
|
|
Packit |
8480eb |
close(ap->state_pipe[1]);
|
|
Packit |
8480eb |
ap->state_pipe[0] = -1;
|
|
Packit |
8480eb |
ap->state_pipe[1] = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ap->pipefd >= 0)
|
|
Packit |
8480eb |
close(ap->pipefd);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ap->kpipefd >= 0)
|
|
Packit |
8480eb |
close(ap->kpipefd);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int umount_autofs_indirect(struct autofs_point *ap, const char *root)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
char mountpoint[PATH_MAX + 1];
|
|
Packit |
8480eb |
int rv, retries;
|
|
Packit |
8480eb |
unsigned int unused;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (root)
|
|
Packit |
8480eb |
strcpy(mountpoint, root);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
strcpy(mountpoint, ap->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If we are trying to shutdown make sure we can umount */
|
|
Packit |
8480eb |
rv = ops->askumount(ap->logopt, ap->ioctlfd, &unused);
|
|
Packit |
8480eb |
if (rv == -1) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
logerr("ioctl failed: %s", estr);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
} else if (!unused) {
|
|
Packit |
8480eb |
#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN)
|
|
Packit |
8480eb |
if (!ap->shutdown)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
error(ap->logopt, "ask umount returned busy %s", ap->path);
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ops->close(ap->logopt, ap->ioctlfd);
|
|
Packit |
8480eb |
ap->ioctlfd = -1;
|
|
Packit |
8480eb |
sched_yield();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
retries = UMOUNT_RETRIES;
|
|
Packit |
8480eb |
while ((rv = umount(mountpoint)) == -1 && retries--) {
|
|
Packit |
8480eb |
struct timespec tm = {0, 200000000};
|
|
Packit |
8480eb |
if (errno != EBUSY)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
nanosleep(&tm, NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (rv == -1) {
|
|
Packit |
8480eb |
switch (errno) {
|
|
Packit |
8480eb |
case ENOENT:
|
|
Packit |
8480eb |
case EINVAL:
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"mount point %s does not exist", mountpoint);
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case EBUSY:
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
"mount point %s is in use", mountpoint);
|
|
Packit |
8480eb |
if (ap->state == ST_SHUTDOWN_FORCE) {
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
goto force_umount;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the umount returns EBUSY there may be
|
|
Packit |
8480eb |
* a mount request in progress so we need to
|
|
Packit |
8480eb |
* recover unless we have been explicitly
|
|
Packit |
8480eb |
* asked to shutdown and configure option
|
|
Packit |
8480eb |
* ENABLE_IGNORE_BUSY_MOUNTS is enabled.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
#ifdef ENABLE_IGNORE_BUSY_MOUNTS
|
|
Packit |
8480eb |
if (ap->shutdown) {
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
ops->open(ap->logopt,
|
|
Packit |
8480eb |
&ap->ioctlfd, ap->dev, mountpoint);
|
|
Packit |
8480eb |
if (ap->ioctlfd < 0) {
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"could not recover autofs path %s",
|
|
Packit |
8480eb |
mountpoint);
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case ENOTDIR:
|
|
Packit |
8480eb |
error(ap->logopt, "mount point is not a directory");
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* We have successfully umounted the mount so we now close
|
|
Packit |
8480eb |
* the descriptors. The kernel end of the kernel pipe will
|
|
Packit |
8480eb |
* have been put during the umount super block cleanup.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
close_mount_fds(ap);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
force_umount:
|
|
Packit |
8480eb |
if (rv != 0) {
|
|
Packit |
8480eb |
warn(ap->logopt,
|
|
Packit |
8480eb |
"forcing umount of indirect mount %s", mountpoint);
|
|
Packit |
8480eb |
rv = umount2(mountpoint, MNT_DETACH);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
info(ap->logopt, "umounted indirect mount %s", mountpoint);
|
|
Packit |
8480eb |
if (ap->submount)
|
|
Packit |
8480eb |
rm_unwanted(ap, mountpoint, 1);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return rv;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void mnts_cleanup(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct mnt_list *mnts = (struct mnt_list *) arg;
|
|
Packit |
8480eb |
free_mnt_list(mnts);
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void *expire_proc_indirect(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct autofs_point *ap;
|
|
Packit |
8480eb |
struct mapent *me = NULL;
|
|
Packit |
8480eb |
struct mnt_list *mnts = NULL, *next;
|
|
Packit |
8480eb |
struct expire_args *ea;
|
|
Packit |
8480eb |
struct expire_args ec;
|
|
Packit Service |
71cd40 |
unsigned int now;
|
|
Packit |
8480eb |
int offsets, submnts, count;
|
|
Packit |
8480eb |
int retries;
|
|
Packit |
8480eb |
int ioctlfd, cur_state;
|
|
Packit |
8480eb |
int status, ret, left;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ea = (struct expire_args *) arg;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_lock(&ea->mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ap = ec.ap = ea->ap;
|
|
Packit Service |
71cd40 |
now = ea->when;
|
|
Packit |
8480eb |
ec.status = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ea->signaled = 1;
|
|
Packit |
8480eb |
status = pthread_cond_signal(&ea->cond);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_unlock(&ea->mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(expire_cleanup, &ec);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
left = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Get a list of real mounts and expire them if possible */
|
|
Packit Service |
71cd40 |
mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
|
|
Packit |
8480eb |
pthread_cleanup_push(mnts_cleanup, mnts);
|
|
Packit |
8480eb |
for (next = mnts; next; next = next->next) {
|
|
Packit |
8480eb |
char *ind_key;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit Service |
71cd40 |
if (!strcmp(next->fs_type, "autofs")) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If we have submounts check if this path lives below
|
|
Packit |
8480eb |
* one of them and pass on the state change.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
Packit Service |
71cd40 |
if (strstr(next->opts, "indirect"))
|
|
Packit Service |
71cd40 |
master_notify_submount(ap, next->path, ap->state);
|
|
Packit Service |
71cd40 |
else if (strstr(next->opts, "offset")) {
|
|
Packit |
8480eb |
struct map_source *map;
|
|
Packit |
8480eb |
struct mapent_cache *mc = NULL;
|
|
Packit |
8480eb |
struct mapent *me = NULL;
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* It's got a mount, deal with in the outer loop */
|
|
Packit Service |
71cd40 |
if (is_mounted(_PATH_MOUNTED, next->path, MNTS_REAL)) {
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Don't touch submounts */
|
|
Packit Service |
71cd40 |
if (master_find_submount(ap, next->path)) {
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_source_writelock(ap->entry);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
map = ap->entry->maps;
|
|
Packit |
8480eb |
while (map) {
|
|
Packit |
8480eb |
mc = map->mc;
|
|
Packit |
8480eb |
cache_writelock(mc);
|
|
Packit Service |
71cd40 |
me = cache_lookup_distinct(mc, next->path);
|
|
Packit |
8480eb |
if (me)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
map = map->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!mc || !me) {
|
|
Packit |
8480eb |
master_source_unlock(ap->entry);
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (me->ioctlfd == -1) {
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
master_source_unlock(ap->entry);
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Check for manual umount */
|
|
Packit |
8480eb |
if (fstat(me->ioctlfd, &st) == -1 ||
|
|
Packit |
8480eb |
!count_mounts(ap, me->key, st.st_dev)) {
|
|
Packit |
8480eb |
ops->close(ap->logopt, me->ioctlfd);
|
|
Packit |
8480eb |
me->ioctlfd = -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cache_unlock(mc);
|
|
Packit |
8480eb |
master_source_unlock(ap->entry);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ap->state == ST_EXPIRE || ap->state == ST_PRUNE)
|
|
Packit |
8480eb |
pthread_testcancel();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the mount corresponds to an offset trigger then
|
|
Packit |
8480eb |
* the key is the path, otherwise it's the last component.
|
|
Packit |
8480eb |
*/
|
|
Packit Service |
71cd40 |
ind_key = strrchr(next->path, '/');
|
|
Packit |
8480eb |
if (ind_key)
|
|
Packit |
8480eb |
ind_key++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If me->key starts with a '/' and it's not an autofs
|
|
Packit |
8480eb |
* filesystem it's a nested mount and we need to use
|
|
Packit |
8480eb |
* the ioctlfd of the mount to send the expire.
|
|
Packit |
8480eb |
* Otherwise it's a top level indirect mount (possibly
|
|
Packit |
8480eb |
* with offsets in it) and we use the usual ioctlfd.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
|
|
Packit |
8480eb |
master_source_readlock(ap->entry);
|
|
Packit Service |
71cd40 |
me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
|
|
Packit |
8480eb |
if (!me && ind_key)
|
|
Packit |
8480eb |
me = lookup_source_mapent(ap, ind_key, LKP_NORMAL);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ioctlfd = ap->ioctlfd;
|
|
Packit |
8480eb |
if (me) {
|
|
Packit |
8480eb |
if (*me->key == '/')
|
|
Packit |
8480eb |
ioctlfd = me->ioctlfd;
|
|
Packit |
8480eb |
cache_unlock(me->mc);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
71cd40 |
debug(ap->logopt, "expire %s", next->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
Packit Service |
71cd40 |
ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
left++;
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If there are no more real mounts left we could still
|
|
Packit |
8480eb |
* have some offset mounts with no '/' offset or symlinks
|
|
Packit |
8480eb |
* so we need to umount or unlink them here.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
Packit |
8480eb |
retries = (count_mounts(ap, ap->path, ap->dev) + 1);
|
|
Packit |
8480eb |
while (retries--) {
|
|
Packit Service |
71cd40 |
ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, now);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
left++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
count = offsets = submnts = 0;
|
|
Packit Service |
71cd40 |
mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
|
|
Packit |
8480eb |
pthread_cleanup_push(mnts_cleanup, mnts);
|
|
Packit |
8480eb |
/* Are there any real mounts left */
|
|
Packit |
8480eb |
for (next = mnts; next; next = next->next) {
|
|
Packit Service |
71cd40 |
if (strcmp(next->fs_type, "autofs"))
|
|
Packit |
8480eb |
count++;
|
|
Packit |
8480eb |
else {
|
|
Packit Service |
71cd40 |
if (strstr(next->opts, "indirect"))
|
|
Packit |
8480eb |
submnts++;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
offsets++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (submnts)
|
|
Packit Service |
71cd40 |
info(ap->logopt,
|
|
Packit |
8480eb |
"%d submounts remaining in %s", submnts, ap->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* EXPIRE_MULTI is synchronous, so we can be sure (famous last
|
|
Packit |
8480eb |
* words) the umounts are done by the time we reach here
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (count)
|
|
Packit Service |
71cd40 |
info(ap->logopt, "%d remaining in %s", count, ap->path);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ec.status = left;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_setcancelstate(cur_state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void expire_send_fail(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct pending_args *mt = arg;
|
|
Packit |
8480eb |
struct autofs_point *ap = mt->ap;
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt->wait_queue_token, -ENOENT);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void *do_expire_indirect(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct pending_args *args, mt;
|
|
Packit |
8480eb |
struct autofs_point *ap;
|
|
Packit |
8480eb |
int status, state;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
args = (struct pending_args *) arg;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_lock(args);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memcpy(&mt, args, sizeof(struct pending_args));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ap = mt.ap;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
args->signaled = 1;
|
|
Packit |
8480eb |
status = pthread_cond_signal(&args->cond);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_unlock(args);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(expire_send_fail, &mt;;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = do_expire(mt.ap, mt.name, mt.len);
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt.wait_queue_token, -status);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
ops->send_ready(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt.wait_queue_token);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_pop(0);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_indirect_t *pkt)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct pending_args *mt;
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
pthread_t thid;
|
|
Packit |
8480eb |
struct timespec wait;
|
|
Packit |
8480eb |
int status, state;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt, "token %ld, name %s",
|
|
Packit |
8480eb |
(unsigned long) pkt->wait_queue_token, pkt->name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt = malloc(sizeof(struct pending_args));
|
|
Packit |
8480eb |
if (!mt) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
logerr("malloc: %s", estr);
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_cond_init(mt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_init(&mt->mutex, NULL);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt->ap = ap;
|
|
Packit |
8480eb |
strncpy(mt->name, pkt->name, pkt->len);
|
|
Packit |
8480eb |
mt->name[pkt->len] = '\0';
|
|
Packit |
8480eb |
mt->len = pkt->len;
|
|
Packit |
8480eb |
mt->wait_queue_token = pkt->wait_queue_token;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_lock(mt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_create(&thid, &th_attr_detached, do_expire_indirect, mt);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
error(ap->logopt, "expire thread create failed");
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, pkt->wait_queue_token, -status);
|
|
Packit |
8480eb |
pending_mutex_unlock(mt);
|
|
Packit |
8480eb |
pending_cond_destroy(mt);
|
|
Packit |
8480eb |
pending_mutex_destroy(mt);
|
|
Packit |
8480eb |
free_pending_args(mt);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(free_pending_args, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_mutex_destroy, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_cond_destroy, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_mutex_unlock, mt);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt->signaled = 0;
|
|
Packit |
8480eb |
while (!mt->signaled) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &wait);
|
|
Packit |
8480eb |
wait.tv_sec += 2;
|
|
Packit |
8480eb |
status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
|
|
Packit |
8480eb |
if (status && status != ETIMEDOUT)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void mount_send_fail(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct pending_args *mt = arg;
|
|
Packit |
8480eb |
struct autofs_point *ap = mt->ap;
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt->wait_queue_token, -ENOENT);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void *do_mount_indirect(void *arg)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
struct pending_args *args, mt;
|
|
Packit |
8480eb |
struct autofs_point *ap;
|
|
Packit |
8480eb |
char buf[PATH_MAX + 1];
|
|
Packit |
8480eb |
struct stat st;
|
|
Packit |
8480eb |
int len, status, state;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
args = (struct pending_args *) arg;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_lock(args);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memcpy(&mt, args, sizeof(struct pending_args));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ap = mt.ap;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
set_thread_mount_request_log_id(&mt;;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
args->signaled = 1;
|
|
Packit |
8480eb |
status = pthread_cond_signal(&args->cond);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_unlock(args);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(mount_send_fail, &mt;;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
len = ncat_path(buf, sizeof(buf), ap->path, mt.name, mt.len);
|
|
Packit |
8480eb |
if (!len) {
|
|
Packit |
8480eb |
crit(ap->logopt, "path to be mounted is to long");
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt.wait_queue_token,
|
|
Packit |
8480eb |
-ENAMETOOLONG);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
pthread_exit(NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = lstat(buf, &st);
|
|
Packit |
8480eb |
if (status != -1 && !(S_ISDIR(st.st_mode) && st.st_dev == mt.dev)) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
"indirect trigger not valid or already mounted %s", buf);
|
|
Packit |
8480eb |
ops->send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
pthread_exit(NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info(ap->logopt, "attempting to mount entry %s", buf);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
set_tsd_user_vars(ap->logopt, mt.uid, mt.gid);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
ops->send_ready(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt.wait_queue_token);
|
|
Packit |
8480eb |
info(ap->logopt, "mounted %s", buf);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
/* TODO: get mount return status from lookup_nss_mount */
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, mt.wait_queue_token, -ENOENT);
|
|
Packit |
8480eb |
info(ap->logopt, "failed to mount %s", buf);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_pop(0);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct ioctl_ops *ops = get_ioctl_ops();
|
|
Packit |
8480eb |
pthread_t thid;
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
struct pending_args *mt;
|
|
Packit |
8480eb |
struct timespec wait;
|
|
Packit |
8480eb |
struct mapent *me;
|
|
Packit |
8480eb |
int status, state;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_mutex_lock();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt, "token %ld, name %s, request pid %u",
|
|
Packit |
8480eb |
(unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Ignore packet if we're trying to shut down */
|
|
Packit |
8480eb |
if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, pkt->wait_queue_token, -ENOENT);
|
|
Packit |
8480eb |
master_mutex_unlock();
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Check if we recorded a mount fail for this key anywhere */
|
|
Packit |
8480eb |
me = lookup_source_mapent(ap, pkt->name, LKP_DISTINCT);
|
|
Packit |
8480eb |
if (me) {
|
|
Packit |
8480eb |
if (me->status >= monotonic_time(NULL)) {
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt, ap->ioctlfd,
|
|
Packit |
8480eb |
pkt->wait_queue_token, -ENOENT);
|
|
Packit |
8480eb |
cache_unlock(me->mc);
|
|
Packit |
8480eb |
master_mutex_unlock();
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
cache_unlock(me->mc);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt = malloc(sizeof(struct pending_args));
|
|
Packit |
8480eb |
if (!mt) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
logerr("malloc: %s", estr);
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
|
|
Packit |
8480eb |
master_mutex_unlock();
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
memset(mt, 0, sizeof(struct pending_args));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_cond_init(mt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_mutex_init(&mt->mutex, NULL);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pending_mutex_lock(mt);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt->ap = ap;
|
|
Packit |
8480eb |
strncpy(mt->name, pkt->name, pkt->len);
|
|
Packit |
8480eb |
mt->name[pkt->len] = '\0';
|
|
Packit |
8480eb |
mt->len = pkt->len;
|
|
Packit |
8480eb |
mt->dev = pkt->dev;
|
|
Packit |
8480eb |
mt->uid = pkt->uid;
|
|
Packit |
8480eb |
mt->gid = pkt->gid;
|
|
Packit |
8480eb |
mt->pid = pkt->pid;
|
|
Packit |
8480eb |
mt->wait_queue_token = pkt->wait_queue_token;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = pthread_create(&thid, &th_attr_detached, do_mount_indirect, mt);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
error(ap->logopt, "expire thread create failed");
|
|
Packit |
8480eb |
ops->send_fail(ap->logopt,
|
|
Packit |
8480eb |
ap->ioctlfd, pkt->wait_queue_token, -status);
|
|
Packit |
8480eb |
master_mutex_unlock();
|
|
Packit |
8480eb |
pending_mutex_unlock(mt);
|
|
Packit |
8480eb |
pending_cond_destroy(mt);
|
|
Packit |
8480eb |
pending_mutex_destroy(mt);
|
|
Packit |
8480eb |
free_pending_args(mt);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master_mutex_unlock();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_push(free_pending_args, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_mutex_destroy, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_cond_destroy, mt);
|
|
Packit |
8480eb |
pthread_cleanup_push(pending_mutex_unlock, mt);
|
|
Packit |
8480eb |
pthread_setcancelstate(state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mt->signaled = 0;
|
|
Packit |
8480eb |
while (!mt->signaled) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &wait);
|
|
Packit |
8480eb |
wait.tv_sec += 2;
|
|
Packit |
8480eb |
status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
|
|
Packit |
8480eb |
if (status && status != ETIMEDOUT)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
pthread_cleanup_pop(1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|