Blame modules/parse_sun.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  parse_sun.c - module for Linux automountd to parse a Sun-format
Packit 8480eb
 *                automounter map
Packit 8480eb
 * 
Packit 8480eb
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
Packit 8480eb
 *   Copyright 2000 Jeremy Fitzhardinge <jeremy@goop.org>
Packit 8480eb
 *   Copyright 2004, 2005 Ian Kent <raven@themaw.net>
Packit 8480eb
 *
Packit 8480eb
 *   This program is free software; you can redistribute it and/or modify
Packit 8480eb
 *   it under the terms of the GNU General Public License as published by
Packit 8480eb
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 *   USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 *   version; 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
Packit 8480eb
#define MODPREFIX "parse(sun): "
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
	int slashify_colons;	/* Change colons to slashes? */
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
	1			/* Do slashify_colons */
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
int destroy_logpri_fifo(struct autofs_point *ap);
Packit 8480eb
static char *concat_options(char *left, char *right);
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
/* 
Packit 8480eb
 * $- and &-expand a Sun-style map entry and return the length of the entry.
Packit 8480eb
 * If "dst" is NULL, just count the length.
Packit 8480eb
 */
Packit 8480eb
int expandsunent(const char *src, char *dst, const char *key,
Packit 8480eb
		 const struct substvar *svc, int slashify_colons)
