Blame modules/parse_amd.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *
Packit 8480eb
 *  Copyright 2013 Ian Kent <raven@themaw.net>
Packit 8480eb
 *  Copyright 2013 Red Hat, Inc.
Packit 8480eb
 *  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 <stdio.h>
Packit 8480eb
#include <malloc.h>
Packit 8480eb
#include <netdb.h>
Packit 8480eb
#include <stdlib.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <limits.h>
Packit 8480eb
#include <sys/param.h>
Packit 8480eb
#include <sys/socket.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <sys/vfs.h>
Packit 8480eb
#include <sys/utsname.h>
Packit 8480eb
#include <netinet/in.h>
Packit 8480eb
#include <sys/mount.h>
Packit 8480eb
#include <linux/fs.h>
Packit 8480eb
Packit 8480eb
#define MODULE_PARSE
Packit 8480eb
#include "automount.h"
Packit 8480eb
#include "nsswitch.h"
Packit 8480eb
Packit 8480eb
#define MODPREFIX "parse(amd): "
Packit 8480eb
Packit 8480eb
int parse_version = AUTOFS_PARSE_VERSION;	/* Required by protocol */
Packit 8480eb
Packit 8480eb
static struct mount_mod *mount_nfs = NULL;
Packit 8480eb
static int init_ctr = 0;
Packit 8480eb
static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
Packit 8480eb
static void instance_mutex_lock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_lock(&instance_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void instance_mutex_unlock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_unlock(&instance_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
extern const char *global_options;
Packit 8480eb
Packit 8480eb
struct parse_context {
Packit 8480eb
	char *optstr;		/* Mount options */
Packit 8480eb
	char *macros;		/* Map wide macro defines */
Packit 8480eb
	struct substvar *subst;	/* $-substitutions */
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
struct multi_mnt {
Packit 8480eb
	char *path;
Packit 8480eb
	char *options;
Packit 8480eb
	char *location;
Packit 8480eb
	struct multi_mnt *next;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
/* Default context */
Packit 8480eb
Packit 8480eb
static struct parse_context default_context = {
Packit 8480eb
	NULL,			/* No mount options */
Packit 8480eb
	NULL,			/* No map wide macros */
Packit 8480eb
	NULL			/* The substvar local vars table */
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
/* Free all storage associated with this context */
Packit 8480eb
static void kill_context(struct parse_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	macro_lock();
Packit 8480eb
	macro_free_table(ctxt->subst);
Packit 8480eb
	macro_unlock();
Packit 8480eb
	if (ctxt->optstr)
Packit 8480eb
		free(ctxt->optstr);
Packit 8480eb
	if (ctxt->macros)
Packit 8480eb
		free(ctxt->macros);
Packit 8480eb
	free(ctxt);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int parse_init(int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	struct parse_context *ctxt;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
Packit 8480eb
	sel_hash_init();
Packit 8480eb
Packit 8480eb
	/* Set up context and escape chain */
Packit 8480eb
Packit 8480eb
	if (!(ctxt = (struct parse_context *) malloc(sizeof(struct parse_context)))) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		*context = NULL;
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	*context = (void *) ctxt;
Packit 8480eb
Packit 8480eb
	*ctxt = default_context;
Packit 8480eb
Packit 8480eb
	/* We only need this once.  NFS mounts are so common that we cache
Packit 8480eb
	   this module. */
Packit 8480eb
	instance_mutex_lock();
Packit 8480eb
	if (mount_nfs)
Packit 8480eb
		init_ctr++;
Packit 8480eb
	else {
Packit 8480eb
		if ((mount_nfs = open_mount("nfs", MODPREFIX))) {
Packit 8480eb
			init_ctr++;
Packit 8480eb
		} else {
Packit 8480eb
			kill_context(ctxt);
Packit 8480eb
			*context = NULL;
Packit 8480eb
			instance_mutex_unlock();
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	instance_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int parse_reinit(int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct substvar *add_lookup_vars(struct autofs_point *ap,
Packit 8480eb
					const char *key, int key_len,
Packit 8480eb
					struct map_source *source,
Packit 8480eb
					struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct substvar *list = sv;
Packit 8480eb
	struct thread_stdenv_vars *tsv;
Packit 8480eb
	char lkp_key[PATH_MAX + 1];
Packit 8480eb
	char path[PATH_MAX + 1];
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	int len;
Packit 8480eb
Packit 8480eb
	len = strlen(ap->path) + 1 + key_len + 1;
Packit 8480eb
	if (len > PATH_MAX) {
Packit 8480eb
		error(ap->logopt, MODPREFIX
Packit 8480eb
		      "error: lookup key is greater than PATH_MAX");
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ap->pref) {
Packit 8480eb
		if (snprintf(lkp_key, sizeof(lkp_key), "%s%s",
Packit 8480eb
			     ap->pref, key) >= sizeof(lkp_key)) {
Packit 8480eb
			error(ap->logopt, MODPREFIX "key too long");
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	} else {
Packit 8480eb
		if (snprintf(lkp_key, sizeof(lkp_key), "%s",
Packit 8480eb
			     key) >= sizeof(lkp_key)) {
Packit 8480eb
			error(ap->logopt, MODPREFIX "key too long");
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (*key == '/')
Packit 8480eb
		strcpy(path, key);
Packit 8480eb
	else {
Packit 8480eb
		strcpy(path, ap->path);
Packit 8480eb
		strcat(path, "/");
Packit 8480eb
		strcat(path, key);
Packit 8480eb
	}
Packit 8480eb
	list = macro_addvar(list, "path", 4, path);
Packit 8480eb
Packit 8480eb
	me = cache_lookup_distinct(source->mc, lkp_key);
Packit 8480eb
	if (me)
Packit 8480eb
		list = macro_addvar(list, "key", 3, me->key);
Packit 8480eb
Packit 8480eb
	while (!me) {
Packit 8480eb
		char match[PATH_MAX + 1];
Packit 8480eb
		char *prefix;
Packit 8480eb
Packit 8480eb
		strcpy(match, lkp_key);
Packit 8480eb
		while ((prefix = strrchr(match, '/'))) {
Packit 8480eb
			*prefix = '\0';
Packit 8480eb
			me = cache_partial_match_wild(source->mc, match);
Packit 8480eb
			if (me) {
Packit 8480eb
				list = macro_addvar(list, "key", 3, lkp_key);
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!me) {
Packit 8480eb
			me = cache_lookup_distinct(source->mc, "*");
Packit 8480eb
			if (me)
Packit 8480eb
				list = macro_addvar(list, "key", 3, lkp_key);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (source->name)
Packit 8480eb
		list = macro_addvar(list, "map", 3, source->name);
Packit 8480eb
	else if (source->argv[0][0])
Packit 8480eb
		list = macro_addvar(list, "map", 3, source->argv[0]);
Packit 8480eb
Packit 8480eb
	tsv = pthread_getspecific(key_thread_stdenv_vars);
Packit 8480eb
	if (tsv) {
Packit 8480eb
		char numbuf[16];
Packit 8480eb
		long num;
Packit 8480eb
		int ret;
Packit 8480eb
Packit 8480eb
		num = (long) tsv->uid;
Packit 8480eb
		ret = sprintf(numbuf, "%ld", num);
Packit 8480eb
		if (ret > 0)
Packit 8480eb
			list = macro_addvar(list, "uid", 3, numbuf);
Packit 8480eb
		num = (long) tsv->gid;
Packit 8480eb
		ret = sprintf(numbuf, "%ld", num);
Packit 8480eb
		if (ret > 0)
Packit 8480eb
			list = macro_addvar(list, "gid", 3, numbuf);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	list = macro_addvar(list, "fs", 2, "${autodir}/${rhost}${rfs}");
Packit 8480eb
	list = macro_addvar(list, "rfs", 3, path);
Packit 8480eb
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit Service 145c60
static int match_my_name(unsigned int logopt, const char *name, struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct addrinfo hints, *cni, *ni, *haddr;
Packit 8480eb
	char host[NI_MAXHOST + 1], numeric[NI_MAXHOST + 1];
Packit 8480eb
	const struct substvar *v;
Packit 8480eb
	int rv = 0, ret;
Packit 8480eb
Packit 8480eb
	v = macro_findvar(sv, "host", 4);
Packit 8480eb
	if (v) {
Packit Service 145c60
		if (!strcmp(v->val, name))
Packit Service 145c60
			return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!v || !v->val) {
Packit 8480eb
		error(logopt, MODPREFIX "error: ${host} not set");
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Check if comparison value is an alias */
Packit 8480eb
Packit 8480eb
	memset(&hints, 0, sizeof(hints));
Packit 8480eb
	hints.ai_flags = AI_CANONNAME;
Packit 8480eb
	hints.ai_family = AF_UNSPEC;
Packit 8480eb
	hints.ai_socktype = SOCK_DGRAM;
Packit 8480eb
Packit 8480eb
	/* Get host canonical name */
Packit 8480eb
	ret = getaddrinfo(v->val, NULL, &hints, &cni);
Packit 8480eb
	if (ret) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit Service 145c60
		      "hostname lookup failed: %s\n", gai_strerror(ret));
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME;
Packit 8480eb
Packit 8480eb
	/* Resolve comparison name to its names and compare */
Packit Service 145c60
	ret = getaddrinfo(name, NULL, &hints, &ni);
Packit 8480eb
	if (ret) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit Service 145c60
		      "hostname lookup failed: %s\n", gai_strerror(ret));
Packit 8480eb
		freeaddrinfo(cni);
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	haddr = ni;
Packit 8480eb
	while (haddr) {
Packit 8480eb
		/* Translate the host address into a numeric string form */
Packit 8480eb
		ret = getnameinfo(haddr->ai_addr, haddr->ai_addrlen,
Packit 8480eb
				  numeric, sizeof(numeric), NULL, 0,
Packit 8480eb
				  NI_NUMERICHOST);
Packit 8480eb
		if (ret) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "host address info lookup failed: %s\n",
Packit 8480eb
			      gai_strerror(ret));
Packit 8480eb
			goto next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* Try to resolve back again to get the canonical name */
Packit 8480eb
		ret = getnameinfo(haddr->ai_addr, haddr->ai_addrlen,
Packit 8480eb
				  host, NI_MAXHOST, NULL, 0, 0);
Packit 8480eb
		if (ret) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "host address info lookup failed: %s\n",
Packit 8480eb
			      gai_strerror(ret));
Packit 8480eb
			goto next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!strcmp(host, cni->ai_canonname)) {
Packit 8480eb
			rv = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
next:
Packit 8480eb
		haddr = haddr->ai_next;
Packit 8480eb
	}
Packit 8480eb
	freeaddrinfo(ni);
Packit 8480eb
	freeaddrinfo(cni);
Packit 8480eb
out:
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit Service 145c60
static int eval_selector(unsigned int logopt,
Packit 8480eb
			 struct amd_entry *this, struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct selector *s = this->selector;
Packit 8480eb
	const struct substvar *v;
Packit 8480eb
	unsigned int s_type;
Packit 8480eb
	unsigned int v_type;
Packit Service 145c60
	struct stat st;
Packit Service 145c60
	char *host;
Packit 8480eb
	int res, val, ret = 0;
Packit 8480eb
Packit 8480eb
	s_type = s->sel->flags & SEL_FLAGS_TYPE_MASK;
Packit 8480eb
Packit 8480eb
	switch (s_type) {
Packit 8480eb
	case SEL_FLAG_MACRO:
Packit 8480eb
		v = macro_findvar(sv, s->sel->name, strlen(s->sel->name));
Packit 8480eb
		if (!v) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "failed to get selector %s", s->sel->name);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		v_type = s->sel->flags & SEL_FLAGS_VALUE_MASK;
Packit 8480eb
Packit 8480eb
		switch (v_type) {
Packit 8480eb
		case SEL_FLAG_STR:
Packit Service 145c60
			res = strcmp(v->val, s->comp.value);
Packit Service 145c60
			if (s->compare & SEL_COMP_EQUAL && !res) {
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "matched selector %s(%s) == %s",
Packit Service 145c60
				      v->def, v->val, s->comp.value);
Packit Service 145c60
				ret = 1;
Packit Service 145c60
				break;
Packit Service 145c60
			} else if (s->compare & SEL_COMP_NOTEQUAL && res) {
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "matched selector %s(%s) != %s",
Packit Service 145c60
				      v->def, v->val, s->comp.value);
Packit Service 145c60
				ret = 1;
Packit Service 145c60
				break;
Packit Service 145c60
			}
Packit Service 145c60
Packit Service 145c60
			debug(logopt, MODPREFIX
Packit Service 145c60
				      "did not match selector %s(%s) %s %s",
Packit Service 145c60
				      v->def, v->val,
Packit Service 145c60
				      (s->compare & SEL_COMP_EQUAL ? "==" : "!="),
Packit Service 145c60
				      s->comp.value);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case SEL_FLAG_NUM:
Packit 8480eb
			if (!*s->comp.value) {
Packit 8480eb
				res = 1;
Packit 8480eb
				val = 0;
Packit 8480eb
			} else {
Packit 8480eb
				res = atoi(v->val);
Packit 8480eb
				val = atoi(s->comp.value);
Packit 8480eb
			}
Packit 8480eb
			if (s->compare & SEL_COMP_EQUAL && res == val) {
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "matched selector %s(%s) equal to %s",
Packit 8480eb
				      v->def, v->val, s->comp.value);
Packit 8480eb
				ret = 1;
Packit 8480eb
				break;
Packit 8480eb
			} else if (s->compare & SEL_COMP_NOTEQUAL && res != val) {
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "matched selector %s(%s) not equal to %s",
Packit 8480eb
				      v->def, v->val, s->comp.value);
Packit 8480eb
				ret = 1;
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
				      "did not match selector %s(%s) %s %s",
Packit 8480eb
				      v->def, v->val,
Packit 8480eb
				      (s->compare & SEL_COMP_EQUAL ? "==" : "!="),
Packit 8480eb
				      s->comp.value);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case SEL_FLAG_FUNC1:
Packit 8480eb
		if (s->sel->selector != SEL_TRUE &&
Packit 8480eb
		    s->sel->selector != SEL_FALSE &&
Packit 8480eb
		    !s->func.arg1) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "expected argument missing for selector %s",
Packit 8480eb
			      s->sel->name);
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		switch (s->sel->selector) {
Packit 8480eb
		case SEL_TRUE:
Packit 8480eb
			ret = 1;
Packit 8480eb
			if (s->compare == SEL_COMP_NOT)
Packit 8480eb
				ret = !ret;
Packit 8480eb
			if (ret)
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "matched selector %s(%s)",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			else
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "did not match selector %s(%s)",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case SEL_FALSE:
Packit 8480eb
			if (s->compare == SEL_COMP_NOT)
Packit 8480eb
				ret = !ret;
Packit 8480eb
			if (ret)
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "matched selector %s(%s)",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			else
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "did not match selector %s(%s)",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case SEL_XHOST:
Packit Service 145c60
			ret = match_my_name(logopt, s->func.arg1, sv);
Packit 8480eb
			if (s->compare == SEL_COMP_NOT)
Packit 8480eb
				ret = !ret;
Packit 8480eb
			if (ret)
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "matched selector %s(%s) to host name",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			else
Packit 8480eb
				debug(logopt, MODPREFIX
Packit 8480eb
				      "did not match selector %s(%s) to host name",
Packit 8480eb
				      s->sel->name, s->func.arg1);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case SEL_EXISTS:
Packit Service 145c60
			/* Sould be OK to fail on any error here */
Packit Service 145c60
			ret = !lstat(s->func.arg1, &st);
Packit Service 145c60
			if (s->compare == SEL_COMP_NOT)
Packit Service 145c60
				ret = !ret;
Packit Service 145c60
			if (ret)
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "matched selector %s(%s)",
Packit Service 145c60
				      s->sel->name, s->func.arg1);
Packit Service 145c60
			else
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "did not match selector %s(%s)",
Packit Service 145c60
				      s->sel->name, s->func.arg1);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case SEL_IN_NETWORK:
Packit Service 145c60
			ret = in_network(s->func.arg1);
Packit Service 145c60
			if (s->compare == SEL_COMP_NOT)
Packit Service 145c60
				ret = !ret;
Packit Service 145c60
			if (ret)
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "matched selector %s(%s)",
Packit Service 145c60
				      s->sel->name, s->func.arg1);
Packit Service 145c60
			else
Packit Service 145c60
				debug(logopt, MODPREFIX
Packit Service 145c60
				      "did not match selector %s(%s)",
Packit Service 145c60
				      s->sel->name, s->func.arg1);
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case SEL_FLAG_FUNC2:
Packit 8480eb
		if (!s->func.arg1) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "expected argument missing for selector %s",
Packit 8480eb
			      s->sel->name);
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		switch (s->sel->selector) {
Packit 8480eb
		case SEL_NETGRP:
Packit 8480eb
		case SEL_NETGRPD:
Packit Service 145c60
			if (s->func.arg2)
Packit Service 145c60
				host = s->func.arg2;
Packit Service 145c60
			else {
Packit Service 145c60
				if (s->sel->selector == SEL_NETGRP)
Packit Service 145c60
					v = macro_findvar(sv, "host", 4);
Packit Service 145c60
				else
Packit Service 145c60
					v = macro_findvar(sv, "hostd", 5);
Packit Service 145c60
				if (!v || !*v->val) {
Packit Service 145c60
					error(logopt, MODPREFIX
Packit Service 145c60
					     "failed to get value of ${host}");
Packit Service 145c60
					break;
Packit Service 145c60
				}
Packit Service 145c60
				host = v->val;
Packit Service 145c60
			}
Packit Service 145c60
			ret = innetgr(s->func.arg1, host, NULL, NULL);
Packit Service 145c60
			if (s->compare == SEL_COMP_NOT)
Packit Service 145c60
				ret = !ret;
Packit Service 145c60
			if (ret) {
Packit Service 145c60
				if (!s->func.arg2)
Packit Service 145c60
					debug(logopt, MODPREFIX
Packit Service 145c60
					      "matched selector %s(%s)",
Packit Service 145c60
					      s->sel->name, s->func.arg1);
Packit Service 145c60
				else
Packit Service 145c60
					debug(logopt, MODPREFIX
Packit Service 145c60
					      "matched selector %s(%s,%s)",
Packit Service 145c60
					      s->sel->name, s->func.arg1,
Packit Service 145c60
					      s->func.arg2);
Packit Service 145c60
			} else {
Packit Service 145c60
				if (!s->func.arg2)
Packit Service 145c60
					debug(logopt, MODPREFIX
Packit Service 145c60
					      "did not match selector %s(%s)",
Packit Service 145c60
					      s->sel->name, s->func.arg1);
Packit Service 145c60
				else
Packit Service 145c60
					debug(logopt, MODPREFIX
Packit Service 145c60
					      "did not match selector %s(%s,%s)",
Packit Service 145c60
					      s->sel->name, s->func.arg1, s->func.arg2);
Packit Service 145c60
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	default:
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void update_with_defaults(struct amd_entry *defaults,
Packit 8480eb
				 struct amd_entry *entry,
Packit 8480eb
				 struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	const struct substvar *v;
Packit 8480eb
	unsigned long fstype = entry->flags & AMD_MOUNT_TYPE_MASK;
Packit 8480eb
	char *tmp;
Packit 8480eb
Packit 8480eb
	if (fstype == AMD_MOUNT_TYPE_NONE) {
Packit 8480eb
		unsigned long deftype = defaults->flags & AMD_MOUNT_TYPE_MASK;
Packit 8480eb
		if (deftype != AMD_MOUNT_TYPE_NONE)
Packit 8480eb
			entry->flags |= (defaults->flags & AMD_MOUNT_TYPE_MASK);
Packit 8480eb
		else {
Packit 8480eb
			entry->flags = AMD_MOUNT_TYPE_NFS;
Packit 8480eb
			tmp = strdup("nfs");
Packit 8480eb
			if (tmp)
Packit 8480eb
				entry->type = tmp;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->type && defaults->type) {
Packit 8480eb
		tmp = strdup(defaults->type);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->type = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->map_type && defaults->map_type) {
Packit 8480eb
		tmp = strdup(defaults->map_type);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->map_type = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->pref && defaults->pref) {
Packit 8480eb
		tmp = strdup(defaults->pref);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->pref = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->fs) {
Packit 8480eb
		if (defaults->fs) {
Packit 8480eb
			tmp = strdup(defaults->fs);
Packit 8480eb
			if (tmp)
Packit 8480eb
				entry->fs = tmp;
Packit 8480eb
		} else {
Packit 8480eb
			v = macro_findvar(sv, "fs", 2);
Packit 8480eb
			if (v)
Packit 8480eb
				entry->fs = strdup(v->val);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->rfs) {
Packit 8480eb
		if (defaults->rfs) {
Packit 8480eb
			tmp = strdup(defaults->rfs);
Packit 8480eb
			if (tmp)
Packit 8480eb
				entry->rfs = tmp;
Packit 8480eb
		} else {
Packit 8480eb
			v = macro_findvar(sv, "rfs", 3);
Packit 8480eb
			if (v)
Packit 8480eb
				entry->rfs = strdup(v->val);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->rhost) {
Packit 8480eb
		if (defaults->rhost) {
Packit 8480eb
			tmp = strdup(defaults->rhost);
Packit 8480eb
			if (tmp)
Packit 8480eb
				entry->rhost = tmp;
Packit 8480eb
		} else {
Packit 8480eb
			v = macro_findvar(sv, "host", 4);
Packit 8480eb
			if (v)
Packit 8480eb
				entry->rhost = strdup(v->val);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->dev && defaults->dev) {
Packit 8480eb
		tmp = strdup(defaults->dev);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->dev = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->opts && defaults->opts) {
Packit 8480eb
		tmp = merge_options(defaults->opts, entry->opts);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->addopts && defaults->addopts) {
Packit 8480eb
		tmp = merge_options(defaults->addopts, entry->addopts);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->addopts = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->remopts) {
Packit 8480eb
		if (defaults->remopts) {
Packit 8480eb
			tmp = strdup(defaults->remopts);
Packit 8480eb
			if (tmp)
Packit 8480eb
				entry->remopts = tmp;
Packit 8480eb
		} else {
Packit 8480eb
			v = macro_findvar(sv, "remopts", 7);
Packit 8480eb
			if (v)
Packit 8480eb
				entry->remopts = strdup(v->val);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *normalize_hostname(unsigned int logopt, const char *host,
Packit 8480eb
				unsigned int flags, struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct addrinfo hints, *ni;
Packit 8480eb
	char *name;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (!(flags & CONF_NORMALIZE_HOSTNAMES))
Packit 8480eb
		name = strdup(host);
Packit 8480eb
	else {
Packit 8480eb
		memset(&hints, 0, sizeof(hints));
Packit 8480eb
		hints.ai_flags = AI_CANONNAME;
Packit 8480eb
		hints.ai_family = AF_UNSPEC;
Packit 8480eb
		hints.ai_socktype = SOCK_DGRAM;
Packit 8480eb
Packit 8480eb
		ret = getaddrinfo(host, NULL, &hints, &ni);
Packit 8480eb
		if (ret) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit Service 145c60
			      "hostname lookup failed: %s", gai_strerror(ret));
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
		name = strdup(ni->ai_canonname);
Packit 8480eb
		freeaddrinfo(ni);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!name)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (flags & CONF_DOMAIN_STRIP) {
Packit 8480eb
		const struct substvar *v = macro_findvar(sv, "hostd", 5);
Packit 8480eb
		if (v) {
Packit 8480eb
			char *d1 = strchr(name, '.');
Packit 8480eb
			if (d1) {
Packit 8480eb
				char *d2 = strchr(v->val, '.');
Packit 8480eb
				if (d2 && !strcmp(d1, d2))
Packit 8480eb
					*d1 = '\0';
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return name;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct substvar *expand_entry(struct autofs_point *ap,
Packit 8480eb
				     struct amd_entry *entry,
Packit 8480eb
				     unsigned int flags,
Packit 8480eb
				     struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	unsigned int logopt = ap->logopt;
Packit 8480eb
	char *expand;
Packit 8480eb
Packit 8480eb
	if (entry->rhost && *entry->rhost) {
Packit 8480eb
		char *host = strdup(entry->rhost);
Packit 8480eb
		char *nn;
Packit 8480eb
		if (!host) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			      "failed to allocate storage for rhost");
Packit 8480eb
			goto next;
Packit 8480eb
		}
Packit 8480eb
		if (expand_selectors(ap, host, &expand, sv)) {
Packit 8480eb
			free(host);
Packit 8480eb
			host = expand;
Packit 8480eb
		}
Packit 8480eb
		nn = normalize_hostname(ap->logopt, host, flags, sv);
Packit 8480eb
		if (!nn)
Packit 8480eb
			sv = macro_addvar(sv, "rhost", 5, host);
Packit 8480eb
		else {
Packit 8480eb
			sv = macro_addvar(sv, "rhost", 5, nn);
Packit 8480eb
			free(host);
Packit 8480eb
			host = nn;
Packit 8480eb
		}
Packit 8480eb
		debug(logopt, MODPREFIX
Packit 8480eb
		      "rhost expand(\"%s\") -> %s", entry->rhost, host);
Packit 8480eb
		free(entry->rhost);
Packit 8480eb
		entry->rhost = host;
Packit 8480eb
	}
Packit 8480eb
next:
Packit 8480eb
	if (entry->sublink) {
Packit 8480eb
		if (expand_selectors(ap, entry->sublink, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "sublink expand(\"%s\") -> %s",
Packit 8480eb
			      entry->sublink, expand);
Packit 8480eb
			free(entry->sublink);
Packit 8480eb
			entry->sublink = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "sublink", 7, entry->sublink);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->rfs && *entry->rfs) {
Packit 8480eb
		if (expand_selectors(ap, entry->rfs, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "rfs expand(\"%s\") -> %s", entry->rfs, expand);
Packit 8480eb
			free(entry->rfs);
Packit 8480eb
			entry->rfs = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "rfs", 3, entry->rfs);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->fs && *entry->fs) {
Packit 8480eb
		if (expand_selectors(ap, entry->fs, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "fs expand(\"%s\") -> %s", entry->fs, expand);
Packit 8480eb
			free(entry->fs);
Packit 8480eb
			entry->fs = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "fs", 2, entry->fs);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->opts && *entry->opts) {
Packit 8480eb
		if (expand_selectors(ap, entry->opts, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "ops expand(\"%s\") -> %s", entry->opts, expand);
Packit 8480eb
			free(entry->opts);
Packit 8480eb
			entry->opts = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "opts", 4, entry->opts);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->addopts && *entry->addopts) {
Packit 8480eb
		if (expand_selectors(ap, entry->addopts, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "addopts expand(\"%s\") -> %s",
Packit 8480eb
			      entry->addopts, expand);
Packit 8480eb
			free(entry->addopts);
Packit 8480eb
			entry->addopts = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "addopts", 7, entry->addopts);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->remopts && *entry->remopts) {
Packit 8480eb
		if (expand_selectors(ap, entry->remopts, &expand, sv)) {
Packit 8480eb
			debug(logopt, MODPREFIX
Packit 8480eb
			      "remopts expand(\"%s\") -> %s",
Packit 8480eb
			      entry->remopts, expand);
Packit 8480eb
			free(entry->remopts);
Packit 8480eb
			entry->remopts = expand;
Packit 8480eb
		}
Packit 8480eb
		sv = macro_addvar(sv, "remopts", 7, entry->remopts);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->mount) {
Packit 8480eb
		if (!expand_selectors(ap, entry->mount, &expand, sv)) {
Packit 8480eb
			free(entry->mount);
Packit 8480eb
			if (entry->umount)
Packit 8480eb
				free(entry->umount);
Packit 8480eb
			entry->mount = NULL;
Packit 8480eb
			entry->umount = NULL;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		debug(logopt, MODPREFIX
Packit 8480eb
		      "mount expand(\"%s\") -> %s", entry->mount, expand);
Packit 8480eb
		free(entry->mount);
Packit 8480eb
		entry->mount = expand;
Packit 8480eb
		sv = macro_addvar(sv, "mount", 5, entry->mount);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->umount) {
Packit 8480eb
		if (!expand_selectors(ap, entry->umount, &expand, sv)) {
Packit 8480eb
			free(entry->umount);
Packit 8480eb
			entry->umount = NULL;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		debug(logopt, MODPREFIX
Packit 8480eb
		      "umount expand(\"%s\") -> %s", entry->umount, expand);
Packit 8480eb
		free(entry->umount);
Packit 8480eb
		entry->umount = expand;
Packit 8480eb
		sv = macro_addvar(sv, "umount", 5, entry->umount);
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	return sv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void expand_merge_options(struct autofs_point *ap,
Packit 8480eb
				 struct amd_entry *entry,
Packit 8480eb
				 struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char *tmp;
Packit 8480eb
Packit 8480eb
	if (entry->opts && *entry->opts) {
Packit 8480eb
		if (!expand_selectors(ap, entry->opts, &tmp, sv))
Packit 8480eb
			error(ap->logopt, MODPREFIX "failed to expand opts");
Packit 8480eb
		else {
Packit 8480eb
			free(entry->opts);
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->addopts && *entry->addopts) {
Packit 8480eb
		if (!expand_selectors(ap, entry->addopts, &tmp, sv))
Packit 8480eb
			error(ap->logopt, MODPREFIX "failed to expand addopts");
Packit 8480eb
		else {
Packit 8480eb
			free(entry->addopts);
Packit 8480eb
			entry->addopts = tmp;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->remopts && *entry->remopts) {
Packit 8480eb
		if (!expand_selectors(ap, entry->remopts, &tmp, sv))
Packit 8480eb
			error(ap->logopt, MODPREFIX "failed to expand remopts");
Packit 8480eb
		else {
Packit 8480eb
			free(entry->remopts);
Packit 8480eb
			entry->remopts = tmp;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct substvar *merge_entry_options(struct autofs_point *ap,
Packit 8480eb
					    struct amd_entry *entry,
Packit 8480eb
				            struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char *tmp;
Packit 8480eb
Packit 8480eb
	if (!entry->addopts)
Packit 8480eb
		return sv;
Packit 8480eb
Packit 8480eb
	if (entry->opts && entry->remopts &&
Packit 8480eb
	    !strcmp(entry->opts, entry->remopts)) {
Packit 8480eb
		expand_merge_options(ap, entry, sv);
Packit 8480eb
		tmp = merge_options(entry->opts, entry->addopts);
Packit 8480eb
		if (tmp) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "merge remopts \"%s\" addopts \"%s\" => \"%s\"",
Packit 8480eb
			      entry->opts, entry->addopts, tmp);
Packit 8480eb
			free(entry->opts);
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
			sv = macro_addvar(sv, "opts", 4, entry->opts);
Packit 8480eb
		}
Packit 8480eb
		if (*entry->opts) {
Packit 8480eb
			tmp = strdup(entry->opts);
Packit 8480eb
			if (tmp) {
Packit 8480eb
				free(entry->remopts);
Packit 8480eb
				entry->remopts = tmp;
Packit 8480eb
				sv = macro_addvar(sv, "remopts", 7, entry->remopts);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
		return sv;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	expand_merge_options(ap, entry, sv);
Packit 8480eb
Packit 8480eb
	if (entry->opts && entry->addopts) {
Packit 8480eb
		tmp = merge_options(entry->opts, entry->addopts);
Packit 8480eb
		if (tmp) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "merge opts \"%s\" addopts \"%s\" => \"%s\"",
Packit 8480eb
			      entry->opts, entry->addopts, tmp);
Packit 8480eb
			free(entry->opts);
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
			sv = macro_addvar(sv, "opts", 4, entry->opts);
Packit 8480eb
		}
Packit 8480eb
	} else if (entry->addopts && *entry->addopts) {
Packit 8480eb
		tmp = strdup(entry->addopts);
Packit 8480eb
		if (tmp) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "opts add addopts \"%s\" => \"%s\"", entry->addopts, tmp);
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
			sv = macro_addvar(sv, "opts", 4, entry->opts);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	expand_merge_options(ap, entry, sv);
Packit 8480eb
Packit 8480eb
	if (entry->remopts && entry->addopts) {
Packit 8480eb
		tmp = merge_options(entry->remopts, entry->addopts);
Packit 8480eb
		if (tmp) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "merge remopts \"%s\" addopts \"%s\" => \"%s\"",
Packit 8480eb
			      entry->remopts, entry->addopts, tmp);
Packit 8480eb
			free(entry->remopts);
Packit 8480eb
			entry->remopts = tmp;
Packit 8480eb
			sv = macro_addvar(sv, "remopts", 7, entry->remopts);
Packit 8480eb
		}
Packit 8480eb
	} else if (entry->addopts && *entry->addopts) {
Packit 8480eb
		tmp = strdup(entry->addopts);
Packit 8480eb
		if (tmp) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "remopts add addopts \"%s\" => \"%s\"",
Packit 8480eb
			     entry->addopts, tmp);
Packit 8480eb
			entry->remopts = tmp;
Packit 8480eb
			sv = macro_addvar(sv, "remopts", 7, entry->remopts);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return sv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_auto_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			 struct amd_entry *entry, unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	char target[PATH_MAX + 1];
Packit 8480eb
Packit 8480eb
	if (!entry->map_type) {
Packit 8480eb
		if (strlen(entry->fs) > PATH_MAX) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "error: fs option length is too long");
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
		strcpy(target, entry->fs);
Packit 8480eb
	} else {
Packit 8480eb
		if (strlen(entry->fs) +
Packit 8480eb
		    strlen(entry->map_type) + 5 > PATH_MAX) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "error: fs + maptype options length is too long");
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
		strcpy(target, entry->map_type);
Packit 8480eb
		strcat(target, ",amd:");
Packit 8480eb
		strcat(target, entry->fs);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return do_mount(ap, ap->path,
Packit 8480eb
			name, strlen(name), target, "autofs", entry->opts);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_link_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			 struct amd_entry *entry, unsigned int flags)
Packit 8480eb
{
Packit Service 145c60
	char target[PATH_MAX + 1];
Packit 8480eb
	const char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (entry->sublink) {
Packit 8480eb
		if (strlen(entry->sublink) > PATH_MAX) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "error: sublink option length is too long");
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit Service 145c60
		strcpy(target, entry->sublink);
Packit 8480eb
	} else {
Packit 8480eb
		if (strlen(entry->fs) > PATH_MAX) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "error: fs option length is too long");
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit Service 145c60
		strcpy(target, entry->fs);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!(flags & CONF_AUTOFS_USE_LOFS))
Packit 8480eb
		goto symlink;
Packit 8480eb
Packit 8480eb
	/* For a sublink this might cause an external mount */
Packit 8480eb
	ret = do_mount(ap, ap->path,
Packit 8480eb
		       name, strlen(name), target, "bind", opts);
Packit 8480eb
	if (!ret)
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "bind mount failed, symlinking");
Packit 8480eb
Packit 8480eb
symlink:
Packit 8480eb
	ret = do_mount(ap, ap->path,
Packit 8480eb
		       name, strlen(name), target, "bind", "symlink");
Packit 8480eb
	if (!ret)
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	error(ap->logopt, MODPREFIX
Packit 8480eb
	      "failed to symlink %s to %s", entry->path, target);
Packit 8480eb
Packit 8480eb
	if (entry->sublink) {
Packit 8480eb
		/* failed to complete sublink mount */
Packit 8480eb
		umount_amd_ext_mount(ap, entry);
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_linkx_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			  struct amd_entry *entry, unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	struct stat st;
Packit 8480eb
	char *target;
Packit 8480eb
Packit 8480eb
	if (entry->sublink)
Packit 8480eb
		target = entry->sublink;
Packit 8480eb
	else
Packit 8480eb
		target = entry->fs;
Packit 8480eb
Packit 8480eb
	if (lstat(target, &st) < 0)
Packit 8480eb
		return errno;
Packit 8480eb
Packit 8480eb
	return do_link_mount(ap, name, entry, flags);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_generic_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			    struct amd_entry *entry, const char *target,
Packit 8480eb
			    unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	const char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
Packit 8480eb
	unsigned int umount = 0;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	if (!entry->fs) {
Packit 8480eb
		ret = do_mount(ap, ap->path, name,
Packit 8480eb
			       strlen(name), target, entry->type, opts);
Packit 8480eb
	} else {
Packit 8480eb
		/*
Packit 8480eb
		 * Careful, external mounts may get mounted
Packit 8480eb
		 * multiple times since they are outside of
Packit 8480eb
		 * the automount filesystem.
Packit 8480eb
		 */
Packit Service 145c60
		if (!is_mounted(_PATH_MOUNTED, entry->fs, MNTS_REAL)) {
Packit 8480eb
			ret = do_mount(ap, entry->fs, "/", 1,
Packit 8480eb
				       target, entry->type, opts);
Packit 8480eb
			if (ret)
Packit 8480eb
				goto out;
Packit 8480eb
			umount = 1;
Packit 8480eb
		}
Packit 8480eb
		/* We have an external mount */
Packit Service 145c60
		ext_mount_add(&entry->ext_mount, entry->fs, umount);
Packit 8480eb
		ret = do_link_mount(ap, name, entry, flags);
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_nfs_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			struct amd_entry *entry, unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	char target[PATH_MAX + 1];
Packit 8480eb
	unsigned int proximity;
Packit 8480eb
	char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
Packit 8480eb
	unsigned int umount = 0;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	if (strlen(entry->rhost) + strlen(entry->rfs) + 1 > PATH_MAX) {
Packit 8480eb
		error(ap->logopt, MODPREFIX
Packit 8480eb
		     "error: rhost + rfs options length is too long");
Packit Service 145c60
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	strcpy(target, entry->rhost);
Packit 8480eb
	strcat(target, ":");
Packit 8480eb
	strcat(target, entry->rfs);
Packit 8480eb
Packit 8480eb
	proximity = get_network_proximity(entry->rhost);
Packit 8480eb
	if (proximity == PROXIMITY_OTHER && entry->remopts && *entry->remopts)
Packit 8480eb
		opts = entry->remopts;
Packit 8480eb
Packit 8480eb
	if (!entry->fs) {
Packit 8480eb
		ret = mount_nfs->mount_mount(ap, ap->path, name, strlen(name),
Packit 8480eb
					     target, entry->type, opts,
Packit 8480eb
					     mount_nfs->context);
Packit 8480eb
	} else {
Packit Service 145c60
		if (!is_mounted(_PATH_MOUNTED, entry->fs, MNTS_REAL)) {
Packit 8480eb
			ret = mount_nfs->mount_mount(ap, entry->fs, "/", 1,
Packit 8480eb
						target, entry->type, opts,
Packit 8480eb
						mount_nfs->context);
Packit 8480eb
			if (ret)
Packit 8480eb
				goto out;
Packit 8480eb
			umount = 1;
Packit 8480eb
		}
Packit 8480eb
		/* We might be using an external mount */
Packit Service 145c60
		ext_mount_add(&entry->ext_mount, entry->fs, umount);
Packit 8480eb
		ret = do_link_mount(ap, name, entry, flags);
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_nfsl_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			 struct amd_entry *entry, struct substvar *sv,
Packit 8480eb
			 unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	const struct substvar *host, *hostd;
Packit 8480eb
	struct stat st;
Packit 8480eb
	char *target;
Packit 8480eb
Packit 8480eb
	host = macro_findvar(sv, "host", 4);
Packit 8480eb
	if (!host)
Packit 8480eb
		return do_nfs_mount(ap, name, entry, flags);
Packit 8480eb
	hostd = macro_findvar(sv, "hostd", 5);
Packit 8480eb
	if (!hostd || !*hostd->val)
Packit 8480eb
		return do_nfs_mount(ap, name, entry, flags);
Packit 8480eb
Packit 8480eb
	if (entry->sublink)
Packit 8480eb
		target = entry->sublink;
Packit 8480eb
	else
Packit 8480eb
		target = entry->fs;
Packit 8480eb
Packit 8480eb
	if (strcasecmp(host->val, entry->rhost) ||
Packit 8480eb
	    strcasecmp(hostd->val, entry->rhost))
Packit 8480eb
		return do_nfs_mount(ap, name, entry, flags);
Packit 8480eb
	else if (lstat(target, &st) < 0)
Packit 8480eb
		return do_nfs_mount(ap, name, entry, flags);
Packit 8480eb
Packit 8480eb
	return do_link_mount(ap, name, entry, flags);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int wait_for_expire(struct autofs_point *ap)
Packit 8480eb
{
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	st_wait_task(ap, ST_EXPIRE, 0);
Packit 8480eb
Packit 8480eb
	st_mutex_lock();
Packit 8480eb
	if (ap->state != ST_SHUTDOWN &&
Packit 8480eb
	    ap->state != ST_SHUTDOWN_PENDING &&
Packit 8480eb
	    ap->state != ST_SHUTDOWN_FORCE) {
Packit 8480eb
		ret = 1;
Packit 8480eb
	}
Packit 8480eb
	st_mutex_unlock();
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_host_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
			 struct amd_entry *entry, struct map_source *source,
Packit 8480eb
			 unsigned int flags)
Packit 8480eb
{
Packit 8480eb
	struct lookup_mod *lookup;
Packit 8480eb
	struct map_source *instance;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	const char *argv[2];
Packit 8480eb
	const char **pargv = NULL;
Packit 8480eb
	int status;
Packit 8480eb
	int argc = 0;
Packit 8480eb
	int ret = 1;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * If the mount point name isn't the same as the host name
Packit 8480eb
	 * then we need to symlink to it after the mount. Attempt
Packit 8480eb
	 * the allocation and set entry->path to the base location
Packit 8480eb
	 * of the hosts mount tree so we can find it in
Packit 8480eb
	 * lookup_nss_mount() later.
Packit 8480eb
	 */
Packit 8480eb
	if (strcmp(name, entry->rhost)) {
Packit 8480eb
		char *target;
Packit 8480eb
		size_t len = strlen(ap->path) + strlen(entry->rhost) + 2;
Packit 8480eb
		target = malloc(len);
Packit 8480eb
		if (!target) {
Packit 8480eb
			warn(ap->logopt, MODPREFIX
Packit 8480eb
			     "failed to alloc target to hosts mount base");
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
		strcpy(target, ap->path);
Packit 8480eb
		strcat(target, "/");
Packit 8480eb
		strcat(target, entry->rhost);
Packit 8480eb
		if (entry->path)
Packit 8480eb
			free(entry->path);
Packit 8480eb
		entry->path = target;
Packit 8480eb
		/*
Packit 8480eb
		 * Wait for any expire before racing to mount the
Packit 8480eb
		 * export tree or bail out if we're shutting down.
Packit 8480eb
		*/
Packit 8480eb
		if (!wait_for_expire(ap))
Packit 8480eb
			goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->opts && *entry->opts) {
Packit 8480eb
		argv[0] = entry->opts;
Packit 8480eb
		argv[1] = NULL;
Packit 8480eb
		pargv = argv;
Packit 8480eb
		argc = 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	instance_mutex_lock();
Packit 8480eb
	status = open_lookup("hosts", MODPREFIX, NULL, argc, pargv, &lookup);
Packit 8480eb
	if (status != NSS_STATUS_SUCCESS) {
Packit 8480eb
		debug(ap->logopt, "open lookup module hosts failed");
Packit 8480eb
		instance_mutex_unlock();
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	instance = master_find_source_instance(source,
Packit 8480eb
					 "hosts", "sun", argc, pargv);
Packit 8480eb
	if (!instance) {
Packit 8480eb
		instance = master_add_source_instance(source,
Packit 8480eb
				 "hosts", "sun", monotonic_time(NULL), argc, pargv);
Packit 8480eb
		if (!instance) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "failed to create source instance for hosts map");
Packit 8480eb
			instance_mutex_unlock();
Packit 8480eb
			close_lookup(lookup);
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	instance->lookup = lookup;
Packit 8480eb
	instance_mutex_unlock();
Packit 8480eb
Packit 8480eb
	cache_writelock(source->mc);
Packit 8480eb
	me = cache_lookup_distinct(source->mc, name);
Packit 8480eb
	if (me)
Packit 8480eb
		cache_push_mapent(me, NULL);
Packit 8480eb
	cache_unlock(source->mc);
Packit 8480eb
Packit 8480eb
	master_source_current_wait(ap->entry);
Packit 8480eb
	ap->entry->current = source;
Packit 8480eb
Packit 8480eb
	ret = lookup->lookup_mount(ap, entry->rhost,
Packit 8480eb
				   strlen(entry->rhost), lookup->context);
Packit 8480eb
Packit 8480eb
	if (!strcmp(name, entry->rhost))
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	if (do_mount(ap, ap->path,
Packit 8480eb
		     name, strlen(name), entry->path, "bind", "symlink"))
Packit 8480eb
		warn(ap->logopt, MODPREFIX
Packit 8480eb
		     "failed to create symlink to hosts mount base");
Packit 8480eb
out:
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_program_mount(struct autofs_point *ap,
Packit 8480eb
			    struct amd_entry *entry, const char *name)
Packit 8480eb
{
Packit 8480eb
	char *prog, *str;
Packit 8480eb
	char **argv;
Packit 8480eb
	int argc = -1;
Packit 8480eb
	int rv = 1;
Packit 8480eb
Packit 8480eb
	str = strdup(entry->mount);
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
		error(ap->logopt, MODPREFIX
Packit 8480eb
		      "%s: error creating mount arguments", entry->type);
Packit 8480eb
		free(str);
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* The am-utils documentation doesn't actually say that the
Packit 8480eb
	 * mount (and umount, if given) command need to use ${fs} as
Packit 8480eb
	 * the mount point in the command.
Packit 8480eb
	 *
Packit 8480eb
	 * For program mounts there's no way to know what the mount
Packit 8480eb
	 * point is so ${fs} must be used in the mount (and umount,
Packit 8480eb
	 * if given) in order to create the mount point directory
Packit 8480eb
	 * before executing the mount command and removing it at
Packit 8480eb
	 * umount.
Packit 8480eb
	 */
Packit 8480eb
	if (ext_mount_inuse(entry->fs)) {
Packit 8480eb
		rv = 0;
Packit 8480eb
		ext_mount_add(&entry->ext_mount, entry->fs, 1);
Packit 8480eb
	} else {
Packit Service 145c60
		rv = mkdir_path(entry->fs, 0555);
Packit 8480eb
		if (rv && errno != EEXIST) {
Packit 8480eb
			char buf[MAX_ERR_BUF];
Packit 8480eb
			char *estr;
Packit 8480eb
Packit 8480eb
			estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      MODPREFIX "%s: mkdir_path %s failed: %s",
Packit 8480eb
			      entry->type, entry->fs, estr);
Packit 8480eb
			goto do_free;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		rv = spawnv(ap->logopt, prog, (const char * const *) argv);
Packit 8480eb
		if (WIFEXITED(rv) && !WEXITSTATUS(rv)) {
Packit Service 145c60
			rv = 0;
Packit Service 145c60
			ext_mount_add(&entry->ext_mount, entry->fs, 1);
Packit Service 145c60
			debug(ap->logopt, MODPREFIX
Packit Service 145c60
			      "%s: mounted %s", entry->type, entry->fs);
Packit Service 145c60
		} else {
Packit Service 145c60
			if (!ext_mount_inuse(entry->fs))
Packit Service 145c60
				rmdir_path(ap, entry->fs, ap->dev);
Packit Service 145c60
			error(ap->logopt, MODPREFIX
Packit Service 145c60
			     "%s: failed to mount using: %s",
Packit Service 145c60
			     entry->type, entry->mount);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
do_free:
Packit 8480eb
	free_argv(argc, (const char **) argv);
Packit 8480eb
	free(str);
Packit 8480eb
Packit 8480eb
	if (rv)
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	rv = do_link_mount(ap, name, entry, 0);
Packit 8480eb
	if (!rv)
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	if (umount_amd_ext_mount(ap, entry)) {
Packit 8480eb
		if (!ext_mount_inuse(entry->fs))
Packit 8480eb
			rmdir_path(ap, entry->fs, ap->dev);
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "%s: failed to umount external mount at %s",
Packit 8480eb
		      entry->type, entry->fs);
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_auto_options(unsigned int logopt,
Packit 8480eb
					  struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/*
Packit 8480eb
	 * The amd manual implies all the mount type auto options
Packit 8480eb
	 * are optional but I don't think there's much point if
Packit 8480eb
	 * no map is given. If the option has been intentionally
Packit 8480eb
	 * left blank the mount must be expected to fail so don't
Packit 8480eb
	 * report the error.
Packit 8480eb
	 */
Packit 8480eb
	if (!entry->fs) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: file system not given", entry->type);
Packit 8480eb
		return 0;
Packit 8480eb
	} else if (!*entry->fs)
Packit 8480eb
		return 0;
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_link_options(unsigned int logopt,
Packit 8480eb
					  struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/* fs is the destimation of the link */
Packit 8480eb
	return validate_auto_options(logopt, entry);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_nfs_options(unsigned int logopt,
Packit 8480eb
					 struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/*
Packit 8480eb
	 * Required option rhost will always have a value unless
Packit 8480eb
	 * it has been intentionally left blank. It is set from
Packit 8480eb
	 * ${host} if it is found to be NULL earlier in the parsing
Packit 8480eb
	 * process. Don't report the error if it has been left blank
Packit 8480eb
	 * or if the fs option has been left blank since the mount is
Packit 8480eb
	 * expected to fail.
Packit 8480eb
	 */
Packit 8480eb
	if (!entry->rfs || !*entry->rfs) {
Packit 8480eb
		if (entry->rfs && !*entry->rfs)
Packit 8480eb
			return 0;
Packit 8480eb
		/* Map option fs has been intentionally left blank */
Packit 8480eb
		if (entry->fs && !*entry->fs)
Packit 8480eb
			return 0;
Packit 8480eb
		entry->rfs = strdup(entry->fs);
Packit 8480eb
		if (!entry->rfs) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "%s: remote file system not given", entry->type);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	if (entry->sublink && !entry->fs) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: sublink option requires option fs");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_generic_options(unsigned int logopt,
Packit 8480eb
					     unsigned long fstype,
Packit 8480eb
					     struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/*
Packit 8480eb
	 * If dev or rfs are empty in the map entry the mount is
Packit 8480eb
	 * expected to fail so don't report the error.
Packit 8480eb
	 */
Packit 8480eb
	if (fstype != AMD_MOUNT_TYPE_LOFS) {
Packit 8480eb
		if (!entry->dev) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "%s: mount device not given", entry->type);
Packit 8480eb
			return 0;
Packit 8480eb
		} else if (!*entry->dev)
Packit 8480eb
			return 0;
Packit 8480eb
	} else {
Packit 8480eb
		if (!entry->rfs) {
Packit 8480eb
			/*
Packit 8480eb
			 * Can't use entry->type as the mount type to reprot
Packit 8480eb
			 * the error since entry->type == "bind" not "lofs".
Packit 8480eb
			 */
Packit 8480eb
			error(logopt, MODPREFIX "lofs: mount device not given");
Packit 8480eb
			return 0;
Packit 8480eb
		} else if (!*entry->rfs)
Packit 8480eb
			return 0;
Packit 8480eb
	}
Packit 8480eb
	if (entry->sublink && !entry->fs) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: sublink option requires option fs");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_ufs_fstype(unsigned int logopt,
Packit 8480eb
					struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	const char *type = (const char *) entry->type;
Packit 8480eb
Packit 8480eb
	if (strcmp(type, "ext") && strcmp(type, "ext2") &&
Packit 8480eb
	    strcmp(type, "ext3") && strcmp(type, "ext4") &&
Packit 8480eb
	    strcmp(type, "xfs") && strcmp(type, "jfs")) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: mount type %s not valid as ufs mount type on Linux",
Packit 8480eb
		      type);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_host_options(unsigned int logopt,
Packit 8480eb
					  struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/*
Packit 8480eb
	 * rhost is always non-null, unless it is intentionally left
Packit 8480eb
	 * empty, because it will have the the value of the host name
Packit 8480eb
	 * if it isn't given in the map entry. Don't report an error
Packit 8480eb
	 * if it has been left empty since it's expected to fail.
Packit 8480eb
	 */
Packit 8480eb
	if (!entry->rhost) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: remote host name not given", entry->type);
Packit 8480eb
		return 0;
Packit 8480eb
	} else if (!*entry->rhost)
Packit 8480eb
		return 0;
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int validate_program_options(unsigned int logopt,
Packit 8480eb
					     struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	/*
Packit 8480eb
	 * entry->mount will be NULL if there is a problem expanding
Packit 8480eb
	 * ${} macros in expandamdent().
Packit 8480eb
	 */
Packit 8480eb
	if (!entry->mount) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		      "%s: mount program invalid or not set", entry->type);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!entry->fs || !*entry->fs) {
Packit 8480eb
		error(logopt, MODPREFIX
Packit 8480eb
		    "%s: ${fs} must be used as the mount point but is not set",
Packit 8480eb
		    entry->type);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int amd_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
		     struct amd_entry *entry, struct map_source *source,
Packit 8480eb
		     struct substvar *sv, unsigned int flags,
Packit 8480eb
		     struct parse_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	unsigned long fstype = entry->flags & AMD_MOUNT_TYPE_MASK;
Packit 8480eb
	int ret = 1;
Packit 8480eb
Packit 8480eb
	switch (fstype) {
Packit 8480eb
	case AMD_MOUNT_TYPE_AUTO:
Packit 8480eb
		if (!validate_auto_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_auto_mount(ap, name, entry, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_LOFS:
Packit 8480eb
		if (!validate_generic_options(ap->logopt, fstype, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_generic_mount(ap, name, entry, entry->rfs, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_UFS:
Packit 8480eb
		if (!validate_ufs_fstype(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		/* fall through to validate generic options */
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_EXT:
Packit 8480eb
	case AMD_MOUNT_TYPE_XFS:
Packit 8480eb
	case AMD_MOUNT_TYPE_CDFS:
Packit 8480eb
		if (!validate_generic_options(ap->logopt, fstype, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_generic_mount(ap, name, entry, entry->dev, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_NFS:
Packit 8480eb
		if (!validate_nfs_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_nfs_mount(ap, name, entry, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_NFSL:
Packit 8480eb
		if (!validate_nfs_options(ap->logopt, entry) ||
Packit 8480eb
		    !validate_link_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_nfsl_mount(ap, name, entry, sv, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_LINK:
Packit 8480eb
		if (!validate_link_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_link_mount(ap, name, entry, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_LINKX:
Packit 8480eb
		if (!validate_link_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_linkx_mount(ap, name, entry, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_HOST:
Packit 8480eb
		if (!validate_host_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_host_mount(ap, name, entry, source, flags);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AMD_MOUNT_TYPE_PROGRAM:
Packit 8480eb
		if (!validate_program_options(ap->logopt, entry))
Packit 8480eb
			return 1;
Packit 8480eb
		ret = do_program_mount(ap, entry, name);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	default:
Packit 8480eb
		info(ap->logopt,
Packit 8480eb
		     MODPREFIX "unknown file system type %x", fstype);
Packit 8480eb
		break;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void dequote_entry(struct autofs_point *ap, struct amd_entry *entry)
Packit 8480eb
{
Packit 8480eb
	char *res;
Packit 8480eb
Packit 8480eb
	if (entry->pref) {
Packit 8480eb
		res = dequote(entry->pref, strlen(entry->pref), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "pref dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->pref), entry->pref, res);
Packit 8480eb
			free(entry->pref);
Packit 8480eb
			entry->pref = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->sublink) {
Packit 8480eb
		res = dequote(entry->sublink, strlen(entry->sublink), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "sublink dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->sublink), entry->sublink, res);
Packit 8480eb
			free(entry->sublink);
Packit 8480eb
			entry->sublink = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->fs && *entry->fs) {
Packit 8480eb
		res = dequote(entry->fs, strlen(entry->fs), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "fs dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->fs), entry->fs, res);
Packit 8480eb
			free(entry->fs);
Packit 8480eb
			entry->fs = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->rfs && *entry->rfs) {
Packit 8480eb
		res = dequote(entry->rfs, strlen(entry->rfs), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "rfs dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->rfs), entry->rfs, res);
Packit 8480eb
			free(entry->rfs);
Packit 8480eb
			entry->rfs = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->opts && *entry->opts) {
Packit 8480eb
		res = dequote(entry->opts, strlen(entry->opts), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "ops dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->opts), entry->opts, res);
Packit 8480eb
			free(entry->opts);
Packit 8480eb
			entry->opts = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->remopts && *entry->remopts) {
Packit 8480eb
		res = dequote(entry->remopts, strlen(entry->remopts), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "remopts dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->remopts), entry->remopts, res);
Packit 8480eb
			free(entry->remopts);
Packit 8480eb
			entry->remopts = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (entry->addopts && *entry->addopts) {
Packit 8480eb
		res = dequote(entry->addopts, strlen(entry->addopts), ap->logopt);
Packit 8480eb
		if (res) {
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "addopts dequote(\"%.*s\") -> %s",
Packit 8480eb
			      strlen(entry->addopts), entry->addopts, res);
Packit 8480eb
			free(entry->addopts);
Packit 8480eb
			entry->addopts = res;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void normalize_sublink(unsigned int logopt,
Packit 8480eb
			      struct amd_entry *entry, struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char *new;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	/* Normalizing sublink requires a non-blank fs option */
Packit 8480eb
	if (!*entry->fs)
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	if (entry->sublink && *entry->sublink != '/') {
Packit 8480eb
		len = strlen(entry->fs) + strlen(entry->sublink) + 2;
Packit 8480eb
		new = malloc(len);
Packit 8480eb
		if (!new) {
Packit 8480eb
			error(logopt, MODPREFIX
Packit 8480eb
			      "error: couldn't allocate storage for sublink");
Packit 8480eb
			return;
Packit 8480eb
		}
Packit 8480eb
		strcpy(new, entry->fs);
Packit 8480eb
		strcat(new, "/");
Packit 8480eb
		strcat(new, entry->sublink);
Packit 8480eb
		debug(logopt, MODPREFIX
Packit 8480eb
		      "rfs dequote(\"%.*s\") -> %s",
Packit 8480eb
		      strlen(entry->sublink), entry->sublink, new);
Packit 8480eb
		free(entry->sublink);
Packit 8480eb
		entry->sublink = new;
Packit 8480eb
	}
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Set the prefix.
Packit 8480eb
 *
Packit 8480eb
 * This is done in a couple of places, here is as good a place as
Packit 8480eb
 * any to describe it.
Packit 8480eb
 *
Packit 8480eb
 * If a prefix is present in the map entry then use it.
Packit 8480eb
 *
Packit 8480eb
 * A pref option with the value none is required to use no prefix,
Packit 8480eb
 * otherwise the prefix of the parent map, if any, will be used.
Packit 8480eb
 */
Packit 8480eb
static void update_prefix(struct autofs_point *ap,
Packit 8480eb
			  struct amd_entry *entry, const char *name)
Packit 8480eb
{
Packit 8480eb
	size_t len;
Packit 8480eb
	char *new;
Packit 8480eb
Packit 8480eb
	if (!entry->pref && ap->pref) {
Packit 8480eb
		len = strlen(ap->pref) + strlen(name) + 2;
Packit 8480eb
		new = malloc(len);
Packit 8480eb
		if (new) {
Packit 8480eb
			strcpy(new, ap->pref);
Packit 8480eb
			strcat(new, name);
Packit 8480eb
			strcat(new, "/");
Packit 8480eb
			entry->pref = new;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit Service 145c60
static int match_selectors(unsigned int logopt,
Packit 8480eb
			   struct amd_entry *entry, struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct selector *s = entry->selector;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	/* No selectors, always match */
Packit 8480eb
	if (!s) {
Packit Service 145c60
		debug(logopt, MODPREFIX "no selectors found in location");
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = 0;
Packit 8480eb
Packit 8480eb
	/* All selectors must match */
Packit 8480eb
	while (s) {
Packit Service 145c60
		ret = eval_selector(logopt, entry, sv);
Packit 8480eb
		if (!ret)
Packit 8480eb
			break;
Packit 8480eb
		s = s->next;
Packit 8480eb
	}
Packit 8480eb
	if (!s)
Packit 8480eb
		ret = 1;
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct amd_entry *dup_defaults_entry(struct amd_entry *defaults)
Packit 8480eb
{
Packit 8480eb
	struct amd_entry *entry;
Packit 8480eb
	char *tmp;
Packit 8480eb
Packit 8480eb
	entry = malloc(sizeof(struct amd_entry));
Packit 8480eb
	if (!entry)
Packit 8480eb
		return NULL;
Packit 8480eb
	memset(entry, 0, sizeof(struct amd_entry));
Packit 8480eb
Packit 8480eb
	entry->flags = defaults->flags;
Packit 8480eb
Packit 8480eb
	if (defaults->type) {
Packit 8480eb
		tmp = strdup(defaults->type);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->type = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->map_type) {
Packit 8480eb
		tmp = strdup(defaults->map_type);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->map_type = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->pref) {
Packit 8480eb
		tmp = strdup(defaults->pref);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->pref = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->fs) {
Packit 8480eb
		tmp = strdup(defaults->fs);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->fs = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* These shouldn't be blank in a defaults entry but ... */
Packit 8480eb
Packit 8480eb
	if (defaults->rfs && *defaults->rfs) {
Packit 8480eb
		tmp = strdup(defaults->rfs);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->rfs = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->rhost && *defaults->rhost) {
Packit 8480eb
		tmp = strdup(defaults->rhost);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->rhost = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->dev && *defaults->dev) {
Packit 8480eb
		tmp = strdup(defaults->dev);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->dev = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->opts && *defaults->opts) {
Packit 8480eb
		tmp = strdup(defaults->opts);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->opts = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->addopts && *defaults->addopts) {
Packit 8480eb
		tmp = strdup(defaults->addopts);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->addopts = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (defaults->remopts && *defaults->remopts) {
Packit 8480eb
		tmp = strdup(defaults->remopts);
Packit 8480eb
		if (tmp)
Packit 8480eb
			entry->remopts = tmp;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	INIT_LIST_HEAD(&entry->list);
Packit 8480eb
Packit 8480eb
	return entry;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct amd_entry *make_default_entry(struct autofs_point *ap,
Packit 8480eb
				     struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char *defaults = "opts:=rw,defaults";
Packit 8480eb
	struct amd_entry *defaults_entry;
Packit 8480eb
	struct list_head dflts;
Packit 8480eb
	char *map_type;
Packit 8480eb
Packit 8480eb
	INIT_LIST_HEAD(&dflts);
Packit 8480eb
	if (amd_parse_list(ap, defaults, &dflts, &sv))
Packit 8480eb
		return NULL;
Packit 8480eb
	defaults_entry = list_entry(dflts.next, struct amd_entry, list);
Packit Service 145c60
	list_del_init(&defaults_entry->list);
Packit 8480eb
	/*
Packit 8480eb
	 * If map type isn't given try to inherit from
Packit 8480eb
	 * parent. A NULL map type is valid and means
Packit 8480eb
	 * use configured nss sources.
Packit 8480eb
	 */
Packit 8480eb
	map_type = conf_amd_get_map_type(ap->path);
Packit Service 145c60
	if (map_type)
Packit Service 145c60
		defaults_entry->map_type = strdup(map_type);
Packit 8480eb
	/* The list should now be empty .... */
Packit 8480eb
	free_amd_entry_list(&dflts);
Packit 8480eb
	return defaults_entry;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct amd_entry *select_default_entry(struct autofs_point *ap,
Packit 8480eb
					      struct list_head *entries,
Packit 8480eb
					      struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	unsigned long flags = conf_amd_get_flags(ap->path);
Packit 8480eb
	struct amd_entry *defaults_entry = NULL;
Packit 8480eb
	struct amd_entry *entry_default = NULL;
Packit 8480eb
	struct list_head *p, *head;
Packit 8480eb
Packit 8480eb
	if (!(flags & CONF_SELECTORS_IN_DEFAULTS))
Packit 8480eb
		goto no_sel;
Packit 8480eb
Packit 8480eb
	head = entries;
Packit 8480eb
	p = head->next;
Packit 8480eb
	while (p != head) {
Packit 8480eb
		struct amd_entry *this = list_entry(p, struct amd_entry, list);
Packit 8480eb
Packit 8480eb
		p = p->next;
Packit 8480eb
Packit 8480eb
		if (this->flags & AMD_DEFAULTS_MERGE) {
Packit 8480eb
			if (entry_default)
Packit 8480eb
				free_amd_entry(entry_default);
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			entry_default = this;
Packit 8480eb
			continue;
Packit 8480eb
		} else if (this->flags & AMD_DEFAULTS_RESET) {
Packit 8480eb
			struct amd_entry *new;
Packit 8480eb
			new = dup_defaults_entry(defaults_entry);
Packit 8480eb
			if (new) {
Packit 8480eb
				free_amd_entry(entry_default);
Packit 8480eb
				entry_default = new;
Packit 8480eb
			}
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			free_amd_entry(this);
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * This probably should be a fail since we expect
Packit 8480eb
		 * selectors to pick the default entry.
Packit 8480eb
		 */
Packit 8480eb
		if (!this->selector)
Packit 8480eb
			continue;
Packit 8480eb
Packit Service 145c60
		if (match_selectors(ap->logopt, this, sv)) {
Packit 8480eb
			if (entry_default) {
Packit 8480eb
				/*update_with_defaults(entry_default, this, sv);*/
Packit 8480eb
				free_amd_entry(entry_default);
Packit 8480eb
			}
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			defaults_entry = this;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Not strickly amd semantics but ... */
Packit 8480eb
	if (!defaults_entry && entry_default) {
Packit 8480eb
		defaults_entry = entry_default;
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!defaults_entry) {
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "no matching selector(s) found in defaults, "
Packit 8480eb
		      "using internal defaults");
Packit 8480eb
		goto ret_default;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	goto done;
Packit 8480eb
Packit 8480eb
no_sel:
Packit 8480eb
	if (list_empty(entries))
Packit 8480eb
		goto ret_default;
Packit 8480eb
Packit 8480eb
	defaults_entry = list_entry(entries->next, struct amd_entry, list);
Packit 8480eb
	list_del_init(&defaults_entry->list);
Packit 8480eb
	if (!list_empty(entries)) {
Packit 8480eb
		free_amd_entry(defaults_entry);
Packit 8480eb
		goto ret_default;
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	/*merge_entry_options(ap, defaults_entry, sv);*/
Packit 8480eb
	/*normalize_sublink(ap->logopt, defaults_entry, sv);*/
Packit 8480eb
	return defaults_entry;
Packit 8480eb
Packit 8480eb
ret_default:
Packit 8480eb
	return make_default_entry(ap, sv);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct amd_entry *get_defaults_entry(struct autofs_point *ap,
Packit 8480eb
					    const char *defaults,
Packit 8480eb
					    struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	struct amd_entry *entry;
Packit 8480eb
	struct list_head dflts;
Packit 8480eb
Packit 8480eb
	INIT_LIST_HEAD(&dflts);
Packit 8480eb
Packit 8480eb
	entry = NULL;
Packit 8480eb
	if (!defaults)
Packit 8480eb
		goto out;
Packit 8480eb
	else {
Packit 8480eb
		char *expand;
Packit 8480eb
		if (!expand_selectors(ap, defaults, &expand, sv))
Packit 8480eb
			goto out;
Packit 8480eb
		if (amd_parse_list(ap, expand, &dflts, &sv)) {
Packit 8480eb
			error(ap->logopt, MODPREFIX
Packit 8480eb
			     "failed to parse defaults entry, "
Packit 8480eb
			     "attempting to use internal default");
Packit 8480eb
			free(expand);
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
		entry = select_default_entry(ap, &dflts, sv);
Packit 8480eb
		if (!entry->map_type) {
Packit 8480eb
			/*
Packit 8480eb
			 * If map type isn't given try to inherit from
Packit 8480eb
			 * parent. A NULL map type is valid and means
Packit 8480eb
			 * use configured nss sources.
Packit 8480eb
			 */
Packit 8480eb
			char *map_type = conf_amd_get_map_type(ap->path);
Packit Service 145c60
			if (map_type)
Packit Service 145c60
				entry->map_type = strdup(map_type);
Packit 8480eb
		}
Packit 8480eb
		free(expand);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return entry;
Packit 8480eb
out:
Packit 8480eb
	return make_default_entry(ap, sv);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static struct amd_entry *setup_defaults(struct autofs_point *ap,
Packit 8480eb
					const char *name, int name_len,
Packit 8480eb
					struct map_source *source,
Packit 8480eb
					struct substvar **sv)
Packit 8480eb
{
Packit 8480eb
	struct amd_entry *defaults_entry;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	struct substvar *nsv;
Packit 8480eb
	char *defaults;
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
	defaults = NULL;
Packit 8480eb
	defaults_entry = NULL;
Packit 8480eb
Packit 8480eb
	nsv = add_lookup_vars(ap, name, name_len, source, NULL);
Packit 8480eb
	if (!nsv)
Packit 8480eb
		goto done;
Packit 8480eb
Packit 8480eb
	defaults = conf_amd_get_map_defaults(ap->path);
Packit 8480eb
	if (defaults) {
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "using map_defaults %s for %s", defaults, ap->path);
Packit 8480eb
	} else if ((me = cache_lookup_distinct(mc, "/defaults"))) {
Packit 8480eb
		defaults = strdup(me->mapent);
Packit 8480eb
		if (defaults)
Packit 8480eb
			debug(ap->logopt, MODPREFIX
Packit 8480eb
			      "using /defaults %s from map", defaults);
Packit 8480eb
		else {
Packit 8480eb
			char buf[MAX_ERR_BUF];
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			macro_free_table(nsv);
Packit 8480eb
			nsv = NULL;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	defaults_entry = get_defaults_entry(ap, defaults, nsv);
Packit 8480eb
	if (!defaults_entry) {
Packit 8480eb
		error(ap->logopt, MODPREFIX "failed to get a defaults entry");
Packit 8480eb
		macro_free_table(nsv);
Packit 8480eb
		nsv = NULL;
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	if (defaults)
Packit 8480eb
		free(defaults);
Packit 8480eb
	if (*sv)
Packit 8480eb
		macro_free_table(*sv);
Packit 8480eb
	*sv = nsv;
Packit 8480eb
Packit 8480eb
	return defaults_entry;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int parse_mount(struct autofs_point *ap, const char *name,
Packit 8480eb
		int name_len, const char *mapent, void *context)
Packit 8480eb
{
Packit 8480eb
	struct parse_context *ctxt = (struct parse_context *) context;
Packit 8480eb
	unsigned int flags = conf_amd_get_flags(ap->path);
Packit 8480eb
	struct substvar *sv = NULL;
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	unsigned int at_least_one;
Packit 8480eb
	struct list_head entries, *p, *head;
Packit 8480eb
	struct amd_entry *defaults_entry;
Packit 8480eb
	struct amd_entry *cur_defaults;
Packit 8480eb
	int rv = 1;
Packit 8480eb
	int cur_state;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	source = ap->entry->current;
Packit 8480eb
	ap->entry->current = NULL;
Packit 8480eb
	master_source_current_signal(ap->entry);
Packit 8480eb
Packit 8480eb
	if (!mapent) {
Packit 8480eb
		warn(ap->logopt, MODPREFIX "error: empty map entry");
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	INIT_LIST_HEAD(&entries);
Packit 8480eb
Packit 8480eb
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit 8480eb
Packit 8480eb
	defaults_entry = setup_defaults(ap, name, name_len, source, &sv;;
Packit 8480eb
	if (!defaults_entry) {
Packit 8480eb
		error(ap->logopt, MODPREFIX
Packit 8480eb
		      "failed to setup defaults entry");
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = amd_parse_list(ap, mapent, &entries, &sv;;
Packit 8480eb
	if (ret) {
Packit 8480eb
		error(ap->logopt,
Packit 8480eb
		      MODPREFIX "failed to parse entry: %s", mapent);
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (list_empty(&entries)) {
Packit 8480eb
		error(ap->logopt, MODPREFIX "no location found after parse");
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	cur_defaults = dup_defaults_entry(defaults_entry);
Packit 8480eb
	if (!cur_defaults) {
Packit 8480eb
		error(ap->logopt, MODPREFIX
Packit 8480eb
		      "failed to duplicate defaults entry");
Packit 8480eb
		goto done;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	at_least_one = 0;
Packit 8480eb
	head = &entries;
Packit 8480eb
	p = head->next;
Packit 8480eb
	while (p != head) {
Packit 8480eb
		struct amd_entry *this = list_entry(p, struct amd_entry, list);
Packit 8480eb
		p = p->next;
Packit 8480eb
Packit 8480eb
		if (this->flags & AMD_DEFAULTS_MERGE) {
Packit 8480eb
			free_amd_entry(cur_defaults);
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			cur_defaults = this;
Packit 8480eb
			update_with_defaults(defaults_entry, cur_defaults, sv);
Packit 8480eb
			continue;
Packit 8480eb
		} else if (this->flags & AMD_DEFAULTS_RESET) {
Packit 8480eb
			struct amd_entry *nd, *new;
Packit 8480eb
			struct substvar *nsv = NULL;
Packit 8480eb
Packit 8480eb
			nd = setup_defaults(ap, name, name_len, source, &nsv;;
Packit 8480eb
			if (nd) {
Packit 8480eb
				free_amd_entry(defaults_entry);
Packit 8480eb
				defaults_entry = nd;
Packit 8480eb
				macro_free_table(sv);
Packit 8480eb
				sv = nsv;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			new = dup_defaults_entry(defaults_entry);
Packit 8480eb
			if (new) {
Packit 8480eb
				free_amd_entry(cur_defaults);
Packit 8480eb
				cur_defaults = new;
Packit 8480eb
			}
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			free_amd_entry(this);
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt, "expand defaults entry");
Packit 8480eb
		sv = expand_entry(ap, cur_defaults, flags, sv);
Packit 8480eb
Packit 8480eb
		if (this->flags & AMD_ENTRY_CUT && at_least_one) {
Packit 8480eb
			info(ap->logopt, MODPREFIX
Packit 8480eb
			     "at least one entry tried before cut selector, "
Packit 8480eb
			     "not continuing");
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
Packit Service 145c60
		if (!match_selectors(ap->logopt, this, sv))
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		at_least_one = 1;
Packit 8480eb
Packit Service 19c1f8
		debug(ap->logopt, "expand mount entry");
Packit Service 145c60
		update_with_defaults(cur_defaults, this, sv);
Packit 8480eb
		sv = expand_entry(ap, this, flags, sv);
Packit 8480eb
		sv = merge_entry_options(ap, this, sv);
Packit 8480eb
		normalize_sublink(ap->logopt, this, sv);
Packit 8480eb
		update_prefix(ap, this, name);
Packit 8480eb
Packit 8480eb
		dequote_entry(ap, this);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Type "auto" needs to set the prefix at mount time so
Packit 8480eb
		 * add parsed entry to parent amd mount list and remove
Packit 8480eb
		 * on mount fail.
Packit 8480eb
		 */
Packit 8480eb
		mounts_mutex_lock(ap);
Packit 8480eb
		list_add_tail(&this->entries, &ap->amdmounts);
Packit 8480eb
		mounts_mutex_unlock(ap);
Packit 8480eb
Packit 8480eb
		rv = amd_mount(ap, name, this, source, sv, flags, ctxt);
Packit 8480eb
		mounts_mutex_lock(ap);
Packit 8480eb
		if (!rv) {
Packit 8480eb
			/* Mounted, remove entry from parsed list */
Packit 8480eb
			list_del_init(&this->list);
Packit 8480eb
			mounts_mutex_unlock(ap);
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		/* Not mounted, remove entry from the parent list */
Packit 8480eb
		list_del_init(&this->entries);
Packit 8480eb
		mounts_mutex_unlock(ap);
Packit 8480eb
	}
Packit 8480eb
	free_amd_entry(cur_defaults);
Packit 8480eb
Packit 8480eb
	if (rv)
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "no more locations to try, returning fail");
Packit 8480eb
done:
Packit 8480eb
	free_amd_entry_list(&entries);
Packit 8480eb
	free_amd_entry(defaults_entry);
Packit 8480eb
	macro_free_table(sv);
Packit 8480eb
Packit 8480eb
	pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int parse_done(void *context)
Packit 8480eb
{
Packit 8480eb
	int rv = 0;
Packit 8480eb
	struct parse_context *ctxt = (struct parse_context *) context;
Packit 8480eb
Packit 8480eb
	instance_mutex_lock();
Packit 8480eb
	if (--init_ctr == 0) {
Packit 8480eb
		rv = close_mount(mount_nfs);
Packit 8480eb
		mount_nfs = NULL;
Packit 8480eb
	}
Packit 8480eb
	instance_mutex_unlock();
Packit 8480eb
	if (ctxt)
Packit 8480eb
		kill_context(ctxt);
Packit 8480eb
Packit 8480eb
	return rv;
Packit 8480eb
}