xref: /freebsd/usr.sbin/autofs/common.c (revision 5585582d143cb0bc4cf45b14b7ec47629082e06b)
13914ddf8SEdward Tomasz Napierala /*-
23914ddf8SEdward Tomasz Napierala  * Copyright (c) 2014 The FreeBSD Foundation
33914ddf8SEdward Tomasz Napierala  * All rights reserved.
43914ddf8SEdward Tomasz Napierala  *
53914ddf8SEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
63914ddf8SEdward Tomasz Napierala  * from the FreeBSD Foundation.
73914ddf8SEdward Tomasz Napierala  *
83914ddf8SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
93914ddf8SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
103914ddf8SEdward Tomasz Napierala  * are met:
113914ddf8SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
123914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
133914ddf8SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
143914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
153914ddf8SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
163914ddf8SEdward Tomasz Napierala  *
173914ddf8SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
183914ddf8SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
193914ddf8SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
203914ddf8SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
213914ddf8SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
223914ddf8SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
233914ddf8SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
243914ddf8SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
253914ddf8SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
263914ddf8SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
273914ddf8SEdward Tomasz Napierala  * SUCH DAMAGE.
283914ddf8SEdward Tomasz Napierala  *
293914ddf8SEdward Tomasz Napierala  */
303914ddf8SEdward Tomasz Napierala 
31925fd945SEdward Tomasz Napierala #include <sys/cdefs.h>
32925fd945SEdward Tomasz Napierala __FBSDID("$FreeBSD$");
33925fd945SEdward Tomasz Napierala 
343914ddf8SEdward Tomasz Napierala #include <sys/types.h>
353914ddf8SEdward Tomasz Napierala #include <sys/time.h>
363914ddf8SEdward Tomasz Napierala #include <sys/ioctl.h>
373914ddf8SEdward Tomasz Napierala #include <sys/param.h>
383914ddf8SEdward Tomasz Napierala #include <sys/linker.h>
393914ddf8SEdward Tomasz Napierala #include <sys/mount.h>
403914ddf8SEdward Tomasz Napierala #include <sys/socket.h>
413914ddf8SEdward Tomasz Napierala #include <sys/stat.h>
423914ddf8SEdward Tomasz Napierala #include <sys/wait.h>
433914ddf8SEdward Tomasz Napierala #include <sys/utsname.h>
443914ddf8SEdward Tomasz Napierala #include <assert.h>
453914ddf8SEdward Tomasz Napierala #include <ctype.h>
463914ddf8SEdward Tomasz Napierala #include <err.h>
473914ddf8SEdward Tomasz Napierala #include <errno.h>
483914ddf8SEdward Tomasz Napierala #include <fcntl.h>
493914ddf8SEdward Tomasz Napierala #include <libgen.h>
503914ddf8SEdward Tomasz Napierala #include <netdb.h>
513914ddf8SEdward Tomasz Napierala #include <paths.h>
523914ddf8SEdward Tomasz Napierala #include <signal.h>
533914ddf8SEdward Tomasz Napierala #include <stdbool.h>
543914ddf8SEdward Tomasz Napierala #include <stdint.h>
553dd80c05SEdward Tomasz Napierala #define	_WITH_GETLINE
563914ddf8SEdward Tomasz Napierala #include <stdio.h>
573914ddf8SEdward Tomasz Napierala #include <stdlib.h>
583914ddf8SEdward Tomasz Napierala #include <string.h>
593914ddf8SEdward Tomasz Napierala #include <unistd.h>
603914ddf8SEdward Tomasz Napierala 
613914ddf8SEdward Tomasz Napierala #include <libutil.h>
623914ddf8SEdward Tomasz Napierala 
633914ddf8SEdward Tomasz Napierala #include "autofs_ioctl.h"
643914ddf8SEdward Tomasz Napierala 
653914ddf8SEdward Tomasz Napierala #include "common.h"
663914ddf8SEdward Tomasz Napierala 
673914ddf8SEdward Tomasz Napierala extern FILE *yyin;
683914ddf8SEdward Tomasz Napierala extern char *yytext;
693914ddf8SEdward Tomasz Napierala extern int yylex(void);
703914ddf8SEdward Tomasz Napierala 
713914ddf8SEdward Tomasz Napierala static void	parse_master_yyin(struct node *root, const char *master);
723914ddf8SEdward Tomasz Napierala static void	parse_map_yyin(struct node *parent, const char *map,
733914ddf8SEdward Tomasz Napierala 		    const char *executable_key);
743914ddf8SEdward Tomasz Napierala 
753914ddf8SEdward Tomasz Napierala char *
763914ddf8SEdward Tomasz Napierala checked_strdup(const char *s)
773914ddf8SEdward Tomasz Napierala {
783914ddf8SEdward Tomasz Napierala 	char *c;
793914ddf8SEdward Tomasz Napierala 
803914ddf8SEdward Tomasz Napierala 	assert(s != NULL);
813914ddf8SEdward Tomasz Napierala 
823914ddf8SEdward Tomasz Napierala 	c = strdup(s);
833914ddf8SEdward Tomasz Napierala 	if (c == NULL)
843914ddf8SEdward Tomasz Napierala 		log_err(1, "strdup");
853914ddf8SEdward Tomasz Napierala 	return (c);
863914ddf8SEdward Tomasz Napierala }
873914ddf8SEdward Tomasz Napierala 
883914ddf8SEdward Tomasz Napierala /*
893914ddf8SEdward Tomasz Napierala  * Take two pointers to strings, concatenate the contents with "/" in the
903914ddf8SEdward Tomasz Napierala  * middle, make the first pointer point to the result, the second pointer
913914ddf8SEdward Tomasz Napierala  * to NULL, and free the old strings.
923914ddf8SEdward Tomasz Napierala  *
933914ddf8SEdward Tomasz Napierala  * Concatenate pathnames, basically.
943914ddf8SEdward Tomasz Napierala  */
953914ddf8SEdward Tomasz Napierala static void
963914ddf8SEdward Tomasz Napierala concat(char **p1, char **p2)
973914ddf8SEdward Tomasz Napierala {
983914ddf8SEdward Tomasz Napierala 	int ret;
993914ddf8SEdward Tomasz Napierala 	char *path;
1003914ddf8SEdward Tomasz Napierala 
1013914ddf8SEdward Tomasz Napierala 	assert(p1 != NULL);
1023914ddf8SEdward Tomasz Napierala 	assert(p2 != NULL);
1033914ddf8SEdward Tomasz Napierala 
1043914ddf8SEdward Tomasz Napierala 	if (*p1 == NULL)
1053914ddf8SEdward Tomasz Napierala 		*p1 = checked_strdup("");
1063914ddf8SEdward Tomasz Napierala 
1073914ddf8SEdward Tomasz Napierala 	if (*p2 == NULL)
1083914ddf8SEdward Tomasz Napierala 		*p2 = checked_strdup("");
1093914ddf8SEdward Tomasz Napierala 
1103914ddf8SEdward Tomasz Napierala 	ret = asprintf(&path, "%s/%s", *p1, *p2);
1113914ddf8SEdward Tomasz Napierala 	if (ret < 0)
1123914ddf8SEdward Tomasz Napierala 		log_err(1, "asprintf");
1133914ddf8SEdward Tomasz Napierala 
1143914ddf8SEdward Tomasz Napierala 	/*
1153914ddf8SEdward Tomasz Napierala 	 * XXX
1163914ddf8SEdward Tomasz Napierala 	 */
1173914ddf8SEdward Tomasz Napierala 	//free(*p1);
1183914ddf8SEdward Tomasz Napierala 	//free(*p2);
1193914ddf8SEdward Tomasz Napierala 
1203914ddf8SEdward Tomasz Napierala 	*p1 = path;
1213914ddf8SEdward Tomasz Napierala 	*p2 = NULL;
1223914ddf8SEdward Tomasz Napierala }
1233914ddf8SEdward Tomasz Napierala 
1243914ddf8SEdward Tomasz Napierala /*
1253914ddf8SEdward Tomasz Napierala  * Concatenate two strings, inserting separator between them, unless not needed.
1263914ddf8SEdward Tomasz Napierala  *
1273914ddf8SEdward Tomasz Napierala  * This function is very convenient to use when you do not care about freeing
1283914ddf8SEdward Tomasz Napierala  * memory - which is okay here, because we are a short running process.
1293914ddf8SEdward Tomasz Napierala  */
1303914ddf8SEdward Tomasz Napierala char *
1313914ddf8SEdward Tomasz Napierala separated_concat(const char *s1, const char *s2, char separator)
1323914ddf8SEdward Tomasz Napierala {
1333914ddf8SEdward Tomasz Napierala 	char *result;
1343914ddf8SEdward Tomasz Napierala 	int ret;
1353914ddf8SEdward Tomasz Napierala 
1363914ddf8SEdward Tomasz Napierala 	assert(s1 != NULL);
1373914ddf8SEdward Tomasz Napierala 	assert(s2 != NULL);
1383914ddf8SEdward Tomasz Napierala 
139*5585582dSEdward Tomasz Napierala 	/*
140*5585582dSEdward Tomasz Napierala 	 * If s2 starts with separator - skip it; otherwise concatenating
141*5585582dSEdward Tomasz Napierala 	 * "/" and "/foo" would end up returning "//foo".
142*5585582dSEdward Tomasz Napierala 	 */
143*5585582dSEdward Tomasz Napierala 	if (s2[0] == separator)
144*5585582dSEdward Tomasz Napierala 		s2++;
145*5585582dSEdward Tomasz Napierala 
146*5585582dSEdward Tomasz Napierala 	if (s1[0] == '\0' || s2[0] == '\0' || s1[strlen(s1) - 1] == separator) {
1473914ddf8SEdward Tomasz Napierala 		ret = asprintf(&result, "%s%s", s1, s2);
1483914ddf8SEdward Tomasz Napierala 	} else {
1493914ddf8SEdward Tomasz Napierala 		ret = asprintf(&result, "%s%c%s", s1, separator, s2);
1503914ddf8SEdward Tomasz Napierala 	}
1513914ddf8SEdward Tomasz Napierala 	if (ret < 0)
1523914ddf8SEdward Tomasz Napierala 		log_err(1, "asprintf");
1533914ddf8SEdward Tomasz Napierala 
1543914ddf8SEdward Tomasz Napierala 	//log_debugx("separated_concat: got %s and %s, returning %s", s1, s2, result);
1553914ddf8SEdward Tomasz Napierala 
1563914ddf8SEdward Tomasz Napierala 	return (result);
1573914ddf8SEdward Tomasz Napierala }
1583914ddf8SEdward Tomasz Napierala 
1593914ddf8SEdward Tomasz Napierala void
1603914ddf8SEdward Tomasz Napierala create_directory(const char *path)
1613914ddf8SEdward Tomasz Napierala {
1623914ddf8SEdward Tomasz Napierala 	char *component, *copy, *tofree, *partial;
1633914ddf8SEdward Tomasz Napierala 	int error;
1643914ddf8SEdward Tomasz Napierala 
1653914ddf8SEdward Tomasz Napierala 	assert(path[0] == '/');
1663914ddf8SEdward Tomasz Napierala 
1673914ddf8SEdward Tomasz Napierala 	/*
1683914ddf8SEdward Tomasz Napierala 	 * +1 to skip the leading slash.
1693914ddf8SEdward Tomasz Napierala 	 */
1703914ddf8SEdward Tomasz Napierala 	copy = tofree = checked_strdup(path + 1);
1713914ddf8SEdward Tomasz Napierala 
1723914ddf8SEdward Tomasz Napierala 	partial = NULL;
1733914ddf8SEdward Tomasz Napierala 	for (;;) {
1743914ddf8SEdward Tomasz Napierala 		component = strsep(&copy, "/");
1753914ddf8SEdward Tomasz Napierala 		if (component == NULL)
1763914ddf8SEdward Tomasz Napierala 			break;
1773914ddf8SEdward Tomasz Napierala 		concat(&partial, &component);
1787ebeea9aSEdward Tomasz Napierala 		//log_debugx("creating \"%s\"", partial);
1793914ddf8SEdward Tomasz Napierala 		error = mkdir(partial, 0755);
1807ebeea9aSEdward Tomasz Napierala 		if (error != 0 && errno != EEXIST) {
1817ebeea9aSEdward Tomasz Napierala 			log_warn("cannot create %s", partial);
1827ebeea9aSEdward Tomasz Napierala 			return;
1837ebeea9aSEdward Tomasz Napierala 		}
1843914ddf8SEdward Tomasz Napierala 	}
1853914ddf8SEdward Tomasz Napierala 
1863914ddf8SEdward Tomasz Napierala 	free(tofree);
1873914ddf8SEdward Tomasz Napierala }
1883914ddf8SEdward Tomasz Napierala 
1893914ddf8SEdward Tomasz Napierala struct node *
1903914ddf8SEdward Tomasz Napierala node_new_root(void)
1913914ddf8SEdward Tomasz Napierala {
1923914ddf8SEdward Tomasz Napierala 	struct node *n;
1933914ddf8SEdward Tomasz Napierala 
1943914ddf8SEdward Tomasz Napierala 	n = calloc(1, sizeof(*n));
1953914ddf8SEdward Tomasz Napierala 	if (n == NULL)
1963914ddf8SEdward Tomasz Napierala 		log_err(1, "calloc");
1973914ddf8SEdward Tomasz Napierala 	// XXX
1983914ddf8SEdward Tomasz Napierala 	n->n_key = checked_strdup("/");
1993914ddf8SEdward Tomasz Napierala 	n->n_options = checked_strdup("");
2003914ddf8SEdward Tomasz Napierala 
2013914ddf8SEdward Tomasz Napierala 	TAILQ_INIT(&n->n_children);
2023914ddf8SEdward Tomasz Napierala 
2033914ddf8SEdward Tomasz Napierala 	return (n);
2043914ddf8SEdward Tomasz Napierala }
2053914ddf8SEdward Tomasz Napierala 
2063914ddf8SEdward Tomasz Napierala struct node *
2073914ddf8SEdward Tomasz Napierala node_new(struct node *parent, char *key, char *options, char *location,
2083914ddf8SEdward Tomasz Napierala     const char *config_file, int config_line)
2093914ddf8SEdward Tomasz Napierala {
2103914ddf8SEdward Tomasz Napierala 	struct node *n;
2113914ddf8SEdward Tomasz Napierala 
2123914ddf8SEdward Tomasz Napierala 	n = calloc(1, sizeof(*n));
2133914ddf8SEdward Tomasz Napierala 	if (n == NULL)
2143914ddf8SEdward Tomasz Napierala 		log_err(1, "calloc");
2153914ddf8SEdward Tomasz Napierala 
2163914ddf8SEdward Tomasz Napierala 	TAILQ_INIT(&n->n_children);
2173914ddf8SEdward Tomasz Napierala 	assert(key != NULL);
2183dd80c05SEdward Tomasz Napierala 	assert(key[0] != '\0');
2193914ddf8SEdward Tomasz Napierala 	n->n_key = key;
2203914ddf8SEdward Tomasz Napierala 	if (options != NULL)
2213914ddf8SEdward Tomasz Napierala 		n->n_options = options;
2223914ddf8SEdward Tomasz Napierala 	else
2233914ddf8SEdward Tomasz Napierala 		n->n_options = strdup("");
2243914ddf8SEdward Tomasz Napierala 	n->n_location = location;
2253914ddf8SEdward Tomasz Napierala 	assert(config_file != NULL);
2263914ddf8SEdward Tomasz Napierala 	n->n_config_file = config_file;
2273914ddf8SEdward Tomasz Napierala 	assert(config_line >= 0);
2283914ddf8SEdward Tomasz Napierala 	n->n_config_line = config_line;
2293914ddf8SEdward Tomasz Napierala 
2303914ddf8SEdward Tomasz Napierala 	assert(parent != NULL);
2313914ddf8SEdward Tomasz Napierala 	n->n_parent = parent;
2323914ddf8SEdward Tomasz Napierala 	TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
2333914ddf8SEdward Tomasz Napierala 
2343914ddf8SEdward Tomasz Napierala 	return (n);
2353914ddf8SEdward Tomasz Napierala }
2363914ddf8SEdward Tomasz Napierala 
2373914ddf8SEdward Tomasz Napierala struct node *
2383914ddf8SEdward Tomasz Napierala node_new_map(struct node *parent, char *key, char *options, char *map,
2393914ddf8SEdward Tomasz Napierala     const char *config_file, int config_line)
2403914ddf8SEdward Tomasz Napierala {
2413914ddf8SEdward Tomasz Napierala 	struct node *n;
2423914ddf8SEdward Tomasz Napierala 
2433914ddf8SEdward Tomasz Napierala 	n = calloc(1, sizeof(*n));
2443914ddf8SEdward Tomasz Napierala 	if (n == NULL)
2453914ddf8SEdward Tomasz Napierala 		log_err(1, "calloc");
2463914ddf8SEdward Tomasz Napierala 
2473914ddf8SEdward Tomasz Napierala 	TAILQ_INIT(&n->n_children);
2483914ddf8SEdward Tomasz Napierala 	assert(key != NULL);
2493dd80c05SEdward Tomasz Napierala 	assert(key[0] != '\0');
2503914ddf8SEdward Tomasz Napierala 	n->n_key = key;
2513914ddf8SEdward Tomasz Napierala 	if (options != NULL)
2523914ddf8SEdward Tomasz Napierala 		n->n_options = options;
2533914ddf8SEdward Tomasz Napierala 	else
2543914ddf8SEdward Tomasz Napierala 		n->n_options = strdup("");
2553914ddf8SEdward Tomasz Napierala 	n->n_map = map;
2563914ddf8SEdward Tomasz Napierala 	assert(config_file != NULL);
2573914ddf8SEdward Tomasz Napierala 	n->n_config_file = config_file;
2583914ddf8SEdward Tomasz Napierala 	assert(config_line >= 0);
2593914ddf8SEdward Tomasz Napierala 	n->n_config_line = config_line;
2603914ddf8SEdward Tomasz Napierala 
2613914ddf8SEdward Tomasz Napierala 	assert(parent != NULL);
2623914ddf8SEdward Tomasz Napierala 	n->n_parent = parent;
2633914ddf8SEdward Tomasz Napierala 	TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
2643914ddf8SEdward Tomasz Napierala 
2653914ddf8SEdward Tomasz Napierala 	return (n);
2663914ddf8SEdward Tomasz Napierala }
2673914ddf8SEdward Tomasz Napierala 
2683914ddf8SEdward Tomasz Napierala static struct node *
2693914ddf8SEdward Tomasz Napierala node_duplicate(const struct node *o, struct node *parent)
2703914ddf8SEdward Tomasz Napierala {
2713914ddf8SEdward Tomasz Napierala 	const struct node *child;
2723914ddf8SEdward Tomasz Napierala 	struct node *n;
2733914ddf8SEdward Tomasz Napierala 
2743914ddf8SEdward Tomasz Napierala 	if (parent == NULL)
2753914ddf8SEdward Tomasz Napierala 		parent = o->n_parent;
2763914ddf8SEdward Tomasz Napierala 
2773914ddf8SEdward Tomasz Napierala 	n = node_new(parent, o->n_key, o->n_options, o->n_location,
2783914ddf8SEdward Tomasz Napierala 	    o->n_config_file, o->n_config_line);
2793914ddf8SEdward Tomasz Napierala 
2803914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &o->n_children, n_next)
2813914ddf8SEdward Tomasz Napierala 		node_duplicate(child, n);
2823914ddf8SEdward Tomasz Napierala 
2833914ddf8SEdward Tomasz Napierala 	return (n);
2843914ddf8SEdward Tomasz Napierala }
2853914ddf8SEdward Tomasz Napierala 
2863914ddf8SEdward Tomasz Napierala static void
2873914ddf8SEdward Tomasz Napierala node_delete(struct node *n)
2883914ddf8SEdward Tomasz Napierala {
2893914ddf8SEdward Tomasz Napierala 	struct node *child, *tmp;
2903914ddf8SEdward Tomasz Napierala 
2913914ddf8SEdward Tomasz Napierala 	assert (n != NULL);
2923914ddf8SEdward Tomasz Napierala 
2933914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp)
2943914ddf8SEdward Tomasz Napierala 		node_delete(child);
2953914ddf8SEdward Tomasz Napierala 
2963914ddf8SEdward Tomasz Napierala 	if (n->n_parent != NULL)
2973914ddf8SEdward Tomasz Napierala 		TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
2983914ddf8SEdward Tomasz Napierala 
2993914ddf8SEdward Tomasz Napierala 	free(n);
3003914ddf8SEdward Tomasz Napierala }
3013914ddf8SEdward Tomasz Napierala 
3023914ddf8SEdward Tomasz Napierala /*
3033914ddf8SEdward Tomasz Napierala  * Move (reparent) node 'n' to make it sibling of 'previous', placed
3043914ddf8SEdward Tomasz Napierala  * just after it.
3053914ddf8SEdward Tomasz Napierala  */
3063914ddf8SEdward Tomasz Napierala static void
3073914ddf8SEdward Tomasz Napierala node_move_after(struct node *n, struct node *previous)
3083914ddf8SEdward Tomasz Napierala {
3093914ddf8SEdward Tomasz Napierala 
3103914ddf8SEdward Tomasz Napierala 	TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
3113914ddf8SEdward Tomasz Napierala 	n->n_parent = previous->n_parent;
3123914ddf8SEdward Tomasz Napierala 	TAILQ_INSERT_AFTER(&previous->n_parent->n_children, previous, n, n_next);
3133914ddf8SEdward Tomasz Napierala }
3143914ddf8SEdward Tomasz Napierala 
3153914ddf8SEdward Tomasz Napierala static void
3163914ddf8SEdward Tomasz Napierala node_expand_includes(struct node *root, bool is_master)
3173914ddf8SEdward Tomasz Napierala {
3183914ddf8SEdward Tomasz Napierala 	struct node *n, *n2, *tmp, *tmp2, *tmproot;
3193914ddf8SEdward Tomasz Napierala 	int error;
3203914ddf8SEdward Tomasz Napierala 
3213914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH_SAFE(n, &root->n_children, n_next, tmp) {
3223914ddf8SEdward Tomasz Napierala 		if (n->n_key[0] != '+')
3233914ddf8SEdward Tomasz Napierala 			continue;
3243914ddf8SEdward Tomasz Napierala 
3253914ddf8SEdward Tomasz Napierala 		error = access(AUTO_INCLUDE_PATH, F_OK);
3263914ddf8SEdward Tomasz Napierala 		if (error != 0) {
3273914ddf8SEdward Tomasz Napierala 			log_errx(1, "directory services not configured; "
3283914ddf8SEdward Tomasz Napierala 			    "%s does not exist", AUTO_INCLUDE_PATH);
3293914ddf8SEdward Tomasz Napierala 		}
3303914ddf8SEdward Tomasz Napierala 
3313914ddf8SEdward Tomasz Napierala 		/*
3323914ddf8SEdward Tomasz Napierala 		 * "+1" to skip leading "+".
3333914ddf8SEdward Tomasz Napierala 		 */
3343914ddf8SEdward Tomasz Napierala 		yyin = auto_popen(AUTO_INCLUDE_PATH, n->n_key + 1, NULL);
3353914ddf8SEdward Tomasz Napierala 		assert(yyin != NULL);
3363914ddf8SEdward Tomasz Napierala 
3373914ddf8SEdward Tomasz Napierala 		tmproot = node_new_root();
3383914ddf8SEdward Tomasz Napierala 		if (is_master)
3393914ddf8SEdward Tomasz Napierala 			parse_master_yyin(tmproot, n->n_key);
3403914ddf8SEdward Tomasz Napierala 		else
3413914ddf8SEdward Tomasz Napierala 			parse_map_yyin(tmproot, n->n_key, NULL);
3423914ddf8SEdward Tomasz Napierala 
3433914ddf8SEdward Tomasz Napierala 		error = auto_pclose(yyin);
3443914ddf8SEdward Tomasz Napierala 		yyin = NULL;
3453914ddf8SEdward Tomasz Napierala 		if (error != 0) {
3463914ddf8SEdward Tomasz Napierala 			log_errx(1, "failed to handle include \"%s\"",
3473914ddf8SEdward Tomasz Napierala 			    n->n_key);
3483914ddf8SEdward Tomasz Napierala 		}
3493914ddf8SEdward Tomasz Napierala 
3503914ddf8SEdward Tomasz Napierala 		/*
3513914ddf8SEdward Tomasz Napierala 		 * Entries to be included are now in tmproot.  We need to merge
3523914ddf8SEdward Tomasz Napierala 		 * them with the rest, preserving their place and ordering.
3533914ddf8SEdward Tomasz Napierala 		 */
3543914ddf8SEdward Tomasz Napierala 		TAILQ_FOREACH_REVERSE_SAFE(n2,
3553914ddf8SEdward Tomasz Napierala 		    &tmproot->n_children, nodehead, n_next, tmp2) {
3563914ddf8SEdward Tomasz Napierala 			node_move_after(n2, n);
3573914ddf8SEdward Tomasz Napierala 		}
3583914ddf8SEdward Tomasz Napierala 
3593914ddf8SEdward Tomasz Napierala 		node_delete(n);
3603914ddf8SEdward Tomasz Napierala 		node_delete(tmproot);
3613914ddf8SEdward Tomasz Napierala 	}
3623914ddf8SEdward Tomasz Napierala }
3633914ddf8SEdward Tomasz Napierala 
3643914ddf8SEdward Tomasz Napierala static char *
3653914ddf8SEdward Tomasz Napierala expand_ampersand(char *string, const char *key)
3663914ddf8SEdward Tomasz Napierala {
3673914ddf8SEdward Tomasz Napierala 	char c, *expanded;
3683914ddf8SEdward Tomasz Napierala 	int i, ret, before_len = 0;
3693914ddf8SEdward Tomasz Napierala 	bool backslashed = false;
3703914ddf8SEdward Tomasz Napierala 
3713914ddf8SEdward Tomasz Napierala 	assert(key[0] != '\0');
3723914ddf8SEdward Tomasz Napierala 
3733914ddf8SEdward Tomasz Napierala 	expanded = checked_strdup(string);
3743914ddf8SEdward Tomasz Napierala 
3753914ddf8SEdward Tomasz Napierala 	for (i = 0; string[i] != '\0'; i++) {
3763914ddf8SEdward Tomasz Napierala 		c = string[i];
3773914ddf8SEdward Tomasz Napierala 		if (c == '\\' && backslashed == false) {
3783914ddf8SEdward Tomasz Napierala 			backslashed = true;
3793914ddf8SEdward Tomasz Napierala 			continue;
3803914ddf8SEdward Tomasz Napierala 		}
3813914ddf8SEdward Tomasz Napierala 		if (backslashed) {
3823914ddf8SEdward Tomasz Napierala 			backslashed = false;
3833914ddf8SEdward Tomasz Napierala 			continue;
3843914ddf8SEdward Tomasz Napierala 		}
3853914ddf8SEdward Tomasz Napierala 		backslashed = false;
3863914ddf8SEdward Tomasz Napierala 		if (c != '&')
3873914ddf8SEdward Tomasz Napierala 			continue;
3883914ddf8SEdward Tomasz Napierala 
3893914ddf8SEdward Tomasz Napierala 		/*
3903914ddf8SEdward Tomasz Napierala 		 * The 'before_len' variable contains the number
3913914ddf8SEdward Tomasz Napierala 		 * of characters before the '&'.
3923914ddf8SEdward Tomasz Napierala 		 */
3933914ddf8SEdward Tomasz Napierala 		before_len = i;
3943914ddf8SEdward Tomasz Napierala 		//assert(i + 1 < (int)strlen(string));
3953914ddf8SEdward Tomasz Napierala 
3963914ddf8SEdward Tomasz Napierala 		ret = asprintf(&expanded, "%.*s%s%s",
3973914ddf8SEdward Tomasz Napierala 		    before_len, string, key, string + before_len + 1);
3983914ddf8SEdward Tomasz Napierala 		if (ret < 0)
3993914ddf8SEdward Tomasz Napierala 			log_err(1, "asprintf");
4003914ddf8SEdward Tomasz Napierala 
4013914ddf8SEdward Tomasz Napierala 		//log_debugx("\"%s\" expanded with key \"%s\" to \"%s\"",
4023914ddf8SEdward Tomasz Napierala 		//    string, key, expanded);
4033914ddf8SEdward Tomasz Napierala 
4043914ddf8SEdward Tomasz Napierala 		/*
4053914ddf8SEdward Tomasz Napierala 		 * Figure out where to start searching for next variable.
4063914ddf8SEdward Tomasz Napierala 		 */
4073914ddf8SEdward Tomasz Napierala 		string = expanded;
4083914ddf8SEdward Tomasz Napierala 		i = before_len + strlen(key);
4093914ddf8SEdward Tomasz Napierala 		backslashed = false;
4103914ddf8SEdward Tomasz Napierala 		//assert(i < (int)strlen(string));
4113914ddf8SEdward Tomasz Napierala 	}
4123914ddf8SEdward Tomasz Napierala 
4133914ddf8SEdward Tomasz Napierala 	return (expanded);
4143914ddf8SEdward Tomasz Napierala }
4153914ddf8SEdward Tomasz Napierala 
4163914ddf8SEdward Tomasz Napierala /*
4173914ddf8SEdward Tomasz Napierala  * Expand "&" in n_location.  If the key is NULL, try to use
4183914ddf8SEdward Tomasz Napierala  * key from map entries themselves.  Keep in mind that maps
4193914ddf8SEdward Tomasz Napierala  * consist of tho levels of node structures, the key is one
4203914ddf8SEdward Tomasz Napierala  * level up.
4213914ddf8SEdward Tomasz Napierala  *
4223914ddf8SEdward Tomasz Napierala  * Variant with NULL key is for "automount -LL".
4233914ddf8SEdward Tomasz Napierala  */
4243914ddf8SEdward Tomasz Napierala void
4253914ddf8SEdward Tomasz Napierala node_expand_ampersand(struct node *n, const char *key)
4263914ddf8SEdward Tomasz Napierala {
4273914ddf8SEdward Tomasz Napierala 	struct node *child;
4283914ddf8SEdward Tomasz Napierala 
4293914ddf8SEdward Tomasz Napierala 	if (n->n_location != NULL) {
4303914ddf8SEdward Tomasz Napierala 		if (key == NULL) {
4313914ddf8SEdward Tomasz Napierala 			if (n->n_parent != NULL &&
4323914ddf8SEdward Tomasz Napierala 			    strcmp(n->n_parent->n_key, "*") != 0) {
4333914ddf8SEdward Tomasz Napierala 				n->n_location = expand_ampersand(n->n_location,
4343914ddf8SEdward Tomasz Napierala 				    n->n_parent->n_key);
4353914ddf8SEdward Tomasz Napierala 			}
4363914ddf8SEdward Tomasz Napierala 		} else {
4373914ddf8SEdward Tomasz Napierala 			n->n_location = expand_ampersand(n->n_location, key);
4383914ddf8SEdward Tomasz Napierala 		}
4393914ddf8SEdward Tomasz Napierala 	}
4403914ddf8SEdward Tomasz Napierala 
4413914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next)
4423914ddf8SEdward Tomasz Napierala 		node_expand_ampersand(child, key);
4433914ddf8SEdward Tomasz Napierala }
4443914ddf8SEdward Tomasz Napierala 
4453914ddf8SEdward Tomasz Napierala /*
4463914ddf8SEdward Tomasz Napierala  * Expand "*" in n_key.
4473914ddf8SEdward Tomasz Napierala  */
4483914ddf8SEdward Tomasz Napierala void
4493914ddf8SEdward Tomasz Napierala node_expand_wildcard(struct node *n, const char *key)
4503914ddf8SEdward Tomasz Napierala {
4513914ddf8SEdward Tomasz Napierala 	struct node *child, *expanded;
4523914ddf8SEdward Tomasz Napierala 
4533914ddf8SEdward Tomasz Napierala 	assert(key != NULL);
4543914ddf8SEdward Tomasz Napierala 
4553914ddf8SEdward Tomasz Napierala 	if (strcmp(n->n_key, "*") == 0) {
4563914ddf8SEdward Tomasz Napierala 		expanded = node_duplicate(n, NULL);
4573914ddf8SEdward Tomasz Napierala 		expanded->n_key = checked_strdup(key);
4583914ddf8SEdward Tomasz Napierala 		node_move_after(expanded, n);
4593914ddf8SEdward Tomasz Napierala 	}
4603914ddf8SEdward Tomasz Napierala 
4613914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next)
4623914ddf8SEdward Tomasz Napierala 		node_expand_wildcard(child, key);
4633914ddf8SEdward Tomasz Napierala }
4643914ddf8SEdward Tomasz Napierala 
4653914ddf8SEdward Tomasz Napierala int
4663914ddf8SEdward Tomasz Napierala node_expand_defined(struct node *n)
4673914ddf8SEdward Tomasz Napierala {
4683914ddf8SEdward Tomasz Napierala 	struct node *child;
4693914ddf8SEdward Tomasz Napierala 	int error, cumulated_error = 0;
4703914ddf8SEdward Tomasz Napierala 
4713914ddf8SEdward Tomasz Napierala 	if (n->n_location != NULL) {
4723914ddf8SEdward Tomasz Napierala 		n->n_location = defined_expand(n->n_location);
4733914ddf8SEdward Tomasz Napierala 		if (n->n_location == NULL) {
4743914ddf8SEdward Tomasz Napierala 			log_warnx("failed to expand location for %s",
4753914ddf8SEdward Tomasz Napierala 			    node_path(n));
4763914ddf8SEdward Tomasz Napierala 			return (EINVAL);
4773914ddf8SEdward Tomasz Napierala 		}
4783914ddf8SEdward Tomasz Napierala 	}
4793914ddf8SEdward Tomasz Napierala 
4803914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next) {
4813914ddf8SEdward Tomasz Napierala 		error = node_expand_defined(child);
4823914ddf8SEdward Tomasz Napierala 		if (error != 0 && cumulated_error == 0)
4833914ddf8SEdward Tomasz Napierala 			cumulated_error = error;
4843914ddf8SEdward Tomasz Napierala 	}
4853914ddf8SEdward Tomasz Napierala 
4863914ddf8SEdward Tomasz Napierala 	return (cumulated_error);
4873914ddf8SEdward Tomasz Napierala }
4883914ddf8SEdward Tomasz Napierala 
4893914ddf8SEdward Tomasz Napierala bool
4903914ddf8SEdward Tomasz Napierala node_is_direct_map(const struct node *n)
4913914ddf8SEdward Tomasz Napierala {
4923914ddf8SEdward Tomasz Napierala 
4933914ddf8SEdward Tomasz Napierala 	for (;;) {
4943914ddf8SEdward Tomasz Napierala 		assert(n->n_parent != NULL);
4953914ddf8SEdward Tomasz Napierala 		if (n->n_parent->n_parent == NULL)
4963914ddf8SEdward Tomasz Napierala 			break;
4973914ddf8SEdward Tomasz Napierala 		n = n->n_parent;
4983914ddf8SEdward Tomasz Napierala 	}
4993914ddf8SEdward Tomasz Napierala 
5003914ddf8SEdward Tomasz Napierala 	assert(n->n_key != NULL);
5013914ddf8SEdward Tomasz Napierala 	if (strcmp(n->n_key, "/-") != 0)
5023914ddf8SEdward Tomasz Napierala 		return (false);
5033914ddf8SEdward Tomasz Napierala 
5043914ddf8SEdward Tomasz Napierala 	return (true);
5053914ddf8SEdward Tomasz Napierala }
5063914ddf8SEdward Tomasz Napierala 
5074cdc52bdSEdward Tomasz Napierala bool
5084cdc52bdSEdward Tomasz Napierala node_has_wildcards(const struct node *n)
5094cdc52bdSEdward Tomasz Napierala {
5104cdc52bdSEdward Tomasz Napierala 	const struct node *child;
5114cdc52bdSEdward Tomasz Napierala 
5124cdc52bdSEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next) {
5134cdc52bdSEdward Tomasz Napierala 		if (strcmp(child->n_key, "*") == 0)
5144cdc52bdSEdward Tomasz Napierala 			return (true);
5154cdc52bdSEdward Tomasz Napierala 	}
5164cdc52bdSEdward Tomasz Napierala 
5174cdc52bdSEdward Tomasz Napierala 	return (false);
5184cdc52bdSEdward Tomasz Napierala }
5194cdc52bdSEdward Tomasz Napierala 
5203914ddf8SEdward Tomasz Napierala static void
5213914ddf8SEdward Tomasz Napierala node_expand_maps(struct node *n, bool indirect)
5223914ddf8SEdward Tomasz Napierala {
5233914ddf8SEdward Tomasz Napierala 	struct node *child, *tmp;
5243914ddf8SEdward Tomasz Napierala 
5253914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp) {
5263914ddf8SEdward Tomasz Napierala 		if (node_is_direct_map(child)) {
5273914ddf8SEdward Tomasz Napierala 			if (indirect)
5283914ddf8SEdward Tomasz Napierala 				continue;
5293914ddf8SEdward Tomasz Napierala 		} else {
5303914ddf8SEdward Tomasz Napierala 			if (indirect == false)
5313914ddf8SEdward Tomasz Napierala 				continue;
5323914ddf8SEdward Tomasz Napierala 		}
5333914ddf8SEdward Tomasz Napierala 
5343914ddf8SEdward Tomasz Napierala 		/*
5353914ddf8SEdward Tomasz Napierala 		 * This is the first-level map node; the one that contains
5363914ddf8SEdward Tomasz Napierala 		 * the key and subnodes with mountpoints and actual map names.
5373914ddf8SEdward Tomasz Napierala 		 */
5383914ddf8SEdward Tomasz Napierala 		if (child->n_map == NULL)
5393914ddf8SEdward Tomasz Napierala 			continue;
5403914ddf8SEdward Tomasz Napierala 
5413914ddf8SEdward Tomasz Napierala 		if (indirect) {
5423914ddf8SEdward Tomasz Napierala 			log_debugx("map \"%s\" is an indirect map, parsing",
5433914ddf8SEdward Tomasz Napierala 			    child->n_map);
5443914ddf8SEdward Tomasz Napierala 		} else {
5453914ddf8SEdward Tomasz Napierala 			log_debugx("map \"%s\" is a direct map, parsing",
5463914ddf8SEdward Tomasz Napierala 			    child->n_map);
5473914ddf8SEdward Tomasz Napierala 		}
5484cdc52bdSEdward Tomasz Napierala 		parse_map(child, child->n_map, NULL, NULL);
5493914ddf8SEdward Tomasz Napierala 	}
5503914ddf8SEdward Tomasz Napierala }
5513914ddf8SEdward Tomasz Napierala 
5523914ddf8SEdward Tomasz Napierala static void
5533914ddf8SEdward Tomasz Napierala node_expand_direct_maps(struct node *n)
5543914ddf8SEdward Tomasz Napierala {
5553914ddf8SEdward Tomasz Napierala 
5563914ddf8SEdward Tomasz Napierala 	node_expand_maps(n, false);
5573914ddf8SEdward Tomasz Napierala }
5583914ddf8SEdward Tomasz Napierala 
5593914ddf8SEdward Tomasz Napierala void
5603914ddf8SEdward Tomasz Napierala node_expand_indirect_maps(struct node *n)
5613914ddf8SEdward Tomasz Napierala {
5623914ddf8SEdward Tomasz Napierala 
5633914ddf8SEdward Tomasz Napierala 	node_expand_maps(n, true);
5643914ddf8SEdward Tomasz Napierala }
5653914ddf8SEdward Tomasz Napierala 
5663914ddf8SEdward Tomasz Napierala static char *
5673914ddf8SEdward Tomasz Napierala node_path_x(const struct node *n, char *x)
5683914ddf8SEdward Tomasz Napierala {
5693914ddf8SEdward Tomasz Napierala 	char *path;
5703914ddf8SEdward Tomasz Napierala 
5713914ddf8SEdward Tomasz Napierala 	if (n->n_parent == NULL)
5723914ddf8SEdward Tomasz Napierala 		return (x);
5733914ddf8SEdward Tomasz Napierala 
5743914ddf8SEdward Tomasz Napierala 	/*
5753914ddf8SEdward Tomasz Napierala 	 * Return "/-" for direct maps only if we were asked for path
5763914ddf8SEdward Tomasz Napierala 	 * to the "/-" node itself, not to any of its subnodes.
5773914ddf8SEdward Tomasz Napierala 	 */
5783914ddf8SEdward Tomasz Napierala 	if (n->n_parent->n_parent == NULL &&
5793914ddf8SEdward Tomasz Napierala 	    strcmp(n->n_key, "/-") == 0 &&
5803914ddf8SEdward Tomasz Napierala 	    x[0] != '\0') {
5813914ddf8SEdward Tomasz Napierala 		return (x);
5823914ddf8SEdward Tomasz Napierala 	}
5833914ddf8SEdward Tomasz Napierala 
5843dd80c05SEdward Tomasz Napierala 	assert(n->n_key[0] != '\0');
5853914ddf8SEdward Tomasz Napierala 	path = separated_concat(n->n_key, x, '/');
5863914ddf8SEdward Tomasz Napierala 	free(x);
5873914ddf8SEdward Tomasz Napierala 
5883914ddf8SEdward Tomasz Napierala 	return (node_path_x(n->n_parent, path));
5893914ddf8SEdward Tomasz Napierala }
5903914ddf8SEdward Tomasz Napierala 
5913914ddf8SEdward Tomasz Napierala /*
5923914ddf8SEdward Tomasz Napierala  * Return full path for node, consisting of concatenated
5933914ddf8SEdward Tomasz Napierala  * paths of node itself and all its parents, up to the root.
5943914ddf8SEdward Tomasz Napierala  */
5953914ddf8SEdward Tomasz Napierala char *
5963914ddf8SEdward Tomasz Napierala node_path(const struct node *n)
5973914ddf8SEdward Tomasz Napierala {
5981bc6f464SEdward Tomasz Napierala 	char *path;
5991bc6f464SEdward Tomasz Napierala 	size_t len;
6003914ddf8SEdward Tomasz Napierala 
6011bc6f464SEdward Tomasz Napierala 	path = node_path_x(n, checked_strdup(""));
6021bc6f464SEdward Tomasz Napierala 
6031bc6f464SEdward Tomasz Napierala 	/*
6041bc6f464SEdward Tomasz Napierala 	 * Strip trailing slash, unless the whole path is "/".
6051bc6f464SEdward Tomasz Napierala 	 */
6061bc6f464SEdward Tomasz Napierala 	len = strlen(path);
6071bc6f464SEdward Tomasz Napierala 	if (len > 1 && path[len - 1] == '/')
6081bc6f464SEdward Tomasz Napierala 		path[len - 1] = '\0';
6091bc6f464SEdward Tomasz Napierala 
6101bc6f464SEdward Tomasz Napierala 	return (path);
6113914ddf8SEdward Tomasz Napierala }
6123914ddf8SEdward Tomasz Napierala 
6133914ddf8SEdward Tomasz Napierala static char *
6143914ddf8SEdward Tomasz Napierala node_options_x(const struct node *n, char *x)
6153914ddf8SEdward Tomasz Napierala {
6163914ddf8SEdward Tomasz Napierala 	char *options;
6173914ddf8SEdward Tomasz Napierala 
6183914ddf8SEdward Tomasz Napierala 	options = separated_concat(x, n->n_options, ',');
6193914ddf8SEdward Tomasz Napierala 	if (n->n_parent == NULL)
6203914ddf8SEdward Tomasz Napierala 		return (options);
6213914ddf8SEdward Tomasz Napierala 
6223914ddf8SEdward Tomasz Napierala 	return (node_options_x(n->n_parent, options));
6233914ddf8SEdward Tomasz Napierala }
6243914ddf8SEdward Tomasz Napierala 
6253914ddf8SEdward Tomasz Napierala /*
6263914ddf8SEdward Tomasz Napierala  * Return options for node, consisting of concatenated
6273914ddf8SEdward Tomasz Napierala  * options from the node itself and all its parents,
6283914ddf8SEdward Tomasz Napierala  * up to the root.
6293914ddf8SEdward Tomasz Napierala  */
6303914ddf8SEdward Tomasz Napierala char *
6313914ddf8SEdward Tomasz Napierala node_options(const struct node *n)
6323914ddf8SEdward Tomasz Napierala {
6333914ddf8SEdward Tomasz Napierala 
6343914ddf8SEdward Tomasz Napierala 	return (node_options_x(n, checked_strdup("")));
6353914ddf8SEdward Tomasz Napierala }
6363914ddf8SEdward Tomasz Napierala 
6373914ddf8SEdward Tomasz Napierala static void
6383914ddf8SEdward Tomasz Napierala node_print_indent(const struct node *n, int indent)
6393914ddf8SEdward Tomasz Napierala {
6403914ddf8SEdward Tomasz Napierala 	const struct node *child, *first_child;
6413914ddf8SEdward Tomasz Napierala 	char *path, *options;
6423914ddf8SEdward Tomasz Napierala 
6433914ddf8SEdward Tomasz Napierala 	path = node_path(n);
6443914ddf8SEdward Tomasz Napierala 	options = node_options(n);
6453914ddf8SEdward Tomasz Napierala 
6463914ddf8SEdward Tomasz Napierala 	/*
6473914ddf8SEdward Tomasz Napierala 	 * Do not show both parent and child node if they have the same
6483914ddf8SEdward Tomasz Napierala 	 * mountpoint; only show the child node.  This means the typical,
6493914ddf8SEdward Tomasz Napierala 	 * "key location", map entries are shown in a single line;
6503914ddf8SEdward Tomasz Napierala 	 * the "key mountpoint1 location2 mountpoint2 location2" entries
6513914ddf8SEdward Tomasz Napierala 	 * take multiple lines.
6523914ddf8SEdward Tomasz Napierala 	 */
6533914ddf8SEdward Tomasz Napierala 	first_child = TAILQ_FIRST(&n->n_children);
6543914ddf8SEdward Tomasz Napierala 	if (first_child == NULL || TAILQ_NEXT(first_child, n_next) != NULL ||
6553914ddf8SEdward Tomasz Napierala 	    strcmp(path, node_path(first_child)) != 0) {
6563914ddf8SEdward Tomasz Napierala 		assert(n->n_location == NULL || n->n_map == NULL);
6573914ddf8SEdward Tomasz Napierala 		printf("%*.s%-*s %s%-*s %-*s # %s map %s at %s:%d\n",
6583914ddf8SEdward Tomasz Napierala 		    indent, "",
6593914ddf8SEdward Tomasz Napierala 		    25 - indent,
6603914ddf8SEdward Tomasz Napierala 		    path,
6613914ddf8SEdward Tomasz Napierala 		    options[0] != '\0' ? "-" : " ",
6623914ddf8SEdward Tomasz Napierala 		    20,
6633914ddf8SEdward Tomasz Napierala 		    options[0] != '\0' ? options : "",
6643914ddf8SEdward Tomasz Napierala 		    20,
6653914ddf8SEdward Tomasz Napierala 		    n->n_location != NULL ? n->n_location : n->n_map != NULL ? n->n_map : "",
6663914ddf8SEdward Tomasz Napierala 		    node_is_direct_map(n) ? "direct" : "indirect",
6673914ddf8SEdward Tomasz Napierala 		    indent == 0 ? "referenced" : "defined",
6683914ddf8SEdward Tomasz Napierala 		    n->n_config_file, n->n_config_line);
6693914ddf8SEdward Tomasz Napierala 	}
6703914ddf8SEdward Tomasz Napierala 
6713914ddf8SEdward Tomasz Napierala 	free(path);
6723914ddf8SEdward Tomasz Napierala 	free(options);
6733914ddf8SEdward Tomasz Napierala 
6743914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next)
6753914ddf8SEdward Tomasz Napierala 		node_print_indent(child, indent + 2);
6763914ddf8SEdward Tomasz Napierala }
6773914ddf8SEdward Tomasz Napierala 
6783914ddf8SEdward Tomasz Napierala void
6793914ddf8SEdward Tomasz Napierala node_print(const struct node *n)
6803914ddf8SEdward Tomasz Napierala {
6813914ddf8SEdward Tomasz Napierala 	const struct node *child;
6823914ddf8SEdward Tomasz Napierala 
6833914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &n->n_children, n_next)
6843914ddf8SEdward Tomasz Napierala 		node_print_indent(child, 0);
6853914ddf8SEdward Tomasz Napierala }
6863914ddf8SEdward Tomasz Napierala 
687cc4026a4SEdward Tomasz Napierala static struct node *
688cc4026a4SEdward Tomasz Napierala node_find_x(struct node *node, const char *path)
6893914ddf8SEdward Tomasz Napierala {
6903914ddf8SEdward Tomasz Napierala 	struct node *child, *found;
6913914ddf8SEdward Tomasz Napierala 	char *tmp;
692c37463b3SEdward Tomasz Napierala 	size_t tmplen;
6933914ddf8SEdward Tomasz Napierala 
6943914ddf8SEdward Tomasz Napierala 	//log_debugx("looking up %s in %s", path, node->n_key);
6953914ddf8SEdward Tomasz Napierala 
6963914ddf8SEdward Tomasz Napierala 	tmp = node_path(node);
697c37463b3SEdward Tomasz Napierala 	tmplen = strlen(tmp);
698c37463b3SEdward Tomasz Napierala 	if (strncmp(tmp, path, tmplen) != 0) {
699c37463b3SEdward Tomasz Napierala 		free(tmp);
700c37463b3SEdward Tomasz Napierala 		return (NULL);
701c37463b3SEdward Tomasz Napierala 	}
702c37463b3SEdward Tomasz Napierala 	if (path[tmplen] != '/' && path[tmplen] != '\0') {
703c37463b3SEdward Tomasz Napierala 		/*
704c37463b3SEdward Tomasz Napierala 		 * If we have two map entries like 'foo' and 'foobar', make
705c37463b3SEdward Tomasz Napierala 		 * sure the search for 'foobar' won't match 'foo' instead.
706c37463b3SEdward Tomasz Napierala 		 */
7073914ddf8SEdward Tomasz Napierala 		free(tmp);
7083914ddf8SEdward Tomasz Napierala 		return (NULL);
7093914ddf8SEdward Tomasz Napierala 	}
7103914ddf8SEdward Tomasz Napierala 	free(tmp);
7113914ddf8SEdward Tomasz Napierala 
7123914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &node->n_children, n_next) {
713cc4026a4SEdward Tomasz Napierala 		found = node_find_x(child, path);
7143914ddf8SEdward Tomasz Napierala 		if (found != NULL)
7153914ddf8SEdward Tomasz Napierala 			return (found);
7163914ddf8SEdward Tomasz Napierala 	}
7173914ddf8SEdward Tomasz Napierala 
7183914ddf8SEdward Tomasz Napierala 	return (node);
7193914ddf8SEdward Tomasz Napierala }
7203914ddf8SEdward Tomasz Napierala 
721cc4026a4SEdward Tomasz Napierala struct node *
722cc4026a4SEdward Tomasz Napierala node_find(struct node *root, const char *path)
723cc4026a4SEdward Tomasz Napierala {
724cc4026a4SEdward Tomasz Napierala 	struct node *node;
725cc4026a4SEdward Tomasz Napierala 
726cc4026a4SEdward Tomasz Napierala 	node = node_find_x(root, path);
727cc4026a4SEdward Tomasz Napierala 	if (node == root)
728cc4026a4SEdward Tomasz Napierala 		return (NULL);
729cc4026a4SEdward Tomasz Napierala 	return (node);
730cc4026a4SEdward Tomasz Napierala }
731cc4026a4SEdward Tomasz Napierala 
7323914ddf8SEdward Tomasz Napierala /*
7333914ddf8SEdward Tomasz Napierala  * Canonical form of a map entry looks like this:
7343914ddf8SEdward Tomasz Napierala  *
7353914ddf8SEdward Tomasz Napierala  * key [-options] [ [/mountpoint] [-options2] location ... ]
7363914ddf8SEdward Tomasz Napierala  *
7373914ddf8SEdward Tomasz Napierala  * Entries for executable maps are slightly different, as they
7383914ddf8SEdward Tomasz Napierala  * lack the 'key' field and are always single-line; the key field
7393914ddf8SEdward Tomasz Napierala  * for those maps is taken from 'executable_key' argument.
7403914ddf8SEdward Tomasz Napierala  *
7413914ddf8SEdward Tomasz Napierala  * We parse it in such a way that a map always has two levels - first
7423914ddf8SEdward Tomasz Napierala  * for key, and the second, for the mountpoint.
7433914ddf8SEdward Tomasz Napierala  */
7443914ddf8SEdward Tomasz Napierala static void
7453914ddf8SEdward Tomasz Napierala parse_map_yyin(struct node *parent, const char *map, const char *executable_key)
7463914ddf8SEdward Tomasz Napierala {
7473914ddf8SEdward Tomasz Napierala 	char *key = NULL, *options = NULL, *mountpoint = NULL,
7483914ddf8SEdward Tomasz Napierala 	    *options2 = NULL, *location = NULL;
7493914ddf8SEdward Tomasz Napierala 	int ret;
7503914ddf8SEdward Tomasz Napierala 	struct node *node;
7513914ddf8SEdward Tomasz Napierala 
7523914ddf8SEdward Tomasz Napierala 	lineno = 1;
7533914ddf8SEdward Tomasz Napierala 
7543914ddf8SEdward Tomasz Napierala 	if (executable_key != NULL)
7553914ddf8SEdward Tomasz Napierala 		key = checked_strdup(executable_key);
7563914ddf8SEdward Tomasz Napierala 
7573914ddf8SEdward Tomasz Napierala 	for (;;) {
7583914ddf8SEdward Tomasz Napierala 		ret = yylex();
7593914ddf8SEdward Tomasz Napierala 		if (ret == 0 || ret == NEWLINE) {
76030ae6e00SEdward Tomasz Napierala 			/*
76130ae6e00SEdward Tomasz Napierala 			 * In case of executable map, the key is always
76230ae6e00SEdward Tomasz Napierala 			 * non-NULL, even if the map is empty.  So, make sure
76330ae6e00SEdward Tomasz Napierala 			 * we don't fail empty maps here.
76430ae6e00SEdward Tomasz Napierala 			 */
76530ae6e00SEdward Tomasz Napierala 			if ((key != NULL && executable_key == NULL) ||
76630ae6e00SEdward Tomasz Napierala 			    options != NULL) {
7673914ddf8SEdward Tomasz Napierala 				log_errx(1, "truncated entry at %s, line %d",
7683914ddf8SEdward Tomasz Napierala 				    map, lineno);
7693914ddf8SEdward Tomasz Napierala 			}
7703914ddf8SEdward Tomasz Napierala 			if (ret == 0 || executable_key != NULL) {
7713914ddf8SEdward Tomasz Napierala 				/*
7723914ddf8SEdward Tomasz Napierala 				 * End of file.
7733914ddf8SEdward Tomasz Napierala 				 */
7743914ddf8SEdward Tomasz Napierala 				break;
7753914ddf8SEdward Tomasz Napierala 			} else {
7763914ddf8SEdward Tomasz Napierala 				key = options = NULL;
7773914ddf8SEdward Tomasz Napierala 				continue;
7783914ddf8SEdward Tomasz Napierala 			}
7793914ddf8SEdward Tomasz Napierala 		}
7803914ddf8SEdward Tomasz Napierala 		if (key == NULL) {
7813914ddf8SEdward Tomasz Napierala 			key = checked_strdup(yytext);
7823914ddf8SEdward Tomasz Napierala 			if (key[0] == '+') {
7833914ddf8SEdward Tomasz Napierala 				node_new(parent, key, NULL, NULL, map, lineno);
7843914ddf8SEdward Tomasz Napierala 				key = options = NULL;
7853914ddf8SEdward Tomasz Napierala 				continue;
7863914ddf8SEdward Tomasz Napierala 			}
7873914ddf8SEdward Tomasz Napierala 			continue;
7883914ddf8SEdward Tomasz Napierala 		} else if (yytext[0] == '-') {
7893914ddf8SEdward Tomasz Napierala 			if (options != NULL) {
7903914ddf8SEdward Tomasz Napierala 				log_errx(1, "duplicated options at %s, line %d",
7913914ddf8SEdward Tomasz Napierala 				    map, lineno);
7923914ddf8SEdward Tomasz Napierala 			}
7933914ddf8SEdward Tomasz Napierala 			/*
7943914ddf8SEdward Tomasz Napierala 			 * +1 to skip leading "-".
7953914ddf8SEdward Tomasz Napierala 			 */
7963914ddf8SEdward Tomasz Napierala 			options = checked_strdup(yytext + 1);
7973914ddf8SEdward Tomasz Napierala 			continue;
7983914ddf8SEdward Tomasz Napierala 		}
7993914ddf8SEdward Tomasz Napierala 
8003914ddf8SEdward Tomasz Napierala 		/*
8013914ddf8SEdward Tomasz Napierala 		 * We cannot properly handle a situation where the map key
8023914ddf8SEdward Tomasz Napierala 		 * is "/".  Ignore such entries.
8033914ddf8SEdward Tomasz Napierala 		 *
8043914ddf8SEdward Tomasz Napierala 		 * XXX: According to Piete Brooks, Linux automounter uses
8053914ddf8SEdward Tomasz Napierala 		 *	"/" as a wildcard character in LDAP maps.  Perhaps
8063914ddf8SEdward Tomasz Napierala 		 *	we should work around this braindamage by substituting
8073914ddf8SEdward Tomasz Napierala 		 *	"*" for "/"?
8083914ddf8SEdward Tomasz Napierala 		 */
8093914ddf8SEdward Tomasz Napierala 		if (strcmp(key, "/") == 0) {
8103914ddf8SEdward Tomasz Napierala 			log_warnx("nonsensical map key \"/\" at %s, line %d; "
8113914ddf8SEdward Tomasz Napierala 			    "ignoring map entry ", map, lineno);
8123914ddf8SEdward Tomasz Napierala 
8133914ddf8SEdward Tomasz Napierala 			/*
8143914ddf8SEdward Tomasz Napierala 			 * Skip the rest of the entry.
8153914ddf8SEdward Tomasz Napierala 			 */
8163914ddf8SEdward Tomasz Napierala 			do {
8173914ddf8SEdward Tomasz Napierala 				ret = yylex();
8183914ddf8SEdward Tomasz Napierala 			} while (ret != 0 && ret != NEWLINE);
8193914ddf8SEdward Tomasz Napierala 
8203914ddf8SEdward Tomasz Napierala 			key = options = NULL;
8213914ddf8SEdward Tomasz Napierala 			continue;
8223914ddf8SEdward Tomasz Napierala 		}
8233914ddf8SEdward Tomasz Napierala 
8243914ddf8SEdward Tomasz Napierala 		//log_debugx("adding map node, %s", key);
8253914ddf8SEdward Tomasz Napierala 		node = node_new(parent, key, options, NULL, map, lineno);
8263914ddf8SEdward Tomasz Napierala 		key = options = NULL;
8273914ddf8SEdward Tomasz Napierala 
8283914ddf8SEdward Tomasz Napierala 		for (;;) {
8293914ddf8SEdward Tomasz Napierala 			if (yytext[0] == '/') {
8303914ddf8SEdward Tomasz Napierala 				if (mountpoint != NULL) {
8313914ddf8SEdward Tomasz Napierala 					log_errx(1, "duplicated mountpoint "
8323914ddf8SEdward Tomasz Napierala 					    "in %s, line %d", map, lineno);
8333914ddf8SEdward Tomasz Napierala 				}
8343914ddf8SEdward Tomasz Napierala 				if (options2 != NULL || location != NULL) {
8353914ddf8SEdward Tomasz Napierala 					log_errx(1, "mountpoint out of order "
8363914ddf8SEdward Tomasz Napierala 					    "in %s, line %d", map, lineno);
8373914ddf8SEdward Tomasz Napierala 				}
8383914ddf8SEdward Tomasz Napierala 				mountpoint = checked_strdup(yytext);
8393914ddf8SEdward Tomasz Napierala 				goto again;
8403914ddf8SEdward Tomasz Napierala 			}
8413914ddf8SEdward Tomasz Napierala 
8423914ddf8SEdward Tomasz Napierala 			if (yytext[0] == '-') {
8433914ddf8SEdward Tomasz Napierala 				if (options2 != NULL) {
8443914ddf8SEdward Tomasz Napierala 					log_errx(1, "duplicated options "
8453914ddf8SEdward Tomasz Napierala 					    "in %s, line %d", map, lineno);
8463914ddf8SEdward Tomasz Napierala 				}
8473914ddf8SEdward Tomasz Napierala 				if (location != NULL) {
8483914ddf8SEdward Tomasz Napierala 					log_errx(1, "options out of order "
8493914ddf8SEdward Tomasz Napierala 					    "in %s, line %d", map, lineno);
8503914ddf8SEdward Tomasz Napierala 				}
8513914ddf8SEdward Tomasz Napierala 				options2 = checked_strdup(yytext + 1);
8523914ddf8SEdward Tomasz Napierala 				goto again;
8533914ddf8SEdward Tomasz Napierala 			}
8543914ddf8SEdward Tomasz Napierala 
8553914ddf8SEdward Tomasz Napierala 			if (location != NULL) {
8563914ddf8SEdward Tomasz Napierala 				log_errx(1, "too many arguments "
8573914ddf8SEdward Tomasz Napierala 				    "in %s, line %d", map, lineno);
8583914ddf8SEdward Tomasz Napierala 			}
8593914ddf8SEdward Tomasz Napierala 
8603914ddf8SEdward Tomasz Napierala 			/*
8613914ddf8SEdward Tomasz Napierala 			 * If location field starts with colon, e.g. ":/dev/cd0",
8623914ddf8SEdward Tomasz Napierala 			 * then strip it.
8633914ddf8SEdward Tomasz Napierala 			 */
8643914ddf8SEdward Tomasz Napierala 			if (yytext[0] == ':') {
8653914ddf8SEdward Tomasz Napierala 				location = checked_strdup(yytext + 1);
8663914ddf8SEdward Tomasz Napierala 				if (location[0] == '\0') {
8673914ddf8SEdward Tomasz Napierala 					log_errx(1, "empty location in %s, "
8683914ddf8SEdward Tomasz Napierala 					    "line %d", map, lineno);
8693914ddf8SEdward Tomasz Napierala 				}
8703914ddf8SEdward Tomasz Napierala 			} else {
8713914ddf8SEdward Tomasz Napierala 				location = checked_strdup(yytext);
8723914ddf8SEdward Tomasz Napierala 			}
8733914ddf8SEdward Tomasz Napierala 
8743914ddf8SEdward Tomasz Napierala 			if (mountpoint == NULL)
8753914ddf8SEdward Tomasz Napierala 				mountpoint = checked_strdup("/");
8763914ddf8SEdward Tomasz Napierala 			if (options2 == NULL)
8773914ddf8SEdward Tomasz Napierala 				options2 = checked_strdup("");
8783914ddf8SEdward Tomasz Napierala 
8793914ddf8SEdward Tomasz Napierala #if 0
8803914ddf8SEdward Tomasz Napierala 			log_debugx("adding map node, %s %s %s",
8813914ddf8SEdward Tomasz Napierala 			    mountpoint, options2, location);
8823914ddf8SEdward Tomasz Napierala #endif
8833914ddf8SEdward Tomasz Napierala 			node_new(node, mountpoint, options2, location,
8843914ddf8SEdward Tomasz Napierala 			    map, lineno);
8853914ddf8SEdward Tomasz Napierala 			mountpoint = options2 = location = NULL;
8863914ddf8SEdward Tomasz Napierala again:
8873914ddf8SEdward Tomasz Napierala 			ret = yylex();
8883914ddf8SEdward Tomasz Napierala 			if (ret == 0 || ret == NEWLINE) {
8893914ddf8SEdward Tomasz Napierala 				if (mountpoint != NULL || options2 != NULL ||
8903914ddf8SEdward Tomasz Napierala 				    location != NULL) {
8913914ddf8SEdward Tomasz Napierala 					log_errx(1, "truncated entry "
8923914ddf8SEdward Tomasz Napierala 					    "in %s, line %d", map, lineno);
8933914ddf8SEdward Tomasz Napierala 				}
8943914ddf8SEdward Tomasz Napierala 				break;
8953914ddf8SEdward Tomasz Napierala 			}
8963914ddf8SEdward Tomasz Napierala 		}
8973914ddf8SEdward Tomasz Napierala 	}
8983914ddf8SEdward Tomasz Napierala }
8993914ddf8SEdward Tomasz Napierala 
900f7ae8307SEdward Tomasz Napierala /*
9013dd80c05SEdward Tomasz Napierala  * Parse output of a special map called without argument.  It is a list
9023dd80c05SEdward Tomasz Napierala  * of keys, separated by newlines.  They can contain whitespace, so use
9033dd80c05SEdward Tomasz Napierala  * getline(3) instead of lexer used for maps.
904f7ae8307SEdward Tomasz Napierala  */
905f7ae8307SEdward Tomasz Napierala static void
906f7ae8307SEdward Tomasz Napierala parse_map_keys_yyin(struct node *parent, const char *map)
907f7ae8307SEdward Tomasz Napierala {
9083dd80c05SEdward Tomasz Napierala 	char *line = NULL, *key;
9093dd80c05SEdward Tomasz Napierala 	size_t linecap = 0;
9103dd80c05SEdward Tomasz Napierala 	ssize_t linelen;
911f7ae8307SEdward Tomasz Napierala 
912f7ae8307SEdward Tomasz Napierala 	lineno = 1;
913f7ae8307SEdward Tomasz Napierala 
914f7ae8307SEdward Tomasz Napierala 	for (;;) {
9153dd80c05SEdward Tomasz Napierala 		linelen = getline(&line, &linecap, yyin);
9163dd80c05SEdward Tomasz Napierala 		if (linelen < 0) {
917f7ae8307SEdward Tomasz Napierala 			/*
918f7ae8307SEdward Tomasz Napierala 			 * End of file.
919f7ae8307SEdward Tomasz Napierala 			 */
920f7ae8307SEdward Tomasz Napierala 			break;
921f7ae8307SEdward Tomasz Napierala 		}
9223dd80c05SEdward Tomasz Napierala 		if (linelen <= 1) {
9233dd80c05SEdward Tomasz Napierala 			/*
9243dd80c05SEdward Tomasz Napierala 			 * Empty line, consisting of just the newline.
9253dd80c05SEdward Tomasz Napierala 			 */
9263dd80c05SEdward Tomasz Napierala 			continue;
927f7ae8307SEdward Tomasz Napierala 		}
9283dd80c05SEdward Tomasz Napierala 
9293dd80c05SEdward Tomasz Napierala 		/*
9303dd80c05SEdward Tomasz Napierala 		 * "-1" to strip the trailing newline.
9313dd80c05SEdward Tomasz Napierala 		 */
9323dd80c05SEdward Tomasz Napierala 		key = strndup(line, linelen - 1);
9333dd80c05SEdward Tomasz Napierala 
9343dd80c05SEdward Tomasz Napierala 		log_debugx("adding key \"%s\"", key);
9353dd80c05SEdward Tomasz Napierala 		node_new(parent, key, NULL, NULL, map, lineno);
9363dd80c05SEdward Tomasz Napierala 		lineno++;
9373dd80c05SEdward Tomasz Napierala 	}
9383dd80c05SEdward Tomasz Napierala 	free(line);
939f7ae8307SEdward Tomasz Napierala }
940f7ae8307SEdward Tomasz Napierala 
9413914ddf8SEdward Tomasz Napierala static bool
9423914ddf8SEdward Tomasz Napierala file_is_executable(const char *path)
9433914ddf8SEdward Tomasz Napierala {
9443914ddf8SEdward Tomasz Napierala 	struct stat sb;
9453914ddf8SEdward Tomasz Napierala 	int error;
9463914ddf8SEdward Tomasz Napierala 
9473914ddf8SEdward Tomasz Napierala 	error = stat(path, &sb);
9483914ddf8SEdward Tomasz Napierala 	if (error != 0)
9493914ddf8SEdward Tomasz Napierala 		log_err(1, "cannot stat %s", path);
9503914ddf8SEdward Tomasz Napierala 	if ((sb.st_mode & S_IXUSR) || (sb.st_mode & S_IXGRP) ||
9513914ddf8SEdward Tomasz Napierala 	    (sb.st_mode & S_IXOTH))
9523914ddf8SEdward Tomasz Napierala 		return (true);
9533914ddf8SEdward Tomasz Napierala 	return (false);
9543914ddf8SEdward Tomasz Napierala }
9553914ddf8SEdward Tomasz Napierala 
9563914ddf8SEdward Tomasz Napierala /*
9573914ddf8SEdward Tomasz Napierala  * Parse a special map, e.g. "-hosts".
9583914ddf8SEdward Tomasz Napierala  */
9593914ddf8SEdward Tomasz Napierala static void
9603914ddf8SEdward Tomasz Napierala parse_special_map(struct node *parent, const char *map, const char *key)
9613914ddf8SEdward Tomasz Napierala {
9623914ddf8SEdward Tomasz Napierala 	char *path;
9633914ddf8SEdward Tomasz Napierala 	int error, ret;
9643914ddf8SEdward Tomasz Napierala 
9653914ddf8SEdward Tomasz Napierala 	assert(map[0] == '-');
9663914ddf8SEdward Tomasz Napierala 
9673914ddf8SEdward Tomasz Napierala 	/*
9683914ddf8SEdward Tomasz Napierala 	 * +1 to skip leading "-" in map name.
9693914ddf8SEdward Tomasz Napierala 	 */
9703914ddf8SEdward Tomasz Napierala 	ret = asprintf(&path, "%s/special_%s", AUTO_SPECIAL_PREFIX, map + 1);
9713914ddf8SEdward Tomasz Napierala 	if (ret < 0)
9723914ddf8SEdward Tomasz Napierala 		log_err(1, "asprintf");
9733914ddf8SEdward Tomasz Napierala 
9743914ddf8SEdward Tomasz Napierala 	yyin = auto_popen(path, key, NULL);
9753914ddf8SEdward Tomasz Napierala 	assert(yyin != NULL);
9763914ddf8SEdward Tomasz Napierala 
977f7ae8307SEdward Tomasz Napierala 	if (key == NULL) {
978f7ae8307SEdward Tomasz Napierala 		parse_map_keys_yyin(parent, map);
979f7ae8307SEdward Tomasz Napierala 	} else {
9803914ddf8SEdward Tomasz Napierala 		parse_map_yyin(parent, map, key);
981f7ae8307SEdward Tomasz Napierala 	}
9823914ddf8SEdward Tomasz Napierala 
9833914ddf8SEdward Tomasz Napierala 	error = auto_pclose(yyin);
9843914ddf8SEdward Tomasz Napierala 	yyin = NULL;
9853914ddf8SEdward Tomasz Napierala 	if (error != 0)
9863914ddf8SEdward Tomasz Napierala 		log_errx(1, "failed to handle special map \"%s\"", map);
9873914ddf8SEdward Tomasz Napierala 
9883914ddf8SEdward Tomasz Napierala 	node_expand_includes(parent, false);
9893914ddf8SEdward Tomasz Napierala 	node_expand_direct_maps(parent);
9903914ddf8SEdward Tomasz Napierala 
9913914ddf8SEdward Tomasz Napierala 	free(path);
9923914ddf8SEdward Tomasz Napierala }
9933914ddf8SEdward Tomasz Napierala 
9943914ddf8SEdward Tomasz Napierala /*
9953914ddf8SEdward Tomasz Napierala  * Retrieve and parse map from directory services, e.g. LDAP.
9963914ddf8SEdward Tomasz Napierala  * Note that it is different from executable maps, in that
9973914ddf8SEdward Tomasz Napierala  * the include script outputs the whole map to standard output
9983914ddf8SEdward Tomasz Napierala  * (as opposed to executable maps that only output a single
9993914ddf8SEdward Tomasz Napierala  * entry, without the key), and it takes the map name as an
10003914ddf8SEdward Tomasz Napierala  * argument, instead of key.
10013914ddf8SEdward Tomasz Napierala  */
10023914ddf8SEdward Tomasz Napierala static void
10033914ddf8SEdward Tomasz Napierala parse_included_map(struct node *parent, const char *map)
10043914ddf8SEdward Tomasz Napierala {
10053914ddf8SEdward Tomasz Napierala 	int error;
10063914ddf8SEdward Tomasz Napierala 
10073914ddf8SEdward Tomasz Napierala 	assert(map[0] != '-');
10083914ddf8SEdward Tomasz Napierala 	assert(map[0] != '/');
10093914ddf8SEdward Tomasz Napierala 
10103914ddf8SEdward Tomasz Napierala 	error = access(AUTO_INCLUDE_PATH, F_OK);
10113914ddf8SEdward Tomasz Napierala 	if (error != 0) {
10123914ddf8SEdward Tomasz Napierala 		log_errx(1, "directory services not configured;"
10133914ddf8SEdward Tomasz Napierala 		    " %s does not exist", AUTO_INCLUDE_PATH);
10143914ddf8SEdward Tomasz Napierala 	}
10153914ddf8SEdward Tomasz Napierala 
10163914ddf8SEdward Tomasz Napierala 	yyin = auto_popen(AUTO_INCLUDE_PATH, map, NULL);
10173914ddf8SEdward Tomasz Napierala 	assert(yyin != NULL);
10183914ddf8SEdward Tomasz Napierala 
10193914ddf8SEdward Tomasz Napierala 	parse_map_yyin(parent, map, NULL);
10203914ddf8SEdward Tomasz Napierala 
10213914ddf8SEdward Tomasz Napierala 	error = auto_pclose(yyin);
10223914ddf8SEdward Tomasz Napierala 	yyin = NULL;
10233914ddf8SEdward Tomasz Napierala 	if (error != 0)
10243914ddf8SEdward Tomasz Napierala 		log_errx(1, "failed to handle remote map \"%s\"", map);
10253914ddf8SEdward Tomasz Napierala 
10263914ddf8SEdward Tomasz Napierala 	node_expand_includes(parent, false);
10273914ddf8SEdward Tomasz Napierala 	node_expand_direct_maps(parent);
10283914ddf8SEdward Tomasz Napierala }
10293914ddf8SEdward Tomasz Napierala 
10303914ddf8SEdward Tomasz Napierala void
10314cdc52bdSEdward Tomasz Napierala parse_map(struct node *parent, const char *map, const char *key,
10324cdc52bdSEdward Tomasz Napierala     bool *wildcards)
10333914ddf8SEdward Tomasz Napierala {
10343914ddf8SEdward Tomasz Napierala 	char *path = NULL;
10353914ddf8SEdward Tomasz Napierala 	int error, ret;
10363914ddf8SEdward Tomasz Napierala 	bool executable;
10373914ddf8SEdward Tomasz Napierala 
10383914ddf8SEdward Tomasz Napierala 	assert(map != NULL);
10393914ddf8SEdward Tomasz Napierala 	assert(map[0] != '\0');
10403914ddf8SEdward Tomasz Napierala 
10413914ddf8SEdward Tomasz Napierala 	log_debugx("parsing map \"%s\"", map);
10423914ddf8SEdward Tomasz Napierala 
10434cdc52bdSEdward Tomasz Napierala 	if (wildcards != NULL)
10444cdc52bdSEdward Tomasz Napierala 		*wildcards = false;
10454cdc52bdSEdward Tomasz Napierala 
10464cdc52bdSEdward Tomasz Napierala 	if (map[0] == '-') {
10474cdc52bdSEdward Tomasz Napierala 		if (wildcards != NULL)
10484cdc52bdSEdward Tomasz Napierala 			*wildcards = true;
10493914ddf8SEdward Tomasz Napierala 		return (parse_special_map(parent, map, key));
10504cdc52bdSEdward Tomasz Napierala 	}
10513914ddf8SEdward Tomasz Napierala 
10523914ddf8SEdward Tomasz Napierala 	if (map[0] == '/') {
10533914ddf8SEdward Tomasz Napierala 		path = checked_strdup(map);
10543914ddf8SEdward Tomasz Napierala 	} else {
10553914ddf8SEdward Tomasz Napierala 		ret = asprintf(&path, "%s/%s", AUTO_MAP_PREFIX, map);
10563914ddf8SEdward Tomasz Napierala 		if (ret < 0)
10573914ddf8SEdward Tomasz Napierala 			log_err(1, "asprintf");
10583914ddf8SEdward Tomasz Napierala 		log_debugx("map \"%s\" maps to \"%s\"", map, path);
10593914ddf8SEdward Tomasz Napierala 
10603914ddf8SEdward Tomasz Napierala 		/*
10613914ddf8SEdward Tomasz Napierala 		 * See if the file exists.  If not, try to obtain the map
10623914ddf8SEdward Tomasz Napierala 		 * from directory services.
10633914ddf8SEdward Tomasz Napierala 		 */
10643914ddf8SEdward Tomasz Napierala 		error = access(path, F_OK);
10653914ddf8SEdward Tomasz Napierala 		if (error != 0) {
10663914ddf8SEdward Tomasz Napierala 			log_debugx("map file \"%s\" does not exist; falling "
10673914ddf8SEdward Tomasz Napierala 			    "back to directory services", path);
10683914ddf8SEdward Tomasz Napierala 			return (parse_included_map(parent, map));
10693914ddf8SEdward Tomasz Napierala 		}
10703914ddf8SEdward Tomasz Napierala 	}
10713914ddf8SEdward Tomasz Napierala 
10723914ddf8SEdward Tomasz Napierala 	executable = file_is_executable(path);
10733914ddf8SEdward Tomasz Napierala 
10743914ddf8SEdward Tomasz Napierala 	if (executable) {
10753914ddf8SEdward Tomasz Napierala 		log_debugx("map \"%s\" is executable", map);
10763914ddf8SEdward Tomasz Napierala 
10774cdc52bdSEdward Tomasz Napierala 		if (wildcards != NULL)
10784cdc52bdSEdward Tomasz Napierala 			*wildcards = true;
10794cdc52bdSEdward Tomasz Napierala 
10803914ddf8SEdward Tomasz Napierala 		if (key != NULL) {
10813914ddf8SEdward Tomasz Napierala 			yyin = auto_popen(path, key, NULL);
10823914ddf8SEdward Tomasz Napierala 		} else {
10833914ddf8SEdward Tomasz Napierala 			yyin = auto_popen(path, NULL);
10843914ddf8SEdward Tomasz Napierala 		}
10853914ddf8SEdward Tomasz Napierala 		assert(yyin != NULL);
10863914ddf8SEdward Tomasz Napierala 	} else {
10873914ddf8SEdward Tomasz Napierala 		yyin = fopen(path, "r");
10883914ddf8SEdward Tomasz Napierala 		if (yyin == NULL)
10893914ddf8SEdward Tomasz Napierala 			log_err(1, "unable to open \"%s\"", path);
10903914ddf8SEdward Tomasz Napierala 	}
10913914ddf8SEdward Tomasz Napierala 
10923914ddf8SEdward Tomasz Napierala 	free(path);
10933914ddf8SEdward Tomasz Napierala 	path = NULL;
10943914ddf8SEdward Tomasz Napierala 
10953914ddf8SEdward Tomasz Napierala 	parse_map_yyin(parent, map, executable ? key : NULL);
10963914ddf8SEdward Tomasz Napierala 
10973914ddf8SEdward Tomasz Napierala 	if (executable) {
10983914ddf8SEdward Tomasz Napierala 		error = auto_pclose(yyin);
10993914ddf8SEdward Tomasz Napierala 		yyin = NULL;
11003914ddf8SEdward Tomasz Napierala 		if (error != 0) {
11013914ddf8SEdward Tomasz Napierala 			log_errx(1, "failed to handle executable map \"%s\"",
11023914ddf8SEdward Tomasz Napierala 			    map);
11033914ddf8SEdward Tomasz Napierala 		}
11043914ddf8SEdward Tomasz Napierala 	} else {
11053914ddf8SEdward Tomasz Napierala 		fclose(yyin);
11063914ddf8SEdward Tomasz Napierala 	}
11073914ddf8SEdward Tomasz Napierala 	yyin = NULL;
11083914ddf8SEdward Tomasz Napierala 
11093914ddf8SEdward Tomasz Napierala 	log_debugx("done parsing map \"%s\"", map);
11103914ddf8SEdward Tomasz Napierala 
11113914ddf8SEdward Tomasz Napierala 	node_expand_includes(parent, false);
11123914ddf8SEdward Tomasz Napierala 	node_expand_direct_maps(parent);
11133914ddf8SEdward Tomasz Napierala }
11143914ddf8SEdward Tomasz Napierala 
11153914ddf8SEdward Tomasz Napierala static void
11163914ddf8SEdward Tomasz Napierala parse_master_yyin(struct node *root, const char *master)
11173914ddf8SEdward Tomasz Napierala {
11183914ddf8SEdward Tomasz Napierala 	char *mountpoint = NULL, *map = NULL, *options = NULL;
11193914ddf8SEdward Tomasz Napierala 	int ret;
11203914ddf8SEdward Tomasz Napierala 
11213914ddf8SEdward Tomasz Napierala 	/*
11223914ddf8SEdward Tomasz Napierala 	 * XXX: 1 gives incorrect values; wtf?
11233914ddf8SEdward Tomasz Napierala 	 */
11243914ddf8SEdward Tomasz Napierala 	lineno = 0;
11253914ddf8SEdward Tomasz Napierala 
11263914ddf8SEdward Tomasz Napierala 	for (;;) {
11273914ddf8SEdward Tomasz Napierala 		ret = yylex();
11283914ddf8SEdward Tomasz Napierala 		if (ret == 0 || ret == NEWLINE) {
11293914ddf8SEdward Tomasz Napierala 			if (mountpoint != NULL) {
11303914ddf8SEdward Tomasz Napierala 				//log_debugx("adding map for %s", mountpoint);
11313914ddf8SEdward Tomasz Napierala 				node_new_map(root, mountpoint, options, map,
11323914ddf8SEdward Tomasz Napierala 				    master, lineno);
11333914ddf8SEdward Tomasz Napierala 			}
11343914ddf8SEdward Tomasz Napierala 			if (ret == 0) {
11353914ddf8SEdward Tomasz Napierala 				break;
11363914ddf8SEdward Tomasz Napierala 			} else {
11373914ddf8SEdward Tomasz Napierala 				mountpoint = map = options = NULL;
11383914ddf8SEdward Tomasz Napierala 				continue;
11393914ddf8SEdward Tomasz Napierala 			}
11403914ddf8SEdward Tomasz Napierala 		}
11413914ddf8SEdward Tomasz Napierala 		if (mountpoint == NULL) {
11423914ddf8SEdward Tomasz Napierala 			mountpoint = checked_strdup(yytext);
11433914ddf8SEdward Tomasz Napierala 		} else if (map == NULL) {
11443914ddf8SEdward Tomasz Napierala 			map = checked_strdup(yytext);
11453914ddf8SEdward Tomasz Napierala 		} else if (options == NULL) {
11463914ddf8SEdward Tomasz Napierala 			/*
11473914ddf8SEdward Tomasz Napierala 			 * +1 to skip leading "-".
11483914ddf8SEdward Tomasz Napierala 			 */
11493914ddf8SEdward Tomasz Napierala 			options = checked_strdup(yytext + 1);
11503914ddf8SEdward Tomasz Napierala 		} else {
11513914ddf8SEdward Tomasz Napierala 			log_errx(1, "too many arguments at %s, line %d",
11523914ddf8SEdward Tomasz Napierala 			    master, lineno);
11533914ddf8SEdward Tomasz Napierala 		}
11543914ddf8SEdward Tomasz Napierala 	}
11553914ddf8SEdward Tomasz Napierala }
11563914ddf8SEdward Tomasz Napierala 
11573914ddf8SEdward Tomasz Napierala void
11583914ddf8SEdward Tomasz Napierala parse_master(struct node *root, const char *master)
11593914ddf8SEdward Tomasz Napierala {
11603914ddf8SEdward Tomasz Napierala 
11613914ddf8SEdward Tomasz Napierala 	log_debugx("parsing auto_master file at \"%s\"", master);
11623914ddf8SEdward Tomasz Napierala 
11633914ddf8SEdward Tomasz Napierala 	yyin = fopen(master, "r");
11643914ddf8SEdward Tomasz Napierala 	if (yyin == NULL)
11653914ddf8SEdward Tomasz Napierala 		err(1, "unable to open %s", master);
11663914ddf8SEdward Tomasz Napierala 
11673914ddf8SEdward Tomasz Napierala 	parse_master_yyin(root, master);
11683914ddf8SEdward Tomasz Napierala 
11693914ddf8SEdward Tomasz Napierala 	fclose(yyin);
11703914ddf8SEdward Tomasz Napierala 	yyin = NULL;
11713914ddf8SEdward Tomasz Napierala 
11723914ddf8SEdward Tomasz Napierala 	log_debugx("done parsing \"%s\"", master);
11733914ddf8SEdward Tomasz Napierala 
11743914ddf8SEdward Tomasz Napierala 	node_expand_includes(root, true);
11753914ddf8SEdward Tomasz Napierala 	node_expand_direct_maps(root);
11763914ddf8SEdward Tomasz Napierala }
11773914ddf8SEdward Tomasz Napierala 
11783914ddf8SEdward Tomasz Napierala /*
11793914ddf8SEdward Tomasz Napierala  * Two things daemon(3) does, that we actually also want to do
11803914ddf8SEdward Tomasz Napierala  * when running in foreground, is closing the stdin and chdiring
11813914ddf8SEdward Tomasz Napierala  * to "/".  This is what we do here.
11823914ddf8SEdward Tomasz Napierala  */
11833914ddf8SEdward Tomasz Napierala void
11843914ddf8SEdward Tomasz Napierala lesser_daemon(void)
11853914ddf8SEdward Tomasz Napierala {
11863914ddf8SEdward Tomasz Napierala 	int error, fd;
11873914ddf8SEdward Tomasz Napierala 
11883914ddf8SEdward Tomasz Napierala 	error = chdir("/");
11893914ddf8SEdward Tomasz Napierala 	if (error != 0)
11903914ddf8SEdward Tomasz Napierala 		log_warn("chdir");
11913914ddf8SEdward Tomasz Napierala 
11923914ddf8SEdward Tomasz Napierala 	fd = open(_PATH_DEVNULL, O_RDWR, 0);
11933914ddf8SEdward Tomasz Napierala 	if (fd < 0) {
11943914ddf8SEdward Tomasz Napierala 		log_warn("cannot open %s", _PATH_DEVNULL);
11953914ddf8SEdward Tomasz Napierala 		return;
11963914ddf8SEdward Tomasz Napierala 	}
11973914ddf8SEdward Tomasz Napierala 
11983914ddf8SEdward Tomasz Napierala 	error = dup2(fd, STDIN_FILENO);
11993914ddf8SEdward Tomasz Napierala 	if (error != 0)
12003914ddf8SEdward Tomasz Napierala 		log_warn("dup2");
12013914ddf8SEdward Tomasz Napierala 
12023914ddf8SEdward Tomasz Napierala 	error = close(fd);
12033914ddf8SEdward Tomasz Napierala 	if (error != 0) {
12043914ddf8SEdward Tomasz Napierala 		/* Bloody hell. */
12053914ddf8SEdward Tomasz Napierala 		log_warn("close");
12063914ddf8SEdward Tomasz Napierala 	}
12073914ddf8SEdward Tomasz Napierala }
12083914ddf8SEdward Tomasz Napierala 
12093914ddf8SEdward Tomasz Napierala int
12103914ddf8SEdward Tomasz Napierala main(int argc, char **argv)
12113914ddf8SEdward Tomasz Napierala {
12123914ddf8SEdward Tomasz Napierala 	char *cmdname;
12133914ddf8SEdward Tomasz Napierala 
12143914ddf8SEdward Tomasz Napierala 	if (argv[0] == NULL)
12153914ddf8SEdward Tomasz Napierala 		log_errx(1, "NULL command name");
12163914ddf8SEdward Tomasz Napierala 
12173914ddf8SEdward Tomasz Napierala 	cmdname = basename(argv[0]);
12183914ddf8SEdward Tomasz Napierala 
12193914ddf8SEdward Tomasz Napierala 	if (strcmp(cmdname, "automount") == 0)
12203914ddf8SEdward Tomasz Napierala 		return (main_automount(argc, argv));
12213914ddf8SEdward Tomasz Napierala 	else if (strcmp(cmdname, "automountd") == 0)
12223914ddf8SEdward Tomasz Napierala 		return (main_automountd(argc, argv));
12233914ddf8SEdward Tomasz Napierala 	else if (strcmp(cmdname, "autounmountd") == 0)
12243914ddf8SEdward Tomasz Napierala 		return (main_autounmountd(argc, argv));
12253914ddf8SEdward Tomasz Napierala 	else
12263914ddf8SEdward Tomasz Napierala 		log_errx(1, "binary name should be either \"automount\", "
12273914ddf8SEdward Tomasz Napierala 		    "\"automountd\", or \"autounmountd\"");
12283914ddf8SEdward Tomasz Napierala }
1229