Packit 8480eb
{
Packit 8480eb
	const struct substvar *sv;
Packit 8480eb
	int len, l, seen_colons;
Packit 8480eb
	const char *p;
Packit 8480eb
	char ch;
Packit 8480eb
Packit 8480eb
	len = 0;
Packit 8480eb
	seen_colons = 0;
Packit 8480eb
Packit 8480eb
	while ((ch = *src++)) {
Packit 8480eb
		switch (ch) {
Packit 8480eb
		case '&':
Packit 8480eb
			l = strlen(key);
Packit 8480eb
			/*
Packit 8480eb
			 * In order to ensure that any isspace() characters
Packit 8480eb
			 * in the key are preserved, we need to escape them
Packit 8480eb
			 * here.
Packit 8480eb
			 */
Packit 8480eb
			const char *keyp = key;
Packit 8480eb
			while (*keyp) {
Packit 8480eb
				if (isspace(*keyp)) {
Packit 8480eb
					if (dst) {
Packit 8480eb
						*dst++ = '\\';
Packit 8480eb
						*dst++ = *keyp++;
Packit 8480eb
					} else
Packit 8480eb
						keyp++;
Packit 8480eb
					l++;
Packit 8480eb
				} else {
Packit 8480eb
					if (dst)
Packit 8480eb
						*dst++ = *keyp++;
Packit 8480eb
					else
Packit 8480eb
						keyp++;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
			len += l;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case '$':
Packit 8480eb
			if (*src == '{') {
Packit 8480eb
				p = strchr(++src, '}');
Packit 8480eb
				if (!p) {
Packit 8480eb
					/* Ignore rest of string */
Packit 8480eb
					if (dst)
Packit 8480eb
						*dst = '\0';
Packit 8480eb
					return len;
Packit 8480eb
				}
Packit 8480eb
				sv = macro_findvar(svc, src, p - src);
Packit 8480eb
				if (sv) {
Packit 8480eb
					l = strlen(sv->val);
Packit 8480eb
					if (dst) {
Packit 8480eb
						strcpy(dst, sv->val);
Packit 8480eb
						dst += l;
Packit 8480eb
					}
Packit 8480eb
					len += l;
Packit 8480eb
				}
Packit 8480eb
				src = p + 1;
Packit 8480eb
			} else {
Packit 8480eb
				p = src;
Packit 8480eb
				while (isalnum(*p) || *p == '_')
Packit 8480eb
					p++;
Packit 8480eb
				sv = macro_findvar(svc, src, p - src);
Packit 8480eb
				if (sv) {
Packit 8480eb
					l = strlen(sv->val);
Packit 8480eb
					if (dst) {
Packit 8480eb
						strcpy(dst, sv->val);
Packit 8480eb
						dst += l;
Packit 8480eb
					}
Packit 8480eb
					len += l;
Packit 8480eb
				}
Packit 8480eb
				src = p;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case '\\':
Packit 8480eb
			len++;
Packit 8480eb
			if (dst)
Packit 8480eb
				*dst++ = ch;
Packit 8480eb
Packit 8480eb
			if (*src) {
Packit 8480eb
				len++;
Packit 8480eb
				if (dst)
Packit 8480eb
					*dst++ = *src;
Packit 8480eb
				src++;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case '"':
Packit 8480eb
			len++;
Packit 8480eb
			if (dst)
Packit 8480eb
				*dst++ = ch;
Packit 8480eb
Packit 8480eb
			while (*src && *src != '"') {
Packit 8480eb
				len++;
Packit 8480eb
				if (dst)
Packit 8480eb
					*dst++ = *src;
Packit 8480eb
				src++;
Packit 8480eb
			}
Packit Service 42268b
			if (*src && dst) {
Packit 8480eb
				len++;
Packit Service 42268b
				*dst++ = *src++;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case ':':
Packit 8480eb
			if (dst)
Packit 8480eb
				*(dst++) = 
Packit 8480eb
				  (seen_colons && slashify_colons) ? '/' : ':';
Packit 8480eb
			len++;
Packit 8480eb
			/* Were looking for the colon preceeding a path */
Packit 8480eb
			if (*src == '/')
Packit 8480eb
				seen_colons = 1;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			if (isspace(ch))
Packit 8480eb
				seen_colons = 0;
Packit 8480eb
Packit 8480eb
			if (dst)
Packit 8480eb
				*(dst++) = ch;
Packit 8480eb
			len++;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	if (dst)
Packit 8480eb
		*dst = '\0';
Packit 8480eb
	return len;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_init(int argc, const char *const *argv, struct parse_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	char *noptstr, *def, *val, *macros, *gbl_options;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	int optlen, len, offset;
Packit 8480eb
	const char *xopt;
Packit 8480eb
	int i, bval;
Packit 8480eb
	unsigned int append_options;
Packit 8480eb
Packit 8480eb
	optlen = 0;
Packit 8480eb
Packit 8480eb
	/* Look for options and capture, and create new defines if we need to */
Packit 8480eb
Packit 8480eb
	for (i = 0; i < argc; i++) {
Packit 8480eb
		if (argv[i][0] == '-' &&
Packit 8480eb
		   (argv[i][1] == 'D' || argv[i][1] == '-') ) {
Packit 8480eb
			switch (argv[i][1]) {
Packit 8480eb
			case 'D':
Packit 8480eb
				if (argv[i][2])
Packit 8480eb
					def = strdup(argv[i] + 2);
Packit 8480eb
				else if (++i < argc)
Packit 8480eb
					def = strdup(argv[i]);
Packit 8480eb
				else
Packit 8480eb
					break;
Packit 8480eb
Packit 8480eb
				if (!def) {
Packit 8480eb
					char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
					logerr(MODPREFIX "strdup: %s", estr);
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				val = strchr(def, '=');
Packit 8480eb
				if (val)
Packit 8480eb
					*(val++) = '\0';
Packit 8480eb
				else
Packit 8480eb
					val = "";
Packit 8480eb
Packit 8480eb
				macro_lock();
Packit 8480eb
Packit 8480eb
				ctxt->subst = macro_addvar(ctxt->subst,
Packit 8480eb
							def, strlen(def), val);
Packit 8480eb
Packit 8480eb
				macro_unlock();
Packit 8480eb
Packit 8480eb
				/* we use 5 for the "-D", "=", "," and the null */
Packit 8480eb
				if (ctxt->macros) {
Packit 8480eb
					len = strlen(ctxt->macros) + strlen(def) + strlen(val);
Packit 8480eb
					macros = realloc(ctxt->macros, len + 5);
Packit 8480eb
					if (!macros) {
Packit 8480eb
						free(def);
Packit 8480eb
						break;
Packit 8480eb
					}
Packit 8480eb
					strcat(macros, ",");
Packit 8480eb
				} else { /* No comma, so only +4 */
Packit 8480eb
					len = strlen(def) + strlen(val);
Packit 8480eb
					macros = malloc(len + 4);
Packit 8480eb
					if (!macros) {
Packit 8480eb
						free(def);
Packit 8480eb
						break;
Packit 8480eb
					}
Packit 8480eb
					*macros = '\0';
Packit 8480eb
				}
Packit 8480eb
				ctxt->macros = macros;
Packit 8480eb
Packit 8480eb
				strcat(ctxt->macros, "-D");
Packit 8480eb
				strcat(ctxt->macros, def);
Packit 8480eb
				strcat(ctxt->macros, "=");
Packit 8480eb
				strcat(ctxt->macros, val);
Packit 8480eb
				free(def);
Packit 8480eb
				break;
Packit 8480eb
Packit 8480eb
			case '-':
Packit 8480eb
				if (!strncmp(argv[i] + 2, "no-", 3)) {
Packit 8480eb
					xopt = argv[i] + 5;
Packit 8480eb
					bval = 0;
Packit 8480eb
				} else {
Packit 8480eb
					xopt = argv[i] + 2;
Packit 8480eb
					bval = 1;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				if (!strmcmp(xopt, "slashify-colons", 1))
Packit 8480eb
					ctxt->slashify_colons = bval;
Packit 8480eb
				else
Packit 8480eb
					error(LOGOPT_ANY,
Packit 8480eb
					      MODPREFIX "unknown option: %s",
Packit 8480eb
					      argv[i]);
Packit 8480eb
				break;
Packit 8480eb
Packit 8480eb
			default:
Packit 8480eb
				error(LOGOPT_ANY,
Packit 8480eb
				      MODPREFIX "unknown option: %s", argv[i]);
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
		} else {
Packit 8480eb
			offset = (argv[i][0] == '-' ? 1 : 0);
Packit 8480eb
			len = strlen(argv[i] + offset);
Packit 8480eb
			if (ctxt->optstr) {
Packit 8480eb
				noptstr =
Packit 8480eb
				    (char *) realloc(ctxt->optstr, optlen + len + 2);
Packit 8480eb
				if (noptstr) {
Packit 8480eb
					noptstr[optlen] = ',';
Packit 8480eb
					strcpy(noptstr + optlen + 1, argv[i] + offset);
Packit 8480eb
					optlen += len + 1;
Packit 8480eb
				}
Packit 8480eb
			} else {
Packit 8480eb
				noptstr = (char *) malloc(len + 1);
Packit 8480eb
				if (noptstr) {
Packit 8480eb
					strcpy(noptstr, argv[i] + offset);
Packit 8480eb
					optlen = len;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
			if (!noptstr) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				logerr(MODPREFIX "%s", estr);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			ctxt->optstr = noptstr;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	gbl_options = NULL;
Packit 8480eb
	if (global_options) {
Packit 8480eb
		if (ctxt->optstr && strstr(ctxt->optstr, global_options))
Packit 8480eb
			goto options_done;
Packit 8480eb
		gbl_options = strdup(global_options);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (gbl_options) {
Packit 8480eb
		append_options = defaults_get_append_options();
Packit 8480eb
		if (append_options) {
Packit 8480eb
			char *tmp = concat_options(gbl_options, ctxt->optstr);
Packit 8480eb
			if (!tmp) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				logerr(MODPREFIX "concat_options: %s", estr);
Packit 8480eb
				free(gbl_options);
Packit 8480eb
			} else
Packit 8480eb
				ctxt->optstr = tmp;
Packit 8480eb
		} else {
Packit 8480eb
			if (!ctxt->optstr)
Packit 8480eb
				ctxt->optstr = gbl_options;
Packit 8480eb
			else
Packit 8480eb
				free(gbl_options);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
options_done:
Packit 8480eb
Packit 8480eb
	debug(LOGOPT_NONE,
Packit 8480eb
	      MODPREFIX "init gathered global options: %s", ctxt->optstr);
Packit 8480eb
Packit 8480eb
	return 0;
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
	*context = NULL;
Packit 8480eb
Packit 8480eb
	/* Set up context and escape chain */
Packit 8480eb
Packit 8480eb
	ctxt = (struct parse_context *) malloc(sizeof(struct parse_context));
Packit 8480eb
	if (!ctxt) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*ctxt = default_context;
Packit 8480eb
Packit 8480eb
	if (do_init(argc, argv, ctxt)) {
Packit 8480eb
		free(ctxt);
Packit 8480eb
		return 1;
Packit 8480eb
	}
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
			instance_mutex_unlock();
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	instance_mutex_unlock();
Packit 8480eb
Packit 8480eb
	*context = (void *) ctxt;
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
	struct parse_context *ctxt = (struct parse_context *) *context;
Packit 8480eb
	struct parse_context *new;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
Packit 8480eb
	new = (struct parse_context *) malloc(sizeof(struct parse_context));
Packit 8480eb
	if (!new) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*new = default_context;
Packit 8480eb
Packit Service 0f11ce
	if (do_init(argc, argv, new)) {
Packit Service 0f11ce
		free(new);
Packit 8480eb
		return 1;
Packit Service 0f11ce
	}
Packit 8480eb
Packit 8480eb
	kill_context(ctxt);
Packit 8480eb
Packit 8480eb
	*context = (void *) new;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static const char *parse_options(const char *str, char **ret, unsigned int logopt)
Packit 8480eb
{
Packit 8480eb
	const char *cp = str;
Packit 8480eb
	int len;
Packit 8480eb
Packit 8480eb
	if (*cp++ != '-')
Packit 8480eb
		return str;
Packit 8480eb
Packit 8480eb
	if (*ret != NULL)
Packit 8480eb
		free(*ret);
Packit 8480eb
Packit 8480eb
	len = chunklen(cp, 0);
Packit 8480eb
	*ret = dequote(cp, len, logopt);
Packit 8480eb
Packit 8480eb
	return cp + len;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *concat_options(char *left, char *right)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *ret;
Packit 8480eb
Packit 8480eb
	if (left == NULL || *left == '\0') {
Packit 8480eb
		ret = strdup(right);
Packit 8480eb
		free(right);
Packit 8480eb
		return ret;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (right == NULL || *right == '\0') {
Packit 8480eb
		ret = strdup(left);
Packit 8480eb
		free(left);
Packit 8480eb
		return ret;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = malloc(strlen(left) + strlen(right) + 2);
Packit 8480eb
Packit 8480eb
	if (ret == NULL) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	strcpy(ret, left);
Packit 8480eb
	strcat(ret, ",");
Packit 8480eb
	strcat(ret, right);
Packit 8480eb
Packit 8480eb
	free(left);
Packit 8480eb
	free(right);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int sun_mount(struct autofs_point *ap, const char *root,
Packit 8480eb
			const char *name, int namelen,
Packit 8480eb
			const char *loc, int loclen, const char *options,
Packit 8480eb
			struct parse_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	char *fstype = "nfs";	/* Default filesystem type */
Packit 8480eb
	int nonstrict = 1;
Packit 8480eb
	int use_weight_only = ap->flags & MOUNT_FLAG_USE_WEIGHT_ONLY;
Packit 8480eb
	int rv, cur_state;
Packit 8480eb
	char *mountpoint;
Packit 8480eb
	char *what;
Packit 8480eb
	char *type;
Packit 8480eb
Packit 8480eb
	if (*options == '\0')
Packit 8480eb
		options = NULL;
Packit 8480eb
Packit 8480eb
	if (options) {
Packit 8480eb
		char *noptions;
Packit 8480eb
		const char *comma;
Packit 8480eb
		char *np;
Packit 8480eb
		int len = strlen(options) + 1;
Packit 8480eb
Packit 8480eb
		noptions = np = alloca(len);
Packit 8480eb
		*np = '\0';
Packit 8480eb
Packit 8480eb
		/* Extract fstype= pseudo option */
Packit 8480eb
		for (comma = options; *comma != '\0';) {
Packit 8480eb
			const char *cp;
Packit 8480eb
Packit 8480eb
			while (*comma == ',')
Packit 8480eb
				comma++;
Packit 8480eb
Packit 8480eb
			cp = comma;
Packit 8480eb
Packit 8480eb
			while (*comma != '\0' && *comma != ',')
Packit 8480eb
				comma++;
Packit 8480eb
Packit 8480eb
			if (_strncmp("fstype=", cp, 7) == 0) {
Packit 8480eb
				int typelen = comma - (cp + 7);
Packit 8480eb
				fstype = alloca(typelen + 1);
Packit 8480eb
				memcpy(fstype, cp + 7, typelen);
Packit 8480eb
				fstype[typelen] = '\0';
Packit 8480eb
			} else if (_strncmp("nonstrict", cp, 9) == 0) {
Packit 8480eb
				nonstrict = 1;
Packit 8480eb
			} else if (_strncmp("strict", cp, 6) == 0 &&
Packit 8480eb
				   comma - cp == 6) {
Packit 8480eb
				nonstrict = 0;
Packit 8480eb
			} else if (_strncmp("nobrowse", cp, 8) == 0 ||
Packit 8480eb
				   _strncmp("browse", cp, 6) == 0 ||
Packit 8480eb
				   _strncmp("timeout=", cp, 8) == 0) {
Packit 8480eb
				if (strcmp(fstype, "autofs") == 0 ||
Packit 8480eb
				    strstr(cp, "fstype=autofs")) {
Packit 8480eb
					memcpy(np, cp, comma - cp + 1);
Packit 8480eb
					np += comma - cp + 1;
Packit 8480eb
				}
Packit 8480eb
			} else if (_strncmp("no-use-weight-only", cp, 18) == 0) {
Packit 8480eb
				use_weight_only = -1;
Packit 8480eb
			} else if (_strncmp("use-weight-only", cp, 15) == 0) {
Packit 8480eb
				use_weight_only = MOUNT_FLAG_USE_WEIGHT_ONLY;
Packit 8480eb
			} else if (_strncmp("bg", cp, 2) == 0 ||
Packit 8480eb
				   _strncmp("nofg", cp, 4) == 0) {
Packit 8480eb
				continue;
Packit 8480eb
			} else {
Packit 8480eb
				memcpy(np, cp, comma - cp + 1);
Packit 8480eb
				np += comma - cp + 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (np > noptions + len) {
Packit 8480eb
			warn(ap->logopt, MODPREFIX "options string truncated");
Packit 8480eb
			np[len] = '\0';
Packit 8480eb
		} else
Packit 8480eb
			*(np - 1) = '\0';
Packit 8480eb
Packit 8480eb
		options = noptions;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!strcmp(fstype, "autofs") && ctxt->macros) {
Packit 8480eb
		char *noptions = NULL;
Packit 8480eb
Packit 8480eb
		if (!options || *options == '\0') {
Packit 8480eb
			noptions = alloca(strlen(ctxt->macros) + 1);
Packit 8480eb
			*noptions = '\0';
Packit 8480eb
		} else {
Packit 8480eb
			int len = strlen(options) + strlen(ctxt->macros) + 2;
Packit 8480eb
			noptions = alloca(len);
Packit 8480eb
Packit 8480eb
			if (noptions) {
Packit 8480eb
				strcpy(noptions, options);
Packit 8480eb
				strcat(noptions, ",");
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (noptions && *noptions != '\0') {
Packit 8480eb
			strcat(noptions, ctxt->macros);
Packit 8480eb
			options = noptions;
Packit 8480eb
		} else {
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      MODPREFIX "alloca failed for options");
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	mountpoint = alloca(namelen + 1);
Packit 8480eb
	sprintf(mountpoint, "%.*s", namelen, name);
Packit 8480eb
Packit 8480eb
	type = ap->entry->maps->type;
Packit 8480eb
	if (type && !strcmp(type, "hosts")) {
Packit 8480eb
		if (options && *options != '\0') {
Packit 8480eb
			int len = strlen(options);
Packit 8480eb
			int suid = strstr(options, "suid") ? 0 : 7;
Packit 8480eb
			int dev = strstr(options, "dev") ? 0 : 6;
Packit 8480eb
			int nointr = strstr(options, "nointr") ? 0 : 5;
Packit 8480eb
Packit 8480eb
			if (suid || dev || nointr) {
Packit 8480eb
				char *tmp = alloca(len + suid + dev + nointr + 1);
Packit 8480eb
				if (!tmp) {
Packit 8480eb
					error(ap->logopt, MODPREFIX
Packit 8480eb
					      "alloca failed for options");
Packit 8480eb
					if (nonstrict)
Packit 8480eb
						return -1;
Packit 8480eb
					return 1;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				strcpy(tmp, options);
Packit 8480eb
				if (suid)
Packit 8480eb
					strcat(tmp, ",nosuid");
Packit 8480eb
				if (dev)
Packit 8480eb
					strcat(tmp, ",nodev");
Packit 8480eb
				if (nointr)
Packit 8480eb
					strcat(tmp, ",intr");
Packit 8480eb
				options = tmp;
Packit 8480eb
			}
Packit 8480eb
		} else {
Packit 8480eb
			char *tmp = alloca(18);
Packit 8480eb
			if (!tmp) {
Packit 8480eb
				error(ap->logopt,
Packit 8480eb
				      MODPREFIX "alloca failed for options");
Packit 8480eb
				if (nonstrict)
Packit 8480eb
					return -1;
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			strcpy(tmp, "nosuid,nodev,intr");
Packit 8480eb
			options = tmp;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit 8480eb
	if (!strcmp(fstype, "nfs") || !strcmp(fstype, "nfs4")) {
Packit 8480eb
		what = alloca(loclen + 1);
Packit 8480eb
		memcpy(what, loc, loclen);
Packit 8480eb
		what[loclen] = '\0';
Packit 8480eb
Packit 8480eb
		/* Add back "[no-]use-weight-only" for NFS mounts only */
Packit 8480eb
		if (use_weight_only) {
Packit 8480eb
			char *tmp;
Packit 8480eb
			int len;
Packit 8480eb
Packit 8480eb
			if (options && *options != '\0') {
Packit 8480eb
				len = strlen(options) + 19;
Packit 8480eb
				tmp = alloca(len);
Packit 8480eb
				strcpy(tmp, options);
Packit 8480eb
				strcat(tmp, ",");
Packit 8480eb
				if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY)
Packit 8480eb
					strcat(tmp, "use-weight-only");
Packit 8480eb
				else
Packit 8480eb
					strcat(tmp, "no-use-weight-only");
Packit 8480eb
			} else {
Packit 8480eb
				tmp = alloca(19);
Packit 8480eb
				if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY)
Packit 8480eb
					strcpy(tmp, "use-weight-only");
Packit 8480eb
				else
Packit 8480eb
					strcpy(tmp, "no-use-weight-only");
Packit 8480eb
			}
Packit 8480eb
			options = tmp;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "mounting root %s, mountpoint %s, "
Packit 8480eb
		      "what %s, fstype %s, options %s",
Packit 8480eb
		      root, mountpoint, what, fstype, options);
Packit 8480eb
Packit 8480eb
		rv = mount_nfs->mount_mount(ap, root, mountpoint, strlen(mountpoint),
Packit 8480eb
					    what, fstype, options, mount_nfs->context);
Packit 8480eb
	} else {
Packit 8480eb
		if (!loclen)
Packit 8480eb
			what = NULL;
Packit 8480eb
		else {
Packit 8480eb
			what = alloca(loclen + 1);
Packit 8480eb
			if (*loc == ':') {
Packit 8480eb
				loclen--;
Packit 8480eb
				memcpy(what, loc + 1, loclen);
Packit 8480eb
				what[loclen] = '\0';
Packit 8480eb
			} else {
Packit 8480eb
				memcpy(what, loc, loclen);
Packit 8480eb
				what[loclen] = '\0';
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "mounting root %s, mountpoint %s, "
Packit 8480eb
		      "what %s, fstype %s, options %s",
Packit 8480eb
		      root, mountpoint, what, fstype, options);
Packit 8480eb
Packit 8480eb
		/* Generic mount routine */
Packit 8480eb
		rv = do_mount(ap, root, mountpoint, strlen(mountpoint), what, fstype,
Packit 8480eb
			      options);
Packit 8480eb
	}
Packit 8480eb
	pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
Packit 8480eb
	if (nonstrict && rv)
Packit 8480eb
		return -rv;
Packit 8480eb
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Scan map entry looking for evidence it has multiple key/mapent
Packit 8480eb
 * pairs.
Packit 8480eb
 */
Packit 8480eb
static int check_is_multi(const char *mapent)
Packit 8480eb
{
Packit 8480eb
	const char *p = mapent;
Packit 8480eb
	int multi = 0;
Packit 8480eb
	int not_first_chunk = 0;
Packit 8480eb
Packit 8480eb
	if (!p) {
Packit 8480eb
		logerr(MODPREFIX "unexpected NULL map entry pointer");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (*p == '"')
Packit 8480eb
		p++;
Packit 8480eb
Packit 8480eb
	/* If first character is "/" it's a multi-mount */
Packit 8480eb
	if (*p == '/')
Packit 8480eb
		return 1;
Packit 8480eb
Packit 8480eb
	while (*p) {
Packit 8480eb
		p = skipspace(p);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * After the first chunk there can be additional
Packit 8480eb
		 * locations (possibly not multi) or possibly an
Packit 8480eb
		 * options string if the first entry includes the
Packit 8480eb
		 * optional '/' (is multi). Following this any
Packit 8480eb
		 * path that begins with '/' indicates a mutil-mount
Packit 8480eb
		 * entry.
Packit 8480eb
		 */
Packit 8480eb
		if (not_first_chunk) {
Packit 8480eb
			if (*p == '"')
Packit 8480eb
				p++;
Packit 8480eb
			if (*p == '/' || *p == '-') {
Packit 8480eb
				multi = 1;
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		while (*p == '-') {
Packit 8480eb
			p += chunklen(p, 0);
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Expect either a path or location
Packit 8480eb
		 * after which it's a multi mount.
Packit 8480eb
		 */
Packit 8480eb
		p += chunklen(p, check_colon(p));
Packit 8480eb
		not_first_chunk++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return multi;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int
Packit 8480eb
update_offset_entry(struct autofs_point *ap, const char *name,
Packit 8480eb
		    const char *m_root, int m_root_len,
Packit 8480eb
		    const char *path, const char *myoptions, const char *loc,
Packit 8480eb
		    time_t age)
Packit 8480eb
{
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	char m_key[PATH_MAX + 1];
Packit 8480eb
	char m_mapent[MAPENT_MAX_LEN + 1];
Packit 8480eb
	int p_len, m_key_len, m_options_len, m_mapent_len;
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
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
Packit 8480eb
Packit 8480eb
	/* Internal hosts map may have loc == NULL */
Packit 8480eb
	if (!*path) {
Packit 8480eb
		error(ap->logopt,
Packit 8480eb
		      MODPREFIX "syntax error in offset %s -> %s", path, loc);
Packit 8480eb
		return CHE_FAIL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	p_len = strlen(path);
Packit 8480eb
	/* Trailing '/' causes us pain */
Packit 8480eb
	if (p_len > 1) {
Packit 8480eb
		while (p_len > 1 && path[p_len - 1] == '/')
Packit 8480eb
			p_len--;
Packit 8480eb
	}
Packit 8480eb
	m_key_len = m_root_len + p_len;
Packit 8480eb
	if (m_key_len > PATH_MAX) {
Packit 8480eb
		error(ap->logopt, MODPREFIX "multi mount key too long");
Packit 8480eb
		return CHE_FAIL;
Packit 8480eb
	}
Packit 8480eb
	strcpy(m_key, m_root);
Packit 8480eb
	strncat(m_key, path, p_len);
Packit 8480eb
	m_key[m_key_len] = '\0';
Packit 8480eb
Packit 8480eb
	m_options_len = 0;
Packit 8480eb
	if (*myoptions)
Packit 8480eb
		m_options_len = strlen(myoptions) + 2;
Packit 8480eb
Packit 8480eb
	m_mapent_len = loc ? strlen(loc) : 0;
Packit 8480eb
	if (m_mapent_len + m_options_len > MAPENT_MAX_LEN) {
Packit 8480eb
		error(ap->logopt, MODPREFIX "multi mount mapent too long");
Packit 8480eb
		return CHE_FAIL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (*myoptions) {
Packit 8480eb
		strcpy(m_mapent, "-");
Packit 8480eb
		strcat(m_mapent, myoptions);
Packit 8480eb
		if (loc) {
Packit 8480eb
			strcat(m_mapent, " ");
Packit 8480eb
			if (loc)
Packit 8480eb
				strcat(m_mapent, loc);
Packit 8480eb
		}
Packit 8480eb
	} else {
Packit 8480eb
		if (loc)
Packit 8480eb
			strcpy(m_mapent, loc);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = cache_update_offset(mc, name, m_key, m_mapent, age);
Packit 8480eb
	if (ret == CHE_DUPLICATE) {
Packit 8480eb
		warn(ap->logopt, MODPREFIX
Packit 8480eb
		     "syntax error or duplicate offset %s -> %s", path, loc);
Packit 8480eb
		ret = CHE_OK;
Packit 8480eb
	} else if (ret == CHE_FAIL)
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "failed to update multi-mount offset %s -> %s", path, m_mapent);
Packit 8480eb
	else {
Packit 8480eb
		ret = CHE_OK;
Packit 8480eb
		debug(ap->logopt, MODPREFIX
Packit 8480eb
		      "updated multi-mount offset %s -> %s", path, m_mapent);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int validate_location(unsigned int logopt, char *loc)
Packit 8480eb
{
Packit 8480eb
	char *ptr = loc;
Packit 8480eb
Packit 8480eb
	/* We don't know much about these */
Packit 8480eb
	if (*ptr == ':')
Packit 8480eb
		return 1;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * If a ':/' is present now it must be a host name, except
Packit 8480eb
	 * for those special file systems like sshfs which use "#"
Packit 8480eb
	 * and "@" in the host name part and ipv6 addresses that
Packit 8480eb
	 * have ":", "[" and "]".
Packit 8480eb
	 */
Packit 8480eb
	if (!check_colon(ptr)) {
Packit 8480eb
		char *esc;
Packit 8480eb
		/*
Packit 8480eb
		 * Don't forget cases where a colon is present but
Packit 8480eb
		 * not followed by a "/" or, if there is no colon at
Packit 8480eb
		 * all, we don't know if it is actually invalid since
Packit 8480eb
		 * it may be a map name by itself, for example.
Packit 8480eb
		 */
Packit 8480eb
		if (!strchr(ptr, ':') ||
Packit 8480eb
		    ((esc = strchr(ptr, '\\')) && *(esc + 1) == ':') ||
Packit 8480eb
		    !strncmp(ptr, "file:", 5) || !strncmp(ptr, "yp:", 3) ||
Packit 8480eb
		    !strncmp(ptr, "nis:", 4) || !strncmp(ptr, "nisplus:", 8) ||
Packit 8480eb
		    !strncmp(ptr, "ldap:", 5) || !strncmp(ptr, "ldaps:", 6) ||
Packit 8480eb
		    !strncmp(ptr, "sss:", 4) || !strncmp(ptr, "dir:", 4))
Packit 8480eb
			return 1;
Packit 8480eb
		error(logopt,
Packit 8480eb
		      "expected colon delimeter not found in location %s",
Packit 8480eb
		      loc);
Packit 8480eb
		return 0;
Packit 8480eb
	} else {
Packit 8480eb
		while (*ptr && strncmp(ptr, ":/", 2)) {
Packit 8480eb
			if (!(isalnum(*ptr) ||
Packit 8480eb
			    *ptr == '-' || *ptr == '.' || *ptr == '_' ||
Packit 8480eb
			    *ptr == ',' || *ptr == '(' || *ptr == ')' ||
Packit 8480eb
			    *ptr == '#' || *ptr == '@' || *ptr == ':' ||
Packit 8480eb
			    *ptr == '[' || *ptr == ']' || *ptr == '%')) {
Packit 8480eb
				error(logopt, "invalid character \"%c\" "
Packit 8480eb
				      "found in location %s", *ptr, loc);
Packit 8480eb
				return 0;
Packit 8480eb
			}
Packit 8480eb
			ptr++;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (*ptr && !strncmp(ptr, ":/", 2))
Packit 8480eb
			ptr++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Must always be something following */
Packit 8480eb
	if (!*ptr) {
Packit 8480eb
		error(logopt, "invalid location %s", loc);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int parse_mapent(const char *ent, char *g_options, char **options, char **location, int logopt)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	const char *p;
Packit 8480eb
	char *myoptions, *loc;
Packit 8480eb
	int l;
Packit 8480eb
Packit 8480eb
	p = ent;
Packit 8480eb
Packit 8480eb
	myoptions = strdup(g_options);
Packit 8480eb
	if (!myoptions) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(logopt, MODPREFIX "strdup: %s", estr);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Local options are appended to per-map options */
Packit 8480eb
	if (*p == '-') {
Packit 8480eb
		do {
Packit 8480eb
			char *tmp, *newopt = NULL;
Packit 8480eb
Packit 8480eb
			p = parse_options(p, &newopt, logopt);
Packit 8480eb
			if (newopt && strstr(newopt, myoptions)) {
Packit 8480eb
				free(myoptions);
Packit 8480eb
				myoptions = newopt;
Packit 8480eb
			} else {
Packit 8480eb
				tmp = concat_options(myoptions, newopt);
Packit 8480eb
				if (!tmp) {
Packit 8480eb
					char *estr;
Packit 8480eb
					estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
					error(logopt, MODPREFIX
Packit 8480eb
					      "concat_options: %s", estr);
Packit 8480eb
					if (newopt)
Packit 8480eb
						free(newopt);
Packit 8480eb
					free(myoptions);
Packit 8480eb
					return 0;
Packit 8480eb
				}
Packit 8480eb
				myoptions = tmp;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
		} while (*p == '-');
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, MODPREFIX "gathered options: %s", myoptions);
Packit 8480eb
Packit 8480eb
	l = chunklen(p, check_colon(p));
Packit 8480eb
	loc = dequote(p, l, logopt);
Packit 8480eb
	if (!loc) {
Packit 8480eb
		if (strstr(myoptions, "fstype=autofs") &&
Packit 8480eb
		    strstr(myoptions, "hosts")) {
Packit 8480eb
			warn(logopt, MODPREFIX "possible missing location");
Packit 8480eb
			free(myoptions);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
		*options = myoptions;
Packit 8480eb
		*location = NULL;
Packit 8480eb
		return (p - ent);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Location can't begin with a '/' */
Packit 8480eb
	if (*p == '/') {
Packit 8480eb
		warn(logopt, MODPREFIX "error location begins with \"/\"");
Packit 8480eb
		free(myoptions);
Packit 8480eb
		free(loc);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!validate_location(logopt, loc)) {
Packit 8480eb
		free(myoptions);
Packit 8480eb
		free(loc);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
Packit 8480eb
Packit 8480eb
	p += l;
Packit 8480eb
	p = skipspace(p);
Packit 8480eb
Packit 8480eb
	while (*p && ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/'))) {
Packit 8480eb
		char *tmp, *ent_chunk;
Packit 8480eb
Packit 8480eb
		l = chunklen(p, check_colon(p));
Packit 8480eb
		ent_chunk = dequote(p, l, logopt);
Packit 8480eb
		if (!ent_chunk) {
Packit 8480eb
			if (strstr(myoptions, "fstype=autofs") &&
Packit 8480eb
			    strstr(myoptions, "hosts")) {
Packit 8480eb
				warn(logopt, MODPREFIX
Packit 8480eb
				     "null location or out of memory");
Packit 8480eb
				free(myoptions);
Packit 8480eb
				free(loc);
Packit 8480eb
				return 0;
Packit 8480eb
			}
Packit 8480eb
			goto next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* Location can't begin with a '/' */
Packit 8480eb
		if (*p == '/') {
Packit 8480eb
			warn(logopt,
Packit 8480eb
			      MODPREFIX "error location begins with \"/\"");
Packit 8480eb
			free(ent_chunk);
Packit 8480eb
			free(myoptions);
Packit 8480eb
			free(loc);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!validate_location(logopt, ent_chunk)) {
Packit 8480eb
			free(ent_chunk);
Packit 8480eb
			free(myoptions);
Packit 8480eb
			free(loc);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent_chunk);
Packit 8480eb
Packit 8480eb
		tmp = realloc(loc, strlen(loc) + l + 2);
Packit 8480eb
		if (!tmp) {
Packit 8480eb
			error(logopt, MODPREFIX "out of memory");
Packit 8480eb
			free(ent_chunk);
Packit 8480eb
			free(myoptions);
Packit 8480eb
			free(loc);
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
		loc = tmp;
Packit 8480eb
Packit 8480eb
		strcat(loc, " ");
Packit 8480eb
		strcat(loc, ent_chunk);
Packit 8480eb
Packit 8480eb
		free(ent_chunk);
Packit 8480eb
next:
Packit 8480eb
		p += l;
Packit 8480eb
		p = skipspace(p);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*options = myoptions;
Packit 8480eb
	*location = loc;
Packit 8480eb
Packit 8480eb
	return (p - ent);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void cleanup_multi_triggers(struct autofs_point *ap,
Packit 8480eb
			    struct mapent *me, const char *root, int start,
Packit 8480eb
			    const char *base)
Packit 8480eb
{
Packit 8480eb
	char path[PATH_MAX + 1];
Packit 8480eb
	char offset[PATH_MAX + 1];
Packit 8480eb
	char *poffset = 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
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
Packit 8480eb
	/* Make sure "none" of the offsets have an active mount. */
Packit 8480eb
	while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) {
Packit 8480eb
		oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list);
Packit 8480eb
		/* root offset is a special case */
Packit 8480eb
		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
Packit 8480eb
			continue;
Packit 8480eb
Packit 8480eb
		strcpy(path, root);
Packit 8480eb
		strcat(path, poffset);
Packit 8480eb
		if (umount(path)) {
Packit 8480eb
			error(ap->logopt, "error recovering from mount fail");
Packit 8480eb
			error(ap->logopt, "cannot umount offset %s", path);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int mount_subtree(struct autofs_point *ap, struct mapent *me,
Packit 8480eb
			 const char *name, char *loc, char *options, void *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent *mm;
Packit 8480eb
	struct mapent *ro;
Packit 8480eb
	char *mm_root, *mm_base, *mm_key;
Packit 8480eb
	const char *mnt_root;
Packit 8480eb
	unsigned int mm_root_len, mnt_root_len;
Packit 8480eb
	int start, ret = 0, rv;
Packit 8480eb
Packit 8480eb
	rv = 0;
Packit 8480eb
Packit 8480eb
	mm = me->multi;
Packit 8480eb
	mm_key = mm->key;
Packit 8480eb
Packit 8480eb
	if (*mm_key == '/') {
Packit 8480eb
		mm_root = mm_key;
Packit 8480eb
		start = strlen(mm_key);
Packit 8480eb
	} else {
Packit 8480eb
		start = strlen(ap->path) + strlen(mm_key) + 1;
Packit 8480eb
		mm_root = alloca(start + 3);
Packit 8480eb
		strcpy(mm_root, ap->path);
Packit 8480eb
		strcat(mm_root, "/");
Packit 8480eb
		strcat(mm_root, mm_key);
Packit 8480eb
	}
Packit 8480eb
	mm_root_len = strlen(mm_root);
Packit 8480eb
Packit 8480eb
	mnt_root = mm_root;
Packit 8480eb
	mnt_root_len = mm_root_len;
Packit 8480eb
Packit 8480eb
	if (me == me->multi) {
Packit 8480eb
		/* name = NULL */
Packit 8480eb
		/* destination = mm_root */
Packit 8480eb
		mm_base = "/";
Packit 8480eb
Packit 8480eb
		/* Mount root offset if it exists */
Packit 8480eb
		ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
Packit 8480eb
		if (ro) {
Packit 8480eb
			char *myoptions, *ro_loc, *tmp;
Packit 8480eb
			int namelen = name ? strlen(name) : 0;
Packit 8480eb
			const char *root;
Packit 8480eb
			int ro_len;
Packit 8480eb
Packit Service 0f11ce
			myoptions = NULL;
Packit Service 0f11ce
			ro_loc = NULL;
Packit Service 0f11ce
Packit 8480eb
			rv = parse_mapent(ro->mapent,
Packit 8480eb
				options, &myoptions, &ro_loc, ap->logopt);
Packit 8480eb
			if (!rv) {
Packit 8480eb
				warn(ap->logopt,
Packit 8480eb
				      MODPREFIX "failed to parse root offset");
Packit 8480eb
				cache_delete_offset_list(me->mc, name);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			ro_len = 0;
Packit 8480eb
			if (ro_loc)
Packit 8480eb
				ro_len = strlen(ro_loc);
Packit 8480eb
Packit 8480eb
			tmp = alloca(mnt_root_len + 2);
Packit 8480eb
			strcpy(tmp, mnt_root);
Packit 8480eb
			tmp[mnt_root_len] = '/';
Packit 8480eb
			tmp[mnt_root_len + 1] = '\0';
Packit 8480eb
			root = tmp;
Packit 8480eb
Packit 8480eb
			rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
Packit 8480eb
Packit 8480eb
			free(myoptions);
Packit 8480eb
			if (ro_loc)
Packit 8480eb
				free(ro_loc);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (ro && rv == 0) {
Packit 8480eb
			ret = mount_multi_triggers(ap, me, mnt_root, start, mm_base);
Packit 8480eb
			if (ret == -1) {
Packit 8480eb
				error(ap->logopt, MODPREFIX
Packit 8480eb
					 "failed to mount offset triggers");
Packit 8480eb
				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
		} else if (rv <= 0) {
Packit 8480eb
			ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
Packit 8480eb
			if (ret == -1) {
Packit 8480eb
				error(ap->logopt, MODPREFIX
Packit 8480eb
					 "failed to mount offset triggers");
Packit 8480eb
				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	} else {
Packit 8480eb
		int loclen = strlen(loc);
Packit 8480eb
		int namelen = strlen(name);
Packit 8480eb
Packit 8480eb
		mnt_root = name;
Packit 8480eb
Packit 8480eb
		/* name = mm_root + mm_base */
Packit 8480eb
		/* destination = mm_root + mm_base = name */
Packit 8480eb
		mm_base = &me->key[start];
Packit 8480eb
Packit 8480eb
		rv = sun_mount(ap, mnt_root, name, namelen, loc, loclen, options, ctxt);
Packit 8480eb
		if (rv == 0) {
Packit 8480eb
			ret = mount_multi_triggers(ap, me->multi, mnt_root, start, mm_base);
Packit 8480eb
			if (ret == -1) {
Packit 8480eb
				error(ap->logopt, MODPREFIX
Packit 8480eb
					 "failed to mount offset triggers");
Packit 8480eb
				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
		} else if (rv < 0) {
Packit 8480eb
			char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
Packit 8480eb
	
Packit 8480eb
			strcpy(mm_root_base, mm_root);
Packit 8480eb
			strcat(mm_root_base, mm_base);
Packit 8480eb
Packit 8480eb
			ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
Packit 8480eb
			if (ret == -1) {
Packit 8480eb
				error(ap->logopt, MODPREFIX
Packit 8480eb
					 "failed to mount offset triggers");
Packit 8480eb
				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Mount for base of tree failed */
Packit 8480eb
	if (rv > 0)
Packit 8480eb
		return rv;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Convert fail on nonstrict, non-empty multi-mount
Packit 8480eb
	 * to success
Packit 8480eb
	 */
Packit 8480eb
	if (rv < 0 && ret > 0)
Packit 8480eb
		rv = 0;
Packit 8480eb
Packit 8480eb
	return rv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *do_expandsunent(const char *src, const char *key,
Packit 8480eb
			     const struct substvar *svc, int slashify_colons)
Packit 8480eb
{
Packit 8480eb
	char *mapent;
Packit 8480eb
	int len;
Packit 8480eb
Packit 8480eb
	len = expandsunent(src, NULL, key, svc, slashify_colons);
Packit 8480eb
	if (len == 0) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
	len++;
Packit 8480eb
Packit 8480eb
	mapent = malloc(len);
Packit 8480eb
	if (!mapent)
Packit 8480eb
		return NULL;
Packit 8480eb
	memset(mapent, 0, len);
Packit 8480eb
Packit 8480eb
	expandsunent(src, mapent, key, svc, slashify_colons);
Packit 8480eb
Packit 8480eb
	return mapent;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * syntax is:
Packit 8480eb
 *	[-options] location [location] ...
Packit 8480eb
 *	[-options] [mountpoint [-options] location [location] ... ]...
Packit 8480eb
 *
Packit 8480eb
 * There are three ways this routine can be called. One where we parse
Packit 8480eb
 * offsets in a multi-mount entry adding them to the cache for later lookups.
Packit 8480eb
 * Another where we parse a multi-mount entry looking for a root offset mount
Packit 8480eb
 * and mount it if it exists and also mount its offsets down to the first
Packit 8480eb
 * level nexting point. Finally to mount non multi-mounts and to mount a
Packit 8480eb
 * lower level multi-mount nesting point and its offsets.
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
	char buf[MAX_ERR_BUF];
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	char *pmapent, *options;
Packit 8480eb
	const char *p;
Packit 8480eb
	int mapent_len, rv = 0;
Packit 8480eb
	int cur_state;
Packit 8480eb
	int slashify = ctxt->slashify_colons;
Packit 8480eb
	unsigned int append_options;
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
	mc = source->mc;
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
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit 8480eb
Packit 8480eb
	/* Offset map entries have been expanded already, avoid expanding
Packit 8480eb
	 * them again so that the quote handling is consistent between map
Packit 8480eb
	 * entry locations and (previously expanded) offset map entry
Packit 8480eb
	 * locations.
Packit 8480eb
	 */
Packit 8480eb
	if (*name == '/') {
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		me = cache_lookup_distinct(mc, name);
Packit 8480eb
		if (me && me->multi && me->multi != me) {
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			mapent_len = strlen(mapent) + 1;
Packit 8480eb
			pmapent = malloc(mapent_len + 1);
Packit 8480eb
			if (!pmapent) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			memset(pmapent, 0, mapent_len + 1);
Packit 8480eb
			strcpy(pmapent, mapent);
Packit 8480eb
			goto dont_expand;
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	macro_lock();
Packit 8480eb
	ctxt->subst = addstdenv(ctxt->subst, NULL);
Packit 8480eb
Packit 8480eb
	pmapent = do_expandsunent(mapent, name, ctxt->subst, slashify);
Packit 8480eb
	if (!pmapent) {
Packit 8480eb
		error(ap->logopt, MODPREFIX "failed to expand map entry");
Packit 8480eb
		ctxt->subst = removestdenv(ctxt->subst, NULL);
Packit 8480eb
		macro_unlock();
Packit 8480eb
		pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	mapent_len = strlen(pmapent) + 1;
Packit 8480eb
Packit 8480eb
	ctxt->subst = removestdenv(ctxt->subst, NULL);
Packit 8480eb
	macro_unlock();
Packit 8480eb
Packit 8480eb
dont_expand:
Packit 8480eb
	pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "expanded entry: %s", pmapent);
Packit 8480eb
Packit 8480eb
	append_options = defaults_get_append_options();
Packit 8480eb
	options = strdup(ctxt->optstr ? ctxt->optstr : "");
Packit 8480eb
	if (!options) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		free(pmapent);
Packit 8480eb
		logerr(MODPREFIX "strdup: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	p = skipspace(pmapent);
Packit 8480eb
Packit 8480eb
	/* Deal with 0 or more options */
Packit 8480eb
	if (*p == '-') {
Packit 8480eb
		char *tmp, *mnt_options = NULL;
Packit 8480eb
Packit 8480eb
		do {
Packit 8480eb
			char *noptions = NULL;
Packit 8480eb
Packit 8480eb
			p = parse_options(p, &noptions, ap->logopt);
Packit 8480eb
			if (mnt_options && noptions && strstr(noptions, mnt_options)) {
Packit 8480eb
				free(mnt_options);
Packit 8480eb
				mnt_options = noptions;
Packit 8480eb
			} else {
Packit 8480eb
				tmp = concat_options(mnt_options, noptions);
Packit 8480eb
				if (!tmp) {
Packit 8480eb
					char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
					error(ap->logopt,
Packit 8480eb
					      MODPREFIX "concat_options: %s", estr);
Packit 8480eb
					if (noptions)
Packit 8480eb
						free(noptions);
Packit 8480eb
					if (mnt_options)
Packit 8480eb
						free(mnt_options);
Packit 8480eb
					free(options);
Packit 8480eb
					free(pmapent);
Packit 8480eb
					return 1;
Packit 8480eb
				}
Packit 8480eb
				mnt_options = tmp;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
		} while (*p == '-');
Packit 8480eb
Packit 8480eb
		if (options && !append_options) {
Packit 8480eb
			free(options);
Packit 8480eb
			options = NULL;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (append_options) {
Packit 8480eb
			if (options && mnt_options && strstr(mnt_options, options)) {
Packit 8480eb
				free(options);
Packit 8480eb
				options = mnt_options;
Packit 8480eb
			} else {
Packit 8480eb
				tmp = concat_options(options, mnt_options);
Packit 8480eb
				if (!tmp) {
Packit 8480eb
					char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
					error(ap->logopt, MODPREFIX "concat_options: %s", estr);
Packit 8480eb
					if (options)
Packit 8480eb
						free(options);
Packit 8480eb
					if (mnt_options)
Packit 8480eb
						free(mnt_options);
Packit 8480eb
					free(pmapent);
Packit 8480eb
					return 1;
Packit 8480eb
				}
Packit 8480eb
				options = tmp;
Packit 8480eb
			}
Packit 8480eb
		} else
Packit 8480eb
			options = mnt_options;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "gathered options: %s", options);
Packit 8480eb
Packit 8480eb
	if (check_is_multi(p)) {
Packit 8480eb
		char *m_root = NULL;
Packit 8480eb
		int m_root_len;
Packit 8480eb
		time_t age;
Packit 8480eb
		int l;
Packit 8480eb
Packit 8480eb
		/* If name starts with "/" it's a direct mount */
Packit 8480eb
		if (*name == '/') {
Packit 8480eb
			m_root_len = name_len;
Packit 8480eb
			m_root = alloca(m_root_len + 1);
Packit 8480eb
			if (!m_root) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				logerr(MODPREFIX "alloca: %s", estr);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			strcpy(m_root, name);
Packit 8480eb
		} else {
Packit 8480eb
			m_root_len = strlen(ap->path) + name_len + 1;
Packit 8480eb
			m_root = alloca(m_root_len + 1);
Packit 8480eb
			if (!m_root) {
Packit 8480eb
				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				logerr(MODPREFIX "alloca: %s", estr);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			strcpy(m_root, ap->path);
Packit 8480eb
			strcat(m_root, "/");
Packit 8480eb
			strcat(m_root, name);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		me = cache_lookup_distinct(mc, name);
Packit 8480eb
		if (!me) {
Packit 8480eb
			free(options);
Packit 8480eb
			free(pmapent);
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
			error(ap->logopt,
Packit 8480eb
			      MODPREFIX "can't find multi root %s", name);
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		cache_multi_writelock(me);
Packit 8480eb
		/* So we know we're the multi-mount root */
Packit 8480eb
		if (!me->multi)
Packit 8480eb
			me->multi = me;
Packit 8480eb
		else {
Packit 8480eb
			/*
Packit 8480eb
			 * The amd host mount type assumes the lookup name
Packit 8480eb
			 * is the host name for the host mount but amd uses
Packit 8480eb
			 * ${rhost} for this.
Packit 8480eb
			 *
Packit 8480eb
			 * This introduces the possibility of multiple
Packit 8480eb
			 * concurrent mount requests since constructing a
Packit 8480eb
			 * mount tree that isn't under the lookup name can't
Packit 8480eb
			 * take advantage of the kernel queuing of other
Packit 8480eb
			 * concurrent lookups while the mount tree is
Packit 8480eb
			 * constructed.
Packit 8480eb
			 *
Packit 8480eb
			 * Consequently multi-mount updates (currently only
Packit 8480eb
			 * done for the internal hosts map which the amd
Packit 8480eb
			 * parser also uses for its hosts map) can't be
Packit 8480eb
			 * allowed for amd mounts.
Packit 8480eb
			 */
Packit 8480eb
			if (source->flags & MAP_FLAG_FORMAT_AMD) {
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				cache_multi_unlock(me);
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
				return 0;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		age = me->age;
Packit 8480eb
Packit 8480eb
		/* It's a multi-mount; deal with it */
Packit 8480eb
		do {
Packit 8480eb
			char *path, *myoptions, *loc;
Packit 8480eb
			int status;
Packit 8480eb
Packit 8480eb
			if ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/')) {
Packit 8480eb
				l = 0;
Packit 8480eb
				path = dequote("/", 1, ap->logopt);
Packit 8480eb
				debug(ap->logopt,
Packit 8480eb
				      MODPREFIX "dequote(\"/\") -> %s", path);
Packit 8480eb
			} else {
Packit 8480eb
				l = span_space(p, mapent_len - (p - pmapent));
Packit 8480eb
				path = sanitize_path(p, l, LKP_MULTI, ap->logopt);
Packit 8480eb
				debug(ap->logopt, MODPREFIX
Packit 8480eb
				      "dequote(\"%.*s\") -> %s", l, p, path);
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (!path) {
Packit 8480eb
				warn(ap->logopt, MODPREFIX "null path or out of memory");
Packit 8480eb
				cache_delete_offset_list(mc, name);
Packit 8480eb
				cache_multi_unlock(me);
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			p += l;
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
Packit Service 0f11ce
			myoptions = NULL;
Packit Service 0f11ce
			loc = NULL;
Packit Service 0f11ce
Packit 8480eb
			l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
Packit 8480eb
			if (!l) {
Packit 8480eb
				cache_delete_offset_list(mc, name);
Packit 8480eb
				cache_multi_unlock(me);
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				free(path);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			p += l;
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
Packit 8480eb
			master_source_current_wait(ap->entry);
Packit 8480eb
			ap->entry->current = source;
Packit 8480eb
Packit 8480eb
			status = update_offset_entry(ap, name,
Packit 8480eb
						     m_root, m_root_len,
Packit 8480eb
						     path, myoptions, loc, age);
Packit 8480eb
Packit 8480eb
			if (status != CHE_OK) {
Packit 8480eb
				warn(ap->logopt, MODPREFIX "error adding multi-mount");
Packit 8480eb
				cache_delete_offset_list(mc, name);
Packit 8480eb
				cache_multi_unlock(me);
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				free(path);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				free(myoptions);
Packit 8480eb
				if (loc)
Packit 8480eb
					free(loc);
Packit 8480eb
				pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (loc)
Packit 8480eb
				free(loc);
Packit 8480eb
			free(path);
Packit 8480eb
			free(myoptions);
Packit 8480eb
		} while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * We've got the ordered list of multi-mount entries so go
Packit 8480eb
		 * through and remove any stale entries if this is the top
Packit 8480eb
		 * of the multi-mount and set the parent entry of each.
Packit 8480eb
		 */
Packit 8480eb
		if (me == me->multi)
Packit 8480eb
			clean_stale_multi_triggers(ap, me, NULL, NULL);
Packit 8480eb
		cache_set_parents(me);
Packit 8480eb
Packit 8480eb
		rv = mount_subtree(ap, me, name, NULL, options, ctxt);
Packit 8480eb
Packit 8480eb
		cache_multi_unlock(me);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		free(options);
Packit 8480eb
		free(pmapent);
Packit 8480eb
		pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
Packit 8480eb
		return rv;
Packit 8480eb
	} else {
Packit 8480eb
		/* Normal (and non-root multi-mount) entries */
Packit 8480eb
		char *loc;
Packit 8480eb
		int loclen;
Packit 8480eb
		int l;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * If this is an offset belonging to a multi-mount entry
Packit 8480eb
		 * it's already been parsed (above) and any option string
Packit 8480eb
		 * has already been stripped so just use the remainder.
Packit 8480eb
		 */
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		if (*name == '/' &&
Packit 8480eb
		   (me = cache_lookup_distinct(mc, name)) && me->multi) {
Packit 8480eb
			loc = strdup(p);
Packit 8480eb
			if (!loc) {
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				cache_unlock(mc);
Packit 8480eb
				warn(ap->logopt, MODPREFIX "out of memory");
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			cache_multi_writelock(me);
Packit 8480eb
			rv = mount_subtree(ap, me, name, loc, options, ctxt);
Packit 8480eb
			cache_multi_unlock(me);
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			free(loc);
Packit 8480eb
			free(options);
Packit 8480eb
			free(pmapent);
Packit 8480eb
			return rv;
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		l = chunklen(p, check_colon(p));
Packit 8480eb
		loc = dequote(p, l, ap->logopt);
Packit 8480eb
		if (!loc) {
Packit 8480eb
			free(options);
Packit 8480eb
			free(pmapent);
Packit 8480eb
			warn(ap->logopt, MODPREFIX "null location or out of memory");
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* Location can't begin with a '/' */
Packit 8480eb
		if (*p == '/') {
Packit 8480eb
			free(options);
Packit 8480eb
			free(pmapent);
Packit 8480eb
			free(loc);
Packit 8480eb
			warn(ap->logopt,
Packit 8480eb
			      MODPREFIX "error location begins with \"/\"");
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!validate_location(ap->logopt, loc)) {
Packit 8480eb
			free(loc);
Packit 8480eb
			free(options);
Packit 8480eb
			free(pmapent);
Packit 8480eb
			return 1;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt,
Packit 8480eb
		      MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
Packit 8480eb
Packit 8480eb
		p += l;
Packit 8480eb
		p = skipspace(p);
Packit 8480eb
Packit 8480eb
		while (*p) {
Packit 8480eb
			char *tmp, *ent;
Packit 8480eb
Packit 8480eb
			l = chunklen(p, check_colon(p));
Packit 8480eb
			ent = dequote(p, l, ap->logopt);
Packit 8480eb
			if (!ent) {
Packit 8480eb
				free(loc);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				warn(ap->logopt,
Packit 8480eb
				     MODPREFIX "null location or out of memory");
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (!validate_location(ap->logopt, ent)) {
Packit 8480eb
				free(ent);
Packit 8480eb
				free(loc);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			debug(ap->logopt,
Packit 8480eb
			      MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent);
Packit 8480eb
Packit 8480eb
			tmp = realloc(loc, strlen(loc) + l + 2);
Packit 8480eb
			if (!tmp) {
Packit 8480eb
				free(ent);
Packit 8480eb
				free(loc);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				error(ap->logopt, MODPREFIX "out of memory");
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
			loc = tmp;
Packit 8480eb
Packit 8480eb
			strcat(loc, " ");
Packit 8480eb
			strcat(loc, ent);
Packit 8480eb
Packit 8480eb
			free(ent);
Packit 8480eb
Packit 8480eb
			p += l;
Packit 8480eb
			p = skipspace(p);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * If options are asking for a hosts map loc should be
Packit 8480eb
		 * NULL but we see it can contain junk, so ....
Packit 8480eb
		 */
Packit 8480eb
		if ((strstr(options, "fstype=autofs") &&
Packit 8480eb
		     strstr(options, "hosts"))) {
Packit 8480eb
			if (loc) {
Packit 8480eb
				free(loc);
Packit 8480eb
				loc = NULL;
Packit 8480eb
			}
Packit 8480eb
			loclen = 0;
Packit 8480eb
		} else {
Packit 8480eb
			loclen = strlen(loc);
Packit 8480eb
			if (loclen == 0) {
Packit 8480eb
				free(loc);
Packit 8480eb
				free(options);
Packit 8480eb
				free(pmapent);
Packit 8480eb
				error(ap->logopt,
Packit 8480eb
				      MODPREFIX "entry %s is empty!", name);
Packit 8480eb
				return 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		debug(ap->logopt,
Packit 8480eb
		      MODPREFIX "core of entry: options=%s, loc=%.*s",
Packit 8480eb
		      options, loclen, loc);
Packit 8480eb
Packit 8480eb
		if (!strcmp(ap->path, "/-"))
Packit 8480eb
			rv = sun_mount(ap, name, name, name_len,
Packit 8480eb
				       loc, loclen, options, ctxt);
Packit 8480eb
		else
Packit 8480eb
			rv = sun_mount(ap, ap->path, name, name_len,
Packit 8480eb
				       loc, loclen, options, ctxt);
Packit 8480eb
Packit 8480eb
		if (loc)
Packit 8480eb
			free(loc);
Packit 8480eb
		free(options);
Packit 8480eb
		free(pmapent);
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
}