xref: /freebsd-src/usr.sbin/autofs/automountd.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
13914ddf8SEdward Tomasz Napierala /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3abdd3945SEdward Tomasz Napierala  *
43914ddf8SEdward Tomasz Napierala  * Copyright (c) 2014 The FreeBSD Foundation
53914ddf8SEdward Tomasz Napierala  *
63914ddf8SEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
73914ddf8SEdward Tomasz Napierala  * from the FreeBSD Foundation.
83914ddf8SEdward Tomasz Napierala  *
93914ddf8SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
103914ddf8SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
113914ddf8SEdward Tomasz Napierala  * are met:
123914ddf8SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
133914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
143914ddf8SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
153914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
163914ddf8SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
173914ddf8SEdward Tomasz Napierala  *
183914ddf8SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
193914ddf8SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
203914ddf8SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
213914ddf8SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
223914ddf8SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
233914ddf8SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
243914ddf8SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
253914ddf8SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
263914ddf8SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
273914ddf8SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
283914ddf8SEdward Tomasz Napierala  * SUCH DAMAGE.
293914ddf8SEdward Tomasz Napierala  *
303914ddf8SEdward Tomasz Napierala  */
313914ddf8SEdward Tomasz Napierala 
323914ddf8SEdward Tomasz Napierala #include <sys/types.h>
333914ddf8SEdward Tomasz Napierala #include <sys/time.h>
343914ddf8SEdward Tomasz Napierala #include <sys/ioctl.h>
353914ddf8SEdward Tomasz Napierala #include <sys/param.h>
363914ddf8SEdward Tomasz Napierala #include <sys/linker.h>
373914ddf8SEdward Tomasz Napierala #include <sys/mount.h>
383914ddf8SEdward Tomasz Napierala #include <sys/socket.h>
393914ddf8SEdward Tomasz Napierala #include <sys/stat.h>
403914ddf8SEdward Tomasz Napierala #include <sys/wait.h>
413914ddf8SEdward Tomasz Napierala #include <sys/utsname.h>
423914ddf8SEdward Tomasz Napierala #include <assert.h>
433914ddf8SEdward Tomasz Napierala #include <ctype.h>
443914ddf8SEdward Tomasz Napierala #include <errno.h>
453914ddf8SEdward Tomasz Napierala #include <fcntl.h>
463914ddf8SEdward Tomasz Napierala #include <libgen.h>
47592d6e85SEdward Tomasz Napierala #include <libutil.h>
483914ddf8SEdward Tomasz Napierala #include <netdb.h>
493914ddf8SEdward Tomasz Napierala #include <signal.h>
503914ddf8SEdward Tomasz Napierala #include <stdbool.h>
513914ddf8SEdward Tomasz Napierala #include <stdint.h>
523914ddf8SEdward Tomasz Napierala #include <stdio.h>
533914ddf8SEdward Tomasz Napierala #include <stdlib.h>
543914ddf8SEdward Tomasz Napierala #include <string.h>
553914ddf8SEdward Tomasz Napierala #include <unistd.h>
563914ddf8SEdward Tomasz Napierala 
573914ddf8SEdward Tomasz Napierala #include "autofs_ioctl.h"
583914ddf8SEdward Tomasz Napierala 
593914ddf8SEdward Tomasz Napierala #include "common.h"
603914ddf8SEdward Tomasz Napierala 
613914ddf8SEdward Tomasz Napierala #define AUTOMOUNTD_PIDFILE	"/var/run/automountd.pid"
623914ddf8SEdward Tomasz Napierala 
633914ddf8SEdward Tomasz Napierala static int nchildren = 0;
643914ddf8SEdward Tomasz Napierala static int autofs_fd;
653914ddf8SEdward Tomasz Napierala static int request_id;
663914ddf8SEdward Tomasz Napierala 
673914ddf8SEdward Tomasz Napierala static void
done(int request_error,bool wildcards)684cdc52bdSEdward Tomasz Napierala done(int request_error, bool wildcards)
693914ddf8SEdward Tomasz Napierala {
703914ddf8SEdward Tomasz Napierala 	struct autofs_daemon_done add;
713914ddf8SEdward Tomasz Napierala 	int error;
723914ddf8SEdward Tomasz Napierala 
733914ddf8SEdward Tomasz Napierala 	memset(&add, 0, sizeof(add));
743914ddf8SEdward Tomasz Napierala 	add.add_id = request_id;
754cdc52bdSEdward Tomasz Napierala 	add.add_wildcards = wildcards;
763914ddf8SEdward Tomasz Napierala 	add.add_error = request_error;
773914ddf8SEdward Tomasz Napierala 
783914ddf8SEdward Tomasz Napierala 	log_debugx("completing request %d with error %d",
793914ddf8SEdward Tomasz Napierala 	    request_id, request_error);
803914ddf8SEdward Tomasz Napierala 
813914ddf8SEdward Tomasz Napierala 	error = ioctl(autofs_fd, AUTOFSDONE, &add);
82da0ba097SEdward Tomasz Napierala 	if (error != 0)
833914ddf8SEdward Tomasz Napierala 		log_warn("AUTOFSDONE");
843914ddf8SEdward Tomasz Napierala }
853914ddf8SEdward Tomasz Napierala 
863914ddf8SEdward Tomasz Napierala /*
873914ddf8SEdward Tomasz Napierala  * Remove "fstype=whatever" from optionsp and return the "whatever" part.
883914ddf8SEdward Tomasz Napierala  */
893914ddf8SEdward Tomasz Napierala static char *
pick_option(const char * option,char ** optionsp)903914ddf8SEdward Tomasz Napierala pick_option(const char *option, char **optionsp)
913914ddf8SEdward Tomasz Napierala {
923914ddf8SEdward Tomasz Napierala 	char *tofree, *pair, *newoptions;
933914ddf8SEdward Tomasz Napierala 	char *picked = NULL;
943914ddf8SEdward Tomasz Napierala 	bool first = true;
953914ddf8SEdward Tomasz Napierala 
963914ddf8SEdward Tomasz Napierala 	tofree = *optionsp;
973914ddf8SEdward Tomasz Napierala 
9827525377SEdward Tomasz Napierala 	newoptions = calloc(1, strlen(*optionsp) + 1);
993914ddf8SEdward Tomasz Napierala 	if (newoptions == NULL)
1003914ddf8SEdward Tomasz Napierala 		log_err(1, "calloc");
1013914ddf8SEdward Tomasz Napierala 
1023914ddf8SEdward Tomasz Napierala 	while ((pair = strsep(optionsp, ",")) != NULL) {
1033914ddf8SEdward Tomasz Napierala 		/*
1043914ddf8SEdward Tomasz Napierala 		 * XXX: strncasecmp(3) perhaps?
1053914ddf8SEdward Tomasz Napierala 		 */
1063914ddf8SEdward Tomasz Napierala 		if (strncmp(pair, option, strlen(option)) == 0) {
1073914ddf8SEdward Tomasz Napierala 			picked = checked_strdup(pair + strlen(option));
1083914ddf8SEdward Tomasz Napierala 		} else {
1093914ddf8SEdward Tomasz Napierala 			if (first == false)
1103914ddf8SEdward Tomasz Napierala 				strcat(newoptions, ",");
1113914ddf8SEdward Tomasz Napierala 			else
1123914ddf8SEdward Tomasz Napierala 				first = false;
1133914ddf8SEdward Tomasz Napierala 			strcat(newoptions, pair);
1143914ddf8SEdward Tomasz Napierala 		}
1153914ddf8SEdward Tomasz Napierala 	}
1163914ddf8SEdward Tomasz Napierala 
1173914ddf8SEdward Tomasz Napierala 	free(tofree);
1183914ddf8SEdward Tomasz Napierala 	*optionsp = newoptions;
1193914ddf8SEdward Tomasz Napierala 
1203914ddf8SEdward Tomasz Napierala 	return (picked);
1213914ddf8SEdward Tomasz Napierala }
1223914ddf8SEdward Tomasz Napierala 
1233914ddf8SEdward Tomasz Napierala static void
create_subtree(const struct node * node,bool incomplete)1243914ddf8SEdward Tomasz Napierala create_subtree(const struct node *node, bool incomplete)
1253914ddf8SEdward Tomasz Napierala {
1263914ddf8SEdward Tomasz Napierala 	const struct node *child;
1273914ddf8SEdward Tomasz Napierala 	char *path;
1283914ddf8SEdward Tomasz Napierala 	bool wildcard_found = false;
1293914ddf8SEdward Tomasz Napierala 
1303914ddf8SEdward Tomasz Napierala 	/*
1313914ddf8SEdward Tomasz Napierala 	 * Skip wildcard nodes.
1323914ddf8SEdward Tomasz Napierala 	 */
1333914ddf8SEdward Tomasz Napierala 	if (strcmp(node->n_key, "*") == 0)
1343914ddf8SEdward Tomasz Napierala 		return;
1353914ddf8SEdward Tomasz Napierala 
1363914ddf8SEdward Tomasz Napierala 	path = node_path(node);
1373914ddf8SEdward Tomasz Napierala 	log_debugx("creating subtree at %s", path);
1383914ddf8SEdward Tomasz Napierala 	create_directory(path);
1393914ddf8SEdward Tomasz Napierala 
1403914ddf8SEdward Tomasz Napierala 	if (incomplete) {
1413914ddf8SEdward Tomasz Napierala 		TAILQ_FOREACH(child, &node->n_children, n_next) {
1423914ddf8SEdward Tomasz Napierala 			if (strcmp(child->n_key, "*") == 0) {
1433914ddf8SEdward Tomasz Napierala 				wildcard_found = true;
1443914ddf8SEdward Tomasz Napierala 				break;
1453914ddf8SEdward Tomasz Napierala 			}
1463914ddf8SEdward Tomasz Napierala 		}
1473914ddf8SEdward Tomasz Napierala 
1483914ddf8SEdward Tomasz Napierala 		if (wildcard_found) {
1493914ddf8SEdward Tomasz Napierala 			log_debugx("node %s contains wildcard entry; "
1503914ddf8SEdward Tomasz Napierala 			    "not creating its subdirectories due to -d flag",
1513914ddf8SEdward Tomasz Napierala 			    path);
1523914ddf8SEdward Tomasz Napierala 			free(path);
1533914ddf8SEdward Tomasz Napierala 			return;
1543914ddf8SEdward Tomasz Napierala 		}
1553914ddf8SEdward Tomasz Napierala 	}
1563914ddf8SEdward Tomasz Napierala 
1573914ddf8SEdward Tomasz Napierala 	free(path);
1583914ddf8SEdward Tomasz Napierala 
1593914ddf8SEdward Tomasz Napierala 	TAILQ_FOREACH(child, &node->n_children, n_next)
1603914ddf8SEdward Tomasz Napierala 		create_subtree(child, incomplete);
1613914ddf8SEdward Tomasz Napierala }
1623914ddf8SEdward Tomasz Napierala 
1633914ddf8SEdward Tomasz Napierala static void
exit_callback(void)1643914ddf8SEdward Tomasz Napierala exit_callback(void)
1653914ddf8SEdward Tomasz Napierala {
1663914ddf8SEdward Tomasz Napierala 
1674cdc52bdSEdward Tomasz Napierala 	done(EIO, true);
1683914ddf8SEdward Tomasz Napierala }
1693914ddf8SEdward Tomasz Napierala 
1703914ddf8SEdward Tomasz Napierala static void
handle_request(const struct autofs_daemon_request * adr,char * cmdline_options,bool incomplete_hierarchy)1713914ddf8SEdward Tomasz Napierala handle_request(const struct autofs_daemon_request *adr, char *cmdline_options,
1723914ddf8SEdward Tomasz Napierala     bool incomplete_hierarchy)
1733914ddf8SEdward Tomasz Napierala {
1743914ddf8SEdward Tomasz Napierala 	const char *map;
1753914ddf8SEdward Tomasz Napierala 	struct node *root, *parent, *node;
1763914ddf8SEdward Tomasz Napierala 	FILE *f;
17752df29e6SEdward Tomasz Napierala 	char *key, *options, *fstype, *nobrowse, *retrycnt, *tmp;
1783914ddf8SEdward Tomasz Napierala 	int error;
1794cdc52bdSEdward Tomasz Napierala 	bool wildcards;
1803914ddf8SEdward Tomasz Napierala 
1813914ddf8SEdward Tomasz Napierala 	log_debugx("got request %d: from %s, path %s, prefix \"%s\", "
1823914ddf8SEdward Tomasz Napierala 	    "key \"%s\", options \"%s\"", adr->adr_id, adr->adr_from,
1833914ddf8SEdward Tomasz Napierala 	    adr->adr_path, adr->adr_prefix, adr->adr_key, adr->adr_options);
1843914ddf8SEdward Tomasz Napierala 
1853914ddf8SEdward Tomasz Napierala 	/*
1863914ddf8SEdward Tomasz Napierala 	 * Try to notify the kernel about any problems.
1873914ddf8SEdward Tomasz Napierala 	 */
1883914ddf8SEdward Tomasz Napierala 	request_id = adr->adr_id;
1893914ddf8SEdward Tomasz Napierala 	atexit(exit_callback);
1903914ddf8SEdward Tomasz Napierala 
1913914ddf8SEdward Tomasz Napierala 	if (strncmp(adr->adr_from, "map ", 4) != 0) {
1923914ddf8SEdward Tomasz Napierala 		log_errx(1, "invalid mountfrom \"%s\"; failing request",
1933914ddf8SEdward Tomasz Napierala 		    adr->adr_from);
1943914ddf8SEdward Tomasz Napierala 	}
1953914ddf8SEdward Tomasz Napierala 
1963914ddf8SEdward Tomasz Napierala 	map = adr->adr_from + 4; /* 4 for strlen("map "); */
1973914ddf8SEdward Tomasz Napierala 	root = node_new_root();
1983914ddf8SEdward Tomasz Napierala 	if (adr->adr_prefix[0] == '\0' || strcmp(adr->adr_prefix, "/") == 0) {
19952df29e6SEdward Tomasz Napierala 		/*
20052df29e6SEdward Tomasz Napierala 		 * Direct map.  autofs(4) doesn't have a way to determine
20152df29e6SEdward Tomasz Napierala 		 * correct map key, but since it's a direct map, we can just
20252df29e6SEdward Tomasz Napierala 		 * use adr_path instead.
20352df29e6SEdward Tomasz Napierala 		 */
2043914ddf8SEdward Tomasz Napierala 		parent = root;
20552df29e6SEdward Tomasz Napierala 		key = checked_strdup(adr->adr_path);
2063914ddf8SEdward Tomasz Napierala 	} else {
20752df29e6SEdward Tomasz Napierala 		/*
20852df29e6SEdward Tomasz Napierala 		 * Indirect map.
20952df29e6SEdward Tomasz Napierala 		 */
2103914ddf8SEdward Tomasz Napierala 		parent = node_new_map(root, checked_strdup(adr->adr_prefix),
21161d75c32SEdward Tomasz Napierala 		    NULL,  checked_strdup(map),
2123914ddf8SEdward Tomasz Napierala 		    checked_strdup("[kernel request]"), lineno);
21352df29e6SEdward Tomasz Napierala 
21452df29e6SEdward Tomasz Napierala 		if (adr->adr_key[0] == '\0')
21552df29e6SEdward Tomasz Napierala 			key = NULL;
21652df29e6SEdward Tomasz Napierala 		else
21752df29e6SEdward Tomasz Napierala 			key = checked_strdup(adr->adr_key);
2183914ddf8SEdward Tomasz Napierala 	}
2194cdc52bdSEdward Tomasz Napierala 
2204cdc52bdSEdward Tomasz Napierala 	/*
2214cdc52bdSEdward Tomasz Napierala 	 * "Wildcards" here actually means "make autofs(4) request
2224cdc52bdSEdward Tomasz Napierala 	 * automountd(8) action if the node being looked up does not
2234cdc52bdSEdward Tomasz Napierala 	 * exist, even though the parent is marked as cached".  This
2244cdc52bdSEdward Tomasz Napierala 	 * needs to be done for maps with wildcard entries, but also
2254cdc52bdSEdward Tomasz Napierala 	 * for special and executable maps.
2264cdc52bdSEdward Tomasz Napierala 	 */
22752df29e6SEdward Tomasz Napierala 	parse_map(parent, map, key, &wildcards);
2284cdc52bdSEdward Tomasz Napierala 	if (!wildcards)
2294cdc52bdSEdward Tomasz Napierala 		wildcards = node_has_wildcards(parent);
2304cdc52bdSEdward Tomasz Napierala 	if (wildcards)
2314cdc52bdSEdward Tomasz Napierala 		log_debugx("map may contain wildcard entries");
2324cdc52bdSEdward Tomasz Napierala 	else
2334cdc52bdSEdward Tomasz Napierala 		log_debugx("map does not contain wildcard entries");
2344cdc52bdSEdward Tomasz Napierala 
23552df29e6SEdward Tomasz Napierala 	if (key != NULL)
23652df29e6SEdward Tomasz Napierala 		node_expand_wildcard(root, key);
2374cdc52bdSEdward Tomasz Napierala 
2383914ddf8SEdward Tomasz Napierala 	node = node_find(root, adr->adr_path);
2393914ddf8SEdward Tomasz Napierala 	if (node == NULL) {
2403914ddf8SEdward Tomasz Napierala 		log_errx(1, "map %s does not contain key for \"%s\"; "
2413914ddf8SEdward Tomasz Napierala 		    "failing mount", map, adr->adr_path);
2423914ddf8SEdward Tomasz Napierala 	}
2433914ddf8SEdward Tomasz Napierala 
244f7ae8307SEdward Tomasz Napierala 	options = node_options(node);
2455c16a48aSEdward Tomasz Napierala 
2465c16a48aSEdward Tomasz Napierala 	/*
2475c16a48aSEdward Tomasz Napierala 	 * Append options from auto_master.
2485c16a48aSEdward Tomasz Napierala 	 */
2495c16a48aSEdward Tomasz Napierala 	options = concat(options, ',', adr->adr_options);
250f7ae8307SEdward Tomasz Napierala 
251f7ae8307SEdward Tomasz Napierala 	/*
252f7ae8307SEdward Tomasz Napierala 	 * Prepend options passed via automountd(8) command line.
253f7ae8307SEdward Tomasz Napierala 	 */
2546d8e60c3SEdward Tomasz Napierala 	options = concat(cmdline_options, ',', options);
25561d75c32SEdward Tomasz Napierala 
25661d75c32SEdward Tomasz Napierala 	if (node->n_location == NULL) {
25761d75c32SEdward Tomasz Napierala 		log_debugx("found node defined at %s:%d; not a mountpoint",
25861d75c32SEdward Tomasz Napierala 		    node->n_config_file, node->n_config_line);
259f7ae8307SEdward Tomasz Napierala 
260f7ae8307SEdward Tomasz Napierala 		nobrowse = pick_option("nobrowse", &options);
26152df29e6SEdward Tomasz Napierala 		if (nobrowse != NULL && key == NULL) {
262f7ae8307SEdward Tomasz Napierala 			log_debugx("skipping map %s due to \"nobrowse\" "
263f7ae8307SEdward Tomasz Napierala 			    "option; exiting", map);
2644cdc52bdSEdward Tomasz Napierala 			done(0, true);
265f7ae8307SEdward Tomasz Napierala 
266f7ae8307SEdward Tomasz Napierala 			/*
267f7ae8307SEdward Tomasz Napierala 			 * Exit without calling exit_callback().
268f7ae8307SEdward Tomasz Napierala 			 */
269f7ae8307SEdward Tomasz Napierala 			quick_exit(0);
270f7ae8307SEdward Tomasz Napierala 		}
271f7ae8307SEdward Tomasz Napierala 
2723914ddf8SEdward Tomasz Napierala 		/*
2733914ddf8SEdward Tomasz Napierala 		 * Not a mountpoint; create directories in the autofs mount
2743914ddf8SEdward Tomasz Napierala 		 * and complete the request.
2753914ddf8SEdward Tomasz Napierala 		 */
2763914ddf8SEdward Tomasz Napierala 		create_subtree(node, incomplete_hierarchy);
2773914ddf8SEdward Tomasz Napierala 
27852df29e6SEdward Tomasz Napierala 		if (incomplete_hierarchy && key != NULL) {
2793914ddf8SEdward Tomasz Napierala 			/*
2803914ddf8SEdward Tomasz Napierala 			 * We still need to create the single subdirectory
2813914ddf8SEdward Tomasz Napierala 			 * user is trying to access.
2823914ddf8SEdward Tomasz Napierala 			 */
28352df29e6SEdward Tomasz Napierala 			tmp = concat(adr->adr_path, '/', key);
2843914ddf8SEdward Tomasz Napierala 			node = node_find(root, tmp);
2853914ddf8SEdward Tomasz Napierala 			if (node != NULL)
2863914ddf8SEdward Tomasz Napierala 				create_subtree(node, false);
2873914ddf8SEdward Tomasz Napierala 		}
2883914ddf8SEdward Tomasz Napierala 
2893914ddf8SEdward Tomasz Napierala 		log_debugx("nothing to mount; exiting");
2904cdc52bdSEdward Tomasz Napierala 		done(0, wildcards);
2913914ddf8SEdward Tomasz Napierala 
2923914ddf8SEdward Tomasz Napierala 		/*
2933914ddf8SEdward Tomasz Napierala 		 * Exit without calling exit_callback().
2943914ddf8SEdward Tomasz Napierala 		 */
2953914ddf8SEdward Tomasz Napierala 		quick_exit(0);
2963914ddf8SEdward Tomasz Napierala 	}
2973914ddf8SEdward Tomasz Napierala 
2983914ddf8SEdward Tomasz Napierala 	log_debugx("found node defined at %s:%d; it is a mountpoint",
2993914ddf8SEdward Tomasz Napierala 	    node->n_config_file, node->n_config_line);
3003914ddf8SEdward Tomasz Napierala 
30152df29e6SEdward Tomasz Napierala 	if (key != NULL)
30252df29e6SEdward Tomasz Napierala 		node_expand_ampersand(node, key);
3033914ddf8SEdward Tomasz Napierala 	error = node_expand_defined(node);
3043914ddf8SEdward Tomasz Napierala 	if (error != 0) {
3053914ddf8SEdward Tomasz Napierala 		log_errx(1, "variable expansion failed for %s; "
3063914ddf8SEdward Tomasz Napierala 		    "failing mount", adr->adr_path);
3073914ddf8SEdward Tomasz Napierala 	}
3083914ddf8SEdward Tomasz Napierala 
3093914ddf8SEdward Tomasz Napierala 	/*
3103914ddf8SEdward Tomasz Napierala 	 * Append "automounted".
3113914ddf8SEdward Tomasz Napierala 	 */
3126d8e60c3SEdward Tomasz Napierala 	options = concat(options, ',', "automounted");
3133914ddf8SEdward Tomasz Napierala 
3143914ddf8SEdward Tomasz Napierala 	/*
315f7ae8307SEdward Tomasz Napierala 	 * Remove "nobrowse", mount(8) doesn't understand it.
316f7ae8307SEdward Tomasz Napierala 	 */
317f7ae8307SEdward Tomasz Napierala 	pick_option("nobrowse", &options);
318f7ae8307SEdward Tomasz Napierala 
319f7ae8307SEdward Tomasz Napierala 	/*
3203914ddf8SEdward Tomasz Napierala 	 * Figure out fstype.
3213914ddf8SEdward Tomasz Napierala 	 */
3223914ddf8SEdward Tomasz Napierala 	fstype = pick_option("fstype=", &options);
3233914ddf8SEdward Tomasz Napierala 	if (fstype == NULL) {
3243914ddf8SEdward Tomasz Napierala 		log_debugx("fstype not specified in options; "
3253914ddf8SEdward Tomasz Napierala 		    "defaulting to \"nfs\"");
3263914ddf8SEdward Tomasz Napierala 		fstype = checked_strdup("nfs");
3273914ddf8SEdward Tomasz Napierala 	}
3283914ddf8SEdward Tomasz Napierala 
3293914ddf8SEdward Tomasz Napierala 	if (strcmp(fstype, "nfs") == 0) {
3303914ddf8SEdward Tomasz Napierala 		/*
3313914ddf8SEdward Tomasz Napierala 		 * The mount_nfs(8) command defaults to retry undefinitely.
3323914ddf8SEdward Tomasz Napierala 		 * We do not want that behaviour, because it leaves mount_nfs(8)
3333914ddf8SEdward Tomasz Napierala 		 * instances and automountd(8) children hanging forever.
3343914ddf8SEdward Tomasz Napierala 		 * Disable retries unless the option was passed explicitly.
3353914ddf8SEdward Tomasz Napierala 		 */
3363914ddf8SEdward Tomasz Napierala 		retrycnt = pick_option("retrycnt=", &options);
3373914ddf8SEdward Tomasz Napierala 		if (retrycnt == NULL) {
3383914ddf8SEdward Tomasz Napierala 			log_debugx("retrycnt not specified in options; "
3393914ddf8SEdward Tomasz Napierala 			    "defaulting to 1");
3406d8e60c3SEdward Tomasz Napierala 			options = concat(options, ',', "retrycnt=1");
3413914ddf8SEdward Tomasz Napierala 		} else {
3426d8e60c3SEdward Tomasz Napierala 			options = concat(options, ',',
3436d8e60c3SEdward Tomasz Napierala 			    concat("retrycnt", '=', retrycnt));
3443914ddf8SEdward Tomasz Napierala 		}
3453914ddf8SEdward Tomasz Napierala 	}
3463914ddf8SEdward Tomasz Napierala 
3473914ddf8SEdward Tomasz Napierala 	f = auto_popen("mount", "-t", fstype, "-o", options,
3483914ddf8SEdward Tomasz Napierala 	    node->n_location, adr->adr_path, NULL);
3493914ddf8SEdward Tomasz Napierala 	assert(f != NULL);
3503914ddf8SEdward Tomasz Napierala 	error = auto_pclose(f);
3513914ddf8SEdward Tomasz Napierala 	if (error != 0)
3523914ddf8SEdward Tomasz Napierala 		log_errx(1, "mount failed");
3533914ddf8SEdward Tomasz Napierala 
3543914ddf8SEdward Tomasz Napierala 	log_debugx("mount done; exiting");
3554cdc52bdSEdward Tomasz Napierala 	done(0, wildcards);
3563914ddf8SEdward Tomasz Napierala 
3573914ddf8SEdward Tomasz Napierala 	/*
3583914ddf8SEdward Tomasz Napierala 	 * Exit without calling exit_callback().
3593914ddf8SEdward Tomasz Napierala 	 */
3603914ddf8SEdward Tomasz Napierala 	quick_exit(0);
3613914ddf8SEdward Tomasz Napierala }
3623914ddf8SEdward Tomasz Napierala 
36375afaef2SEdward Tomasz Napierala static void
sigchld_handler(int dummy __unused)36475afaef2SEdward Tomasz Napierala sigchld_handler(int dummy __unused)
36575afaef2SEdward Tomasz Napierala {
36675afaef2SEdward Tomasz Napierala 
36775afaef2SEdward Tomasz Napierala 	/*
36875afaef2SEdward Tomasz Napierala 	 * The only purpose of this handler is to make SIGCHLD
36975afaef2SEdward Tomasz Napierala 	 * interrupt the AUTOFSREQUEST ioctl(2), so we can call
37075afaef2SEdward Tomasz Napierala 	 * wait_for_children().
37175afaef2SEdward Tomasz Napierala 	 */
37275afaef2SEdward Tomasz Napierala }
37375afaef2SEdward Tomasz Napierala 
37475afaef2SEdward Tomasz Napierala static void
register_sigchld(void)37575afaef2SEdward Tomasz Napierala register_sigchld(void)
37675afaef2SEdward Tomasz Napierala {
37775afaef2SEdward Tomasz Napierala 	struct sigaction sa;
37875afaef2SEdward Tomasz Napierala 	int error;
37975afaef2SEdward Tomasz Napierala 
38075afaef2SEdward Tomasz Napierala 	bzero(&sa, sizeof(sa));
38175afaef2SEdward Tomasz Napierala 	sa.sa_handler = sigchld_handler;
38275afaef2SEdward Tomasz Napierala 	sigfillset(&sa.sa_mask);
38375afaef2SEdward Tomasz Napierala 	error = sigaction(SIGCHLD, &sa, NULL);
38475afaef2SEdward Tomasz Napierala 	if (error != 0)
38575afaef2SEdward Tomasz Napierala 		log_err(1, "sigaction");
38675afaef2SEdward Tomasz Napierala 
38775afaef2SEdward Tomasz Napierala }
38875afaef2SEdward Tomasz Napierala 
38975afaef2SEdward Tomasz Napierala 
3903914ddf8SEdward Tomasz Napierala static int
wait_for_children(bool block)3913914ddf8SEdward Tomasz Napierala wait_for_children(bool block)
3923914ddf8SEdward Tomasz Napierala {
3933914ddf8SEdward Tomasz Napierala 	pid_t pid;
3943914ddf8SEdward Tomasz Napierala 	int status;
3953914ddf8SEdward Tomasz Napierala 	int num = 0;
3963914ddf8SEdward Tomasz Napierala 
3973914ddf8SEdward Tomasz Napierala 	for (;;) {
3983914ddf8SEdward Tomasz Napierala 		/*
3993914ddf8SEdward Tomasz Napierala 		 * If "block" is true, wait for at least one process.
4003914ddf8SEdward Tomasz Napierala 		 */
4013914ddf8SEdward Tomasz Napierala 		if (block && num == 0)
4023914ddf8SEdward Tomasz Napierala 			pid = wait4(-1, &status, 0, NULL);
4033914ddf8SEdward Tomasz Napierala 		else
4043914ddf8SEdward Tomasz Napierala 			pid = wait4(-1, &status, WNOHANG, NULL);
4053914ddf8SEdward Tomasz Napierala 		if (pid <= 0)
4063914ddf8SEdward Tomasz Napierala 			break;
4073914ddf8SEdward Tomasz Napierala 		if (WIFSIGNALED(status)) {
4083914ddf8SEdward Tomasz Napierala 			log_warnx("child process %d terminated with signal %d",
4093914ddf8SEdward Tomasz Napierala 			    pid, WTERMSIG(status));
4103914ddf8SEdward Tomasz Napierala 		} else if (WEXITSTATUS(status) != 0) {
41145c3925dSEdward Tomasz Napierala 			log_debugx("child process %d terminated with exit status %d",
4123914ddf8SEdward Tomasz Napierala 			    pid, WEXITSTATUS(status));
4133914ddf8SEdward Tomasz Napierala 		} else {
4143914ddf8SEdward Tomasz Napierala 			log_debugx("child process %d terminated gracefully", pid);
4153914ddf8SEdward Tomasz Napierala 		}
4163914ddf8SEdward Tomasz Napierala 		num++;
4173914ddf8SEdward Tomasz Napierala 	}
4183914ddf8SEdward Tomasz Napierala 
4193914ddf8SEdward Tomasz Napierala 	return (num);
4203914ddf8SEdward Tomasz Napierala }
4213914ddf8SEdward Tomasz Napierala 
4223914ddf8SEdward Tomasz Napierala static void
usage_automountd(void)4233914ddf8SEdward Tomasz Napierala usage_automountd(void)
4243914ddf8SEdward Tomasz Napierala {
4253914ddf8SEdward Tomasz Napierala 
4263914ddf8SEdward Tomasz Napierala 	fprintf(stderr, "usage: automountd [-D name=value][-m maxproc]"
4273914ddf8SEdward Tomasz Napierala 	    "[-o opts][-Tidv]\n");
4283914ddf8SEdward Tomasz Napierala 	exit(1);
4293914ddf8SEdward Tomasz Napierala }
4303914ddf8SEdward Tomasz Napierala 
4313914ddf8SEdward Tomasz Napierala int
main_automountd(int argc,char ** argv)4323914ddf8SEdward Tomasz Napierala main_automountd(int argc, char **argv)
4333914ddf8SEdward Tomasz Napierala {
4343914ddf8SEdward Tomasz Napierala 	struct pidfh *pidfh;
4353914ddf8SEdward Tomasz Napierala 	pid_t pid, otherpid;
4363914ddf8SEdward Tomasz Napierala 	const char *pidfile_path = AUTOMOUNTD_PIDFILE;
4373914ddf8SEdward Tomasz Napierala 	char *options = NULL;
4383914ddf8SEdward Tomasz Napierala 	struct autofs_daemon_request request;
4393914ddf8SEdward Tomasz Napierala 	int ch, debug = 0, error, maxproc = 30, retval, saved_errno;
4403914ddf8SEdward Tomasz Napierala 	bool dont_daemonize = false, incomplete_hierarchy = false;
4413914ddf8SEdward Tomasz Napierala 
4423914ddf8SEdward Tomasz Napierala 	defined_init();
4433914ddf8SEdward Tomasz Napierala 
4443914ddf8SEdward Tomasz Napierala 	while ((ch = getopt(argc, argv, "D:Tdim:o:v")) != -1) {
4453914ddf8SEdward Tomasz Napierala 		switch (ch) {
4463914ddf8SEdward Tomasz Napierala 		case 'D':
4473914ddf8SEdward Tomasz Napierala 			defined_parse_and_add(optarg);
4483914ddf8SEdward Tomasz Napierala 			break;
4493914ddf8SEdward Tomasz Napierala 		case 'T':
4503914ddf8SEdward Tomasz Napierala 			/*
4513914ddf8SEdward Tomasz Napierala 			 * For compatibility with other implementations,
4523914ddf8SEdward Tomasz Napierala 			 * such as OS X.
4533914ddf8SEdward Tomasz Napierala 			 */
4543914ddf8SEdward Tomasz Napierala 			debug++;
4553914ddf8SEdward Tomasz Napierala 			break;
4563914ddf8SEdward Tomasz Napierala 		case 'd':
4573914ddf8SEdward Tomasz Napierala 			dont_daemonize = true;
4583914ddf8SEdward Tomasz Napierala 			debug++;
4593914ddf8SEdward Tomasz Napierala 			break;
4603914ddf8SEdward Tomasz Napierala 		case 'i':
4613914ddf8SEdward Tomasz Napierala 			incomplete_hierarchy = true;
4623914ddf8SEdward Tomasz Napierala 			break;
4633914ddf8SEdward Tomasz Napierala 		case 'm':
4643914ddf8SEdward Tomasz Napierala 			maxproc = atoi(optarg);
4653914ddf8SEdward Tomasz Napierala 			break;
4663914ddf8SEdward Tomasz Napierala 		case 'o':
4676d8e60c3SEdward Tomasz Napierala 			options = concat(options, ',', optarg);
4683914ddf8SEdward Tomasz Napierala 			break;
4693914ddf8SEdward Tomasz Napierala 		case 'v':
4703914ddf8SEdward Tomasz Napierala 			debug++;
4713914ddf8SEdward Tomasz Napierala 			break;
4723914ddf8SEdward Tomasz Napierala 		case '?':
4733914ddf8SEdward Tomasz Napierala 		default:
4743914ddf8SEdward Tomasz Napierala 			usage_automountd();
4753914ddf8SEdward Tomasz Napierala 		}
4763914ddf8SEdward Tomasz Napierala 	}
4773914ddf8SEdward Tomasz Napierala 	argc -= optind;
4783914ddf8SEdward Tomasz Napierala 	if (argc != 0)
4793914ddf8SEdward Tomasz Napierala 		usage_automountd();
4803914ddf8SEdward Tomasz Napierala 
4813914ddf8SEdward Tomasz Napierala 	log_init(debug);
4823914ddf8SEdward Tomasz Napierala 
4833914ddf8SEdward Tomasz Napierala 	pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
4843914ddf8SEdward Tomasz Napierala 	if (pidfh == NULL) {
4853914ddf8SEdward Tomasz Napierala 		if (errno == EEXIST) {
4863914ddf8SEdward Tomasz Napierala 			log_errx(1, "daemon already running, pid: %jd.",
4873914ddf8SEdward Tomasz Napierala 			    (intmax_t)otherpid);
4883914ddf8SEdward Tomasz Napierala 		}
4893914ddf8SEdward Tomasz Napierala 		log_err(1, "cannot open or create pidfile \"%s\"",
4903914ddf8SEdward Tomasz Napierala 		    pidfile_path);
4913914ddf8SEdward Tomasz Napierala 	}
4923914ddf8SEdward Tomasz Napierala 
4933914ddf8SEdward Tomasz Napierala 	autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
4943914ddf8SEdward Tomasz Napierala 	if (autofs_fd < 0 && errno == ENOENT) {
4953914ddf8SEdward Tomasz Napierala 		saved_errno = errno;
4963914ddf8SEdward Tomasz Napierala 		retval = kldload("autofs");
4973914ddf8SEdward Tomasz Napierala 		if (retval != -1)
4983914ddf8SEdward Tomasz Napierala 			autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
4993914ddf8SEdward Tomasz Napierala 		else
5003914ddf8SEdward Tomasz Napierala 			errno = saved_errno;
5013914ddf8SEdward Tomasz Napierala 	}
5023914ddf8SEdward Tomasz Napierala 	if (autofs_fd < 0)
5033914ddf8SEdward Tomasz Napierala 		log_err(1, "failed to open %s", AUTOFS_PATH);
5043914ddf8SEdward Tomasz Napierala 
5053914ddf8SEdward Tomasz Napierala 	if (dont_daemonize == false) {
5063914ddf8SEdward Tomasz Napierala 		if (daemon(0, 0) == -1) {
5073914ddf8SEdward Tomasz Napierala 			log_warn("cannot daemonize");
5083914ddf8SEdward Tomasz Napierala 			pidfile_remove(pidfh);
5093914ddf8SEdward Tomasz Napierala 			exit(1);
5103914ddf8SEdward Tomasz Napierala 		}
5113914ddf8SEdward Tomasz Napierala 	} else {
5123914ddf8SEdward Tomasz Napierala 		lesser_daemon();
5133914ddf8SEdward Tomasz Napierala 	}
5143914ddf8SEdward Tomasz Napierala 
5153914ddf8SEdward Tomasz Napierala 	pidfile_write(pidfh);
5163914ddf8SEdward Tomasz Napierala 
51775afaef2SEdward Tomasz Napierala 	register_sigchld();
51875afaef2SEdward Tomasz Napierala 
5193914ddf8SEdward Tomasz Napierala 	for (;;) {
5203914ddf8SEdward Tomasz Napierala 		log_debugx("waiting for request from the kernel");
5213914ddf8SEdward Tomasz Napierala 
5223914ddf8SEdward Tomasz Napierala 		memset(&request, 0, sizeof(request));
5233914ddf8SEdward Tomasz Napierala 		error = ioctl(autofs_fd, AUTOFSREQUEST, &request);
5243914ddf8SEdward Tomasz Napierala 		if (error != 0) {
5253914ddf8SEdward Tomasz Napierala 			if (errno == EINTR) {
5263914ddf8SEdward Tomasz Napierala 				nchildren -= wait_for_children(false);
5273914ddf8SEdward Tomasz Napierala 				assert(nchildren >= 0);
5283914ddf8SEdward Tomasz Napierala 				continue;
5293914ddf8SEdward Tomasz Napierala 			}
5303914ddf8SEdward Tomasz Napierala 
5313914ddf8SEdward Tomasz Napierala 			log_err(1, "AUTOFSREQUEST");
5323914ddf8SEdward Tomasz Napierala 		}
5333914ddf8SEdward Tomasz Napierala 
5343914ddf8SEdward Tomasz Napierala 		if (dont_daemonize) {
5353914ddf8SEdward Tomasz Napierala 			log_debugx("not forking due to -d flag; "
5363914ddf8SEdward Tomasz Napierala 			    "will exit after servicing a single request");
5373914ddf8SEdward Tomasz Napierala 		} else {
5383914ddf8SEdward Tomasz Napierala 			nchildren -= wait_for_children(false);
5393914ddf8SEdward Tomasz Napierala 			assert(nchildren >= 0);
5403914ddf8SEdward Tomasz Napierala 
5413914ddf8SEdward Tomasz Napierala 			while (maxproc > 0 && nchildren >= maxproc) {
5423914ddf8SEdward Tomasz Napierala 				log_debugx("maxproc limit of %d child processes hit; "
5433914ddf8SEdward Tomasz Napierala 				    "waiting for child process to exit", maxproc);
5443914ddf8SEdward Tomasz Napierala 				nchildren -= wait_for_children(true);
5453914ddf8SEdward Tomasz Napierala 				assert(nchildren >= 0);
5463914ddf8SEdward Tomasz Napierala 			}
5473914ddf8SEdward Tomasz Napierala 			log_debugx("got request; forking child process #%d",
5483914ddf8SEdward Tomasz Napierala 			    nchildren);
5493914ddf8SEdward Tomasz Napierala 			nchildren++;
5503914ddf8SEdward Tomasz Napierala 
5513914ddf8SEdward Tomasz Napierala 			pid = fork();
5523914ddf8SEdward Tomasz Napierala 			if (pid < 0)
5533914ddf8SEdward Tomasz Napierala 				log_err(1, "fork");
5543914ddf8SEdward Tomasz Napierala 			if (pid > 0)
5553914ddf8SEdward Tomasz Napierala 				continue;
5563914ddf8SEdward Tomasz Napierala 		}
5573914ddf8SEdward Tomasz Napierala 
5583914ddf8SEdward Tomasz Napierala 		pidfile_close(pidfh);
5593914ddf8SEdward Tomasz Napierala 		handle_request(&request, options, incomplete_hierarchy);
5603914ddf8SEdward Tomasz Napierala 	}
5613914ddf8SEdward Tomasz Napierala 
5623914ddf8SEdward Tomasz Napierala 	pidfile_close(pidfh);
5633914ddf8SEdward Tomasz Napierala 
5643914ddf8SEdward Tomasz Napierala 	return (0);
5653914ddf8SEdward Tomasz Napierala }
5663914ddf8SEdward Tomasz Napierala 
567