diff usr/src/cmd/fs.d/autofs/autod_main.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/autofs/autod_main.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,1049 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)autod_main.c	1.81	08/02/12 SMI"
+
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <memory.h>
+#include <stropts.h>
+#include <netconfig.h>
+#include <stdarg.h>
+#include <sys/resource.h>
+#include <sys/systeminfo.h>
+#include <syslog.h>
+#include <errno.h>
+#include <sys/sockio.h>
+#include <rpc/xdr.h>
+#include <net/if.h>
+#include <netdir.h>
+#include <string.h>
+#include <thread.h>
+#include <locale.h>
+#include <door.h>
+#include "automount.h"
+#include <sys/vfs.h>
+#include <sys/mnttab.h>
+#include <arpa/inet.h>
+#include <rpcsvc/daemon_utils.h>
+#include <deflt.h>
+#include <strings.h>
+#include <priv.h>
+#include <tsol/label.h>
+#include <sys/utsname.h>
+#include <sys/thread.h>
+#include <nfs/rnode.h>
+#include <nfs/nfs.h>
+#include <wait.h>
+
+static void autofs_doorfunc(void *, char *, size_t, door_desc_t *, uint_t);
+static void autofs_setdoor(int);
+static void autofs_mntinfo_1_r(autofs_lookupargs *, autofs_mountres *);
+static void autofs_mount_1_free_r(struct autofs_mountres *);
+static void autofs_lookup_1_r(autofs_lookupargs *, autofs_lookupres *);
+static void autofs_lookup_1_free_args(autofs_lookupargs *);
+static void autofs_unmount_1_r(umntrequest *, umntres *);
+static void autofs_unmount_1_free_args(umntrequest *);
+static void autofs_readdir_1_r(autofs_rddirargs *, autofs_rddirres *);
+static void autofs_readdir_1_free_r(struct autofs_rddirres *);
+static int decode_args(xdrproc_t, autofs_door_args_t *, caddr_t *, int);
+static bool_t encode_res(xdrproc_t, autofs_door_res_t **, caddr_t, int *);
+static void usage();
+static void warn_hup(int);
+static void free_action_list();
+static int start_autofs_svcs();
+static void automountd_wait_for_cleanup(pid_t);
+
+/*
+ * Private autofs system call
+ */
+extern int _autofssys(int, void *);
+
+#define	CTIME_BUF_LEN 26
+
+#define	RESOURCE_FACTOR 8
+#ifdef DEBUG
+#define	AUTOFS_DOOR	"/var/run/autofs_door"
+#endif /* DEBUG */
+
+static thread_key_t	s_thr_key;
+
+struct autodir *dir_head;
+struct autodir *dir_tail;
+char self[64];
+
+time_t timenow;
+int verbose = 0;
+int trace = 0;
+int automountd_nobrowse = 0;
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+
+{
+	pid_t pid;
+	int c, error;
+	struct rlimit rlset;
+	char *defval;
+
+	if (geteuid() != 0) {
+		(void) fprintf(stderr, "%s must be run as root\n", argv[0]);
+		exit(1);
+	}
+
+	/*
+	 * Read in the values from config file first before we check
+	 * commandline options so the options override the file.
+	 */
+	if ((defopen(AUTOFSADMIN)) == 0) {
+		if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) {
+			if (strncasecmp("true", defval, 4) == 0)
+				verbose = TRUE;
+			else
+				verbose = FALSE;
+		}
+		if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) {
+			if (strncasecmp("true", defval, 4) == 0)
+				automountd_nobrowse = TRUE;
+			else
+				automountd_nobrowse = FALSE;
+		}
+		if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) {
+			errno = 0;
+			trace = strtol(defval, (char **)NULL, 10);
+			if (errno != 0)
+				trace = 0;
+		}
+		put_automountd_env();
+
+		/* close defaults file */
+		defopen(NULL);
+	}
+
+	while ((c = getopt(argc, argv, "vnTD:")) != EOF) {
+		switch (c) {
+		case 'v':
+			verbose++;
+			break;
+		case 'n':
+			automountd_nobrowse++;
+			break;
+		case 'T':
+			trace++;
+			break;
+		case 'D':
+			(void) putenv(optarg);
+			break;
+		default:
+			usage();
+		}
+	}
+
+	if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) {
+		error = errno;
+		(void) fprintf(stderr,
+			"automountd: can't determine hostname, error: %d\n",
+			error);
+		exit(1);
+	}
+
+#ifndef DEBUG
+	pid = fork();
+	if (pid < 0) {
+		perror("cannot fork");
+		exit(1);
+	}
+	if (pid)
+		exit(0);
+#endif
+
+	(void) setsid();
+	openlog("automountd", LOG_PID, LOG_DAEMON);
+	(void) setlocale(LC_ALL, "");
+
+	/*
+	 * Create the door_servers to manage fork/exec requests for
+	 * mounts and executable automount maps
+	 */
+	if ((did_fork_exec = door_create(automountd_do_fork_exec,
+	    NULL, NULL)) == -1) {
+		syslog(LOG_ERR, "door_create failed: %m, Exiting.");
+		exit(errno);
+	}
+	if ((did_exec_map = door_create(automountd_do_exec_map,
+	    NULL, NULL)) == -1) {
+		syslog(LOG_ERR, "door_create failed: %m, Exiting.");
+		if (door_revoke(did_fork_exec) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+			    did_fork_exec);
+		}
+		exit(errno);
+	}
+	/*
+	 * Before we become multithreaded we fork allowing the parent
+	 * to become a door server to handle all mount and unmount
+	 * requests. This works around a potential hang in using
+	 * fork1() within a multithreaded environment
+	 */
+
+	pid = fork1();
+	if (pid < 0) {
+		syslog(LOG_ERR,
+			"can't fork the automountd mount process %m");
+		if (door_revoke(did_fork_exec) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+				did_fork_exec);
+		}
+		if (door_revoke(did_exec_map) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+				did_exec_map);
+		}
+		exit(1);
+	} else if (pid > 0) {
+		/* this is the door server process */
+		automountd_wait_for_cleanup(pid);
+	}
+
+
+	(void) rwlock_init(&cache_lock, USYNC_THREAD, NULL);
+	(void) rwlock_init(&autofs_rddir_cache_lock, USYNC_THREAD, NULL);
+
+	/*
+	 * initialize the name services, use NULL arguments to ensure
+	 * we don't initialize the stack of files used in file service
+	 */
+	(void) ns_setup(NULL, NULL);
+
+	/*
+	 * we're using doors and its thread management now so we need to
+	 * make sure we have more than the default of 256 file descriptors
+	 * available.
+	 */
+	rlset.rlim_cur = RLIM_INFINITY;
+	rlset.rlim_max = RLIM_INFINITY;
+	if (setrlimit(RLIMIT_NOFILE, &rlset) == -1)
+		syslog(LOG_ERR, "setrlimit failed for %s: %s", AUTOMOUNTD,
+		    strerror(errno));
+
+	(void) enable_extended_FILE_stdio(-1, -1);
+
+	/*
+	 * establish our lock on the lock file and write our pid to it.
+	 * exit if some other process holds the lock, or if there's any
+	 * error in writing/locking the file.
+	 */
+	pid = _enter_daemon_lock(AUTOMOUNTD);
+	switch (pid) {
+	case 0:
+		break;
+	case -1:
+		syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD);
+		exit(2);
+	default:
+		/* daemon was already running */
+		exit(0);
+	}
+
+	/*
+	 * If we coredump it'll be /core.
+	 */
+	if (chdir("/") < 0)
+		syslog(LOG_ERR, "chdir /: %m");
+
+	/*
+	 * Create cache_cleanup thread
+	 */
+	if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL,
+			THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) {
+		syslog(LOG_ERR, "unable to create cache_cleanup thread");
+		exit(1);
+	}
+
+	/* other initializations */
+	(void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL);
+
+	/*
+	 * On a labeled system, allow read-down nfs mounts if privileged
+	 * (PRIV_NET_MAC_AWARE) to do so.  Otherwise, ignore the error
+	 * and "mount equal label only" behavior will result.
+	 */
+	if (is_system_labeled()) {
+		(void) setpflags(NET_MAC_AWARE, 1);
+		(void) setpflags(NET_MAC_AWARE_INHERIT, 1);
+	}
+
+	(void) signal(SIGHUP, warn_hup);
+
+	/* start services */
+	return (start_autofs_svcs());
+
+}
+
+/*
+ * The old automounter supported a SIGHUP
+ * to allow it to resynchronize internal
+ * state with the /etc/mnttab.
+ * This is no longer relevant, but we
+ * need to catch the signal and warn
+ * the user.
+ */
+/* ARGSUSED */
+static void
+warn_hup(i)
+	int i;
+{
+	syslog(LOG_ERR, "SIGHUP received: ignored");
+	(void) signal(SIGHUP, warn_hup);
+}
+
+static void
+usage()
+{
+	(void) fprintf(stderr, "Usage: automountd\n"
+	    "\t[-T]\t\t(trace requests)\n"
+	    "\t[-v]\t\t(verbose error msgs)\n"
+	    "\t[-D n=s]\t(define env variable)\n");
+	exit(1);
+	/* NOTREACHED */
+}
+
+static void
+autofs_readdir_1_r(
+	autofs_rddirargs *req,
+	autofs_rddirres *res)
+{
+	if (trace > 0)
+		trace_prt(1, "READDIR REQUEST	: %s @ %ld\n",
+		    req->rda_map, req->rda_offset);
+
+	do_readdir(req, res);
+	if (trace > 0)
+		trace_prt(1, "READDIR REPLY	: status=%d\n", res->rd_status);
+}
+
+static void
+autofs_readdir_1_free_r(struct autofs_rddirres *res)
+{
+	if (res->rd_status == AUTOFS_OK) {
+		if (res->rd_rddir.rddir_entries)
+			free(res->rd_rddir.rddir_entries);
+	}
+}
+
+
+/* ARGSUSED */
+static void
+autofs_unmount_1_r(
+	umntrequest *m,
+	umntres *res)
+{
+	struct umntrequest *ul;
+
+	if (trace > 0) {
+		char ctime_buf[CTIME_BUF_LEN];
+		if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
+			ctime_buf[0] = '\0';
+
+		trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf);
+		for (ul = m; ul; ul = ul->next)
+			trace_prt(1, " resource=%s fstype=%s mntpnt=%s"
+			    " mntopts=%s %s\n",
+			    ul->mntresource,
+			    ul->fstype,
+			    ul->mntpnt,
+			    ul->mntopts,
+			    ul->isdirect ? "direct" : "indirect");
+	}
+
+
+	res->status = do_unmount1(m);
+
+	if (trace > 0)
+		trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status);
+}
+
+static void
+autofs_lookup_1_r(
+	autofs_lookupargs *m,
+	autofs_lookupres *res)
+{
+	autofs_action_t action;
+	struct	linka link;
+	int status;
+
+	if (trace > 0) {
+		char ctime_buf[CTIME_BUF_LEN];
+		if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
+			ctime_buf[0] = '\0';
+
+		trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf);
+		trace_prt(1, "  name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
+		    m->name, m->subdir, m->map, m->opts, m->path, m->isdirect);
+	}
+
+	bzero(&link, sizeof (struct linka));
+
+	status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path,
+	    (uint_t)m->isdirect, m->uid, &action, &link);
+	if (status == 0) {
+		/*
+		 * Return action list to kernel.
+		 */
+		res->lu_res = AUTOFS_OK;
+		if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) {
+			res->lu_type.lookup_result_type_u.lt_linka = link;
+		}
+	} else {
+		/*
+		 * Entry not found
+		 */
+		res->lu_res = AUTOFS_NOENT;
+	}
+	res->lu_verbose = verbose;
+
+	if (trace > 0)
+		trace_prt(1, "LOOKUP REPLY    : status=%d\n", res->lu_res);
+}
+
+static void
+autofs_mntinfo_1_r(
+	autofs_lookupargs *m,
+	autofs_mountres *res)
+{
+	int status;
+	action_list		*alp = NULL;
+
+	if (trace > 0) {
+		char ctime_buf[CTIME_BUF_LEN];
+		if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
+			ctime_buf[0] = '\0';
+
+		trace_prt(1, "MOUNT REQUEST:   %s", ctime_buf);
+		trace_prt(1, "  name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
+		    m->name, m->subdir, m->map, m->opts, m->path, m->isdirect);
+	}
+
+	status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path,
+	    (uint_t)m->isdirect, m->uid, &alp, DOMOUNT_USER);
+	if (status != 0) {
+		/*
+		 * An error occurred, free action list if allocated.
+		 */
+		if (alp != NULL) {
+			free_action_list(alp);
+			alp = NULL;
+		}
+	}
+	if (alp != NULL) {
+		/*
+		 * Return action list to kernel.
+		 */
+		res->mr_type.status = AUTOFS_ACTION;
+		res->mr_type.mount_result_type_u.list = alp;
+	} else {
+		/*
+		 * No work to do left for the kernel
+		 */
+		res->mr_type.status = AUTOFS_DONE;
+		res->mr_type.mount_result_type_u.error = status;
+	}
+
+	if (trace > 0) {
+		switch (res->mr_type.status) {
+		case AUTOFS_ACTION:
+			trace_prt(1,
+			    "MOUNT REPLY    : status=%d, AUTOFS_ACTION\n",
+			    status);
+			break;
+		case AUTOFS_DONE:
+			trace_prt(1,
+			    "MOUNT REPLY    : status=%d, AUTOFS_DONE\n",
+			    status);
+			break;
+		default:
+			trace_prt(1, "MOUNT REPLY    : status=%d, UNKNOWN\n",
+			    status);
+		}
+	}
+
+	if (status && verbose) {
+		if (m->isdirect) {
+			/* direct mount */
+			syslog(LOG_ERR, "mount of %s failed", m->path);
+		} else {
+			/* indirect mount */
+			syslog(LOG_ERR,
+			    "mount of %s/%s failed", m->path, m->name);
+		}
+	}
+}
+
+static void
+autofs_mount_1_free_r(struct autofs_mountres *res)
+{
+	if (res->mr_type.status == AUTOFS_ACTION) {
+		if (trace > 2)
+			trace_prt(1, "freeing action list\n");
+		free_action_list(res->mr_type.mount_result_type_u.list);
+	}
+}
+
+/*
+ * Used for reporting messages from code shared with automount command.
+ * Formats message into a buffer and calls syslog.
+ *
+ * Print an error.  Works like printf (fmt string and variable args)
+ * except that it will subsititute an error message for a "%m" string
+ * (like syslog).
+ */
+void
+pr_msg(const char *fmt, ...)
+{
+	va_list ap;
+	char fmtbuff[BUFSIZ], buff[BUFSIZ];
+	const char *p1;
+	char *p2;
+
+	p2 = fmtbuff;
+	fmt = gettext(fmt);
+
+	for (p1 = fmt; *p1; p1++) {
+		if (*p1 == '%' && *(p1 + 1) == 'm') {
+			(void) strcpy(p2, strerror(errno));
+			p2 += strlen(p2);
+			p1++;
+		} else {
+			*p2++ = *p1;
+		}
+	}
+	if (p2 > fmtbuff && *(p2-1) != '\n')
+		*p2++ = '\n';
+	*p2 = '\0';
+
+	va_start(ap, fmt);
+	(void) vsprintf(buff, fmtbuff, ap);
+	va_end(ap);
+	syslog(LOG_ERR, buff);
+}
+
+static void
+free_action_list(action_list *alp)
+{
+	action_list *p, *next = NULL;
+	struct mounta *mp;
+
+	for (p = alp; p != NULL; p = next) {
+		switch (p->action.action) {
+		case AUTOFS_MOUNT_RQ:
+			mp = &(p->action.action_list_entry_u.mounta);
+			/* LINTED pointer alignment */
+			if (mp->fstype) {
+				if (strcmp(mp->fstype, "autofs") == 0) {
+					free_autofs_args((autofs_args *)
+					    mp->dataptr);
+				} else if (strncmp(mp->fstype, "nfs", 3) == 0) {
+					free_nfs_args((struct nfs_args *)
+					    mp->dataptr);
+				}
+			}
+			mp->dataptr = NULL;
+			mp->datalen = 0;
+			free_mounta(mp);
+			break;
+		case AUTOFS_LINK_RQ:
+			syslog(LOG_ERR,
+			    "non AUTOFS_MOUNT_RQ requests not implemented\n");
+			break;
+		default:
+			syslog(LOG_ERR,
+			    "non AUTOFS_MOUNT_RQ requests not implemented\n");
+			break;
+		}
+		next = p->next;
+		free(p);
+	}
+}
+
+static void
+autofs_lookup_1_free_args(autofs_lookupargs *args)
+{
+	if (args->map)
+		free(args->map);
+	if (args->path)
+		free(args->path);
+	if (args->name)
+		free(args->name);
+	if (args->subdir)
+		free(args->subdir);
+	if (args->opts)
+		free(args->opts);
+}
+
+static void
+autofs_unmount_1_free_args(umntrequest *args)
+{
+	if (args->mntresource)
+		free(args->mntresource);
+	if (args->mntpnt)
+		free(args->mntpnt);
+	if (args->fstype)
+		free(args->fstype);
+	if (args->mntopts)
+		free(args->mntopts);
+	if (args->next)
+		autofs_unmount_1_free_args(args->next);
+}
+
+static void
+autofs_setdoor(int did)
+{
+
+	if (did < 0) {
+		did = 0;
+	}
+
+	(void) _autofssys(AUTOFS_SETDOOR, &did);
+}
+
+void *
+autofs_get_buffer(size_t size)
+{
+	autofs_tsd_t *tsd = NULL;
+
+	/*
+	 * Make sure the buffer size is aligned
+	 */
+	(void) thr_getspecific(s_thr_key, (void **)&tsd);
+	if (tsd == NULL) {
+		tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t));
+		if (tsd == NULL) {
+			return (NULL);
+		}
+		tsd->atsd_buf = malloc(size);
+		if (tsd->atsd_buf != NULL)
+			tsd->atsd_len = size;
+		else
+			tsd->atsd_len = 0;
+		(void) thr_setspecific(s_thr_key, tsd);
+	} else {
+		if (tsd->atsd_buf && (tsd->atsd_len < size)) {
+			free(tsd->atsd_buf);
+			tsd->atsd_buf = malloc(size);
+			if (tsd->atsd_buf != NULL)
+				tsd->atsd_len = size;
+			else {
+				tsd->atsd_len = 0;
+			}
+		}
+	}
+	if (tsd->atsd_buf) {
+		bzero(tsd->atsd_buf, size);
+		return (tsd->atsd_buf);
+	} else {
+		syslog(LOG_ERR,
+		    gettext("Can't Allocate tsd buffer, size %d"), size);
+		return (NULL);
+	}
+}
+
+/*
+ * Each request will automatically spawn a new thread with this
+ * as its entry point.
+ */
+/* ARGUSED */
+static void
+autofs_doorfunc(
+	void *cookie,
+	char *argp,
+	size_t arg_size,
+	door_desc_t *dp,
+	uint_t n_desc)
+{
+	char			*res;
+	int			 res_size;
+	int			 which;
+	int			 error = 0;
+	int			 srsz = 0;
+	autofs_lookupargs	*xdrargs;
+	autofs_lookupres	 lookup_res;
+	autofs_rddirargs	*rddir_args;
+	autofs_rddirres		 rddir_res;
+	autofs_mountres		 mount_res;
+	umntrequest		*umnt_args;
+	umntres			 umount_res;
+	autofs_door_res_t	*door_res;
+	autofs_door_res_t	 failed_res;
+
+	if (arg_size < sizeof (autofs_door_args_t)) {
+		failed_res.res_status = EINVAL;
+		error = door_return((char *)&failed_res,
+		    sizeof (autofs_door_res_t), NULL, 0);
+		/*
+		 * If we got here the door_return() failed.
+		 */
+		syslog(LOG_ERR, "Bad argument, door_return failure %d", error);
+		return;
+	}
+
+	timenow = time((time_t *)NULL);
+
+	which = ((autofs_door_args_t *)argp)->cmd;
+	switch (which) {
+	case AUTOFS_LOOKUP:
+		if (error = decode_args(xdr_autofs_lookupargs,
+		    (autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
+		    sizeof (autofs_lookupargs))) {
+			syslog(LOG_ERR,
+			    "error allocating lookup arguments buffer");
+			failed_res.res_status = error;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = 0;
+			break;
+		}
+		bzero(&lookup_res, sizeof (autofs_lookupres));
+
+		autofs_lookup_1_r(xdrargs, &lookup_res);
+
+		autofs_lookup_1_free_args(xdrargs);
+		free(xdrargs);
+
+		if (!encode_res(xdr_autofs_lookupres, &door_res,
+		    (caddr_t)&lookup_res, &res_size)) {
+			syslog(LOG_ERR,
+			    "error allocating lookup results buffer");
+			failed_res.res_status = EINVAL;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+		} else {
+			door_res->res_status = 0;
+			res = (caddr_t)door_res;
+		}
+		break;
+
+	case AUTOFS_MNTINFO:
+		if (error = decode_args(xdr_autofs_lookupargs,
+		    (autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
+		    sizeof (autofs_lookupargs))) {
+			syslog(LOG_ERR,
+			    "error allocating lookup arguments buffer");
+			failed_res.res_status = error;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = 0;
+			break;
+		}
+
+		autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res);
+
+		autofs_lookup_1_free_args(xdrargs);
+		free(xdrargs);
+
+		/*
+		 * Only reason we would get a NULL res is because
+		 * we could not allocate a results buffer.  Use
+		 * a local one to return the error EAGAIN as has
+		 * always been done when memory allocations fail.
+		 */
+		if (!encode_res(xdr_autofs_mountres, &door_res,
+		    (caddr_t)&mount_res, &res_size)) {
+			syslog(LOG_ERR,
+			    "error allocating mount results buffer");
+			failed_res.res_status = EAGAIN;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+		} else {
+			door_res->res_status = 0;
+			res = (caddr_t)door_res;
+		}
+		autofs_mount_1_free_r(&mount_res);
+		break;
+
+	case AUTOFS_UNMOUNT:
+		if (error = decode_args(xdr_umntrequest,
+		    (autofs_door_args_t *)argp,
+		    (caddr_t *)&umnt_args, sizeof (umntrequest))) {
+			syslog(LOG_ERR,
+			    "error allocating unmount argument buffer");
+			failed_res.res_status = error;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = sizeof (autofs_door_res_t);
+			break;
+		}
+
+		autofs_unmount_1_r(umnt_args, &umount_res);
+
+		error = umount_res.status;
+
+		autofs_unmount_1_free_args(umnt_args);
+		free(umnt_args);
+
+		if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res,
+		    &res_size)) {
+			syslog(LOG_ERR,
+			    "error allocating unmount results buffer");
+			failed_res.res_status = EINVAL;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = sizeof (autofs_door_res_t);
+		} else {
+			door_res->res_status = 0;
+			res = (caddr_t)door_res;
+		}
+		break;
+
+	case AUTOFS_READDIR:
+		if (error = decode_args(xdr_autofs_rddirargs,
+		    (autofs_door_args_t *)argp,
+		    (caddr_t *)&rddir_args,
+		    sizeof (autofs_rddirargs))) {
+			syslog(LOG_ERR,
+			    "error allocating readdir argument buffer");
+			failed_res.res_status = error;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = sizeof (autofs_door_res_t);
+			break;
+		}
+
+		autofs_readdir_1_r(rddir_args, &rddir_res);
+
+		free(rddir_args->rda_map);
+		free(rddir_args);
+
+		if (!encode_res(xdr_autofs_rddirres, &door_res,
+		    (caddr_t)&rddir_res, &res_size)) {
+			syslog(LOG_ERR,
+			    "error allocating readdir results buffer");
+			failed_res.res_status = ENOMEM;
+			failed_res.xdr_len = 0;
+			res = (caddr_t)&failed_res;
+			res_size = sizeof (autofs_door_res_t);
+		} else {
+			door_res->res_status = 0;
+			res = (caddr_t)door_res;
+		}
+		autofs_readdir_1_free_r(&rddir_res);
+		break;
+#ifdef MALLOC_DEBUG
+	case AUTOFS_DUMP_DEBUG:
+			check_leaks("/var/tmp/automountd.leak");
+			error = door_return(NULL, 0, NULL, 0);
+			/*
+			 * If we got here, door_return() failed
+			 */
+			syslog(LOG_ERR, "dump debug door_return failure %d",
+			    error);
+			return;
+#endif
+	case NULLPROC:
+			res = NULL;
+			res_size = 0;
+			break;
+	default:
+			failed_res.res_status = EINVAL;
+			res = (char *)&failed_res;
+			res_size = sizeof (autofs_door_res_t);
+			break;
+	}
+
+	srsz = res_size;
+	errno = 0;
+	error = door_return(res, res_size, NULL, 0);
+
+	if (errno == E2BIG) {
+		/*
+		 * Failed due to encoded results being bigger than the
+		 * kernel expected bufsize. Passing actual results size
+		 * back down to kernel.
+		 */
+		failed_res.res_status = EOVERFLOW;
+		failed_res.xdr_len = srsz;
+		res = (caddr_t)&failed_res;
+		res_size = sizeof (autofs_door_res_t);
+	} else {
+		syslog(LOG_ERR, "door_return failed %d, buffer %p, "
+		    "buffer size %d", error, (void *)res, res_size);
+		res = NULL;
+		res_size = 0;
+	}
+	(void) door_return(res, res_size, NULL, 0);
+	/* NOTREACHED */
+}
+
+static int
+start_autofs_svcs(void)
+{
+	int doorfd;
+#ifdef DEBUG
+	int dfd;
+#endif
+
+	if ((doorfd = door_create(autofs_doorfunc, NULL,
+	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+		syslog(LOG_ERR, gettext("Unable to create door\n"));
+		return (1);
+	}
+
+#ifdef DEBUG
+	/*
+	 * Create a file system path for the door
+	 */
+	if ((dfd = open(AUTOFS_DOOR, O_RDWR|O_CREAT|O_TRUNC,
+	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
+		syslog(LOG_ERR, "Unable to open %s: %m\n", AUTOFS_DOOR);
+		(void) close(doorfd);
+		return (1);
+	}
+
+	/*
+	 * stale associations clean up
+	 */
+	(void) fdetach(AUTOFS_DOOR);
+
+	/*
+	 * Register in the namespace to the kernel to door_ki_open.
+	 */
+	if (fattach(doorfd, AUTOFS_DOOR) == -1) {
+		syslog(LOG_ERR, "Unable to fattach door %m\n", AUTOFS_DOOR);
+		(void) close(dfd);
+		(void) close(doorfd);
+		return (1);
+	}
+#endif /* DEBUG */
+
+	/*
+	 * Pass door name to kernel for door_ki_open
+	 */
+	autofs_setdoor(doorfd);
+
+	(void) thr_keycreate(&s_thr_key, NULL);
+
+	/*
+	 * Wait for incoming calls
+	 */
+	/*CONSTCOND*/
+	while (1)
+		(void) pause();
+
+	/* NOTREACHED */
+	syslog(LOG_ERR, gettext("Door server exited"));
+	return (10);
+}
+
+static int
+decode_args(
+	xdrproc_t xdrfunc,
+	autofs_door_args_t *argp,
+	caddr_t *xdrargs,
+	int size)
+{
+	XDR xdrs;
+
+	caddr_t tmpargs = (caddr_t)&((autofs_door_args_t *)argp)->xdr_arg;
+	size_t arg_size = ((autofs_door_args_t *)argp)->xdr_len;
+
+	xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE);
+
+	*xdrargs = malloc(size);
+	if (*xdrargs == NULL) {
+		syslog(LOG_ERR, "error allocating arguments buffer");
+		return (ENOMEM);
+	}
+
+	bzero(*xdrargs, size);
+
+	if (!(*xdrfunc)(&xdrs, *xdrargs)) {
+		free(*xdrargs);
+		*xdrargs = NULL;
+		syslog(LOG_ERR, "error decoding arguments");
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+
+static bool_t
+encode_res(
+	xdrproc_t xdrfunc,
+	autofs_door_res_t **results,
+	caddr_t resp,
+	int *size)
+{
+	XDR xdrs;
+
+	*size = xdr_sizeof((*xdrfunc), resp);
+	*results = autofs_get_buffer(
+	    sizeof (autofs_door_res_t) + *size);
+	if (*results == NULL) {
+		(*results)->res_status = ENOMEM;
+		return (FALSE);
+	}
+	(*results)->xdr_len = *size;
+	*size = sizeof (autofs_door_res_t) + (*results)->xdr_len;
+	xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res),
+	    (*results)->xdr_len, XDR_ENCODE);
+	if (!(*xdrfunc)(&xdrs, resp)) {
+		(*results)->res_status = EINVAL;
+		syslog(LOG_ERR, "error encoding results");
+		return (FALSE);
+	}
+	(*results)->res_status = 0;
+	return (TRUE);
+}
+
+static void
+automountd_wait_for_cleanup(pid_t pid)
+{
+	int status;
+	int child_exitval;
+
+	/*
+	 * Wait for the main automountd process to exit so we cleanup
+	 */
+	(void) waitpid(pid, &status, 0);
+
+	child_exitval = WEXITSTATUS(status);
+
+	/*
+	 * Shutdown the door server for mounting and unmounting
+	 * filesystems
+	 */
+	if (door_revoke(did_fork_exec) == -1) {
+		syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_fork_exec);
+	}
+	if (door_revoke(did_exec_map) == -1) {
+		syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_exec_map);
+	}
+	exit(child_exitval);
+}