Blame lib/mounts.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  mounts.c - module for mount utilities.
Packit 8480eb
 *
Packit 8480eb
 *   Copyright 2002-2005 Ian Kent <raven@themaw.net> - All Rights Reserved
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; incorporated herein by reference.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <stdlib.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <limits.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <sys/ioctl.h>
Packit 8480eb
#include <sys/mount.h>
Packit 8480eb
#include <sys/wait.h>
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <stdio.h>
Packit 8480eb
#include <dirent.h>
Packit 8480eb
#include <sys/vfs.h>
Packit 8480eb
#include <pwd.h>
Packit 8480eb
#include <grp.h>
Packit 8480eb
#include <libgen.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
#define MAX_OPTIONS_LEN		80
Packit 8480eb
#define MAX_MNT_NAME_LEN	30
Packit 8480eb
#define MAX_ENV_NAME		15
Packit 8480eb
Packit 8480eb
#define EBUFSIZ 1024
Packit 8480eb
Packit 8480eb
const unsigned int t_indirect = AUTOFS_TYPE_INDIRECT;
Packit 8480eb
const unsigned int t_direct = AUTOFS_TYPE_DIRECT;
Packit 8480eb
const unsigned int t_offset = AUTOFS_TYPE_OFFSET;
Packit 8480eb
const unsigned int type_count = 3;
Packit 8480eb
Packit 8480eb
static const char options_template[]       = "fd=%d,pgrp=%u,minproto=5,maxproto=%d";
Packit 8480eb
static const char options_template_extra[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d,%s";
Packit 8480eb
static const char mnt_name_template[]      = "automount(pid%u)";
Packit 8480eb
Packit 8480eb
static struct kernel_mod_version kver = {0, 0};
Packit 8480eb
static const char kver_options_template[]  = "fd=%d,pgrp=%u,minproto=3,maxproto=5";
Packit 8480eb
Packit 8480eb
extern size_t detached_thread_stack_size;
Packit 8480eb
static size_t maxgrpbuf = 0;
Packit 8480eb
Packit 8480eb
#define EXT_MOUNTS_HASH_SIZE    50
Packit 8480eb
Packit 8480eb
struct ext_mount {
Packit 8480eb
	char *mountpoint;
Packit 8480eb
	unsigned int umount;
Packit 8480eb
	struct list_head mount;
Packit 8480eb
	struct list_head mounts;
Packit 8480eb
};
Packit 8480eb
static struct list_head ext_mounts_hash[EXT_MOUNTS_HASH_SIZE];
Packit 8480eb
static unsigned int ext_mounts_hash_init_done = 0;
Packit 8480eb
static pthread_mutex_t ext_mount_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
Packit 8480eb
unsigned int linux_version_code(void)
Packit 8480eb
{
Packit 8480eb
	struct utsname my_utsname;
Packit 8480eb
	unsigned int p, q, r;
Packit 8480eb
	char *tmp, *save;
Packit 8480eb
Packit 8480eb
	if (uname(&my_utsname))
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	p = q = r = 0;
Packit 8480eb
Packit 8480eb
	tmp = strtok_r(my_utsname.release, ".", &save);
Packit 8480eb
	if (!tmp)
Packit 8480eb
		return 0;
Packit 8480eb
	p = (unsigned int ) atoi(tmp);
Packit 8480eb
Packit 8480eb
	tmp = strtok_r(NULL, ".", &save);
Packit 8480eb
	if (!tmp)
Packit 8480eb
		return KERNEL_VERSION(p, 0, 0);
Packit 8480eb
	q = (unsigned int) atoi(tmp);
Packit 8480eb
Packit 8480eb
	tmp = strtok_r(NULL, ".", &save);
Packit 8480eb
	if (!tmp)
Packit 8480eb
		return KERNEL_VERSION(p, q, 0);
Packit 8480eb
	r = (unsigned int) atoi(tmp);
Packit 8480eb
Packit 8480eb
	return KERNEL_VERSION(p, q, r);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int query_kproto_ver(void)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops;
Packit 8480eb
	char dir[] = "/tmp/autoXXXXXX", *t_dir;
Packit 8480eb
	char options[MAX_OPTIONS_LEN + 1];
Packit 8480eb
	pid_t pgrp = getpgrp();
Packit 8480eb
	int pipefd[2], ioctlfd, len;
Packit 8480eb
	struct stat st;
Packit 8480eb
Packit 8480eb
	t_dir = mkdtemp(dir);
Packit 8480eb
	if (!t_dir)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	if (pipe(pipefd) == -1) {
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	len = snprintf(options, MAX_OPTIONS_LEN,
Packit 8480eb
		       kver_options_template, pipefd[1], (unsigned) pgrp);
Packit 8480eb
	if (len < 0) {
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (mount("automount", t_dir, "autofs", MS_MGC_VAL, options)) {
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	close(pipefd[1]);
Packit 8480eb
Packit 8480eb
	if (stat(t_dir, &st) == -1) {
Packit 8480eb
		umount(t_dir);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ops = get_ioctl_ops();
Packit 8480eb
	if (!ops) {
Packit 8480eb
		umount(t_dir);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ops->open(LOGOPT_NONE, &ioctlfd, st.st_dev, t_dir);
Packit 8480eb
	if (ioctlfd == -1) {
Packit 8480eb
		umount(t_dir);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close_ioctl_ctl();
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ops->catatonic(LOGOPT_NONE, ioctlfd);
Packit 8480eb
Packit 8480eb
	/* If this ioctl() doesn't work, it is kernel version 2 */
Packit 8480eb
	if (ops->protover(LOGOPT_NONE, ioctlfd, &kver.major)) {
Packit 8480eb
		ops->close(LOGOPT_NONE, ioctlfd);
Packit 8480eb
		umount(t_dir);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close_ioctl_ctl();
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* If this ioctl() doesn't work, version is 4 or less */
Packit 8480eb
	if (ops->protosubver(LOGOPT_NONE, ioctlfd, &kver.minor)) {
Packit 8480eb
		ops->close(LOGOPT_NONE, ioctlfd);
Packit 8480eb
		umount(t_dir);
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		close_ioctl_ctl();
Packit 8480eb
		rmdir(t_dir);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ops->close(LOGOPT_NONE, ioctlfd);
Packit 8480eb
	umount(t_dir);
Packit 8480eb
	close(pipefd[0]);
Packit 8480eb
	close_ioctl_ctl();
Packit 8480eb
	rmdir(t_dir);
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int get_kver_major(void)
Packit 8480eb
{
Packit 8480eb
	return kver.major;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int get_kver_minor(void)
Packit 8480eb
{
Packit 8480eb
	return kver.minor;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
#ifdef HAVE_MOUNT_NFS
Packit 8480eb
static int extract_version(char *start, struct nfs_mount_vers *vers)
Packit 8480eb
{
Packit 8480eb
	char *s_ver = strchr(start, ' ');
Packit 8480eb
	if (!s_ver)
Packit 8480eb
		return 0;
Packit 8480eb
	while (*s_ver && !isdigit(*s_ver)) {
Packit 8480eb
		s_ver++;
Packit 8480eb
		if (!*s_ver)
Packit 8480eb
			return 0;
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
	vers->major = atoi(strtok(s_ver, "."));
Packit 8480eb
	vers->minor = (unsigned int) atoi(strtok(NULL, "."));
Packit 8480eb
	vers->fix = (unsigned int) atoi(strtok(NULL, "."));
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int check_nfs_mount_version(struct nfs_mount_vers *vers,
Packit 8480eb
			    struct nfs_mount_vers *check)
Packit 8480eb
{
Packit 8480eb
	pid_t f;
Packit 8480eb
	int ret, status, pipefd[2];
Packit 8480eb
	char errbuf[EBUFSIZ + 1], *p, *sp;
Packit 8480eb
	int errp, errn;
Packit 8480eb
	sigset_t allsigs, tmpsig, oldsig;
Packit 8480eb
	char *s_ver;
Packit 8480eb
	int cancel_state;
Packit 8480eb
Packit 8480eb
	if (open_pipe(pipefd))
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
Packit 8480eb
Packit 8480eb
	sigfillset(&allsigs);
Packit 8480eb
	pthread_sigmask(SIG_BLOCK, &allsigs, &oldsig);
Packit 8480eb
Packit 8480eb
	open_mutex_lock();
Packit 8480eb
	f = fork();
Packit 8480eb
	if (f == 0) {
Packit 8480eb
		reset_signals();
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		dup2(pipefd[1], STDOUT_FILENO);
Packit 8480eb
		dup2(pipefd[1], STDERR_FILENO);
Packit 8480eb
		close(pipefd[1]);
Packit 8480eb
Packit 8480eb
		execl(PATH_MOUNT_NFS, PATH_MOUNT_NFS, "-V", (char *) NULL);
Packit 8480eb
		_exit(255);	/* execv() failed */
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = 0;
Packit 8480eb
Packit 8480eb
	tmpsig = oldsig;
Packit 8480eb
Packit 8480eb
	sigaddset(&tmpsig, SIGCHLD);
Packit 8480eb
	pthread_sigmask(SIG_SETMASK, &tmpsig, NULL);
Packit 8480eb
	open_mutex_unlock();
Packit 8480eb
Packit 8480eb
	close(pipefd[1]);
Packit 8480eb
Packit 8480eb
	if (f < 0) {
Packit 8480eb
		close(pipefd[0]);
Packit 8480eb
		pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
Packit 8480eb
		pthread_setcancelstate(cancel_state, NULL);
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	errp = 0;
Packit 8480eb
	do {
Packit 8480eb
		while (1) {
Packit 8480eb
			errn = read(pipefd[0], errbuf + errp, EBUFSIZ - errp);
Packit 8480eb
			if (errn == -1 && errno == EINTR)
Packit 8480eb
				continue;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (errn > 0) {
Packit 8480eb
			errp += errn;
Packit 8480eb
Packit 8480eb
			sp = errbuf;
Packit 8480eb
			while (errp && (p = memchr(sp, '\n', errp))) {
Packit 8480eb
				*p++ = '\0';
Packit 8480eb
				errp -= (p - sp);
Packit 8480eb
				sp = p;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (errp && sp != errbuf)
Packit 8480eb
				memmove(errbuf, sp, errp);
Packit 8480eb
Packit 8480eb
			if (errp >= EBUFSIZ) {
Packit 8480eb
				/* Line too long, split */
Packit 8480eb
				errbuf[errp] = '\0';
Packit 8480eb
				if ((s_ver = strstr(errbuf, "nfs-utils"))) {
Packit 8480eb
					if (extract_version(s_ver, vers))
Packit 8480eb
						ret = 1;
Packit 8480eb
				}
Packit 8480eb
				errp = 0;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if ((s_ver = strstr(errbuf, "nfs-utils"))) {
Packit 8480eb
				if (extract_version(s_ver, vers))
Packit 8480eb
					ret = 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	} while (errn > 0);
Packit 8480eb
Packit 8480eb
	close(pipefd[0]);
Packit 8480eb
Packit 8480eb
	if (errp > 0) {
Packit 8480eb
		/* End of file without \n */
Packit 8480eb
		errbuf[errp] = '\0';
Packit 8480eb
		if ((s_ver = strstr(errbuf, "nfs-utils"))) {
Packit 8480eb
			if (extract_version(s_ver, vers))
Packit 8480eb
				ret = 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ret) {
Packit 8480eb
		if ((vers->major < check->major) ||
Packit 8480eb
		    ((vers->major == check->major) && (vers->minor < check->minor)) ||
Packit 8480eb
		    ((vers->major == check->major) && (vers->minor == check->minor) &&
Packit 8480eb
		     (vers->fix < check->fix)))
Packit 8480eb
			ret = 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (waitpid(f, &status, 0) != f)
Packit 8480eb
		debug(LOGOPT_NONE, "no process found to wait for");
Packit 8480eb
Packit 8480eb
	pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
Packit 8480eb
	pthread_setcancelstate(cancel_state, NULL);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
#else
Packit 8480eb
int check_nfs_mount_version(struct nfs_mount_vers *vers,
Packit 8480eb
			    struct nfs_mount_vers *check)
Packit 8480eb
{
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
static char *set_env_name(const char *prefix, const char *name, char *buf)
Packit 8480eb
{
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	len = strlen(name);
Packit 8480eb
	if (prefix)
Packit 8480eb
		len += strlen(prefix);
Packit 8480eb
	len++;
Packit 8480eb
Packit 8480eb
	if (len > MAX_ENV_NAME)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (!prefix)
Packit 8480eb
		strcpy(buf, name);
Packit 8480eb
	else {
Packit 8480eb
		strcpy(buf, prefix);
Packit 8480eb
		strcat(buf, name);
Packit 8480eb
	}
Packit 8480eb
	return buf;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct substvar *do_macro_addvar(struct substvar *list,
Packit 8480eb
					const char *prefix,
Packit 8480eb
					const char *name,
Packit 8480eb
					const char *val)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ENV_NAME + 1];
Packit 8480eb
	char *new;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	new = set_env_name(prefix, name, buf);
Packit 8480eb
	if (new) {
Packit 8480eb
		len = strlen(new);
Packit 8480eb
		list = macro_addvar(list, new, len, val);
Packit 8480eb
	}
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct substvar *do_macro_removevar(struct substvar *list,
Packit 8480eb
					   const char *prefix,
Packit 8480eb
					   const char *name)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ENV_NAME + 1];
Packit 8480eb
	char *new;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	new = set_env_name(prefix, name, buf);
Packit 8480eb
	if (new) {
Packit 8480eb
		len = strlen(new);
Packit 8480eb
		list = macro_removevar(list, new, len);
Packit 8480eb
	}
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct substvar *addstdenv(struct substvar *sv, const char *prefix)
Packit 8480eb
{
Packit 8480eb
	struct substvar *list = sv;
Packit 8480eb
	struct thread_stdenv_vars *tsv;
Packit 8480eb
	char numbuf[16];
Packit 8480eb
Packit 8480eb
	tsv = pthread_getspecific(key_thread_stdenv_vars);
Packit 8480eb
	if (tsv) {
Packit 8480eb
		const struct substvar *mv;
Packit 8480eb
		int ret;
Packit 8480eb
		long num;
Packit 8480eb
Packit 8480eb
		num = (long) tsv->uid;
Packit 8480eb
		ret = sprintf(numbuf, "%ld", num);
Packit 8480eb
		if (ret > 0)
Packit 8480eb
			list = do_macro_addvar(list, prefix, "UID", numbuf);
Packit 8480eb
		num = (long) tsv->gid;
Packit 8480eb
		ret = sprintf(numbuf, "%ld", num);
Packit 8480eb
		if (ret > 0)
Packit 8480eb
			list = do_macro_addvar(list, prefix, "GID", numbuf);
Packit 8480eb
		list = do_macro_addvar(list, prefix, "USER", tsv->user);
Packit 8480eb
		list = do_macro_addvar(list, prefix, "GROUP", tsv->group);
Packit 8480eb
		list = do_macro_addvar(list, prefix, "HOME", tsv->home);
Packit 8480eb
		mv = macro_findvar(list, "HOST", 4);
Packit 8480eb
		if (mv) {
Packit 8480eb
			char *shost = strdup(mv->val);
Packit 8480eb
			if (shost) {
Packit 8480eb
				char *dot = strchr(shost, '.');
Packit 8480eb
				if (dot)
Packit 8480eb
					*dot = '\0';
Packit 8480eb
				list = do_macro_addvar(list,
Packit 8480eb
						       prefix, "SHOST", shost);
Packit 8480eb
				free(shost);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct substvar *removestdenv(struct substvar *sv, const char *prefix)
Packit 8480eb
{
Packit 8480eb
	struct substvar *list = sv;
Packit 8480eb
Packit 8480eb
	list = do_macro_removevar(list, prefix, "UID");
Packit 8480eb
	list = do_macro_removevar(list, prefix, "USER");
Packit 8480eb
	list = do_macro_removevar(list, prefix, "HOME");
Packit 8480eb
	list = do_macro_removevar(list, prefix, "GID");
Packit 8480eb
	list = do_macro_removevar(list, prefix, "GROUP");
Packit 8480eb
	list = do_macro_removevar(list, prefix, "SHOST");
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void add_std_amd_vars(struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char *tmp;
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_arch();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("arch", 4, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_karch();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("karch", 5, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_os();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("os", 2, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_full_os();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("full_os", 7, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_os_ver();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("osver", 5, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_vendor();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("vendor", 6, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Umm ... HP_UX cluster name, probably not used */
Packit 8480eb
	tmp = conf_amd_get_cluster();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("cluster", 7, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	} else {
Packit 8480eb
		const struct substvar *v = macro_findvar(sv, "domain", 4);
Packit 8480eb
		if (v && *v->val) {
Packit 8480eb
			tmp = strdup(v->val);
Packit Service 0f11ce
			if (tmp) {
Packit 8480eb
				macro_global_addvar("cluster", 7, tmp);
Packit Service 0f11ce
				free(tmp);
Packit Service 0f11ce
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tmp = conf_amd_get_auto_dir();
Packit 8480eb
	if (tmp) {
Packit 8480eb
		macro_global_addvar("autodir", 7, tmp);
Packit 8480eb
		free(tmp);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void remove_std_amd_vars(void)
Packit 8480eb
{
Packit 8480eb
	macro_global_removevar("autodir", 7);
Packit 8480eb
	macro_global_removevar("cluster", 7);
Packit 8480eb
	macro_global_removevar("vendor", 6);
Packit 8480eb
	macro_global_removevar("osver", 5);
Packit 8480eb
	macro_global_removevar("full_os", 7);
Packit 8480eb
	macro_global_removevar("os", 2);
Packit 8480eb
	macro_global_removevar("karch", 5);
Packit 8480eb
	macro_global_removevar("arch", 4);
Packit 8480eb
	return;
Packit 8480eb
 }
Packit 8480eb
Packit 8480eb
struct amd_entry *new_amd_entry(const struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct amd_entry *new;
Packit 8480eb
	const struct substvar *v;
Packit 8480eb
	char *path;
Packit 8480eb
Packit 8480eb
	v = macro_findvar(sv, "path", 4);
Packit 8480eb
	if (!v)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	path = strdup(v->val);
Packit 8480eb
	if (!path)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	new = malloc(sizeof(struct amd_entry));
Packit 8480eb
	if (!new) {
Packit 8480eb
		free(path);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	memset(new, 0, sizeof(*new));
Packit 8480eb
	new->path = path;
Packit 8480eb
	INIT_LIST_HEAD(&new->list);
Packit 8480eb
	INIT_LIST_HEAD(&new->entries);
Packit 8480eb
	INIT_LIST_HEAD(&new->ext_mount);
Packit 8480eb
Packit 8480eb
	return new;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void clear_amd_entry(struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	if (!entry)
Packit 8480eb
		return;
Packit 8480eb
	if (entry->path)
Packit 8480eb
		free(entry->path);
Packit 8480eb
	if (entry->map_type)
Packit 8480eb
		free(entry->map_type);
Packit 8480eb
	if (entry->pref)
Packit 8480eb
		free(entry->pref);
Packit 8480eb
	if (entry->fs)
Packit 8480eb
		free(entry->fs);
Packit 8480eb
	if (entry->rhost)
Packit 8480eb
		free(entry->rhost);
Packit 8480eb
	if (entry->rfs)
Packit 8480eb
		free(entry->rfs);
Packit 8480eb
	if (entry->opts)
Packit 8480eb
		free(entry->opts);
Packit 8480eb
	if (entry->addopts)
Packit 8480eb
		free(entry->addopts);
Packit 8480eb
	if (entry->remopts)
Packit 8480eb
		free(entry->remopts);
Packit 8480eb
	if (entry->sublink)
Packit 8480eb
		free(entry->sublink);
Packit 8480eb
	if (entry->selector)
Packit 8480eb
		free_selector(entry->selector);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void free_amd_entry(struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	clear_amd_entry(entry);
Packit 8480eb
	free(entry);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void free_amd_entry_list(struct list_head *entries)
Packit 8480eb
{
Packit 8480eb
	if (!list_empty(entries)) {
Packit 8480eb
		struct list_head *head = entries;
Packit 8480eb
		struct amd_entry *this;
Packit 8480eb
		struct list_head *p;
Packit 8480eb
Packit 8480eb
		p = head->next;
Packit 8480eb
		while (p != head) {
Packit 8480eb
			this = list_entry(p, struct amd_entry, list);
Packit 8480eb
			p = p->next;
Packit 8480eb
			free_amd_entry(this);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Make common autofs mount options string
Packit 8480eb
 */
Packit Service 42268b
char *make_options_string(char *path, int pipefd, const char *extra)
Packit 8480eb
{
Packit 8480eb
	char *options;
Packit Service 42268b
	int len;
Packit Service 62b5af
Packit Service 42268b
	options = malloc(MAX_OPTIONS_LEN + 1);
Packit 8480eb
	if (!options) {
Packit 8480eb
		logerr("can't malloc options string");
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit Service 42268b
	if (extra) 
Packit Service 42268b
		len = snprintf(options, MAX_OPTIONS_LEN,
Packit 8480eb
				options_template_extra,
Packit 8480eb
				pipefd, (unsigned) getpgrp(),
Packit Service 42268b
				AUTOFS_MAX_PROTO_VERSION, extra);
Packit 8480eb
	else
Packit Service 42268b
		len = snprintf(options, MAX_OPTIONS_LEN, options_template,
Packit 8480eb
			pipefd, (unsigned) getpgrp(),
Packit 8480eb
			AUTOFS_MAX_PROTO_VERSION);
Packit 8480eb
Packit Service 42268b
	if (len >= MAX_OPTIONS_LEN) {
Packit Service 42268b
		logerr("buffer to small for options - truncated");
Packit Service 42268b
		len = MAX_OPTIONS_LEN - 1;
Packit 8480eb
	}
Packit 8480eb
Packit Service 42268b
	if (len < 0) {
Packit Service 42268b
		logerr("failed to malloc autofs mount options for %s", path);
Packit Service 42268b
		free(options);
Packit Service 42268b
		return NULL;
Packit 8480eb
	}
Packit 8480eb
	options[len] = '\0';
Packit Service 62b5af
Packit Service 42268b
	return options;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
char *make_mnt_name_string(char *path)
Packit 8480eb
{
Packit 8480eb
	char *mnt_name;
Packit 8480eb
	int len;
Packit 8480eb
Packit 8480eb
	mnt_name = malloc(MAX_MNT_NAME_LEN + 1);
Packit 8480eb
	if (!mnt_name) {
Packit 8480eb
		logerr("can't malloc mnt_name string");
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	len = snprintf(mnt_name, MAX_MNT_NAME_LEN,
Packit 8480eb
			mnt_name_template, (unsigned) getpid());
Packit 8480eb
Packit 8480eb
	if (len >= MAX_MNT_NAME_LEN) {
Packit 8480eb
		logerr("buffer to small for mnt_name - truncated");
Packit 8480eb
		len = MAX_MNT_NAME_LEN - 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (len < 0) {
Packit 8480eb
		logerr("failed setting up mnt_name for autofs path %s", path);
Packit 8480eb
		free(mnt_name);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
	mnt_name[len] = '\0';
Packit 8480eb
Packit 8480eb
	return mnt_name;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void ext_mounts_hash_init(void)
Packit 8480eb
{
Packit 8480eb
	int i;
Packit 8480eb
	for (i = 0; i < EXT_MOUNTS_HASH_SIZE; i++)
Packit 8480eb
		INIT_LIST_HEAD(&ext_mounts_hash[i]);
Packit 8480eb
	ext_mounts_hash_init_done = 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct ext_mount *ext_mount_lookup(const char *mountpoint)
Packit 8480eb
{
Packit 8480eb
	u_int32_t hval = hash(mountpoint, EXT_MOUNTS_HASH_SIZE);
Packit 8480eb
	struct list_head *p, *head;
Packit 8480eb
Packit 8480eb
	if (!ext_mounts_hash_init_done)
Packit 8480eb
		ext_mounts_hash_init();
Packit 8480eb
Packit 8480eb
	if (list_empty(&ext_mounts_hash[hval]))
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	head = &ext_mounts_hash[hval];
Packit 8480eb
	list_for_each(p, head) {
Packit 8480eb
		struct ext_mount *this = list_entry(p, struct ext_mount, mount);
Packit 8480eb
		if (!strcmp(this->mountpoint, mountpoint))
Packit 8480eb
			return this;
Packit 8480eb
	}
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int ext_mount_add(struct list_head *entry, const char *path, unsigned int umount)
Packit 8480eb
{
Packit 8480eb
	struct ext_mount *em;
Packit 8480eb
	u_int32_t hval;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	pthread_mutex_lock(&ext_mount_hash_mutex);
Packit 8480eb
Packit 8480eb
	em = ext_mount_lookup(path);
Packit 8480eb
	if (em) {
Packit 8480eb
		struct list_head *p, *head;
Packit 8480eb
		head = &em->mounts;
Packit 8480eb
		list_for_each(p, head) {
Packit 8480eb
			if (p == entry)
Packit 8480eb
				goto done;
Packit 8480eb
		}
Packit 8480eb
		list_add_tail(entry, &em->mounts);
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	em = malloc(sizeof(struct ext_mount));
Packit Service 0c8d10
	if (!em)
Packit 8480eb
		goto done;
Packit 8480eb
Packit 8480eb
	em->mountpoint = strdup(path);
Packit 8480eb
	if (!em->mountpoint) {
Packit 8480eb
		free(em);
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
	em->umount = umount;
Packit 8480eb
	INIT_LIST_HEAD(&em->mount);
Packit 8480eb
	INIT_LIST_HEAD(&em->mounts);
Packit 8480eb
Packit 8480eb
	hval = hash(path, EXT_MOUNTS_HASH_SIZE);
Packit 8480eb
	list_add_tail(&em->mount, &ext_mounts_hash[hval]);
Packit 8480eb
Packit 8480eb
	list_add_tail(entry, &em->mounts);
Packit 8480eb
Packit 8480eb
	ret = 1;
Packit 8480eb
done:
Packit 8480eb
	pthread_mutex_unlock(&ext_mount_hash_mutex);
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int ext_mount_remove(struct list_head *entry, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct ext_mount *em;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	pthread_mutex_lock(&ext_mount_hash_mutex);
Packit 8480eb
Packit 8480eb
	em = ext_mount_lookup(path);
Packit 8480eb
	if (!em)
Packit 8480eb
		goto done;
Packit 8480eb
Packit 8480eb
	list_del_init(entry);
Packit 8480eb
Packit 8480eb
	if (!list_empty(&em->mounts))
Packit 8480eb
		goto done;
Packit 8480eb
	else {
Packit 8480eb
		list_del_init(&em->mount);
Packit 8480eb
		if (em->umount)
Packit 8480eb
			ret = 1;
Packit 8480eb
		if (list_empty(&em->mount)) {
Packit 8480eb
			free(em->mountpoint);
Packit 8480eb
			free(em);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	pthread_mutex_unlock(&ext_mount_hash_mutex);
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int ext_mount_inuse(const char *path)
Packit 8480eb
{
Packit 8480eb
	struct ext_mount *em;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	pthread_mutex_lock(&ext_mount_hash_mutex);
Packit 8480eb
	em = ext_mount_lookup(path);
Packit 8480eb
	if (!em)
Packit 8480eb
		goto done;
Packit 8480eb
Packit 8480eb
	if (!list_empty(&em->mounts))
Packit 8480eb
		ret = 1;
Packit 8480eb
done:
Packit 8480eb
	pthread_mutex_unlock(&ext_mount_hash_mutex);
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit Service b92782
/* From glibc decode_name() */
Packit Service b92782
/* Since the values in a line are separated by spaces, a name cannot
Packit Service b92782
 * contain a space.  Therefore some programs encode spaces in names
Packit Service b92782
 * by the strings "\040".  We undo the encoding when reading an entry.
Packit Service b92782
 * The decoding happens in place.
Packit Service b92782
 */
Packit Service b92782
static char *local_decode_name(char *buf)
Packit Service b92782
{
Packit Service b92782
	char *rp = buf;
Packit Service b92782
	char *wp = buf;
Packit Service b92782
Packit Service b92782
	do {
Packit Service b92782
		if (rp[0] == '\\' && rp[1] == '0' &&
Packit Service b92782
		    rp[2] == '4' && rp[3] == '0') {
Packit Service b92782
			/* \040 is a SPACE.  */
Packit Service b92782
			*wp++ = ' ';
Packit Service b92782
			rp += 3;
Packit Service b92782
		} else if (rp[0] == '\\' && rp[1] == '0' &&
Packit Service b92782
			   rp[2] == '1' && rp[3] == '1') {
Packit Service b92782
			/* \011 is a TAB.  */
Packit Service b92782
			*wp++ = '\t';
Packit Service b92782
			rp += 3;
Packit Service b92782
		} else if (rp[0] == '\\' && rp[1] == '0' &&
Packit Service b92782
			   rp[2] == '1' && rp[3] == '2') {
Packit Service b92782
			/* \012 is a NEWLINE.  */
Packit Service b92782
			*wp++ = '\n';
Packit Service b92782
			rp += 3;
Packit Service b92782
		} else if (rp[0] == '\\' && rp[1] == '\\') {
Packit Service b92782
			/*
Packit Service b92782
			 * We have to escape \\ to be able to represent
Packit Service b92782
			 * all characters.
Packit Service b92782
			 */
Packit Service b92782
			*wp++ = '\\';
Packit Service b92782
			rp += 1;
Packit Service b92782
		} else if (rp[0] == '\\' && rp[1] == '1' &&
Packit Service b92782
			   rp[2] == '3' && rp[3] == '4') {
Packit Service b92782
			/* \134 is also \\.  */
Packit Service b92782
			*wp++ = '\\';
Packit Service b92782
			rp += 3;
Packit Service b92782
		} else
Packit Service b92782
			*wp++ = *rp;
Packit Service b92782
	} while (*rp++ != '\0');
Packit Service b92782
Packit Service b92782
	return buf;
Packit Service b92782
}
Packit Service b92782
Packit Service b92782
/* From glibc getmntent_r() */
Packit Service b92782
static struct mntent *
Packit Service b92782
local_getmntent_r(FILE *tab, struct mntent *mnt, char *buf, int size)
Packit Service b92782
{
Packit Service b92782
	char *cp, *head;
Packit Service b92782
Packit Service b92782
	do {
Packit Service b92782
		char *end_ptr;
Packit Service b92782
Packit Service b92782
		if (fgets(buf, size, tab) == NULL)
Packit Service b92782
			return 0;
Packit Service b92782
Packit Service b92782
		end_ptr = strchr(buf, '\n');
Packit Service b92782
		if (end_ptr != NULL) {
Packit Service b92782
			while (end_ptr[-1] == ' ' || end_ptr[-1] == '\t')
Packit Service b92782
				end_ptr--;
Packit Service b92782
			*end_ptr = '\0';
Packit Service b92782
		} else {
Packit Service b92782
			/* Whole line was not read. Do it now but forget it. */
Packit Service b92782
			char tmp[1024];
Packit Service b92782
			while (fgets(tmp, sizeof tmp, tab) != NULL)
Packit Service b92782
				if (strchr(tmp, '\n') != NULL)
Packit Service b92782
					break;
Packit Service b92782
		}
Packit Service b92782
Packit Service b92782
		head = buf + strspn(buf, " \t");
Packit Service b92782
	/* skip empty lines and comment lines */
Packit Service b92782
	} while (head[0] == '\0' || head[0] == '#');
Packit Service b92782
Packit Service b92782
	cp = strsep(&head, " \t");
Packit Service b92782
	mnt->mnt_fsname = cp != NULL ? local_decode_name(cp) : (char *) "";
Packit Service b92782
	if (head)
Packit Service b92782
		head += strspn(head, " \t");
Packit Service b92782
	cp = strsep(&head, " \t");
Packit Service b92782
	mnt->mnt_dir = cp != NULL ? local_decode_name (cp) : (char *) "";
Packit Service b92782
	if (head)
Packit Service b92782
		head += strspn(head, " \t");
Packit Service b92782
	cp = strsep(&head, " \t");
Packit Service b92782
	mnt->mnt_type = cp != NULL ? local_decode_name (cp) : (char *) "";
Packit Service b92782
	if (head)
Packit Service b92782
		head += strspn (head, " \t");
Packit Service b92782
	cp = strsep (&head, " \t");
Packit Service b92782
	mnt->mnt_opts = cp != NULL ? local_decode_name (cp) : (char *) "";
Packit Service b92782
Packit Service b92782
	/* autofs doesn't need freq or passno */
Packit Service b92782
Packit Service b92782
	return mnt;
Packit Service b92782
}
Packit Service b92782
Packit Service 559e19
int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
Packit Service 559e19
{
Packit Service 559e19
	struct mnt_list *this;
Packit Service 559e19
	int rv, ret;
Packit Service 559e19
Packit Service 559e19
	ret = 1;
Packit Service 559e19
	this = mnts;
Packit Service 559e19
	while (this) {
Packit Service 559e19
		if (this->flags & MNTS_AUTOFS)
Packit Service 559e19
			rv = umount2(this->mp, MNT_DETACH);
Packit Service 559e19
		else
Packit Service 559e19
			rv = spawn_umount(ap->logopt, "-l", this->mp, NULL);
Packit Service 559e19
		if (rv == -1) {
Packit Service 559e19
			debug(ap->logopt,
Packit Service 559e19
			      "can't unlink %s from mount tree", this->mp);
Packit Service 559e19
Packit Service 559e19
			switch (errno) {
Packit Service 559e19
			case EINVAL:
Packit Service 559e19
				warn(ap->logopt,
Packit Service 559e19
				      "bad superblock or not mounted");
Packit Service 559e19
				break;
Packit Service 559e19
Packit Service 559e19
			case ENOENT:
Packit Service 559e19
			case EFAULT:
Packit Service 559e19
				ret = 0;
Packit Service 559e19
				warn(ap->logopt, "bad path for mount");
Packit Service 559e19
				break;
Packit Service 559e19
			}
Packit Service 559e19
		}
Packit Service 559e19
		this = this->next;
Packit Service 559e19
	}
Packit Service 559e19
Packit Service 559e19
	return ret;
Packit Service 559e19
}
Packit Service 559e19
Packit 8480eb
/*
Packit 8480eb
 * Get list of mounts under path in longest->shortest order
Packit 8480eb
 */
Packit Service 4ea472
struct mnt_list *get_mnt_list(const char *path, int include)
Packit 8480eb
{
Packit 8480eb
	FILE *tab;
Packit 8480eb
	size_t pathlen = strlen(path);
Packit 8480eb
	struct mntent mnt_wrk;
Packit 8480eb
	char buf[PATH_MAX * 3];
Packit 8480eb
	struct mntent *mnt;
Packit 8480eb
	struct mnt_list *ent, *mptr, *last;
Packit 8480eb
	struct mnt_list *list = NULL;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	if (!path || !pathlen || pathlen > PATH_MAX)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit Service 4ea472
	tab = open_setmntent_r(_PROC_MOUNTS);
Packit 8480eb
	if (!tab) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, PATH_MAX - 1);
Packit Service 42268b
		logerr("setmntent: %s", estr);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit Service 42268b
	while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
Packit 8480eb
		len = strlen(mnt->mnt_dir);
Packit 8480eb
Packit 8480eb
		if ((!include && len <= pathlen) ||
Packit 8480eb
	  	     strncmp(mnt->mnt_dir, path, pathlen) != 0)
Packit 8480eb
			continue;
Packit 8480eb
Packit Service ba7922
		/* Not a subdirectory of requested mp? */
Packit Service ba7922
		/* mp_len == 1 => everything is subdir    */
Packit 8480eb
		if (pathlen > 1 && len > pathlen &&
Packit 8480eb
				mnt->mnt_dir[pathlen] != '/')
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		ent = malloc(sizeof(*ent));
Packit 8480eb
		if (!ent) {
Packit 8480eb
			endmntent(tab);
Packit 8480eb
			free_mnt_list(list);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
		memset(ent, 0, sizeof(*ent));
Packit 8480eb
Packit 8480eb
		mptr = list;
Packit 8480eb
		last = NULL;
Packit 8480eb
		while (mptr) {
Packit Service ba7922
			if (len >= strlen(mptr->mp))
Packit 8480eb
				break;
Packit 8480eb
			last = mptr;
Packit 8480eb
			mptr = mptr->next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (mptr == list)
Packit 8480eb
			list = ent;
Packit 8480eb
		else
Packit 8480eb
			last->next = ent;
Packit 8480eb
Packit 8480eb
		ent->next = mptr;
Packit 8480eb
Packit Service ba7922
		ent->mp = malloc(len + 1);
Packit Service ba7922
		if (!ent->mp) {
Packit Service 71cd40
			endmntent(tab);
Packit Service 71cd40
			free_mnt_list(list);
Packit Service 71cd40
			return NULL;
Packit Service 71cd40
		}
Packit Service ba7922
		strcpy(ent->mp, mnt->mnt_dir);
Packit Service 42268b
Packit Service ac2cd1
		if (!strcmp(mnt->mnt_type, "autofs"))
Packit Service ac2cd1
			ent->flags |= MNTS_AUTOFS;
Packit Service ac2cd1
Packit Service ac2cd1
		if (ent->flags & MNTS_AUTOFS) {
Packit Service ac2cd1
			if (strstr(mnt->mnt_opts, "indirect"))
Packit Service ac2cd1
				ent->flags |= MNTS_INDIRECT;
Packit Service ac2cd1
			else if (strstr(mnt->mnt_opts, "direct"))
Packit Service ac2cd1
				ent->flags |= MNTS_DIRECT;
Packit Service ac2cd1
			else if (strstr(mnt->mnt_opts, "offset"))
Packit Service ac2cd1
				ent->flags |= MNTS_OFFSET;
Packit Service 42268b
		}
Packit 8480eb
	}
Packit Service 42268b
	endmntent(tab);
Packit 8480eb
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void free_mnt_list(struct mnt_list *list)
Packit 8480eb
{
Packit 8480eb
	struct mnt_list *next;
Packit 8480eb
Packit 8480eb
	if (!list)
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	next = list;
Packit 8480eb
	while (next) {
Packit 8480eb
		struct mnt_list *this = next;
Packit 8480eb
Packit 8480eb
		next = this->next;
Packit 8480eb
Packit Service ba7922
		if (this->mp)
Packit Service ba7922
			free(this->mp);
Packit Service 42268b
Packit 8480eb
		free(this);
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit Service 4ea472
static int table_is_mounted(const char *mp, unsigned int type)
Packit 8480eb
{
Packit 8480eb
	struct mntent *mnt;
Packit 8480eb
	struct mntent mnt_wrk;
Packit 8480eb
	char buf[PATH_MAX * 3];
Packit Service ba7922
	size_t mp_len = strlen(mp);
Packit 8480eb
	FILE *tab;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit Service ba7922
	if (!mp || !mp_len || mp_len >= PATH_MAX)
Packit 8480eb
		return 0;
Packit 8480eb
Packit Service 2b5401
	tab = open_fopen_r(_PROC_MOUNTS);
Packit 8480eb
	if (!tab) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, PATH_MAX - 1);
Packit Service 2b5401
		logerr("fopen: %s", estr);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit Service 2b5401
	while ((mnt = local_getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
Packit 8480eb
		size_t len = strlen(mnt->mnt_dir);
Packit 8480eb
Packit 8480eb
		if (type) {
Packit 8480eb
			unsigned int autofs_fs;
Packit 8480eb
Packit 8480eb
			autofs_fs = !strcmp(mnt->mnt_type, "autofs");
Packit 8480eb
Packit 8480eb
			if (type & MNTS_REAL)
Packit 8480eb
				if (autofs_fs)
Packit 8480eb
					continue;
Packit 8480eb
Packit 8480eb
			if (type & MNTS_AUTOFS)
Packit 8480eb
				if (!autofs_fs)
Packit 8480eb
					continue;
Packit 8480eb
		}
Packit 8480eb
Packit Service ba7922
		if (mp_len == len && !strncmp(mp, mnt->mnt_dir, mp_len)) {
Packit 8480eb
			ret = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit Service 2b5401
	fclose(tab);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit Service 4ea472
static int ioctl_is_mounted(const char *mp, unsigned int type)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	unsigned int mounted;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	/* If the ioctl fails fall back to the potentially resource
Packit 8480eb
	 * intensive mount table check.
Packit 8480eb
	 */
Packit Service ba7922
	ret = ops->ismountpoint(LOGOPT_NONE, -1, mp, &mounted);
Packit 8480eb
	if (ret == -1)
Packit Service 4ea472
		return table_is_mounted(mp, type);
Packit 8480eb
Packit 8480eb
	if (mounted) {
Packit 8480eb
		switch (type) {
Packit 8480eb
		case MNTS_ALL:
Packit 8480eb
			return 1;
Packit 8480eb
		case MNTS_AUTOFS:
Packit 8480eb
			return (mounted & DEV_IOCTL_IS_AUTOFS);
Packit 8480eb
		case MNTS_REAL:
Packit 8480eb
			return (mounted & DEV_IOCTL_IS_OTHER);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit Service 4ea472
int is_mounted(const char *mp, unsigned int type)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
Packit 8480eb
	if (ops->ismountpoint)
Packit Service 4ea472
		return ioctl_is_mounted(mp, type);
Packit 8480eb
	else
Packit Service 4ea472
		return table_is_mounted(mp, type);
Packit Service 42268b
}
Packit Service 42268b
Packit 8480eb
/*
Packit 8480eb
 * Since we have to look at the entire mount tree for direct
Packit 8480eb
 * mounts (all mounts under "/") and we may have a large number
Packit 8480eb
 * of entries to traverse again and again we need to
Packit 8480eb
 * use a more efficient method than the routines above.
Packit 8480eb
 *
Packit 8480eb
 * Thre tree_... routines allow us to read the mount tree
Packit 8480eb
 * once and pass it to subsequent functions for use. Since
Packit 8480eb
 * it's a tree structure searching should be a low overhead
Packit 8480eb
 * operation.
Packit 8480eb
 */
Packit 8480eb
void tree_free_mnt_tree(struct mnt_list *tree)
Packit 8480eb
{
Packit 8480eb
	struct list_head *head, *p;
Packit 8480eb
Packit 8480eb
	if (!tree)
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	tree_free_mnt_tree(tree->left);
Packit 8480eb
	tree_free_mnt_tree(tree->right);
Packit 8480eb
Packit 8480eb
	head = &tree->self;
Packit 8480eb
	p = head->next;
Packit 8480eb
	while (p != head) {
Packit 8480eb
		struct mnt_list *this;
Packit 8480eb
Packit 8480eb
		this = list_entry(p, struct mnt_list, self);
Packit 8480eb
Packit 8480eb
		p = p->next;
Packit 8480eb
Packit 8480eb
		list_del(&this->self);
Packit 8480eb
Packit Service ba7922
		free(this->mp);
Packit 8480eb
Packit 8480eb
		free(this);
Packit 8480eb
	}
Packit 8480eb
Packit Service ba7922
	free(tree->mp);
Packit 8480eb
	free(tree);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Make tree of system mounts in /proc/mounts.
Packit 8480eb
 */
Packit Service 4ea472
struct mnt_list *tree_make_mnt_tree(const char *path)
Packit 8480eb
{
Packit 8480eb
	FILE *tab;
Packit 8480eb
	struct mntent mnt_wrk;
Packit 8480eb
	char buf[PATH_MAX * 3];
Packit 8480eb
	struct mntent *mnt;
Packit 8480eb
	struct mnt_list *ent, *mptr;
Packit 8480eb
	struct mnt_list *tree = NULL;
Packit 8480eb
	size_t plen;
Packit 8480eb
	int eq;
Packit 8480eb
Packit Service 4ea472
	tab = open_setmntent_r(_PROC_MOUNTS);
Packit 8480eb
	if (!tab) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, PATH_MAX - 1);
Packit Service 42268b
		logerr("setmntent: %s", estr);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	plen = strlen(path);
Packit 8480eb
Packit Service 42268b
	while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
Packit 8480eb
		size_t len = strlen(mnt->mnt_dir);
Packit 8480eb
Packit 8480eb
		/* Not matching path */
Packit 8480eb
		if (strncmp(mnt->mnt_dir, path, plen))
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		/* Not a subdirectory of requested path */
Packit 8480eb
		if (plen > 1 && len > plen && mnt->mnt_dir[plen] != '/')
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		ent = malloc(sizeof(*ent));
Packit 8480eb
		if (!ent) {
Packit 8480eb
			endmntent(tab);
Packit 8480eb
			tree_free_mnt_tree(tree);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
		memset(ent, 0, sizeof(*ent));
Packit 8480eb
Packit 8480eb
		INIT_LIST_HEAD(&ent->self);
Packit 8480eb
		INIT_LIST_HEAD(&ent->list);
Packit 8480eb
		INIT_LIST_HEAD(&ent->entries);
Packit 8480eb
		INIT_LIST_HEAD(&ent->sublist);
Packit 8480eb
Packit Service ba7922
		ent->mp = malloc(len + 1);
Packit Service ba7922
		if (!ent->mp) {
Packit Service 42268b
			endmntent(tab);
Packit Service 42268b
			free(ent);
Packit Service 42268b
			tree_free_mnt_tree(tree);
Packit Service 42268b
			return NULL;
Packit Service 42268b
		}
Packit Service ba7922
		strcpy(ent->mp, mnt->mnt_dir);
Packit Service 42268b
Packit Service ac2cd1
		if (!strcmp(mnt->mnt_type, "autofs"))
Packit Service ac2cd1
			ent->flags |= MNTS_AUTOFS;
Packit Service 42268b
Packit Service ac2cd1
		if (ent->flags & MNTS_AUTOFS) {
Packit Service ac2cd1
			if (strstr(mnt->mnt_opts, "indirect"))
Packit Service ac2cd1
				ent->flags |= MNTS_INDIRECT;
Packit Service ac2cd1
			else if (strstr(mnt->mnt_opts, "direct"))
Packit Service ac2cd1
				ent->flags |= MNTS_DIRECT;
Packit Service ac2cd1
			else if (strstr(mnt->mnt_opts, "offset"))
Packit Service ac2cd1
				ent->flags |= MNTS_OFFSET;
Packit 8480eb
		}
Packit Service 42268b
Packit 8480eb
		mptr = tree;
Packit 8480eb
		while (mptr) {
Packit Service ba7922
			int elen = strlen(ent->mp);
Packit Service ba7922
			int mlen = strlen(mptr->mp);
Packit 8480eb
Packit 8480eb
			if (elen < mlen) {
Packit 8480eb
				if (mptr->left) {
Packit 8480eb
					mptr = mptr->left;
Packit 8480eb
					continue;
Packit 8480eb
				} else {
Packit 8480eb
					mptr->left = ent;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
			} else if (elen > mlen) {
Packit 8480eb
				if (mptr->right) {
Packit 8480eb
					mptr = mptr->right;
Packit 8480eb
					continue;
Packit 8480eb
				} else {
Packit 8480eb
					mptr->right = ent;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
Packit Service ba7922
			eq = strcmp(ent->mp, mptr->mp);
Packit 8480eb
			if (eq < 0) {
Packit 8480eb
				if (mptr->left)
Packit 8480eb
					mptr = mptr->left;
Packit 8480eb
				else {
Packit 8480eb
					mptr->left = ent;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
			} else if (eq > 0) {
Packit 8480eb
				if (mptr->right)
Packit 8480eb
					mptr = mptr->right;
Packit 8480eb
				else {
Packit 8480eb
					mptr->right = ent;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
			} else {
Packit 8480eb
				list_add_tail(&ent->self, &mptr->self);
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!tree)
Packit 8480eb
			tree = ent;
Packit 8480eb
	}
Packit Service 42268b
	endmntent(tab);
Packit 8480eb
Packit 8480eb
	return tree;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Get list of mounts under "path" in longest->shortest order
Packit 8480eb
 */
Packit 8480eb
int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include)
Packit 8480eb
{
Packit 8480eb
	size_t mlen, plen;
Packit 8480eb
Packit 8480eb
	if (!mnts)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	plen = strlen(path);
Packit Service ba7922
	mlen = strlen(mnts->mp);
Packit 8480eb
	if (mlen < plen)
Packit 8480eb
		return tree_get_mnt_list(mnts->right, list, path, include);
Packit 8480eb
	else {
Packit 8480eb
		struct list_head *self, *p;
Packit 8480eb
Packit 8480eb
		tree_get_mnt_list(mnts->left, list, path, include);
Packit 8480eb
Packit 8480eb
		if ((!include && mlen <= plen) ||
Packit Service ba7922
				strncmp(mnts->mp, path, plen))
Packit 8480eb
			goto skip;
Packit 8480eb
Packit Service ba7922
		if (plen > 1 && mlen > plen && mnts->mp[plen] != '/')
Packit 8480eb
			goto skip;
Packit 8480eb
Packit 8480eb
		INIT_LIST_HEAD(&mnts->list);
Packit 8480eb
		list_add(&mnts->list, list);
Packit 8480eb
Packit 8480eb
		self = &mnts->self;
Packit 8480eb
		list_for_each(p, self) {
Packit 8480eb
			struct mnt_list *this;
Packit 8480eb
Packit 8480eb
			this = list_entry(p, struct mnt_list, self);
Packit 8480eb
			INIT_LIST_HEAD(&this->list);
Packit 8480eb
			list_add(&this->list, list);
Packit 8480eb
		}
Packit 8480eb
skip:
Packit 8480eb
		tree_get_mnt_list(mnts->right, list, path, include);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (list_empty(list))
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Get list of mounts under "path" in longest->shortest order
Packit 8480eb
 */
Packit 8480eb
int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include)
Packit 8480eb
{
Packit 8480eb
	size_t mlen, plen;
Packit 8480eb
Packit 8480eb
	if (!mnts)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	plen = strlen(path);
Packit Service ba7922
	mlen = strlen(mnts->mp);
Packit 8480eb
	if (mlen < plen)
Packit 8480eb
		return tree_get_mnt_sublist(mnts->right, list, path, include);
Packit 8480eb
	else {
Packit 8480eb
		struct list_head *self, *p;
Packit 8480eb
Packit 8480eb
		tree_get_mnt_sublist(mnts->left, list, path, include);
Packit 8480eb
Packit 8480eb
		if ((!include && mlen <= plen) ||
Packit Service ba7922
				strncmp(mnts->mp, path, plen))
Packit 8480eb
			goto skip;
Packit 8480eb
Packit Service ba7922
		if (plen > 1 && mlen > plen && mnts->mp[plen] != '/')
Packit 8480eb
			goto skip;
Packit 8480eb
Packit 8480eb
		INIT_LIST_HEAD(&mnts->sublist);
Packit 8480eb
		list_add(&mnts->sublist, list);
Packit 8480eb
Packit 8480eb
		self = &mnts->self;
Packit 8480eb
		list_for_each(p, self) {
Packit 8480eb
			struct mnt_list *this;
Packit 8480eb
Packit 8480eb
			this = list_entry(p, struct mnt_list, self);
Packit 8480eb
			INIT_LIST_HEAD(&this->sublist);
Packit 8480eb
			list_add(&this->sublist, list);
Packit 8480eb
		}
Packit 8480eb
skip:
Packit 8480eb
		tree_get_mnt_sublist(mnts->right, list, path, include);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (list_empty(list))
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path)
Packit 8480eb
{
Packit 8480eb
	int mlen, plen;
Packit 8480eb
Packit 8480eb
	if (!mnts)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	plen = strlen(path);
Packit Service ba7922
	mlen = strlen(mnts->mp);
Packit 8480eb
	if (mlen < plen)
Packit 8480eb
		return tree_find_mnt_ents(mnts->right, list, path);
Packit 8480eb
	else if (mlen > plen)
Packit 8480eb
		return tree_find_mnt_ents(mnts->left, list, path);
Packit 8480eb
	else {
Packit 8480eb
		struct list_head *self, *p;
Packit 8480eb
Packit 8480eb
		tree_find_mnt_ents(mnts->left, list, path);
Packit 8480eb
Packit Service ba7922
		if (!strcmp(mnts->mp, path)) {
Packit 8480eb
			INIT_LIST_HEAD(&mnts->entries);
Packit 8480eb
			list_add(&mnts->entries, list);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		self = &mnts->self;
Packit 8480eb
		list_for_each(p, self) {
Packit 8480eb
			struct mnt_list *this;
Packit 8480eb
Packit 8480eb
			this = list_entry(p, struct mnt_list, self);
Packit 8480eb
Packit Service ba7922
			if (!strcmp(this->mp, path)) {
Packit 8480eb
				INIT_LIST_HEAD(&this->entries);
Packit 8480eb
				list_add(&this->entries, list);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		tree_find_mnt_ents(mnts->right, list, path);
Packit 8480eb
Packit 8480eb
		if (!list_empty(list))
Packit 8480eb
			return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void set_tsd_user_vars(unsigned int logopt, uid_t uid, gid_t gid)
Packit 8480eb
{
Packit 8480eb
	struct thread_stdenv_vars *tsv;
Packit 8480eb
	struct passwd pw;
Packit 8480eb
	struct passwd *ppw = &pw;
Packit 8480eb
	struct passwd **pppw = &pp;;
Packit 8480eb
	struct group gr;
Packit 8480eb
	struct group *pgr;
Packit 8480eb
	struct group **ppgr;
Packit 8480eb
	char *pw_tmp, *gr_tmp;
Packit 8480eb
	int status, tmplen, grplen;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Setup thread specific data values for macro
Packit 8480eb
	 * substution in map entries during the mount.
Packit 8480eb
	 * Best effort only as it must go ahead.
Packit 8480eb
	 */
Packit 8480eb
Packit 8480eb
	tsv = malloc(sizeof(struct thread_stdenv_vars));
Packit 8480eb
	if (!tsv) {
Packit 8480eb
		error(logopt, "failed alloc tsv storage");
Packit 8480eb
		return;
Packit 8480eb
	}
Packit 8480eb
	memset(tsv, 0, sizeof(struct thread_stdenv_vars));
Packit 8480eb
Packit 8480eb
	tsv->uid = uid;
Packit 8480eb
	tsv->gid = gid;
Packit 8480eb
Packit 8480eb
	/* Try to get passwd info */
Packit 8480eb
Packit 8480eb
	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
Packit 8480eb
	if (tmplen < 0) {
Packit 8480eb
		error(logopt, "failed to get buffer size for getpwuid_r");
Packit 8480eb
		goto free_tsv;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	pw_tmp = malloc(tmplen + 1);
Packit 8480eb
	if (!pw_tmp) {
Packit 8480eb
		error(logopt, "failed to malloc buffer for getpwuid_r");
Packit 8480eb
		goto free_tsv;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = getpwuid_r(uid, ppw, pw_tmp, tmplen, pppw);
Packit 8480eb
	if (status || !ppw) {
Packit 8480eb
		error(logopt, "failed to get passwd info from getpwuid_r");
Packit 8480eb
		free(pw_tmp);
Packit 8480eb
		goto free_tsv;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tsv->user = strdup(pw.pw_name);
Packit 8480eb
	if (!tsv->user) {
Packit 8480eb
		error(logopt, "failed to malloc buffer for user");
Packit 8480eb
		free(pw_tmp);
Packit 8480eb
		goto free_tsv;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	tsv->home = strdup(pw.pw_dir);
Packit 8480eb
	if (!tsv->home) {
Packit 8480eb
		error(logopt, "failed to malloc buffer for home");
Packit 8480eb
		free(pw_tmp);
Packit 8480eb
		goto free_tsv_user;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	free(pw_tmp);
Packit 8480eb
Packit 8480eb
	/* Try to get group info */
Packit 8480eb
Packit 8480eb
	grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
Packit 8480eb
	if (grplen < 0) {
Packit 8480eb
		error(logopt, "failed to get buffer size for getgrgid_r");
Packit 8480eb
		goto free_tsv_home;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	gr_tmp = NULL;
Packit 8480eb
	status = ERANGE;
Packit 8480eb
#ifdef ENABLE_LIMIT_GETGRGID_SIZE
Packit 8480eb
	if (!maxgrpbuf)
Packit 8480eb
		maxgrpbuf = detached_thread_stack_size * 0.9;
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
	/* If getting the group name fails go on without it. It's
Packit 8480eb
	 * used to set an environment variable for program maps
Packit 8480eb
	 * which may or may not use it so it isn't critical to
Packit 8480eb
	 * operation.
Packit 8480eb
	 */
Packit 8480eb
Packit 8480eb
	tmplen = grplen;
Packit 8480eb
	while (1) {
Packit 8480eb
		char *tmp = realloc(gr_tmp, tmplen + 1);
Packit 8480eb
		if (!tmp) {
Packit 8480eb
			error(logopt, "failed to malloc buffer for getgrgid_r");
Packit 8480eb
			goto no_group;
Packit 8480eb
		}
Packit 8480eb
		gr_tmp = tmp;
Packit 8480eb
		pgr = &gr;
Packit 8480eb
		ppgr = &pg;;
Packit 8480eb
		status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr);
Packit 8480eb
		if (status != ERANGE)
Packit 8480eb
			break;
Packit 8480eb
		tmplen += grplen;
Packit 8480eb
Packit 8480eb
		/* Don't tempt glibc to alloca() larger than is (likely)
Packit 8480eb
		 * available on the stack if limit-getgrgid-size is enabled.
Packit 8480eb
		 */
Packit 8480eb
		if (!maxgrpbuf || (tmplen < maxgrpbuf))
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		/* Add a message so we know this happened */
Packit 8480eb
		debug(logopt, "group buffer allocation would be too large");
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
no_group:
Packit 8480eb
	if (status || !pgr)
Packit 8480eb
		error(logopt, "failed to get group info from getgrgid_r");
Packit 8480eb
	else {
Packit 8480eb
		tsv->group = strdup(gr.gr_name);
Packit 8480eb
		if (!tsv->group)
Packit 8480eb
			error(logopt, "failed to malloc buffer for group");
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (gr_tmp)
Packit 8480eb
		free(gr_tmp);
Packit 8480eb
Packit 8480eb
	status = pthread_setspecific(key_thread_stdenv_vars, tsv);
Packit 8480eb
	if (status) {
Packit 8480eb
		error(logopt, "failed to set stdenv thread var");
Packit 8480eb
		goto free_tsv_group;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
Packit 8480eb
free_tsv_group:
Packit 8480eb
	if (tsv->group)
Packit 8480eb
		free(tsv->group);
Packit 8480eb
free_tsv_home:
Packit 8480eb
	free(tsv->home);
Packit 8480eb
free_tsv_user:
Packit 8480eb
	free(tsv->user);
Packit 8480eb
free_tsv:
Packit 8480eb
	free(tsv);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
const char *mount_type_str(const unsigned int type)
Packit 8480eb
{
Packit 8480eb
	static const char *str_type[] = {
Packit 8480eb
		"indirect",
Packit 8480eb
		"direct",
Packit 8480eb
		"offset"
Packit 8480eb
	};
Packit 8480eb
	unsigned int pos, i;
Packit 8480eb
Packit 8480eb
	for (pos = 0, i = type; pos < type_count; i >>= 1, pos++)
Packit 8480eb
		if (i & 0x1)
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
	return (pos == type_count ? NULL : str_type[pos]);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void set_exp_timeout(struct autofs_point *ap,
Packit 8480eb
		     struct map_source *source, time_t timeout)
Packit 8480eb
{
Packit 8480eb
	ap->exp_timeout = timeout;
Packit 8480eb
	if (source)
Packit 8480eb
		source->exp_timeout = timeout;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
time_t get_exp_timeout(struct autofs_point *ap, struct map_source *source)
Packit 8480eb
{
Packit 8480eb
	time_t timeout = ap->exp_timeout;
Packit 8480eb
Packit 8480eb
	if (source && ap->type == LKP_DIRECT)
Packit 8480eb
		timeout = source->exp_timeout;
Packit 8480eb
Packit 8480eb
	return timeout;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void notify_mount_result(struct autofs_point *ap,
Packit 8480eb
			 const char *path, time_t timeout, const char *type)
Packit 8480eb
{
Packit 8480eb
	if (timeout)
Packit 8480eb
		info(ap->logopt,
Packit 8480eb
		    "mounted %s on %s with timeout %u, freq %u seconds",
Packit 8480eb
		    type, path, (unsigned int) timeout,
Packit 8480eb
		    (unsigned int) ap->exp_runfreq);
Packit 8480eb
	else
Packit 8480eb
		info(ap->logopt,
Packit 8480eb
		     "mounted %s on %s with timeouts disabled",
Packit 8480eb
		     type, path);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_remount_direct(struct autofs_point *ap, int fd, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	int status = REMOUNT_SUCCESS;
Packit 8480eb
	uid_t uid;
Packit 8480eb
	gid_t gid;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	ops->requester(ap->logopt, fd, path, &uid, &gid;;
Packit 8480eb
	if (uid != -1 && gid != -1)
Packit 8480eb
		set_tsd_user_vars(ap->logopt, uid, gid);
Packit 8480eb
Packit 8480eb
	ret = lookup_nss_mount(ap, NULL, path, strlen(path));
Packit 8480eb
	if (ret)
Packit 8480eb
		info(ap->logopt, "re-connected to %s", path);
Packit 8480eb
	else {
Packit 8480eb
		status = REMOUNT_FAIL;
Packit 8480eb
		info(ap->logopt, "failed to re-connect %s", path);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return status;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_remount_indirect(struct autofs_point *ap, int fd, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	int status = REMOUNT_SUCCESS;
Packit 8480eb
	struct dirent **de;
Packit 8480eb
	char buf[PATH_MAX + 1];
Packit 8480eb
	uid_t uid;
Packit 8480eb
	gid_t gid;
Packit 8480eb
	unsigned int mounted;
Packit 8480eb
	int n, size;
Packit 8480eb
Packit 8480eb
	n = scandir(path, &de, 0, alphasort);
Packit 8480eb
	if (n < 0)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	size = sizeof(buf);
Packit 8480eb
Packit 8480eb
	while (n--) {
Packit 8480eb
		int ret, len;
Packit 8480eb
Packit 8480eb
		if (strcmp(de[n]->d_name, ".") == 0 ||
Packit 8480eb
		    strcmp(de[n]->d_name, "..") == 0) {
Packit 8480eb
			free(de[n]);
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		ret = cat_path(buf, size, path, de[n]->d_name);
Packit 8480eb
		if (!ret) {
Packit 8480eb
			do {
Packit 8480eb
				free(de[n]);
Packit 8480eb
			} while (n--);
Packit 8480eb
			free(de);
Packit 8480eb
			return -1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		ops->ismountpoint(ap->logopt, -1, buf, &mounted);
Packit 8480eb
		if (!mounted) {
Packit 8480eb
			struct dirent **de2;
Packit 8480eb
			int i, j;
Packit 8480eb
Packit 8480eb
			i = j = scandir(buf, &de2, 0, alphasort);
Packit 8480eb
			if (i < 0) {
Packit 8480eb
				free(de[n]);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
			while (i--)
Packit 8480eb
				free(de2[i]);
Packit 8480eb
			free(de2);
Packit 8480eb
			if (j <= 2) {
Packit 8480eb
				free(de[n]);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		ops->requester(ap->logopt, fd, buf, &uid, &gid;;
Packit 8480eb
		if (uid != -1 && gid != -1)
Packit 8480eb
			set_tsd_user_vars(ap->logopt, uid, gid);
Packit 8480eb
Packit 8480eb
		len = strlen(de[n]->d_name);
Packit 8480eb
Packit 8480eb
		ret = lookup_nss_mount(ap, NULL, de[n]->d_name, len);
Packit 8480eb
		if (ret)
Packit 8480eb
			info(ap->logopt, "re-connected to %s", buf);
Packit 8480eb
		else {
Packit 8480eb
			status = REMOUNT_FAIL;
Packit 8480eb
			info(ap->logopt, "failed to re-connect %s", buf);
Packit 8480eb
		}
Packit 8480eb
		free(de[n]);
Packit 8480eb
	}
Packit 8480eb
	free(de);
Packit 8480eb
Packit 8480eb
	return status;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int remount_active_mount(struct autofs_point *ap,
Packit 8480eb
				struct mapent *me, const char *path, dev_t devid,
Packit 8480eb
				const unsigned int type, int *ioctlfd)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	const char *str_type = mount_type_str(type);
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	unsigned int mounted;
Packit 8480eb
	time_t timeout;
Packit 8480eb
	struct stat st;
Packit 8480eb
	int fd;
Packit 8480eb
Packit 8480eb
	*ioctlfd = -1;
Packit 8480eb
Packit 8480eb
	/* Open failed, no mount present */
Packit 8480eb
	ops->open(ap->logopt, &fd, devid, path);
Packit 8480eb
	if (fd == -1)
Packit 8480eb
		return REMOUNT_OPEN_FAIL;
Packit 8480eb
Packit 8480eb
	if (!me)
Packit 8480eb
		timeout = get_exp_timeout(ap, NULL);
Packit 8480eb
	else
Packit 8480eb
		timeout = get_exp_timeout(ap, me->source);
Packit 8480eb
Packit 8480eb
	/* Re-reading the map, set timeout and return */
Packit 8480eb
	if (ap->state == ST_READMAP) {
Packit 8480eb
		debug(ap->logopt, "already mounted, update timeout");
Packit 8480eb
		ops->timeout(ap->logopt, fd, timeout);
Packit 8480eb
		ops->close(ap->logopt, fd);
Packit 8480eb
		return REMOUNT_READ_MAP;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "trying to re-connect to mount %s", path);
Packit 8480eb
Packit 8480eb
	/* Mounted so set pipefd and timeout etc. */
Packit 8480eb
	if (ops->catatonic(ap->logopt, fd) == -1) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, "set catatonic failed: %s", estr);
Packit 8480eb
		debug(ap->logopt, "couldn't re-connect to mount %s", path);
Packit 8480eb
		ops->close(ap->logopt, fd);
Packit 8480eb
		return REMOUNT_OPEN_FAIL;
Packit 8480eb
	}
Packit 8480eb
	if (ops->setpipefd(ap->logopt, fd, ap->kpipefd) == -1) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, "set pipefd failed: %s", estr);
Packit 8480eb
		debug(ap->logopt, "couldn't re-connect to mount %s", path);
Packit 8480eb
		ops->close(ap->logopt, fd);
Packit 8480eb
		return REMOUNT_OPEN_FAIL;
Packit 8480eb
	}
Packit 8480eb
	ops->timeout(ap->logopt, fd, timeout);
Packit 8480eb
	if (fstat(fd, &st) == -1) {
Packit 8480eb
		error(ap->logopt,
Packit 8480eb
		      "failed to stat %s mount %s", str_type, path);
Packit 8480eb
		debug(ap->logopt, "couldn't re-connect to mount %s", path);
Packit 8480eb
		ops->close(ap->logopt, fd);
Packit 8480eb
		return REMOUNT_STAT_FAIL;
Packit 8480eb
	}
Packit 8480eb
	if (type != t_indirect)
Packit 8480eb
		cache_set_ino_index(me->mc, path, st.st_dev, st.st_ino);
Packit 8480eb
	else
Packit 8480eb
		ap->dev = st.st_dev;
Packit 8480eb
	notify_mount_result(ap, path, timeout, str_type);
Packit 8480eb
Packit 8480eb
	*ioctlfd = fd;
Packit 8480eb
Packit 8480eb
	/* Any mounts on or below? */
Packit 8480eb
	if (ops->ismountpoint(ap->logopt, fd, path, &mounted) == -1) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, "ismountpoint %s failed: %s", path, estr);
Packit 8480eb
		debug(ap->logopt, "couldn't re-connect to mount %s", path);
Packit 8480eb
		ops->close(ap->logopt, fd);
Packit 8480eb
		return REMOUNT_FAIL;
Packit 8480eb
	}
Packit 8480eb
	if (!mounted) {
Packit 8480eb
		/*
Packit 8480eb
		 * If we're an indirect mount we pass back the fd.
Packit 8480eb
		 * But if were a direct or offset mount with no active
Packit 8480eb
		 * mount we don't retain an open file descriptor.
Packit 8480eb
		 */
Packit 8480eb
		if (type != t_indirect) {
Packit 8480eb
			ops->close(ap->logopt, fd);
Packit 8480eb
			*ioctlfd = -1;
Packit 8480eb
		}
Packit 8480eb
	} else {
Packit 8480eb
		/*
Packit 8480eb
		 * What can I do if we can't remount the existing
Packit 8480eb
		 * mount(s) (possibly a partial failure), everything
Packit 8480eb
		 * following will be broken?
Packit 8480eb
		 */
Packit 8480eb
		if (type == t_indirect)
Packit 8480eb
			do_remount_indirect(ap, fd, path);
Packit 8480eb
		else
Packit 8480eb
			do_remount_direct(ap, fd, path);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "re-connected to mount %s", path);
Packit 8480eb
Packit 8480eb
	return REMOUNT_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int try_remount(struct autofs_point *ap, struct mapent *me, unsigned int type)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	const char *path;
Packit 8480eb
	int ret, fd;
Packit 8480eb
	dev_t devid;
Packit 8480eb
Packit 8480eb
	if (type == t_indirect)
Packit 8480eb
		path = ap->path;
Packit 8480eb
	else
Packit 8480eb
		path = me->key;
Packit 8480eb
Packit 8480eb
	ret = ops->mount_device(ap->logopt, path, type, &devid);
Packit 8480eb
	if (ret == -1 || ret == 0)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	ret = remount_active_mount(ap, me, path, devid, type, &fd;;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * The directory must exist since we found a device
Packit 8480eb
	 * number for the mount but we can't know if we created
Packit 8480eb
	 * it or not. However, if this is an indirect mount with
Packit 8480eb
	 * the nobrowse option we need to remove the mount point
Packit 8480eb
	 * directory at umount anyway.
Packit 8480eb
	 */
Packit 8480eb
	if (type == t_indirect) {
Packit 8480eb
		if (ap->flags & MOUNT_FLAG_GHOST)
Packit 8480eb
			ap->flags &= ~MOUNT_FLAG_DIR_CREATED;
Packit 8480eb
		else
Packit 8480eb
			ap->flags |= MOUNT_FLAG_DIR_CREATED;
Packit 8480eb
	} else
Packit 8480eb
		me->flags &= ~MOUNT_FLAG_DIR_CREATED;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Either we opened the mount or we're re-reading the map.
Packit 8480eb
	 * If we opened the mount and ioctlfd is not -1 we have
Packit 8480eb
	 * a descriptor for the indirect mount so we need to
Packit 8480eb
	 * record that in the mount point struct. Otherwise we're
Packit 8480eb
	 * re-reading the map.
Packit 8480eb
	*/
Packit 8480eb
	if (ret == REMOUNT_READ_MAP)
Packit 8480eb
		return 1;
Packit 8480eb
	else if (ret == REMOUNT_SUCCESS) {
Packit 8480eb
		if (fd != -1) {
Packit 8480eb
			if (type == t_indirect)
Packit 8480eb
				ap->ioctlfd = fd;
Packit 8480eb
			else
Packit 8480eb
				me->ioctlfd = fd;
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* Indirect mount requires a valid fd */
Packit 8480eb
		if (type != t_indirect)
Packit 8480eb
			return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Since we got the device number above a mount exists so
Packit 8480eb
	 * any other failure warrants a failure return here.
Packit 8480eb
	 */
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * When exiting mounts need be set catatonic, regardless of whether they
Packit 8480eb
 * are busy on not, to avoid a hang on access once the daemon has gone
Packit 8480eb
 * away.
Packit 8480eb
 */
Packit 8480eb
static int set_mount_catatonic(struct autofs_point *ap, struct mapent *me, int ioctlfd)
Packit 8480eb
{
Packit 8480eb
	struct ioctl_ops *ops = get_ioctl_ops();
Packit 8480eb
	unsigned int opened = 0;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *path;
Packit 8480eb
	int fd = -1;
Packit 8480eb
	int error;
Packit 8480eb
	dev_t dev;
Packit 8480eb
Packit 8480eb
	path = ap->path;
Packit 8480eb
	dev = ap->dev;
Packit 8480eb
	if (me && (ap->type == LKP_DIRECT || *me->key == '/')) {
Packit 8480eb
		path = me->key;
Packit 8480eb
		dev = me->dev;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ioctlfd >= 0)
Packit 8480eb
		fd = ioctlfd;
Packit 8480eb
	else if (me && me->ioctlfd >= 0)
Packit 8480eb
		fd = me->ioctlfd;
Packit 8480eb
	else {
Packit 8480eb
		error = ops->open(ap->logopt, &fd, dev, path);
Packit 8480eb
		if (error == -1) {
Packit 8480eb
			int err = errno;
Packit 8480eb
			char *estr;
Packit 8480eb
Packit 8480eb
			if (errno == ENOENT)
Packit 8480eb
				return 0;
Packit 8480eb
Packit 8480eb
			estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      "failed to open ioctlfd for %s, error: %s",
Packit 8480eb
			      path, estr);
Packit 8480eb
			return err;
Packit 8480eb
		}
Packit 8480eb
		opened = 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (fd >= 0) {
Packit 8480eb
		error = ops->catatonic(ap->logopt, fd);
Packit 8480eb
		if (error == -1) {
Packit 8480eb
			int err = errno;
Packit 8480eb
			char *estr;
Packit 8480eb
Packit 8480eb
			estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      "failed to set %s catatonic, error: %s",
Packit 8480eb
			      path, estr);
Packit 8480eb
			if (opened)
Packit 8480eb
				ops->close(ap->logopt, fd);
Packit 8480eb
			return err;
Packit 8480eb
		}
Packit 8480eb
		if (opened)
Packit 8480eb
			ops->close(ap->logopt, fd);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "set %s catatonic", path);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void set_multi_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
Packit 8480eb
{
Packit 8480eb
	if (!list_empty(&me->multi_list)) {
Packit 8480eb
		struct list_head *head = &me->multi_list;
Packit 8480eb
		struct list_head *p;
Packit 8480eb
Packit 8480eb
		list_for_each(p, head) {
Packit 8480eb
			struct mapent *this;
Packit 8480eb
Packit 8480eb
			this = list_entry(p, struct mapent, multi_list);
Packit 8480eb
			set_mount_catatonic(ap, this, this->ioctlfd);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void set_indirect_mount_tree_catatonic(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	struct master_mapent *entry = ap->entry;
Packit 8480eb
	struct map_source *map;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
Packit Service 4ea472
	if (!is_mounted(ap->path, MNTS_AUTOFS))
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	map = entry->maps;
Packit 8480eb
	while (map) {
Packit 8480eb
		mc = map->mc;
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		me = cache_enumerate(mc, NULL);
Packit 8480eb
		while (me) {
Packit 8480eb
			/* Skip negative map entries and wildcard entries */
Packit 8480eb
			if (!me->mapent)
Packit 8480eb
				goto next;
Packit 8480eb
Packit 8480eb
			if (!strcmp(me->key, "*"))
Packit 8480eb
				goto next;
Packit 8480eb
Packit 8480eb
			/* Only need to set offset mounts catatonic */
Packit 8480eb
			if (me->multi && me->multi == me)
Packit 8480eb
				set_multi_mount_tree_catatonic(ap, me);
Packit 8480eb
next:
Packit 8480eb
			me = cache_enumerate(mc, me);
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		map = map->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* By the time this function is called ap->ioctlfd will have
Packit 8480eb
	 * been closed so don't try and use it.
Packit 8480eb
	 */
Packit 8480eb
	set_mount_catatonic(ap, NULL, -1);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void set_direct_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
Packit 8480eb
{
Packit 8480eb
	/* Set offset mounts catatonic for this mapent */
Packit 8480eb
	if (me->multi && me->multi == me)
Packit 8480eb
		set_multi_mount_tree_catatonic(ap, me);
Packit 8480eb
	set_mount_catatonic(ap, me, me->ioctlfd);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int umount_ent(struct autofs_point *ap, const char *path)
Packit 8480eb
{
Packit 8480eb
	int rv;
Packit 8480eb
Packit 8480eb
	rv = spawn_umount(ap->logopt, path, NULL);
Packit 8480eb
	/* We are doing a forced shutcwdown down so unlink busy mounts */
Packit 8480eb
	if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) {
Packit 8480eb
		if (ap->state == ST_SHUTDOWN_FORCE) {
Packit 8480eb
			info(ap->logopt, "forcing umount of %s", path);
Packit 8480eb
			rv = spawn_umount(ap->logopt, "-l", path, NULL);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Verify that we actually unmounted the thing.  This is a
Packit 8480eb
		 * belt and suspenders approach to not eating user data.
Packit 8480eb
		 * We have seen cases where umount succeeds, but there is
Packit 8480eb
		 * still a file system mounted on the mount point.  How
Packit 8480eb
		 * this happens has not yet been determined, but we want to
Packit 8480eb
		 * make sure to return failure here, if that is the case,
Packit 8480eb
		 * so that we do not try to call rmdir_path on the
Packit 8480eb
		 * directory.
Packit 8480eb
		 */
Packit Service 4ea472
		if (!rv && is_mounted(path, MNTS_REAL)) {
Packit 8480eb
			crit(ap->logopt,
Packit 8480eb
			     "the umount binary reported that %s was "
Packit 8480eb
			     "unmounted, but there is still something "
Packit 8480eb
			     "mounted on this path.", path);
Packit 8480eb
			rv = -1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int umount_amd_ext_mount(struct autofs_point *ap, struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	int rv = 1;
Packit 8480eb
Packit 8480eb
	if (entry->umount) {
Packit 8480eb
		char *prog, *str;
Packit 8480eb
		char **argv;
Packit 8480eb
		int argc = -1;
Packit 8480eb
Packit 8480eb
		str = strdup(entry->umount);
Packit 8480eb
		if (!str)
Packit 8480eb
			goto out;
Packit 8480eb
Packit 8480eb
		prog = NULL;
Packit 8480eb
		argv = NULL;
Packit 8480eb
Packit 8480eb
		argc = construct_argv(str, &prog, &argv);
Packit 8480eb
		if (argc == -1) {
Packit 8480eb
			free(str);
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!ext_mount_remove(&entry->ext_mount, entry->fs)) {
Packit 8480eb
			rv =0;
Packit 8480eb
			goto out_free;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		rv = spawnv(ap->logopt, prog, (const char * const *) argv);
Packit 8480eb
		if (rv == -1 || (WIFEXITED(rv) && WEXITSTATUS(rv)))
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			     "failed to umount program mount at %s", entry->fs);
Packit 8480eb
		else {
Packit 8480eb
			rv = 0;
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      "umounted program mount at %s", entry->fs);
Packit 8480eb
			rmdir_path(ap, entry->fs, ap->dev);
Packit 8480eb
		}
Packit 8480eb
out_free:
Packit 8480eb
		free_argv(argc, (const char **) argv);
Packit 8480eb
		free(str);
Packit 8480eb
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ext_mount_remove(&entry->ext_mount, entry->fs)) {
Packit 8480eb
		rv = umount_ent(ap, entry->fs);
Packit 8480eb
		if (rv)
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      "failed to umount external mount %s", entry->fs);
Packit 8480eb
		else
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      "umounted external mount %s", entry->fs);
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_mount_autofs_offset(struct autofs_point *ap,
Packit 8480eb
				  struct mapent *oe, const char *root,
Packit 8480eb
				  char *offset)
Packit 8480eb
Packit 8480eb
{
Packit 8480eb
	int mounted = 0;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, "mount offset %s at %s", oe->key, root);
Packit 8480eb
Packit 8480eb
	ret = mount_autofs_offset(ap, oe, root, offset);
Packit 8480eb
	if (ret >= MOUNT_OFFSET_OK)
Packit 8480eb
		mounted++;
Packit 8480eb
	else {
Packit 8480eb
		if (ret != MOUNT_OFFSET_IGNORE)
Packit 8480eb
			warn(ap->logopt, "failed to mount offset");
Packit 8480eb
		else {
Packit 8480eb
			debug(ap->logopt, "ignoring \"nohide\" trigger %s",
Packit 8480eb
			      oe->key);
Packit 8480eb
			free(oe->mapent);
Packit 8480eb
			oe->mapent = NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return mounted;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
Packit 8480eb
			 const char *root, unsigned int start, const char *base)
Packit 8480eb
{
Packit 8480eb
	char path[PATH_MAX + 1];
Packit 8480eb
	char *offset = path;
Packit 8480eb
	struct mapent *oe;
Packit 8480eb
	struct list_head *pos = NULL;
Packit 8480eb
	unsigned int fs_path_len;
Packit 8480eb
	int mounted;
Packit 8480eb
Packit 8480eb
	fs_path_len = start + strlen(base);
Packit 8480eb
	if (fs_path_len > PATH_MAX)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	mounted = 0;
Packit 8480eb
	offset = cache_get_offset(base, offset, start, &me->multi_list, &pos;;
Packit 8480eb
	while (offset) {
Packit 8480eb
		int plen = fs_path_len + strlen(offset);
Packit 8480eb
Packit 8480eb
		if (plen > PATH_MAX) {
Packit 8480eb
			warn(ap->logopt, "path loo long");
Packit 8480eb
			goto cont;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		oe = cache_lookup_offset(base, offset, start, &me->multi_list);
Packit 8480eb
		if (!oe || !oe->mapent)
Packit 8480eb
			goto cont;
Packit 8480eb
Packit 8480eb
		mounted += do_mount_autofs_offset(ap, oe, root, offset);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * If re-constructing a multi-mount it's necessary to walk
Packit 8480eb
		 * into nested mounts, unlike the usual "mount only what's
Packit 8480eb
		 * needed as you go" behavior.
Packit 8480eb
		 */
Packit 8480eb
		if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
Packit 8480eb
			if (oe->ioctlfd != -1 ||
Packit Service 4ea472
			    is_mounted(oe->key, MNTS_REAL)) {
Packit 8480eb
				char oe_root[PATH_MAX + 1];
Packit 8480eb
				strcpy(oe_root, root);
Packit 8480eb
				strcat(oe_root, offset); 
Packit 8480eb
				mount_multi_triggers(ap, oe, oe_root, strlen(oe_root), base);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
cont:
Packit 8480eb
		offset = cache_get_offset(base,
Packit 8480eb
				offset, start, &me->multi_list, &pos;;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return mounted;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
Packit 8480eb
{
Packit 8480eb
	char *dir, *path;
Packit 8480eb
	unsigned int split;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (ap->type == LKP_DIRECT)
Packit 8480eb
		return rmdir_path(ap, oe->key, oe->multi->dev);
Packit 8480eb
Packit 8480eb
	dir = strdup(oe->key);
Packit 8480eb
Packit 8480eb
	if (ap->flags & MOUNT_FLAG_GHOST)
Packit 8480eb
		split = strlen(ap->path) + strlen(oe->multi->key) + 1;
Packit 8480eb
	else
Packit 8480eb
		split = strlen(ap->path);
Packit 8480eb
Packit 8480eb
	dir[split] = '\0';
Packit 8480eb
	path = &dir[split + 1];
Packit 8480eb
Packit 8480eb
	if (chdir(dir) == -1) {
Packit 8480eb
		error(ap->logopt, "failed to chdir to %s", dir);
Packit 8480eb
		free(dir);
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = rmdir_path(ap, path, ap->dev);
Packit 8480eb
Packit 8480eb
	free(dir);
Packit 8480eb
Packit 8480eb
	if (chdir("/") == -1)
Packit 8480eb
		error(ap->logopt, "failed to chdir to /");
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
Packit 8480eb
{
Packit 8480eb
	char path[PATH_MAX + 1];
Packit 8480eb
	char *offset;
Packit 8480eb
	struct mapent *oe;
Packit 8480eb
	struct list_head *mm_root, *pos;
Packit 8480eb
	const char o_root[] = "/";
Packit 8480eb
	const char *mm_base;
Packit 8480eb
	int left, start;
Packit 8480eb
Packit 8480eb
	left = 0;
Packit 8480eb
	start = strlen(root);
Packit 8480eb
Packit 8480eb
	mm_root = &me->multi->multi_list;
Packit 8480eb
Packit 8480eb
	if (!base)
Packit 8480eb
		mm_base = o_root;
Packit 8480eb
	else
Packit 8480eb
		mm_base = base;
Packit 8480eb
Packit 8480eb
	pos = NULL;
Packit 8480eb
	offset = path;
Packit 8480eb
Packit 8480eb
	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
Packit 8480eb
		char *oe_base;
Packit 8480eb
Packit 8480eb
		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
Packit 8480eb
		/* root offset is a special case */
Packit 8480eb
		if (!oe || (strlen(oe->key) - start) == 1)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Check for and umount subtree offsets resulting from
Packit 8480eb
		 * nonstrict mount fail.
Packit 8480eb
		 */
Packit 8480eb
		oe_base = oe->key + strlen(root);
Packit 8480eb
		left += umount_multi_triggers(ap, oe, root, oe_base);
Packit 8480eb
Packit 8480eb
		if (oe->ioctlfd != -1 ||
Packit Service 4ea472
		    is_mounted(oe->key, MNTS_REAL)) {
Packit 8480eb
			left++;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt, "umount offset %s", oe->key);
Packit 8480eb
Packit 8480eb
		if (umount_autofs_offset(ap, oe)) {
Packit 8480eb
			warn(ap->logopt, "failed to umount offset");
Packit 8480eb
			left++;
Packit 8480eb
		} else {
Packit 8480eb
			struct stat st;
Packit 8480eb
			int ret;
Packit 8480eb
Packit 8480eb
			if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
Packit 8480eb
				continue;
Packit 8480eb
Packit 8480eb
			/*
Packit 8480eb
			 * An error due to partial directory removal is
Packit 8480eb
			 * ok so only try and remount the offset if the
Packit 8480eb
			 * actual mount point still exists.
Packit 8480eb
			 */
Packit 8480eb
			ret = rmdir_path_offset(ap, oe);
Packit 8480eb
			if (ret == -1 && !stat(oe->key, &st)) {
Packit 8480eb
				ret = do_mount_autofs_offset(ap, oe, root, offset);
Packit 8480eb
				if (ret)
Packit 8480eb
					left++;
Packit 8480eb
				/* But we did origianlly create this */
Packit 8480eb
				oe->flags |= MOUNT_FLAG_DIR_CREATED;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!left && me->multi == me) {
Packit 8480eb
		struct mapent_cache *mc = me->mc;
Packit 8480eb
		int status;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Special case.
Packit 8480eb
		 * If we can't umount the root container then we can't
Packit 8480eb
		 * delete the offsets from the cache and we need to put
Packit 8480eb
		 * the offset triggers back.
Packit 8480eb
		 */
Packit Service 4ea472
		if (is_mounted(root, MNTS_REAL)) {
Packit 8480eb
			info(ap->logopt, "unmounting dir = %s", root);
Packit 8480eb
			if (umount_ent(ap, root) &&
Packit Service 4ea472
			    is_mounted(root, MNTS_REAL)) {
Packit 8480eb
				if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0)
Packit 8480eb
					warn(ap->logopt,
Packit 8480eb
					     "failed to remount offset triggers");
Packit 8480eb
				return ++left;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* We're done - clean out the offsets */
Packit 8480eb
		status = cache_delete_offset_list(mc, me->key);
Packit 8480eb
		if (status != CHE_OK)
Packit 8480eb
			warn(ap->logopt, "couldn't delete offset list");
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return left;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int clean_stale_multi_triggers(struct autofs_point *ap,
Packit 8480eb
			       struct mapent *me, char *top, const char *base)
Packit 8480eb
{
Packit 8480eb
	char *root;
Packit 8480eb
	char mm_top[PATH_MAX + 1];
Packit 8480eb
	char path[PATH_MAX + 1];
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *offset;
Packit 8480eb
	struct mapent *oe;
Packit 8480eb
	struct list_head *mm_root, *pos;
Packit 8480eb
	const char o_root[] = "/";
Packit 8480eb
	const char *mm_base;
Packit 8480eb
	int left, start;
Packit 8480eb
	time_t age;
Packit 8480eb
Packit 8480eb
	if (top)
Packit 8480eb
		root = top;
Packit 8480eb
	else {
Packit 8480eb
		if (!strchr(me->multi->key, '/'))
Packit 8480eb
			/* Indirect multi-mount root */
Packit 8480eb
			/* sprintf okay - if it's mounted, it's
Packit 8480eb
			 * PATH_MAX or less bytes */
Packit 8480eb
			sprintf(mm_top, "%s/%s", ap->path, me->multi->key);
Packit 8480eb
		else
Packit 8480eb
			strcpy(mm_top, me->multi->key);
Packit 8480eb
		root = mm_top;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	left = 0;
Packit 8480eb
	start = strlen(root);
Packit 8480eb
Packit 8480eb
	mm_root = &me->multi->multi_list;
Packit 8480eb
Packit 8480eb
	if (!base)
Packit 8480eb
		mm_base = o_root;
Packit 8480eb
	else
Packit 8480eb
		mm_base = base;
Packit 8480eb
Packit 8480eb
	pos = NULL;
Packit 8480eb
	offset = path;
Packit 8480eb
	age = me->multi->age;
Packit 8480eb
Packit 8480eb
	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
Packit 8480eb
		char *oe_base;
Packit 8480eb
		char *key;
Packit 8480eb
		int ret;
Packit 8480eb
Packit 8480eb
		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
Packit 8480eb
		/* root offset is a special case */
Packit 8480eb
		if (!oe || (strlen(oe->key) - start) == 1)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		/* Check for and umount stale subtree offsets */
Packit 8480eb
		oe_base = oe->key + strlen(root);
Packit 8480eb
		ret = clean_stale_multi_triggers(ap, oe, root, oe_base);
Packit 8480eb
		left += ret;
Packit 8480eb
		if (ret)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		if (oe->age == age)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * If an offset that has an active mount has been removed
Packit 8480eb
		 * from the multi-mount we don't want to attempt to trigger
Packit 8480eb
		 * mounts for it. Obviously this is because it has been
Packit 8480eb
		 * removed, but less obvious is the potential strange
Packit 8480eb
		 * behaviour that can result if we do try and mount it
Packit 8480eb
		 * again after it's been expired. For example, if an NFS
Packit 8480eb
		 * file system is no longer exported and is later umounted
Packit 8480eb
		 * it can be mounted again without any error message but
Packit 8480eb
		 * shows as an empty directory. That's going to confuse
Packit 8480eb
		 * people for sure.
Packit 8480eb
		 *
Packit 8480eb
		 * If the mount cannot be umounted (the process is now
Packit 8480eb
		 * using a stale mount) the offset needs to be invalidated
Packit 8480eb
		 * so no further mounts will be attempted but the offset
Packit 8480eb
		 * cache entry must remain so expires can continue to
Packit 8480eb
		 * attempt to umount it. If the mount can be umounted and
Packit 8480eb
		 * the offset is removed, at least for NFS we will get
Packit 8480eb
		 * ESTALE errors when attempting list the directory.
Packit 8480eb
		 */
Packit 8480eb
		if (oe->ioctlfd != -1 ||
Packit Service 4ea472
		    is_mounted(oe->key, MNTS_REAL)) {
Packit 8480eb
			if (umount_ent(ap, oe->key) &&
Packit Service 4ea472
			    is_mounted(oe->key, MNTS_REAL)) {
Packit 8480eb
				debug(ap->logopt,
Packit 8480eb
				      "offset %s has active mount, invalidate",
Packit 8480eb
				      oe->key);
Packit 8480eb
				if (oe->mapent) {
Packit 8480eb
					free(oe->mapent);
Packit 8480eb
					oe->mapent = NULL;
Packit 8480eb
				}
Packit 8480eb
				left++;
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		key = strdup(oe->key);
Packit 8480eb
		if (!key) {
Packit 8480eb
	                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		        error(ap->logopt, "malloc: %s", estr);
Packit 8480eb
			left++;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt, "umount offset %s", oe->key);
Packit 8480eb
Packit 8480eb
		if (umount_autofs_offset(ap, oe)) {
Packit 8480eb
			warn(ap->logopt, "failed to umount offset %s", key);
Packit 8480eb
			left++;
Packit 8480eb
		} else {
Packit 8480eb
			struct stat st;
Packit 8480eb
Packit 8480eb
			/* Mount point not ours to delete ? */
Packit 8480eb
			if (!(oe->flags & MOUNT_FLAG_DIR_CREATED)) {
Packit 8480eb
				debug(ap->logopt, "delete offset key %s", key);
Packit 8480eb
				if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
Packit 8480eb
					error(ap->logopt,
Packit 8480eb
					     "failed to delete offset key %s", key);
Packit 8480eb
				free(key);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			/*
Packit 8480eb
			 * An error due to partial directory removal is
Packit 8480eb
			 * ok so only try and remount the offset if the
Packit 8480eb
			 * actual mount point still exists.
Packit 8480eb
			 */
Packit 8480eb
			ret = rmdir_path_offset(ap, oe);
Packit 8480eb
			if (ret == -1 && !stat(oe->key, &st)) {
Packit 8480eb
				ret = do_mount_autofs_offset(ap, oe, root, offset);
Packit 8480eb
				if (ret) {
Packit 8480eb
					left++;
Packit 8480eb
					/* But we did origianlly create this */
Packit 8480eb
					oe->flags |= MOUNT_FLAG_DIR_CREATED;
Packit 8480eb
					free(key);
Packit 8480eb
					continue;
Packit 8480eb
				}
Packit 8480eb
				/*
Packit 8480eb
				 * Fall through if the trigger can't be mounted
Packit 8480eb
				 * again, since there is no offset there can't
Packit 8480eb
				 * be any mount requests so remove the map
Packit 8480eb
				 * entry from the cache. There's now a dead
Packit 8480eb
				 * offset mount, but what else can we do ....
Packit 8480eb
				 */
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			debug(ap->logopt, "delete offset key %s", key);
Packit 8480eb
Packit 8480eb
			if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
Packit 8480eb
				error(ap->logopt,
Packit 8480eb
				     "failed to delete offset key %s", key);
Packit 8480eb
		}
Packit 8480eb
		free(key);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return left;
Packit 8480eb
}
Packit 8480eb