Blame daemon/direct.c

Packit Service a4b2a9
/* ----------------------------------------------------------------------- *
Packit Service a4b2a9
 *
Packit Service a4b2a9
 *  direct.c - Linux automounter direct mount handling
Packit Service a4b2a9
 *   
Packit Service a4b2a9
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
Packit Service a4b2a9
 *   Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
Packit Service a4b2a9
 *   Copyright 2001-2005 Ian Kent <raven@themaw.net>
Packit Service a4b2a9
 *
Packit Service a4b2a9
 *   This program is free software; you can redistribute it and/or modify
Packit Service a4b2a9
 *   it under the terms of the GNU General Public License as published by
Packit Service a4b2a9
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit Service a4b2a9
 *   USA; either version 2 of the License, or (at your option) any later
Packit Service a4b2a9
 *   version.
Packit Service a4b2a9
 *   
Packit Service a4b2a9
 *   This program is distributed in the hope that it will be useful,
Packit Service a4b2a9
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a4b2a9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a4b2a9
 *   GNU General Public License for more details.
Packit Service a4b2a9
 *
Packit Service a4b2a9
 * ----------------------------------------------------------------------- */
Packit Service a4b2a9
Packit Service a4b2a9
#include <dirent.h>
Packit Service a4b2a9
#include <libgen.h>
Packit Service a4b2a9
#include <signal.h>
Packit Service a4b2a9
#include <stdio.h>
Packit Service a4b2a9
#include <stdlib.h>
Packit Service a4b2a9
#include <string.h>
Packit Service a4b2a9
#include <sys/ioctl.h>
Packit Service a4b2a9
#include <sys/types.h>
Packit Service a4b2a9
#include <sys/wait.h>
Packit Service a4b2a9
#include <sys/stat.h>
Packit Service a4b2a9
#include <sys/time.h>
Packit Service a4b2a9
#include <sys/poll.h>
Packit Service a4b2a9
#include <sys/mount.h>
Packit Service a4b2a9
#include <sys/vfs.h>
Packit Service a4b2a9
#include <sched.h>
Packit Service a4b2a9
Packit Service a4b2a9
#define INCLUDE_PENDING_FUNCTIONS
Packit Service a4b2a9
#include "automount.h"
Packit Service a4b2a9
Packit Service a4b2a9
/* Attribute to create detached thread */
Packit Service a4b2a9
extern pthread_attr_t th_attr_detached;
Packit Service a4b2a9
Packit Service a4b2a9
struct mnt_params {
Packit Service a4b2a9
	char *options;
Packit Service a4b2a9
};
Packit Service a4b2a9
Packit Service a4b2a9
pthread_key_t key_mnt_direct_params;
Packit Service a4b2a9
pthread_key_t key_mnt_offset_params;
Packit Service a4b2a9
pthread_once_t key_mnt_params_once = PTHREAD_ONCE_INIT;
Packit Service a4b2a9
Packit Service a4b2a9
static void key_mnt_params_destroy(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct mnt_params *mp;
Packit Service a4b2a9
Packit Service a4b2a9
	mp = (struct mnt_params *) arg;
Packit Service a4b2a9
	if (mp->options)
Packit Service a4b2a9
		free(mp->options);
Packit Service a4b2a9
	free(mp);
Packit Service a4b2a9
	return;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void key_mnt_params_init(void)
Packit Service a4b2a9
{
Packit Service a4b2a9
	int status;
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_key_create(&key_mnt_direct_params, key_mnt_params_destroy);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_key_create(&key_mnt_offset_params, key_mnt_params_destroy);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	return;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void mnts_cleanup(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct mnt_list *mnts = (struct mnt_list *) arg;
Packit Service a4b2a9
	tree_free_mnt_tree(mnts);
Packit Service a4b2a9
	return;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service 909613
int do_umount_autofs_direct(struct autofs_point *ap, struct mapent *me)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	int ioctlfd = -1, rv, left, retries;
Packit Service a4b2a9
	int opened = 0;
Packit Service a4b2a9
Packit Service a4b2a9
	left = umount_multi(ap, me->key, 0);
Packit Service a4b2a9
	if (left) {
Packit Service a4b2a9
		warn(ap->logopt, "could not unmount %d dirs under %s",
Packit Service a4b2a9
		     left, me->key);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (me->ioctlfd != -1) {
Packit Service a4b2a9
		if (ap->state == ST_READMAP &&
Packit Service 909613
		    is_mounted(me->key, MNTS_REAL)) {
Packit Service a4b2a9
			error(ap->logopt,
Packit Service a4b2a9
			      "attempt to umount busy direct mount %s",
Packit Service a4b2a9
			      me->key);
Packit Service a4b2a9
			return 1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		ioctlfd = me->ioctlfd;
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
Packit Service a4b2a9
		opened = 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (ioctlfd >= 0) {
Packit Service a4b2a9
		unsigned int status = 1;
Packit Service a4b2a9
Packit Service a4b2a9
		rv = ops->askumount(ap->logopt, ioctlfd, &status);
Packit Service a4b2a9
		if (rv) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(ap->logopt, "ioctl failed: %s", estr);
Packit Service a4b2a9
			/* The ioctl failed so this probably won't
Packit Service a4b2a9
			 * work either but since we opened it here
Packit Service a4b2a9
			 * try anyway. We should set these catatonic
Packit Service a4b2a9
			 * too but ....
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			if (opened)
Packit Service a4b2a9
				ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
			return 1;
Packit Service a4b2a9
		} else if (!status) {
Packit Service a4b2a9
			if (ap->state != ST_SHUTDOWN_FORCE) {
Packit Service a4b2a9
				error(ap->logopt,
Packit Service a4b2a9
				      "ask umount returned busy for %s",
Packit Service a4b2a9
				      me->key);
Packit Service a4b2a9
				if (opened)
Packit Service a4b2a9
					ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
				return 1;
Packit Service a4b2a9
			} else {
Packit Service a4b2a9
				me->ioctlfd = -1;
Packit Service a4b2a9
				ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
				goto force_umount;
Packit Service a4b2a9
			}
Packit Service a4b2a9
		}
Packit Service a4b2a9
		me->ioctlfd = -1;
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		      "couldn't get ioctl fd for direct mount %s", me->key);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	sched_yield();
Packit Service a4b2a9
Packit Service a4b2a9
	retries = UMOUNT_RETRIES;
Packit Service a4b2a9
	while ((rv = umount(me->key)) == -1 && retries--) {
Packit Service a4b2a9
		struct timespec tm = {0, 200000000};
Packit Service a4b2a9
		if (errno != EBUSY)
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		nanosleep(&tm, NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (rv == -1) {
Packit Service a4b2a9
		switch (errno) {
Packit Service a4b2a9
		case ENOENT:
Packit Service a4b2a9
		case EINVAL:
Packit Service a4b2a9
			warn(ap->logopt, "mount point %s does not exist",
Packit Service a4b2a9
			      me->key);
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		case EBUSY:
Packit Service a4b2a9
			warn(ap->logopt, "mount point %s is in use", me->key);
Packit Service a4b2a9
			if (ap->state == ST_SHUTDOWN_FORCE)
Packit Service a4b2a9
				goto force_umount;
Packit Service a4b2a9
			else {
Packit Service a4b2a9
				if (ap->state != ST_READMAP)
Packit Service a4b2a9
					set_direct_mount_tree_catatonic(ap, me);
Packit Service a4b2a9
				return 0;
Packit Service a4b2a9
			}
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		case ENOTDIR:
Packit Service a4b2a9
			error(ap->logopt, "mount point is not a directory");
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
force_umount:
Packit Service a4b2a9
	if (rv != 0) {
Packit Service a4b2a9
		info(ap->logopt, "forcing umount of direct mount %s", me->key);
Packit Service a4b2a9
		rv = umount2(me->key, MNT_DETACH);
Packit Service a4b2a9
	} else
Packit Service a4b2a9
		info(ap->logopt, "umounted direct mount %s", me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
Packit Service a4b2a9
		if  (rmdir(me->key) == -1) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			warn(ap->logopt, "failed to remove dir %s: %s",
Packit Service a4b2a9
			     me->key, estr);
Packit Service a4b2a9
		}
Packit Service a4b2a9
	}
Packit Service a4b2a9
	return rv;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int umount_autofs_direct(struct autofs_point *ap)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct map_source *map;
Packit Service a4b2a9
	struct mapent_cache *nc, *mc;
Packit Service a4b2a9
	struct mapent *me, *ne;
Packit Service a4b2a9
Packit Service a4b2a9
	nc = ap->entry->master->nc;
Packit Service a4b2a9
	cache_readlock(nc);
Packit Service a4b2a9
	pthread_cleanup_push(cache_lock_cleanup, nc);
Packit Service a4b2a9
	map = ap->entry->maps;
Packit Service a4b2a9
	while (map) {
Packit Service a4b2a9
		mc = map->mc;
Packit Service a4b2a9
		pthread_cleanup_push(cache_lock_cleanup, mc);
Packit Service a4b2a9
		cache_readlock(mc);
Packit Service a4b2a9
		me = cache_enumerate(mc, NULL);
Packit Service a4b2a9
		while (me) {
Packit Service a4b2a9
			int error;
Packit Service a4b2a9
Packit Service a4b2a9
			ne = cache_lookup_distinct(nc, me->key);
Packit Service a4b2a9
			if (ne && map->master_line > ne->age) {
Packit Service a4b2a9
				me = cache_enumerate(mc, me);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			/* The daemon is exiting so ...
Packit Service a4b2a9
			 * If we get a fail here we must make our
Packit Service a4b2a9
			 * best effort to set the direct mount trigger
Packit Service a4b2a9
			 * catatonic regardless of the reason for the
Packit Service a4b2a9
			 * failed umount.
Packit Service a4b2a9
			 */
Packit Service 909613
			error = do_umount_autofs_direct(ap, me);
Packit Service a4b2a9
			if (!error)
Packit Service a4b2a9
				goto done;
Packit Service a4b2a9
Packit Service a4b2a9
			if (ap->state != ST_READMAP)
Packit Service a4b2a9
				set_direct_mount_tree_catatonic(ap, me);
Packit Service a4b2a9
done:
Packit Service a4b2a9
			me = cache_enumerate(mc, me);
Packit Service a4b2a9
		}
Packit Service a4b2a9
		pthread_cleanup_pop(1);
Packit Service a4b2a9
		map = map->next;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
Packit Service a4b2a9
	close(ap->state_pipe[0]);
Packit Service a4b2a9
	close(ap->state_pipe[1]);
Packit Service a4b2a9
	if (ap->pipefd >= 0)
Packit Service a4b2a9
		close(ap->pipefd);
Packit Service a4b2a9
	if (ap->kpipefd >= 0) {
Packit Service a4b2a9
		close(ap->kpipefd);
Packit Service a4b2a9
		ap->kpipefd = -1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int do_mount_autofs_direct(struct autofs_point *ap,
Packit Service c5705c
			   struct mapent *me, time_t timeout)
Packit Service a4b2a9
{
Packit Service a4b2a9
	const char *str_direct = mount_type_str(t_direct);
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct mnt_params *mp;
Packit Service a4b2a9
	struct stat st;
Packit Service a4b2a9
	int status, ret, ioctlfd;
Packit Service a4b2a9
	const char *map_name;
Packit Service a4b2a9
	time_t runfreq;
Packit Service a4b2a9
	int err;
Packit Service a4b2a9
Packit Service a4b2a9
	if (timeout) {
Packit Service a4b2a9
		/* Calculate the expire run frequency */
Packit Service a4b2a9
		runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
Packit Service a4b2a9
		if (ap->exp_runfreq)
Packit Service a4b2a9
			ap->exp_runfreq = min(ap->exp_runfreq, runfreq);
Packit Service a4b2a9
		else
Packit Service a4b2a9
			ap->exp_runfreq = runfreq;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (ops->version && !do_force_unlink) {
Packit Service a4b2a9
		ap->flags |= MOUNT_FLAG_REMOUNT;
Packit Service a4b2a9
		ret = try_remount(ap, me, t_direct);
Packit Service a4b2a9
		ap->flags &= ~MOUNT_FLAG_REMOUNT;
Packit Service a4b2a9
		if (ret == 1)
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
		if (ret == 0)
Packit Service a4b2a9
			return -1;
Packit Service a4b2a9
	} else {
Packit Service 888728
		if (ap->state == ST_READMAP && is_mounted(me->key, MNTS_ALL)) {
Packit Service 888728
			time_t tout = get_exp_timeout(ap, me->source);
Packit Service 888728
			int save_ioctlfd, ioctlfd;
Packit Service 888728
Packit Service 888728
			save_ioctlfd = ioctlfd = me->ioctlfd;
Packit Service 888728
Packit Service 888728
			if (ioctlfd == -1)
Packit Service 888728
				ops->open(ap->logopt,
Packit Service 888728
					  &ioctlfd, me->dev, me->key);
Packit Service 888728
Packit Service 888728
			if (ioctlfd < 0) {
Packit Service 888728
				error(ap->logopt,
Packit Service 888728
				     "failed to create ioctl fd for %s",
Packit Service 888728
				     me->key);
Packit Service 888728
				return 0;
Packit Service 888728
			}
Packit Service 888728
Packit Service 888728
			ops->timeout(ap->logopt, ioctlfd, tout);
Packit Service 888728
Packit Service 888728
			if (save_ioctlfd == -1)
Packit Service 888728
				ops->close(ap->logopt, ioctlfd);
Packit Service 888728
Packit Service 888728
			return 0;
Packit Service 888728
		}
Packit Service 888728
Packit Service 732a40
		ret = unlink_mount_tree(ap, ap->path);
Packit Service 732a40
		if (!ret) {
Packit Service 732a40
			error(ap->logopt,
Packit Service 732a40
			     "already mounted as other than autofs "
Packit Service 732a40
			     "or failed to unlink entry in tree");
Packit Service 732a40
			goto out_err;
Packit Service c5705c
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (me->ioctlfd != -1) {
Packit Service a4b2a9
			error(ap->logopt, "active direct mount %s", me->key);
Packit Service a4b2a9
			return -1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_once(&key_mnt_params_once, key_mnt_params_init);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	mp = pthread_getspecific(key_mnt_direct_params);
Packit Service a4b2a9
	if (!mp) {
Packit Service a4b2a9
		mp = (struct mnt_params *) malloc(sizeof(struct mnt_params));
Packit Service a4b2a9
		if (!mp) {
Packit Service a4b2a9
			crit(ap->logopt,
Packit Service a4b2a9
			  "mnt_params value create failed for direct mount %s",
Packit Service a4b2a9
			  ap->path);
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		mp->options = NULL;
Packit Service a4b2a9
Packit Service a4b2a9
		status = pthread_setspecific(key_mnt_direct_params, mp);
Packit Service a4b2a9
		if (status) {
Packit Service a4b2a9
			free(mp);
Packit Service a4b2a9
			fatal(status);
Packit Service a4b2a9
		}
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (!mp->options) {
Packit Service e09cf6
		mp->options = make_options_string(ap->path,
Packit Service e09cf6
				ap->kpipefd, str_direct, ap->flags);
Packit Service a4b2a9
		if (!mp->options)
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	/* In case the directory doesn't exist, try to mkdir it */
Packit Service 15cf98
	if (mkdir_path(me->key, mp_mode) < 0) {
Packit Service a4b2a9
		if (errno != EEXIST && errno != EROFS) {
Packit Service a4b2a9
			crit(ap->logopt,
Packit Service a4b2a9
			     "failed to create mount directory %s", me->key);
Packit Service a4b2a9
			return -1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		/* If we recieve an error, and it's EEXIST or EROFS we know
Packit Service a4b2a9
		   the directory was not created. */
Packit Service a4b2a9
		me->flags &= ~MOUNT_FLAG_DIR_CREATED;
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		/* No errors so the directory was successfully created */
Packit Service a4b2a9
		me->flags |= MOUNT_FLAG_DIR_CREATED;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	map_name = me->mc->map->argv[0];
Packit Service a4b2a9
Packit Service a4b2a9
	ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options);
Packit Service a4b2a9
	if (ret) {
Packit Service a4b2a9
		crit(ap->logopt, "failed to mount autofs path %s", me->key);
Packit Service a4b2a9
		goto out_err;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ret = stat(me->key, &st);
Packit Service a4b2a9
	if (ret == -1) {
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		      "failed to stat direct mount trigger %s", me->key);
Packit Service a4b2a9
		goto out_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (ap->mode && (err = chmod(me->key, ap->mode)))
Packit Service a4b2a9
		warn(ap->logopt, "failed to change mode of %s", me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key);
Packit Service a4b2a9
	if (ioctlfd < 0) {
Packit Service a4b2a9
		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
Packit Service a4b2a9
		goto out_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ops->timeout(ap->logopt, ioctlfd, timeout);
Packit Service a4b2a9
	notify_mount_result(ap, me->key, timeout, str_direct);
Packit Service a4b2a9
	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
Packit Service a4b2a9
	ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
Packit Service a4b2a9
	debug(ap->logopt, "mounted trigger %s", me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
Packit Service a4b2a9
out_umount:
Packit Service a4b2a9
	/* TODO: maybe force umount (-l) */
Packit Service a4b2a9
	umount(me->key);
Packit Service a4b2a9
out_err:
Packit Service a4b2a9
	if (me->flags & MOUNT_FLAG_DIR_CREATED)
Packit Service a4b2a9
		rmdir(me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	return -1;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int mount_autofs_direct(struct autofs_point *ap)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct map_source *map;
Packit Service a4b2a9
	struct mapent_cache *nc, *mc;
Packit Service a4b2a9
	struct mapent *me, *ne, *nested;
Packit Service a4b2a9
	time_t now = monotonic_time(NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	if (strcmp(ap->path, "/-")) {
Packit Service a4b2a9
		error(ap->logopt, "expected direct map, exiting");
Packit Service a4b2a9
		return -1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	/* TODO: check map type */
Packit Service a4b2a9
	if (lookup_nss_read_map(ap, NULL, now))
Packit Service a4b2a9
		lookup_prune_cache(ap, now);
Packit Service a4b2a9
	else {
Packit Service a4b2a9
		error(ap->logopt, "failed to read direct map");
Packit Service a4b2a9
		return -1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Packit Service a4b2a9
	master_source_readlock(ap->entry);
Packit Service a4b2a9
	nc = ap->entry->master->nc;
Packit Service a4b2a9
	cache_readlock(nc);
Packit Service a4b2a9
	pthread_cleanup_push(cache_lock_cleanup, nc);
Packit Service a4b2a9
	map = ap->entry->maps;
Packit Service a4b2a9
	while (map) {
Packit Service a4b2a9
		time_t timeout;
Packit Service a4b2a9
		/*
Packit Service a4b2a9
		 * Only consider map sources that have been read since
Packit Service a4b2a9
		 * the map entry was last updated.
Packit Service a4b2a9
		 */
Packit Service a4b2a9
		if (ap->entry->age > map->age) {
Packit Service a4b2a9
			map = map->next;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		mc = map->mc;
Packit Service a4b2a9
		timeout = get_exp_timeout(ap, map);
Packit Service a4b2a9
		cache_readlock(mc);
Packit Service a4b2a9
		pthread_cleanup_push(cache_lock_cleanup, mc);
Packit Service a4b2a9
		me = cache_enumerate(mc, NULL);
Packit Service a4b2a9
		while (me) {
Packit Service a4b2a9
			ne = cache_lookup_distinct(nc, me->key);
Packit Service a4b2a9
			if (ne) {
Packit Service a4b2a9
				if (map->master_line < ne->age) {
Packit Service a4b2a9
					/* TODO: check return, locking me */
Packit Service c5705c
					do_mount_autofs_direct(ap, me, timeout);
Packit Service a4b2a9
				}
Packit Service a4b2a9
				me = cache_enumerate(mc, me);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			nested = cache_partial_match(nc, me->key);
Packit Service a4b2a9
			if (nested) {
Packit Service a4b2a9
				error(ap->logopt,
Packit Service a4b2a9
				   "removing invalid nested null entry %s",
Packit Service a4b2a9
				   nested->key);
Packit Service a4b2a9
				nested = cache_partial_match(nc, me->key);
Packit Service a4b2a9
				if (nested)
Packit Service a4b2a9
					cache_delete(nc, nested->key);
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			/* TODO: check return, locking me */
Packit Service c5705c
			do_mount_autofs_direct(ap, me, timeout);
Packit Service a4b2a9
Packit Service a4b2a9
			me = cache_enumerate(mc, me);
Packit Service a4b2a9
		}
Packit Service a4b2a9
		pthread_cleanup_pop(1);
Packit Service a4b2a9
		map = map->next;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	int ioctlfd = -1, rv = 1, retries;
Packit Service a4b2a9
	int opened = 0;
Packit Service a4b2a9
Packit Service a4b2a9
	if (me->ioctlfd != -1) {
Packit Service 333f8e
		if (is_mounted(me->key, MNTS_REAL)) {
Packit Service a4b2a9
			error(ap->logopt,
Packit Service a4b2a9
			      "attempt to umount busy offset %s", me->key);
Packit Service a4b2a9
			return 1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		ioctlfd = me->ioctlfd;
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		/* offset isn't mounted, return success and try to recover */
Packit Service 333f8e
		if (!is_mounted(me->key, MNTS_AUTOFS)) {
Packit Service a4b2a9
			debug(ap->logopt,
Packit Service a4b2a9
			      "offset %s not mounted",
Packit Service a4b2a9
			      me->key);
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
Packit Service a4b2a9
		opened = 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (ioctlfd >= 0) {
Packit Service a4b2a9
		unsigned int status = 1;
Packit Service a4b2a9
Packit Service a4b2a9
		rv = ops->askumount(ap->logopt, ioctlfd, &status);
Packit Service a4b2a9
		if (rv) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			logerr("ioctl failed: %s", estr);
Packit Service a4b2a9
			if (opened && ioctlfd != -1)
Packit Service a4b2a9
				ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
			return 1;
Packit Service a4b2a9
		} else if (!status) {
Packit Service a4b2a9
			if (ap->state != ST_SHUTDOWN_FORCE) {
Packit Service a4b2a9
				if (ap->shutdown)
Packit Service a4b2a9
					error(ap->logopt,
Packit Service a4b2a9
					     "ask umount returned busy for %s",
Packit Service a4b2a9
					     me->key);
Packit Service a4b2a9
				if (opened && ioctlfd != -1)
Packit Service a4b2a9
					ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
				return 1;
Packit Service a4b2a9
			} else {
Packit Service a4b2a9
				me->ioctlfd = -1;
Packit Service a4b2a9
				ops->catatonic(ap->logopt, ioctlfd);
Packit Service a4b2a9
				ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
				goto force_umount;
Packit Service a4b2a9
			}
Packit Service a4b2a9
		}
Packit Service a4b2a9
		me->ioctlfd = -1;
Packit Service a4b2a9
		ops->catatonic(ap->logopt, ioctlfd);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		struct stat st;
Packit Service a4b2a9
		char *estr;
Packit Service a4b2a9
		int save_errno = errno;
Packit Service a4b2a9
Packit Service a4b2a9
		/* Non existent directory on remote fs - no mount */
Packit Service a4b2a9
		if (stat(me->key, &st) == -1 && errno == ENOENT)
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
Packit Service a4b2a9
		estr = strerror_r(save_errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		      "couldn't get ioctl fd for offset %s: %s",
Packit Service a4b2a9
		      me->key, estr);
Packit Service a4b2a9
		goto force_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	sched_yield();
Packit Service a4b2a9
Packit Service a4b2a9
	retries = UMOUNT_RETRIES;
Packit Service a4b2a9
	while ((rv = umount(me->key)) == -1 && retries--) {
Packit Service a4b2a9
		struct timespec tm = {0, 200000000};
Packit Service a4b2a9
		if (errno != EBUSY)
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		nanosleep(&tm, NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (rv == -1) {
Packit Service a4b2a9
		switch (errno) {
Packit Service a4b2a9
		case ENOENT:
Packit Service a4b2a9
			warn(ap->logopt, "mount point does not exist");
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		case EBUSY:
Packit Service a4b2a9
			error(ap->logopt, "mount point %s is in use", me->key);
Packit Service a4b2a9
			if (ap->state != ST_SHUTDOWN_FORCE)
Packit Service a4b2a9
				return 1;
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		case ENOTDIR:
Packit Service a4b2a9
			error(ap->logopt, "mount point is not a directory");
Packit Service a4b2a9
			return 0;
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		goto force_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
force_umount:
Packit Service a4b2a9
	if (rv != 0) {
Packit Service a4b2a9
		info(ap->logopt, "forcing umount of offset mount %s", me->key);
Packit Service a4b2a9
		rv = umount2(me->key, MNT_DETACH);
Packit Service a4b2a9
	} else
Packit Service a4b2a9
		info(ap->logopt, "umounted offset mount %s", me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	return rv;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
Packit Service a4b2a9
{
Packit Service a4b2a9
	const char *str_offset = mount_type_str(t_offset);
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	struct mnt_params *mp;
Packit Service a4b2a9
	time_t timeout = get_exp_timeout(ap, me->source);
Packit Service a4b2a9
	struct stat st;
Packit Service a4b2a9
	int ioctlfd, status, ret;
Packit Service a4b2a9
	const char *hosts_map_name = "-hosts";
Packit Service a4b2a9
	const char *map_name = hosts_map_name;
Packit Service a4b2a9
	const char *type;
Packit Service a4b2a9
	char mountpoint[PATH_MAX];
Packit Service a4b2a9
Packit Service a4b2a9
	if (ops->version && ap->flags & MOUNT_FLAG_REMOUNT) {
Packit Service a4b2a9
		ret = try_remount(ap, me, t_offset);
Packit Service a4b2a9
		if (ret == 1)
Packit Service a4b2a9
			return MOUNT_OFFSET_OK;
Packit Service a4b2a9
		/* Offset mount not found, fall thru and try to mount it */
Packit Service a4b2a9
		if (!(ret == -1 && errno == ENOENT))
Packit Service a4b2a9
			return MOUNT_OFFSET_FAIL;
Packit Service a4b2a9
	} else {
Packit Service 333f8e
		if (is_mounted(me->key, MNTS_AUTOFS)) {
Packit Service a4b2a9
			if (ap->state != ST_READMAP)
Packit Service a4b2a9
				warn(ap->logopt,
Packit Service a4b2a9
				     "trigger %s already mounted", me->key);
Packit Service a4b2a9
			return MOUNT_OFFSET_OK;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (me->ioctlfd != -1) {
Packit Service a4b2a9
			error(ap->logopt, "active offset mount %s", me->key);
Packit Service a4b2a9
			return MOUNT_OFFSET_FAIL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_once(&key_mnt_params_once, key_mnt_params_init);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	mp = pthread_getspecific(key_mnt_offset_params);
Packit Service a4b2a9
	if (!mp) {
Packit Service a4b2a9
		mp = (struct mnt_params *) malloc(sizeof(struct mnt_params));
Packit Service a4b2a9
		if (!mp) {
Packit Service a4b2a9
			crit(ap->logopt,
Packit Service a4b2a9
			  "mnt_params value create failed for offset mount %s",
Packit Service a4b2a9
			  me->key);
Packit Service a4b2a9
			return MOUNT_OFFSET_OK;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		mp->options = NULL;
Packit Service a4b2a9
Packit Service a4b2a9
		status = pthread_setspecific(key_mnt_offset_params, mp);
Packit Service a4b2a9
		if (status) {
Packit Service a4b2a9
			free(mp);
Packit Service a4b2a9
			fatal(status);
Packit Service a4b2a9
		}
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (!mp->options) {
Packit Service e09cf6
		mp->options = make_options_string(ap->path,
Packit Service e09cf6
				ap->kpipefd, str_offset, ap->flags);
Packit Service a4b2a9
		if (!mp->options)
Packit Service a4b2a9
			return MOUNT_OFFSET_OK;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	strcpy(mountpoint, root);
Packit Service a4b2a9
	strcat(mountpoint, offset);
Packit Service a4b2a9
Packit Service a4b2a9
	/* In case the directory doesn't exist, try to mkdir it */
Packit Service 15cf98
	if (mkdir_path(mountpoint, mp_mode) < 0) {
Packit Service a4b2a9
		if (errno == EEXIST) {
Packit Service a4b2a9
			/*
Packit Service a4b2a9
			 * If the mount point directory is a real mount
Packit Service a4b2a9
			 * and it isn't the root offset then it must be
Packit Service a4b2a9
			 * a mount that has been automatically mounted by
Packit Service a4b2a9
			 * the kernel NFS client.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			if (me->multi != me &&
Packit Service 333f8e
			    is_mounted(mountpoint, MNTS_REAL))
Packit Service a4b2a9
				return MOUNT_OFFSET_IGNORE;
Packit Service a4b2a9
Packit Service a4b2a9
			/* 
Packit Service a4b2a9
			 * If we recieve an error, and it's EEXIST
Packit Service a4b2a9
			 * we know the directory was not created.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			me->flags &= ~MOUNT_FLAG_DIR_CREATED;
Packit Service a4b2a9
		} else if (errno == EACCES) {
Packit Service a4b2a9
			/*
Packit Service a4b2a9
			 * We require the mount point directory to exist when
Packit Service a4b2a9
			 * installing multi-mount triggers into a host
Packit Service a4b2a9
			 * filesystem.
Packit Service a4b2a9
			 *
Packit Service a4b2a9
			 * If it doesn't exist it is not a valid part of the
Packit Service a4b2a9
			 * mount heirachy.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			debug(ap->logopt,
Packit Service a4b2a9
			     "can't create mount directory: %s, %s",
Packit Service a4b2a9
			     mountpoint, estr);
Packit Service a4b2a9
			return MOUNT_OFFSET_FAIL;
Packit Service a4b2a9
		} else {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			crit(ap->logopt,
Packit Service a4b2a9
			     "failed to create mount directory: %s, %s",
Packit Service a4b2a9
			     mountpoint, estr);
Packit Service a4b2a9
			return MOUNT_OFFSET_FAIL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		/* No errors so the directory was successfully created */
Packit Service a4b2a9
		me->flags |= MOUNT_FLAG_DIR_CREATED;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	debug(ap->logopt,
Packit Service a4b2a9
	      "calling mount -t autofs " SLOPPY " -o %s automount %s",
Packit Service a4b2a9
	      mp->options, mountpoint);
Packit Service a4b2a9
Packit Service a4b2a9
	type = ap->entry->maps->type;
Packit Service a4b2a9
	if (!type || strcmp(ap->entry->maps->type, "hosts"))
Packit Service a4b2a9
		map_name = me->mc->map->argv[0];
Packit Service a4b2a9
Packit Service a4b2a9
	ret = mount(map_name, mountpoint, "autofs", MS_MGC_VAL, mp->options);
Packit Service a4b2a9
	if (ret) {
Packit Service a4b2a9
		crit(ap->logopt,
Packit Service a4b2a9
		     "failed to mount offset trigger %s at %s",
Packit Service a4b2a9
		     me->key, mountpoint);
Packit Service a4b2a9
		goto out_err;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ret = stat(mountpoint, &st);
Packit Service a4b2a9
	if (ret == -1) {
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		     "failed to stat direct mount trigger %s", mountpoint);
Packit Service a4b2a9
		goto out_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ops->open(ap->logopt, &ioctlfd, st.st_dev, mountpoint);
Packit Service a4b2a9
	if (ioctlfd < 0) {
Packit Service a4b2a9
		crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
Packit Service a4b2a9
		goto out_umount;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ops->timeout(ap->logopt, ioctlfd, timeout);
Packit Service a4b2a9
	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
Packit Service a4b2a9
	if (ap->logopt & LOGOPT_DEBUG)
Packit Service a4b2a9
		notify_mount_result(ap, mountpoint, timeout, str_offset);
Packit Service a4b2a9
	else
Packit Service a4b2a9
		notify_mount_result(ap, me->key, timeout, str_offset);
Packit Service a4b2a9
	ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
Packit Service a4b2a9
	debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
Packit Service a4b2a9
Packit Service a4b2a9
	return MOUNT_OFFSET_OK;
Packit Service a4b2a9
Packit Service a4b2a9
out_umount:
Packit Service a4b2a9
	umount(mountpoint);
Packit Service a4b2a9
out_err:
Packit Service a4b2a9
	if (stat(mountpoint, &st) == 0 && me->flags & MOUNT_FLAG_DIR_CREATED)
Packit Service a4b2a9
		 rmdir_path(ap, mountpoint, st.st_dev);
Packit Service a4b2a9
Packit Service a4b2a9
	return MOUNT_OFFSET_FAIL;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
void *expire_proc_direct(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct mnt_list *mnts = NULL, *next;
Packit Service a4b2a9
	struct list_head list, *p;
Packit Service a4b2a9
	struct expire_args *ea;
Packit Service a4b2a9
	struct expire_args ec;
Packit Service a4b2a9
	struct autofs_point *ap;
Packit Service a4b2a9
	struct mapent *me = NULL;
Packit Service c36f2e
	unsigned int how;
Packit Service a4b2a9
	int ioctlfd, cur_state;
Packit Service a4b2a9
	int status, ret, left;
Packit Service a4b2a9
Packit Service a4b2a9
	ea = (struct expire_args *) arg;
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_mutex_lock(&ea->mutex);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	ap = ec.ap = ea->ap;
Packit Service c36f2e
	how = ea->how;
Packit Service a4b2a9
	ec.status = -1;
Packit Service a4b2a9
Packit Service a4b2a9
	ea->signaled = 1;
Packit Service a4b2a9
	status = pthread_cond_signal(&ea->cond);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_mutex_unlock(&ea->mutex);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(expire_cleanup, &ec);
Packit Service a4b2a9
Packit Service a4b2a9
	left = 0;
Packit Service a4b2a9
Packit Service 333f8e
	mnts = tree_make_mnt_tree("/");
Packit Service a4b2a9
	pthread_cleanup_push(mnts_cleanup, mnts);
Packit Service a4b2a9
Packit Service a4b2a9
	/* Get a list of mounts select real ones and expire them if possible */
Packit Service a4b2a9
	INIT_LIST_HEAD(&list);
Packit Service a4b2a9
	if (!tree_get_mnt_list(mnts, &list, "/", 0)) {
Packit Service a4b2a9
		ec.status = 0;
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	list_for_each(p, &list) {
Packit Service a4b2a9
		next = list_entry(p, struct mnt_list, list);
Packit Service a4b2a9
Packit Service a4b2a9
		/*
Packit Service a4b2a9
		 * All direct mounts must be present in the map
Packit Service a4b2a9
		 * entry cache.
Packit Service a4b2a9
		 */
Packit Service a4b2a9
		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Packit Service a4b2a9
		master_source_readlock(ap->entry);
Packit Service 2c4bba
		me = lookup_source_mapent(ap, next->mp, LKP_DISTINCT);
Packit Service a4b2a9
		pthread_cleanup_pop(1);
Packit Service a4b2a9
		if (!me)
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
Packit Service 9c3f8f
		if (next->flags & MNTS_AUTOFS) {
Packit Service a4b2a9
			struct stat st;
Packit Service a4b2a9
			int ioctlfd;
Packit Service a4b2a9
Packit Service a4b2a9
			cache_unlock(me->mc);
Packit Service a4b2a9
Packit Service a4b2a9
			/*
Packit Service a4b2a9
			 * If we have submounts check if this path lives below
Packit Service a4b2a9
			 * one of them and pass on state change.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit Service 9c3f8f
			if (next->flags & MNTS_INDIRECT) {
Packit Service 2c4bba
				master_notify_submount(ap, next->mp, ap->state);
Packit Service a4b2a9
				pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			if (me->ioctlfd == -1) {
Packit Service a4b2a9
				pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			/* It's got a mount, deal with in the outer loop */
Packit Service 909613
			if (is_mounted(me->key, MNTS_REAL)) {
Packit Service a4b2a9
				pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			/*
Packit Service a4b2a9
			 * Maybe a manual umount, repair.
Packit Service a4b2a9
			 * It will take ap->exp_timeout/4 for us to relaize
Packit Service a4b2a9
			 * this so user must still use USR1 signal to close
Packit Service a4b2a9
			 * the open file handle for mounts atop multi-mount
Packit Service a4b2a9
			 * triggers. There is no way that I'm aware of to
Packit Service a4b2a9
			 * avoid maintaining a file handle for control
Packit Service a4b2a9
			 * functions as once it's mounted all opens are
Packit Service a4b2a9
			 * directed to the mount not the trigger.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
Packit Service a4b2a9
			/* Check for manual umount */
Packit Service a4b2a9
			cache_writelock(me->mc);
Packit Service a4b2a9
			if (me->ioctlfd != -1 && 
Packit Service a4b2a9
			    fstat(me->ioctlfd, &st) != -1 &&
Packit Service 2c4bba
			    !count_mounts(ap, next->mp, st.st_dev)) {
Packit Service a4b2a9
				ops->close(ap->logopt, me->ioctlfd);
Packit Service a4b2a9
				me->ioctlfd = -1;
Packit Service a4b2a9
				cache_unlock(me->mc);
Packit Service a4b2a9
				pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
			cache_unlock(me->mc);
Packit Service a4b2a9
Packit Service a4b2a9
			ioctlfd = me->ioctlfd;
Packit Service a4b2a9
Packit Service 2c4bba
			ret = ops->expire(ap->logopt, ioctlfd, next->mp, how);
Packit Service a4b2a9
			if (ret) {
Packit Service a4b2a9
				left++;
Packit Service a4b2a9
				pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
				continue;
Packit Service a4b2a9
			}
Packit Service a4b2a9
Packit Service a4b2a9
			pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (me->ioctlfd >= 0) {
Packit Service a4b2a9
			/* Real mounts have an open ioctl fd */
Packit Service a4b2a9
			ioctlfd = me->ioctlfd;
Packit Service a4b2a9
			cache_unlock(me->mc);
Packit Service a4b2a9
		} else {
Packit Service a4b2a9
			cache_unlock(me->mc);
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (ap->state == ST_EXPIRE || ap->state == ST_PRUNE)
Packit Service a4b2a9
			pthread_testcancel();
Packit Service a4b2a9
Packit Service 2c4bba
		debug(ap->logopt, "send expire to trigger %s", next->mp);
Packit Service a4b2a9
Packit Service a4b2a9
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit Service 2c4bba
		ret = ops->expire(ap->logopt, ioctlfd, next->mp, how);
Packit Service a4b2a9
		if (ret)
Packit Service a4b2a9
			left++;
Packit Service a4b2a9
		pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
Packit Service a4b2a9
	if (left)
Packit Service 63e1c8
		debug(ap->logopt, "%d remaining in %s", left, ap->path);
Packit Service a4b2a9
Packit Service a4b2a9
	ec.status = left;
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_setcancelstate(cur_state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	return NULL;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void expire_send_fail(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct pending_args *mt = arg;
Packit Service a4b2a9
	struct autofs_point *ap = mt->ap;
Packit Service a4b2a9
	ops->send_fail(ap->logopt,
Packit Service a4b2a9
		       mt->ioctlfd, mt->wait_queue_token, -ENOENT);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void *do_expire_direct(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct pending_args *args, mt;
Packit Service a4b2a9
	struct autofs_point *ap;
Packit Service a4b2a9
	size_t len;
Packit Service a4b2a9
	int status, state;
Packit Service a4b2a9
Packit Service a4b2a9
	args = (struct pending_args *) arg;
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_lock(args);
Packit Service a4b2a9
Packit Service a4b2a9
	memcpy(&mt, args, sizeof(struct pending_args));
Packit Service a4b2a9
Packit Service a4b2a9
	ap = mt.ap;
Packit Service a4b2a9
Packit Service a4b2a9
	args->signaled = 1;
Packit Service a4b2a9
	status = pthread_cond_signal(&args->cond);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_unlock(args);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(expire_send_fail, &mt;;
Packit Service a4b2a9
Packit Service a4b2a9
	len = _strlen(mt.name, KEY_MAX_LEN);
Packit Service a4b2a9
	if (!len) {
Packit Service a4b2a9
		warn(ap->logopt, "direct key path too long %s", mt.name);
Packit Service a4b2a9
		/* TODO: force umount ?? */
Packit Service a4b2a9
		pthread_exit(NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	status = do_expire(ap, mt.name, len);
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       mt.ioctlfd, mt.wait_queue_token, -ENOENT);
Packit Service a4b2a9
	else {
Packit Service a4b2a9
		struct mapent *me;
Packit Service a4b2a9
		cache_writelock(mt.mc);
Packit Service a4b2a9
		me = cache_lookup_distinct(mt.mc, mt.name);
Packit Service a4b2a9
		if (me)
Packit Service a4b2a9
			me->ioctlfd = -1;
Packit Service a4b2a9
		cache_unlock(mt.mc);
Packit Service a4b2a9
		ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Packit Service a4b2a9
		ops->close(ap->logopt, mt.ioctlfd);
Packit Service a4b2a9
	}
Packit Service a4b2a9
	pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_pop(0);
Packit Service a4b2a9
Packit Service a4b2a9
	return NULL;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_direct_t *pkt)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct map_source *map;
Packit Service a4b2a9
	struct mapent_cache *mc = NULL;
Packit Service a4b2a9
	struct mapent *me = NULL;
Packit Service a4b2a9
	struct pending_args *mt;
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	pthread_t thid;
Packit Service a4b2a9
	struct timespec wait;
Packit Service a4b2a9
	int status, state;
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Packit Service a4b2a9
Packit Service a4b2a9
	/*
Packit Service a4b2a9
	 * This is a bit of a big deal.
Packit Service a4b2a9
	 * If we can't find the path and the map entry then
Packit Service a4b2a9
	 * we can't send a notification back to the kernel.
Packit Service a4b2a9
	 * Hang results.
Packit Service a4b2a9
	 *
Packit Service a4b2a9
	 * OTOH there is a mount so there should be a path
Packit Service a4b2a9
	 * and since it got mounted we have to trust that
Packit Service a4b2a9
	 * there is an entry in the cache.
Packit Service a4b2a9
	 */
Packit Service a4b2a9
	master_source_writelock(ap->entry);
Packit Service a4b2a9
	map = ap->entry->maps;
Packit Service a4b2a9
	while (map) {
Packit Service a4b2a9
		mc = map->mc;
Packit Service a4b2a9
		cache_writelock(mc);
Packit Service a4b2a9
		me = cache_lookup_ino(mc, pkt->dev, pkt->ino);
Packit Service a4b2a9
		if (me)
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		map = map->next;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (!me) {
Packit Service a4b2a9
		/*
Packit Service a4b2a9
		 * Shouldn't happen as we have been sent this following
Packit Service a4b2a9
		 * successful thread creation and lookup.
Packit Service a4b2a9
		 */
Packit Service a4b2a9
		crit(ap->logopt, "can't find map entry for (%lu,%lu)",
Packit Service a4b2a9
		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	/* Can't expire it if it isn't mounted */
Packit Service a4b2a9
	if (me->ioctlfd == -1) {
Packit Service a4b2a9
		int ioctlfd;
Packit Service a4b2a9
		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
Packit Service a4b2a9
		if (ioctlfd == -1) {
Packit Service a4b2a9
			crit(ap->logopt, "can't open ioctlfd for %s", me->key);
Packit Service a4b2a9
			cache_unlock(mc);
Packit Service a4b2a9
			master_source_unlock(ap->entry);
Packit Service a4b2a9
			pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
			return 1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		ops->send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	mt = malloc(sizeof(struct pending_args));
Packit Service a4b2a9
	if (!mt) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(ap->logopt, "malloc: %s", estr);
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       me->ioctlfd, pkt->wait_queue_token, -ENOMEM);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	pending_cond_init(mt);
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_mutex_init(&mt->mutex, NULL);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	mt->ap = ap;
Packit Service a4b2a9
	mt->ioctlfd = me->ioctlfd;
Packit Service a4b2a9
	mt->mc = mc;
Packit Service a4b2a9
	/* TODO: check length here */
Packit Service a4b2a9
	strcpy(mt->name, me->key);
Packit Service a4b2a9
	mt->dev = me->dev;
Packit Service a4b2a9
	mt->type = NFY_EXPIRE;
Packit Service a4b2a9
	mt->wait_queue_token = pkt->wait_queue_token;
Packit Service a4b2a9
Packit Service a4b2a9
	debug(ap->logopt, "token %ld, name %s",
Packit Service a4b2a9
		  (unsigned long) pkt->wait_queue_token, mt->name);
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_lock(mt);
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_create(&thid, &th_attr_detached, do_expire_direct, mt);
Packit Service a4b2a9
	if (status) {
Packit Service a4b2a9
		error(ap->logopt, "expire thread create failed");
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       mt->ioctlfd, pkt->wait_queue_token, -status);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		pending_mutex_unlock(mt);
Packit Service a4b2a9
		pending_cond_destroy(mt);
Packit Service a4b2a9
		pending_mutex_destroy(mt);
Packit Service a4b2a9
		free_pending_args(mt);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	cache_unlock(mc);
Packit Service a4b2a9
	master_source_unlock(ap->entry);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(free_pending_args, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_mutex_destroy, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_cond_destroy, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_mutex_unlock, mt);
Packit Service a4b2a9
	pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	mt->signaled = 0;
Packit Service a4b2a9
	while (!mt->signaled) {
Packit Service a4b2a9
		clock_gettime(CLOCK_MONOTONIC, &wait);
Packit Service a4b2a9
		wait.tv_sec += 2;
Packit Service a4b2a9
		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
Packit Service a4b2a9
		if (status && status != ETIMEDOUT)
Packit Service a4b2a9
			fatal(status);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void mount_send_fail(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct pending_args *mt = arg;
Packit Service a4b2a9
	struct autofs_point *ap = mt->ap;
Packit Service a4b2a9
	ops->send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token, -ENOENT);
Packit Service a4b2a9
	ops->close(ap->logopt, mt->ioctlfd);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void *do_mount_direct(void *arg)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct pending_args *args, mt;
Packit Service a4b2a9
	struct autofs_point *ap;
Packit Service a4b2a9
	struct stat st;
Packit Service a4b2a9
	int status, state;
Packit Service a4b2a9
Packit Service a4b2a9
	args = (struct pending_args *) arg;
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_lock(args);
Packit Service a4b2a9
Packit Service a4b2a9
	memcpy(&mt, args, sizeof(struct pending_args));
Packit Service a4b2a9
Packit Service a4b2a9
	ap = mt.ap;
Packit Service a4b2a9
Packit Service a4b2a9
	set_thread_mount_request_log_id(&mt;;
Packit Service a4b2a9
Packit Service a4b2a9
	args->signaled = 1;
Packit Service a4b2a9
	status = pthread_cond_signal(&args->cond);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_unlock(args);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(mount_send_fail, &mt;;
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Packit Service a4b2a9
Packit Service 681602
	if (defaults_get_mount_verbose()) {
Packit Service 681602
		pid_t ppid = log_pidinfo(ap, mt.pid, "requestor");
Packit Service 681602
		if (ppid > 0)
Packit Service 681602
			log_pidinfo(ap, ppid, "parent");
Packit Service 681602
	}
Packit Service 681602
Packit Service a4b2a9
	status = fstat(mt.ioctlfd, &st);
Packit Service a4b2a9
	if (status == -1) {
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		      "can't stat direct mount trigger %s", mt.name);
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       mt.ioctlfd, mt.wait_queue_token, -ENOENT);
Packit Service a4b2a9
		ops->close(ap->logopt, mt.ioctlfd);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		pthread_exit(NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	status = stat(mt.name, &st);
Packit Service a4b2a9
	if (status != 0 || !S_ISDIR(st.st_mode) || st.st_dev != mt.dev) {
Packit Service a4b2a9
		error(ap->logopt,
Packit Service a4b2a9
		     "direct trigger not valid or already mounted %s",
Packit Service a4b2a9
		     mt.name);
Packit Service a4b2a9
		ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Packit Service a4b2a9
		ops->close(ap->logopt, mt.ioctlfd);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		pthread_exit(NULL);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	info(ap->logopt, "attempting to mount entry %s", mt.name);
Packit Service a4b2a9
Packit Service a4b2a9
	set_tsd_user_vars(ap->logopt, mt.uid, mt.gid);
Packit Service a4b2a9
Packit Service a4b2a9
	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
Packit Service a4b2a9
	/*
Packit Service a4b2a9
	 * Direct mounts are always a single mount. If it fails there's
Packit Service a4b2a9
	 * nothing to undo so just complain
Packit Service a4b2a9
	 */
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Packit Service a4b2a9
	if (status) {
Packit Service a4b2a9
		struct mapent *me;
Packit Service a4b2a9
		struct statfs fs;
Packit Service a4b2a9
		unsigned int close_fd = 0;
Packit Service a4b2a9
Packit Service a4b2a9
		if (statfs(mt.name, &fs) == -1 ||
Packit Service a4b2a9
		   (fs.f_type == AUTOFS_SUPER_MAGIC &&
Packit Service a4b2a9
		    !master_find_submount(ap, mt.name)))
Packit Service a4b2a9
			close_fd = 1;
Packit Service a4b2a9
		cache_writelock(mt.mc);
Packit Service a4b2a9
		if ((me = cache_lookup_distinct(mt.mc, mt.name))) {
Packit Service a4b2a9
			/*
Packit Service a4b2a9
			 * Careful here, we need to leave the file handle open
Packit Service a4b2a9
			 * for direct mount multi-mounts with no real mount at
Packit Service a4b2a9
			 * their base so they will be expired.
Packit Service a4b2a9
			 */
Packit Service a4b2a9
			if (close_fd && me == me->multi)
Packit Service a4b2a9
				close_fd = 0;
Packit Service a4b2a9
			if (!close_fd)
Packit Service a4b2a9
				me->ioctlfd = mt.ioctlfd;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Packit Service a4b2a9
		cache_unlock(mt.mc);
Packit Service a4b2a9
		if (close_fd)
Packit Service a4b2a9
			ops->close(ap->logopt, mt.ioctlfd);
Packit Service a4b2a9
		info(ap->logopt, "mounted %s", mt.name);
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		/* TODO: get mount return status from lookup_nss_mount */
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       mt.ioctlfd, mt.wait_queue_token, -ENOENT);
Packit Service a4b2a9
		ops->close(ap->logopt, mt.ioctlfd);
Packit Service a4b2a9
		info(ap->logopt, "failed to mount %s", mt.name);
Packit Service a4b2a9
	}
Packit Service a4b2a9
	pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_pop(0);
Packit Service a4b2a9
Packit Service a4b2a9
	return NULL;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct ioctl_ops *ops = get_ioctl_ops();
Packit Service a4b2a9
	struct map_source *map;
Packit Service a4b2a9
	struct mapent_cache *mc = NULL;
Packit Service a4b2a9
	struct mapent *me = NULL;
Packit Service a4b2a9
	pthread_t thid;
Packit Service a4b2a9
	struct pending_args *mt;
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	int status = 0;
Packit Service a4b2a9
	struct timespec wait;
Packit Service a4b2a9
	int ioctlfd, len, state;
Packit Service a4b2a9
	unsigned int kver_major = get_kver_major();
Packit Service a4b2a9
	unsigned int kver_minor = get_kver_minor();
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Packit Service a4b2a9
Packit Service a4b2a9
	master_mutex_lock();
Packit Service a4b2a9
Packit Service a4b2a9
	/*
Packit Service a4b2a9
	 * If our parent is a direct or offset mount that has been
Packit Service a4b2a9
	 * covered by a mount and another lookup occurs after the
Packit Service a4b2a9
	 * mount but before the device and inode are set in the
Packit Service a4b2a9
	 * cache entry we will not be able to find the mapent. So
Packit Service a4b2a9
	 * we must take the source writelock to ensure the parent
Packit Service a4b2a9
	 * has mount is complete before we look for the entry.
Packit Service a4b2a9
	 *
Packit Service a4b2a9
	 * Since the vfs-automount kernel changes we can now block
Packit Service a4b2a9
	 * on covered mounts during mount tree construction so a
Packit Service a4b2a9
	 * write lock is no longer needed. So we now can handle a
Packit Service a4b2a9
	 * wider class of recursively define mount lookups.
Packit Service a4b2a9
	 */
Packit Service a4b2a9
	if (kver_major > 5 || (kver_major == 5 && kver_minor > 1))
Packit Service a4b2a9
		master_source_readlock(ap->entry);
Packit Service a4b2a9
	else
Packit Service a4b2a9
		master_source_writelock(ap->entry);
Packit Service a4b2a9
	map = ap->entry->maps;
Packit Service a4b2a9
	while (map) {
Packit Service a4b2a9
		/*
Packit Service a4b2a9
		 * Only consider map sources that have been read since
Packit Service a4b2a9
		 * the map entry was last updated.
Packit Service a4b2a9
		 */
Packit Service a4b2a9
		if (ap->entry->age > map->age) {
Packit Service a4b2a9
			map = map->next;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		mc = map->mc;
Packit Service a4b2a9
		cache_readlock(mc);
Packit Service a4b2a9
		me = cache_lookup_ino(mc, pkt->dev, pkt->ino);
Packit Service a4b2a9
		if (me)
Packit Service a4b2a9
			break;
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		map = map->next;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (!me) {
Packit Service a4b2a9
		/*
Packit Service a4b2a9
		 * Shouldn't happen as the kernel is telling us
Packit Service a4b2a9
		 * someone has walked on our mount point.
Packit Service a4b2a9
		 */
Packit Service a4b2a9
		logerr("can't find map entry for (%lu,%lu)",
Packit Service a4b2a9
		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	if (me->ioctlfd != -1) {
Packit Service a4b2a9
		/* Maybe someone did a manual umount, clean up ! */
Packit Service a4b2a9
		close(me->ioctlfd);
Packit Service a4b2a9
		me->ioctlfd = -1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
Packit Service a4b2a9
Packit Service a4b2a9
	if (ioctlfd == -1) {
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
Packit Service a4b2a9
		/* TODO:  how do we clear wait q in kernel ?? */
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	debug(ap->logopt, "token %ld, name %s, request pid %u",
Packit Service a4b2a9
		  (unsigned long) pkt->wait_queue_token, me->key, pkt->pid);
Packit Service a4b2a9
Packit Service a4b2a9
	/* Ignore packet if we're trying to shut down */
Packit Service a4b2a9
	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       ioctlfd, pkt->wait_queue_token, -ENOENT);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	/* Check if we recorded a mount fail for this key */
Packit Service a4b2a9
	if (me->status >= monotonic_time(NULL)) {
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       ioctlfd, pkt->wait_queue_token, -ENOENT);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	len = strlen(me->key);
Packit Service a4b2a9
	if (len >= PATH_MAX) {
Packit Service a4b2a9
		error(ap->logopt, "direct mount path too long %s", me->key);
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       ioctlfd, pkt->wait_queue_token, -ENAMETOOLONG);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	mt = malloc(sizeof(struct pending_args));
Packit Service a4b2a9
	if (!mt) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(ap->logopt, "malloc: %s", estr);
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       ioctlfd, pkt->wait_queue_token, -ENOMEM);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	memset(mt, 0, sizeof(struct pending_args));
Packit Service a4b2a9
Packit Service a4b2a9
	pending_cond_init(mt);
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_mutex_init(&mt->mutex, NULL);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
Packit Service a4b2a9
	pending_mutex_lock(mt);
Packit Service a4b2a9
Packit Service a4b2a9
	mt->ap = ap;
Packit Service a4b2a9
	mt->ioctlfd = ioctlfd;
Packit Service a4b2a9
	mt->mc = mc;
Packit Service a4b2a9
	strcpy(mt->name, me->key);
Packit Service a4b2a9
	mt->len = len;
Packit Service a4b2a9
	mt->dev = me->dev;
Packit Service a4b2a9
	mt->type = NFY_MOUNT;
Packit Service a4b2a9
	mt->uid = pkt->uid;
Packit Service a4b2a9
	mt->gid = pkt->gid;
Packit Service a4b2a9
	mt->pid = pkt->pid;
Packit Service a4b2a9
	mt->wait_queue_token = pkt->wait_queue_token;
Packit Service a4b2a9
Packit Service a4b2a9
	status = pthread_create(&thid, &th_attr_detached, do_mount_direct, mt);
Packit Service a4b2a9
	if (status) {
Packit Service a4b2a9
		error(ap->logopt, "missing mount thread create failed");
Packit Service a4b2a9
		ops->send_fail(ap->logopt,
Packit Service a4b2a9
			       ioctlfd, pkt->wait_queue_token, -status);
Packit Service a4b2a9
		ops->close(ap->logopt, ioctlfd);
Packit Service a4b2a9
		cache_unlock(mc);
Packit Service a4b2a9
		master_source_unlock(ap->entry);
Packit Service a4b2a9
		master_mutex_unlock();
Packit Service a4b2a9
		pending_mutex_unlock(mt);
Packit Service a4b2a9
		pending_cond_destroy(mt);
Packit Service a4b2a9
		pending_mutex_destroy(mt);
Packit Service a4b2a9
		free_pending_args(mt);
Packit Service a4b2a9
		pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	cache_unlock(mc);
Packit Service a4b2a9
	master_source_unlock(ap->entry);
Packit Service a4b2a9
Packit Service a4b2a9
	master_mutex_unlock();
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_push(free_pending_args, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_mutex_destroy, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_cond_destroy, mt);
Packit Service a4b2a9
	pthread_cleanup_push(pending_mutex_unlock, mt);
Packit Service a4b2a9
	pthread_setcancelstate(state, NULL);
Packit Service a4b2a9
Packit Service a4b2a9
	mt->signaled = 0;
Packit Service a4b2a9
	while (!mt->signaled) {
Packit Service a4b2a9
		clock_gettime(CLOCK_MONOTONIC, &wait);
Packit Service a4b2a9
		wait.tv_sec += 2;
Packit Service a4b2a9
		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
Packit Service a4b2a9
		if (status && status != ETIMEDOUT)
Packit Service a4b2a9
			fatal(status);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
	pthread_cleanup_pop(1);
Packit Service a4b2a9
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
}
Packit Service a4b2a9