xref: /titanic_50/usr/src/cmd/zoneadmd/zoneadmd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * zoneadmd manages zones; one zoneadmd process is launched for each
31*7c478bd9Sstevel@tonic-gate  * non-global zone on the system.  This daemon juggles four jobs:
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  * - Implement setup and teardown of the zone "virtual platform": mount and
34*7c478bd9Sstevel@tonic-gate  *   unmount filesystems; create and destroy network interfaces; communicate
35*7c478bd9Sstevel@tonic-gate  *   with devfsadmd to lay out devices for the zone; instantiate the zone
36*7c478bd9Sstevel@tonic-gate  *   console device; configure process runtime attributes such as resource
37*7c478bd9Sstevel@tonic-gate  *   controls, pool bindings, fine-grained privileges.
38*7c478bd9Sstevel@tonic-gate  *
39*7c478bd9Sstevel@tonic-gate  * - Launch the zone's init(1M) process.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * - Implement a door server; clients (like zoneadm) connect to the door
42*7c478bd9Sstevel@tonic-gate  *   server and request zone state changes.  The kernel is also a client of
43*7c478bd9Sstevel@tonic-gate  *   this door server.  A request to halt or reboot the zone which originates
44*7c478bd9Sstevel@tonic-gate  *   *inside* the zone results in a door upcall from the kernel into zoneadmd.
45*7c478bd9Sstevel@tonic-gate  *
46*7c478bd9Sstevel@tonic-gate  *   One minor problem is that messages emitted by zoneadmd need to be passed
47*7c478bd9Sstevel@tonic-gate  *   back to the zoneadm process making the request.  These messages need to
48*7c478bd9Sstevel@tonic-gate  *   be rendered in the client's locale; so, this is passed in as part of the
49*7c478bd9Sstevel@tonic-gate  *   request.  The exception is the kernel upcall to zoneadmd, in which case
50*7c478bd9Sstevel@tonic-gate  *   messages are syslog'd.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  *   To make all of this work, the Makefile adds -a to xgettext to extract *all*
53*7c478bd9Sstevel@tonic-gate  *   strings, and an exclusion file (zoneadmd.xcl) is used to exclude those
54*7c478bd9Sstevel@tonic-gate  *   strings which do not need to be translated.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * - Act as a console server for zlogin -C processes; see comments in zcons.c
57*7c478bd9Sstevel@tonic-gate  *   for more information about the zone console architecture.
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  * DESIGN NOTES
60*7c478bd9Sstevel@tonic-gate  *
61*7c478bd9Sstevel@tonic-gate  * Restart:
62*7c478bd9Sstevel@tonic-gate  *   A chief design constraint of zoneadmd is that it should be restartable in
63*7c478bd9Sstevel@tonic-gate  *   the case that the administrator kills it off, or it suffers a fatal error,
64*7c478bd9Sstevel@tonic-gate  *   without the running zone being impacted; this is akin to being able to
65*7c478bd9Sstevel@tonic-gate  *   reboot the service processor of a server without affecting the OS instance.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
71*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
75*7c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate #include <alloca.h>
78*7c478bd9Sstevel@tonic-gate #include <assert.h>
79*7c478bd9Sstevel@tonic-gate #include <errno.h>
80*7c478bd9Sstevel@tonic-gate #include <door.h>
81*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
82*7c478bd9Sstevel@tonic-gate #include <locale.h>
83*7c478bd9Sstevel@tonic-gate #include <signal.h>
84*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
85*7c478bd9Sstevel@tonic-gate #include <stdio.h>
86*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
87*7c478bd9Sstevel@tonic-gate #include <string.h>
88*7c478bd9Sstevel@tonic-gate #include <strings.h>
89*7c478bd9Sstevel@tonic-gate #include <synch.h>
90*7c478bd9Sstevel@tonic-gate #include <syslog.h>
91*7c478bd9Sstevel@tonic-gate #include <thread.h>
92*7c478bd9Sstevel@tonic-gate #include <unistd.h>
93*7c478bd9Sstevel@tonic-gate #include <wait.h>
94*7c478bd9Sstevel@tonic-gate #include <limits.h>
95*7c478bd9Sstevel@tonic-gate #include <zone.h>
96*7c478bd9Sstevel@tonic-gate #include <libcontract.h>
97*7c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
98*7c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
99*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate #include <libzonecfg.h>
102*7c478bd9Sstevel@tonic-gate #include "zoneadmd.h"
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static char *progname;
105*7c478bd9Sstevel@tonic-gate char *zone_name;	/* zone which we are managing */
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static zlog_t logsys;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate mutex_t	lock = DEFAULTMUTEX;	/* to serialize stuff */
110*7c478bd9Sstevel@tonic-gate mutex_t	msglock = DEFAULTMUTEX;	/* for calling setlocale() */
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate static char	zone_door_path[MAXPATHLEN];
113*7c478bd9Sstevel@tonic-gate static int	zone_door = -1;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate boolean_t in_death_throes = B_FALSE;	/* daemon is dying */
116*7c478bd9Sstevel@tonic-gate boolean_t bringup_failure_recovery = B_FALSE; /* ignore certain failures */
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
119*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
120*7c478bd9Sstevel@tonic-gate #endif
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate #define	PATH_TO_INIT	"/sbin/init"
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate #define	DEFAULT_LOCALE	"C"
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate static char *
127*7c478bd9Sstevel@tonic-gate get_execbasename(char *execfullname)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	char *last_slash, *execbasename;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	/* guard against '/' at end of command invocation */
132*7c478bd9Sstevel@tonic-gate 	for (;;) {
133*7c478bd9Sstevel@tonic-gate 		last_slash = strrchr(execfullname, '/');
134*7c478bd9Sstevel@tonic-gate 		if (last_slash == NULL) {
135*7c478bd9Sstevel@tonic-gate 			execbasename = execfullname;
136*7c478bd9Sstevel@tonic-gate 			break;
137*7c478bd9Sstevel@tonic-gate 		} else {
138*7c478bd9Sstevel@tonic-gate 			execbasename = last_slash + 1;
139*7c478bd9Sstevel@tonic-gate 			if (*execbasename == '\0') {
140*7c478bd9Sstevel@tonic-gate 				*last_slash = '\0';
141*7c478bd9Sstevel@tonic-gate 				continue;
142*7c478bd9Sstevel@tonic-gate 			}
143*7c478bd9Sstevel@tonic-gate 			break;
144*7c478bd9Sstevel@tonic-gate 		}
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 	return (execbasename);
147*7c478bd9Sstevel@tonic-gate }
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate static void
150*7c478bd9Sstevel@tonic-gate usage(void)
151*7c478bd9Sstevel@tonic-gate {
152*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage: %s -z zonename\n"), progname);
153*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
154*7c478bd9Sstevel@tonic-gate 	    gettext("\tNote: %s should not be run directly.\n"), progname);
155*7c478bd9Sstevel@tonic-gate 	exit(2);
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
159*7c478bd9Sstevel@tonic-gate static void
160*7c478bd9Sstevel@tonic-gate sigchld(int sig)
161*7c478bd9Sstevel@tonic-gate {
162*7c478bd9Sstevel@tonic-gate }
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate char *
165*7c478bd9Sstevel@tonic-gate localize_msg(char *locale, const char *msg)
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	char *out;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&msglock);
170*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, locale);
171*7c478bd9Sstevel@tonic-gate 	out = gettext(msg);
172*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, DEFAULT_LOCALE);
173*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&msglock);
174*7c478bd9Sstevel@tonic-gate 	return (out);
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE3 */
178*7c478bd9Sstevel@tonic-gate void
179*7c478bd9Sstevel@tonic-gate zerror(zlog_t *zlogp, boolean_t use_strerror, const char *fmt, ...)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	va_list alist;
182*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN * 2]; /* enough space for err msg with a path */
183*7c478bd9Sstevel@tonic-gate 	char *bp;
184*7c478bd9Sstevel@tonic-gate 	int saved_errno = errno;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (zlogp == NULL)
187*7c478bd9Sstevel@tonic-gate 		return;
188*7c478bd9Sstevel@tonic-gate 	if (zlogp == &logsys)
189*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "[zone '%s'] ",
190*7c478bd9Sstevel@tonic-gate 		    zone_name);
191*7c478bd9Sstevel@tonic-gate 	else
192*7c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
193*7c478bd9Sstevel@tonic-gate 	bp = &(buf[strlen(buf)]);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/*
196*7c478bd9Sstevel@tonic-gate 	 * In theory, the locale pointer should be set to either "C" or a
197*7c478bd9Sstevel@tonic-gate 	 * char array, so it should never be NULL
198*7c478bd9Sstevel@tonic-gate 	 */
199*7c478bd9Sstevel@tonic-gate 	assert(zlogp->locale != NULL);
200*7c478bd9Sstevel@tonic-gate 	/* Locale is per process, but we are multi-threaded... */
201*7c478bd9Sstevel@tonic-gate 	fmt = localize_msg(zlogp->locale, fmt);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	va_start(alist, fmt);
204*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(bp, sizeof (buf) - (bp - buf), fmt, alist);
205*7c478bd9Sstevel@tonic-gate 	va_end(alist);
206*7c478bd9Sstevel@tonic-gate 	bp = &(buf[strlen(buf)]);
207*7c478bd9Sstevel@tonic-gate 	if (use_strerror)
208*7c478bd9Sstevel@tonic-gate 		(void) snprintf(bp, sizeof (buf) - (bp - buf), ": %s",
209*7c478bd9Sstevel@tonic-gate 		    strerror(saved_errno));
210*7c478bd9Sstevel@tonic-gate 	if (zlogp == &logsys) {
211*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s", buf);
212*7c478bd9Sstevel@tonic-gate 	} else if (zlogp->logfile != NULL) {
213*7c478bd9Sstevel@tonic-gate 		(void) fprintf(zlogp->logfile, "%s\n", buf);
214*7c478bd9Sstevel@tonic-gate 	} else {
215*7c478bd9Sstevel@tonic-gate 		size_t buflen;
216*7c478bd9Sstevel@tonic-gate 		size_t copylen;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 		buflen = snprintf(zlogp->log, zlogp->loglen, "%s\n", buf);
219*7c478bd9Sstevel@tonic-gate 		copylen = MIN(buflen, zlogp->loglen);
220*7c478bd9Sstevel@tonic-gate 		zlogp->log += copylen;
221*7c478bd9Sstevel@tonic-gate 		zlogp->loglen -= copylen;
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static int
226*7c478bd9Sstevel@tonic-gate mkzonedir(zlog_t *zlogp)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	struct stat st;
229*7c478bd9Sstevel@tonic-gate 	/*
230*7c478bd9Sstevel@tonic-gate 	 * We must create and lock everyone but root out of ZONES_TMPDIR
231*7c478bd9Sstevel@tonic-gate 	 * since anyone can open any UNIX domain socket, regardless of
232*7c478bd9Sstevel@tonic-gate 	 * its file system permissions.  Sigh...
233*7c478bd9Sstevel@tonic-gate 	 */
234*7c478bd9Sstevel@tonic-gate 	if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) {
235*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "could not mkdir '%s'", ZONES_TMPDIR);
236*7c478bd9Sstevel@tonic-gate 		return (-1);
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 	/* paranoia */
239*7c478bd9Sstevel@tonic-gate 	if ((stat(ZONES_TMPDIR, &st) < 0) || ((st.st_mode & S_IFDIR) == 0)) {
240*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "'%s' is not a directory", ZONES_TMPDIR);
241*7c478bd9Sstevel@tonic-gate 		return (-1);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	(void) chmod(ZONES_TMPDIR, S_IRWXU);
244*7c478bd9Sstevel@tonic-gate 	return (0);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate static zoneid_t
248*7c478bd9Sstevel@tonic-gate zone_ready(zlog_t *zlogp)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate 	int err;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if ((err = zonecfg_create_snapshot(zone_name)) != Z_OK) {
253*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "unable to create snapshot: %s",
254*7c478bd9Sstevel@tonic-gate 		    zonecfg_strerror(err));
255*7c478bd9Sstevel@tonic-gate 		return (-1);
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	if (vplat_create(zlogp) != 0) {
259*7c478bd9Sstevel@tonic-gate 		if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
260*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "destroying snapshot: %s",
261*7c478bd9Sstevel@tonic-gate 			    zonecfg_strerror(err));
262*7c478bd9Sstevel@tonic-gate 		return (-1);
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 	if (vplat_bringup(zlogp) != 0) {
265*7c478bd9Sstevel@tonic-gate 		bringup_failure_recovery = B_TRUE;
266*7c478bd9Sstevel@tonic-gate 		(void) vplat_teardown(NULL);
267*7c478bd9Sstevel@tonic-gate 		if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
268*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "destroying snapshot: %s",
269*7c478bd9Sstevel@tonic-gate 			    zonecfg_strerror(err));
270*7c478bd9Sstevel@tonic-gate 		return (-1);
271*7c478bd9Sstevel@tonic-gate 	}
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	return (0);
274*7c478bd9Sstevel@tonic-gate }
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate static int
277*7c478bd9Sstevel@tonic-gate init_template()
278*7c478bd9Sstevel@tonic-gate {
279*7c478bd9Sstevel@tonic-gate 	int fd;
280*7c478bd9Sstevel@tonic-gate 	int err = 0;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
283*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
284*7c478bd9Sstevel@tonic-gate 		return (-1);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	/*
287*7c478bd9Sstevel@tonic-gate 	 * For now, zoneadmd doesn't do anything with the contract.
288*7c478bd9Sstevel@tonic-gate 	 * Deliver no events, don't inherit, and allow it to be orphaned.
289*7c478bd9Sstevel@tonic-gate 	 */
290*7c478bd9Sstevel@tonic-gate 	err |= ct_tmpl_set_critical(fd, 0);
291*7c478bd9Sstevel@tonic-gate 	err |= ct_tmpl_set_informative(fd, 0);
292*7c478bd9Sstevel@tonic-gate 	err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
293*7c478bd9Sstevel@tonic-gate 	err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
294*7c478bd9Sstevel@tonic-gate 	if (err || ct_tmpl_activate(fd)) {
295*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
296*7c478bd9Sstevel@tonic-gate 		return (-1);
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	return (fd);
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate static int
303*7c478bd9Sstevel@tonic-gate mount_early_fs(zlog_t *zlogp, zoneid_t zoneid, const char *spec,
304*7c478bd9Sstevel@tonic-gate     const char *dir, char *fstype)
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	pid_t child;
307*7c478bd9Sstevel@tonic-gate 	int child_status;
308*7c478bd9Sstevel@tonic-gate 	int tmpl_fd;
309*7c478bd9Sstevel@tonic-gate 	ctid_t ct;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if ((tmpl_fd = init_template()) == -1) {
312*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "failed to create contract");
313*7c478bd9Sstevel@tonic-gate 		return (-1);
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	if ((child = fork()) == -1) {
317*7c478bd9Sstevel@tonic-gate 		(void) ct_tmpl_clear(tmpl_fd);
318*7c478bd9Sstevel@tonic-gate 		(void) close(tmpl_fd);
319*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "failed to fork");
320*7c478bd9Sstevel@tonic-gate 		return (-1);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	} else if (child == 0) {	/* child */
323*7c478bd9Sstevel@tonic-gate 		(void) ct_tmpl_clear(tmpl_fd);
324*7c478bd9Sstevel@tonic-gate 		/*
325*7c478bd9Sstevel@tonic-gate 		 * Even though there are no procs running in the zone, we
326*7c478bd9Sstevel@tonic-gate 		 * do this for paranoia's sake.
327*7c478bd9Sstevel@tonic-gate 		 */
328*7c478bd9Sstevel@tonic-gate 		(void) closefrom(0);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 		if (zone_enter(zoneid) == -1) {
331*7c478bd9Sstevel@tonic-gate 			_exit(errno);
332*7c478bd9Sstevel@tonic-gate 		}
333*7c478bd9Sstevel@tonic-gate 		if (mount(spec, dir, MS_DATA, fstype, NULL, 0, NULL, 0) != 0)
334*7c478bd9Sstevel@tonic-gate 			_exit(errno);
335*7c478bd9Sstevel@tonic-gate 		_exit(0);
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	/* parent */
339*7c478bd9Sstevel@tonic-gate 	if (contract_latest(&ct) == -1)
340*7c478bd9Sstevel@tonic-gate 		ct = -1;
341*7c478bd9Sstevel@tonic-gate 	(void) ct_tmpl_clear(tmpl_fd);
342*7c478bd9Sstevel@tonic-gate 	(void) close(tmpl_fd);
343*7c478bd9Sstevel@tonic-gate 	if (waitpid(child, &child_status, 0) != child) {
344*7c478bd9Sstevel@tonic-gate 		/* unexpected: we must have been signalled */
345*7c478bd9Sstevel@tonic-gate 		(void) contract_abandon_id(ct);
346*7c478bd9Sstevel@tonic-gate 		return (-1);
347*7c478bd9Sstevel@tonic-gate 	}
348*7c478bd9Sstevel@tonic-gate 	(void) contract_abandon_id(ct);
349*7c478bd9Sstevel@tonic-gate 	if (WEXITSTATUS(child_status) != 0) {
350*7c478bd9Sstevel@tonic-gate 		errno = WEXITSTATUS(child_status);
351*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "mount of %s failed", dir);
352*7c478bd9Sstevel@tonic-gate 		return (-1);
353*7c478bd9Sstevel@tonic-gate 	}
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	return (0);
356*7c478bd9Sstevel@tonic-gate }
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate static int
359*7c478bd9Sstevel@tonic-gate zone_bootup(zlog_t *zlogp, const char *bootargs)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
362*7c478bd9Sstevel@tonic-gate 	struct stat st;
363*7c478bd9Sstevel@tonic-gate 	char zroot[MAXPATHLEN], initpath[MAXPATHLEN];
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if (init_console_slave(zlogp) != 0)
366*7c478bd9Sstevel@tonic-gate 		return (-1);
367*7c478bd9Sstevel@tonic-gate 	reset_slave_terminal(zlogp);
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
370*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "unable to get zoneid");
371*7c478bd9Sstevel@tonic-gate 		return (-1);
372*7c478bd9Sstevel@tonic-gate 	}
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if (mount_early_fs(zlogp, zoneid, "/proc", "/proc", "proc") != 0)
375*7c478bd9Sstevel@tonic-gate 		return (-1);
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	if (mount_early_fs(zlogp, zoneid, "ctfs", CTFS_ROOT, "ctfs") != 0)
378*7c478bd9Sstevel@tonic-gate 		return (-1);
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (mount_early_fs(zlogp, zoneid, "swap", "/etc/svc/volatile",
381*7c478bd9Sstevel@tonic-gate 	    "tmpfs") != 0)
382*7c478bd9Sstevel@tonic-gate 		return (-1);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (mount_early_fs(zlogp, zoneid, "mnttab", "/etc/mnttab",
385*7c478bd9Sstevel@tonic-gate 	    "mntfs") != 0)
386*7c478bd9Sstevel@tonic-gate 		return (-1);
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	/*
389*7c478bd9Sstevel@tonic-gate 	 * Try to anticipate possible problems: Make sure init is executable.
390*7c478bd9Sstevel@tonic-gate 	 */
391*7c478bd9Sstevel@tonic-gate 	if (zone_get_rootpath(zone_name, zroot, sizeof (zroot)) != Z_OK) {
392*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "unable to determine zone root");
393*7c478bd9Sstevel@tonic-gate 		return (-1);
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 	(void) snprintf(initpath, sizeof (initpath), "%s%s", zroot,
396*7c478bd9Sstevel@tonic-gate 	    PATH_TO_INIT);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	if (stat(initpath, &st) == -1) {
399*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "could not stat %s", initpath);
400*7c478bd9Sstevel@tonic-gate 		return (-1);
401*7c478bd9Sstevel@tonic-gate 	}
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	if ((st.st_mode & S_IXUSR) == 0) {
404*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "%s is not executable", initpath);
405*7c478bd9Sstevel@tonic-gate 		return (-1);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (zone_boot(zoneid, bootargs) == -1) {
409*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "unable to boot zone");
410*7c478bd9Sstevel@tonic-gate 		return (-1);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	return (0);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate static int
417*7c478bd9Sstevel@tonic-gate zone_halt(zlog_t *zlogp)
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	int err;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	if (vplat_teardown(zlogp) != 0) {
422*7c478bd9Sstevel@tonic-gate 		if (!bringup_failure_recovery)
423*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "unable to destroy zone");
424*7c478bd9Sstevel@tonic-gate 		return (-1);
425*7c478bd9Sstevel@tonic-gate 	}
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
428*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "destroying snapshot: %s",
429*7c478bd9Sstevel@tonic-gate 		    zonecfg_strerror(err));
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	return (0);
432*7c478bd9Sstevel@tonic-gate }
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate /*
435*7c478bd9Sstevel@tonic-gate  * Generate AUE_zone_state for a command that boots a zone.
436*7c478bd9Sstevel@tonic-gate  */
437*7c478bd9Sstevel@tonic-gate static void
438*7c478bd9Sstevel@tonic-gate audit_put_record(zlog_t *zlogp, ucred_t *uc, int return_val,
439*7c478bd9Sstevel@tonic-gate     char *new_state)
440*7c478bd9Sstevel@tonic-gate {
441*7c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;
442*7c478bd9Sstevel@tonic-gate 	adt_event_data_t	*event;
443*7c478bd9Sstevel@tonic-gate 	int			pass_fail, fail_reason;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	if (!adt_audit_enabled())
446*7c478bd9Sstevel@tonic-gate 		return;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (return_val == 0) {
449*7c478bd9Sstevel@tonic-gate 		pass_fail = ADT_SUCCESS;
450*7c478bd9Sstevel@tonic-gate 		fail_reason = ADT_SUCCESS;
451*7c478bd9Sstevel@tonic-gate 	} else {
452*7c478bd9Sstevel@tonic-gate 		pass_fail = ADT_FAILURE;
453*7c478bd9Sstevel@tonic-gate 		fail_reason = ADT_FAIL_VALUE_PROGRAM;
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, 0)) {
457*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, gettext("audit failure."));
458*7c478bd9Sstevel@tonic-gate 		return;
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 	if (adt_set_from_ucred(ah, uc, ADT_NEW)) {
461*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, gettext("audit failure."));
462*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
463*7c478bd9Sstevel@tonic-gate 		return;
464*7c478bd9Sstevel@tonic-gate 	}
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	event = adt_alloc_event(ah, ADT_zone_state);
467*7c478bd9Sstevel@tonic-gate 	if (event == NULL) {
468*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, gettext("audit failure."));
469*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
470*7c478bd9Sstevel@tonic-gate 		return;
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 	event->adt_zone_state.zonename = zone_name;
473*7c478bd9Sstevel@tonic-gate 	event->adt_zone_state.new_state = new_state;
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if (adt_put_event(event, pass_fail, fail_reason))
476*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, gettext("audit failure."));
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	adt_free_event(event);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate /*
484*7c478bd9Sstevel@tonic-gate  * The main routine for the door server that deals with zone state transitions.
485*7c478bd9Sstevel@tonic-gate  */
486*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
487*7c478bd9Sstevel@tonic-gate static void
488*7c478bd9Sstevel@tonic-gate server(void *cookie, char *args, size_t alen, door_desc_t *dp,
489*7c478bd9Sstevel@tonic-gate     uint_t n_desc)
490*7c478bd9Sstevel@tonic-gate {
491*7c478bd9Sstevel@tonic-gate 	ucred_t *uc = NULL;
492*7c478bd9Sstevel@tonic-gate 	const priv_set_t *eset;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	zone_state_t zstate;
495*7c478bd9Sstevel@tonic-gate 	zone_cmd_t cmd;
496*7c478bd9Sstevel@tonic-gate 	zone_cmd_arg_t *zargp;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	boolean_t kernelcall;
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	int rval = -1;
501*7c478bd9Sstevel@tonic-gate 	uint64_t uniqid;
502*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = -1;
503*7c478bd9Sstevel@tonic-gate 	zlog_t zlog;
504*7c478bd9Sstevel@tonic-gate 	zlog_t *zlogp;
505*7c478bd9Sstevel@tonic-gate 	zone_cmd_rval_t *rvalp;
506*7c478bd9Sstevel@tonic-gate 	size_t rlen = getpagesize(); /* conservative */
507*7c478bd9Sstevel@tonic-gate 	char *cmd_str = NULL;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	/* LINTED E_BAD_PTR_CAST_ALIGN */
510*7c478bd9Sstevel@tonic-gate 	zargp = (zone_cmd_arg_t *)args;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/*
513*7c478bd9Sstevel@tonic-gate 	 * When we get the door unref message, we've fdetach'd the door, and
514*7c478bd9Sstevel@tonic-gate 	 * it is time for us to shut down zoneadmd.
515*7c478bd9Sstevel@tonic-gate 	 */
516*7c478bd9Sstevel@tonic-gate 	if (zargp == DOOR_UNREF_DATA) {
517*7c478bd9Sstevel@tonic-gate 		/*
518*7c478bd9Sstevel@tonic-gate 		 * See comment at end of main() for info on the last rites.
519*7c478bd9Sstevel@tonic-gate 		 */
520*7c478bd9Sstevel@tonic-gate 		exit(0);
521*7c478bd9Sstevel@tonic-gate 	}
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 	if (zargp == NULL) {
524*7c478bd9Sstevel@tonic-gate 		(void) door_return(NULL, 0, 0, 0);
525*7c478bd9Sstevel@tonic-gate 	}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	rvalp = alloca(rlen);
528*7c478bd9Sstevel@tonic-gate 	bzero(rvalp, rlen);
529*7c478bd9Sstevel@tonic-gate 	zlog.logfile = NULL;
530*7c478bd9Sstevel@tonic-gate 	zlog.buflen = zlog.loglen = rlen - sizeof (zone_cmd_rval_t) + 1;
531*7c478bd9Sstevel@tonic-gate 	zlog.buf = rvalp->errbuf;
532*7c478bd9Sstevel@tonic-gate 	zlog.log = zlog.buf;
533*7c478bd9Sstevel@tonic-gate 	/* defer initialization of zlog.locale until after credential check */
534*7c478bd9Sstevel@tonic-gate 	zlogp = &zlog;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if (alen != sizeof (zone_cmd_arg_t)) {
537*7c478bd9Sstevel@tonic-gate 		/*
538*7c478bd9Sstevel@tonic-gate 		 * This really shouldn't be happening.
539*7c478bd9Sstevel@tonic-gate 		 */
540*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_FALSE, "invalid argument");
541*7c478bd9Sstevel@tonic-gate 		goto out;
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 	cmd = zargp->cmd;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	if (door_ucred(&uc) != 0) {
546*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_TRUE, "door_ucred");
547*7c478bd9Sstevel@tonic-gate 		goto out;
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 	eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
550*7c478bd9Sstevel@tonic-gate 	if (ucred_getzoneid(uc) != GLOBAL_ZONEID ||
551*7c478bd9Sstevel@tonic-gate 	    (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) :
552*7c478bd9Sstevel@tonic-gate 	    ucred_geteuid(uc) != 0)) {
553*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_FALSE, "insufficient privileges");
554*7c478bd9Sstevel@tonic-gate 		goto out;
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	kernelcall = ucred_getpid(uc) == 0;
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	/*
560*7c478bd9Sstevel@tonic-gate 	 * This is safe because we only use a zlog_t throughout the
561*7c478bd9Sstevel@tonic-gate 	 * duration of a door call; i.e., by the time the pointer
562*7c478bd9Sstevel@tonic-gate 	 * might become invalid, the door call would be over.
563*7c478bd9Sstevel@tonic-gate 	 */
564*7c478bd9Sstevel@tonic-gate 	zlog.locale = kernelcall ? DEFAULT_LOCALE : zargp->locale;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lock);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	/*
569*7c478bd9Sstevel@tonic-gate 	 * Once we start to really die off, we don't want more connections.
570*7c478bd9Sstevel@tonic-gate 	 */
571*7c478bd9Sstevel@tonic-gate 	if (in_death_throes) {
572*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&lock);
573*7c478bd9Sstevel@tonic-gate 		ucred_free(uc);
574*7c478bd9Sstevel@tonic-gate 		(void) door_return(NULL, 0, 0, 0);
575*7c478bd9Sstevel@tonic-gate 		thr_exit(NULL);
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/*
579*7c478bd9Sstevel@tonic-gate 	 * Check for validity of command.
580*7c478bd9Sstevel@tonic-gate 	 */
581*7c478bd9Sstevel@tonic-gate 	if (cmd != Z_READY && cmd != Z_BOOT && cmd != Z_REBOOT &&
582*7c478bd9Sstevel@tonic-gate 	    cmd != Z_HALT && cmd != Z_NOTE_UNINSTALLING) {
583*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_FALSE, "invalid command");
584*7c478bd9Sstevel@tonic-gate 		goto out;
585*7c478bd9Sstevel@tonic-gate 	}
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	if (kernelcall && (cmd != Z_HALT && cmd != Z_REBOOT)) {
588*7c478bd9Sstevel@tonic-gate 		/*
589*7c478bd9Sstevel@tonic-gate 		 * Can't happen
590*7c478bd9Sstevel@tonic-gate 		 */
591*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_FALSE, "received unexpected kernel upcall %d",
592*7c478bd9Sstevel@tonic-gate 		    cmd);
593*7c478bd9Sstevel@tonic-gate 		goto out;
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate 	/*
596*7c478bd9Sstevel@tonic-gate 	 * We ignore the possibility of someone calling zone_create(2)
597*7c478bd9Sstevel@tonic-gate 	 * explicitly; all requests must come through zoneadmd.
598*7c478bd9Sstevel@tonic-gate 	 */
599*7c478bd9Sstevel@tonic-gate 	if (zone_get_state(zone_name, &zstate) != Z_OK) {
600*7c478bd9Sstevel@tonic-gate 		/*
601*7c478bd9Sstevel@tonic-gate 		 * Something terribly wrong happened
602*7c478bd9Sstevel@tonic-gate 		 */
603*7c478bd9Sstevel@tonic-gate 		zerror(&logsys, B_FALSE, "unable to determine state of zone");
604*7c478bd9Sstevel@tonic-gate 		goto out;
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (kernelcall) {
608*7c478bd9Sstevel@tonic-gate 		/*
609*7c478bd9Sstevel@tonic-gate 		 * Kernel-initiated requests may lose their validity if the
610*7c478bd9Sstevel@tonic-gate 		 * zone_t the kernel was referring to has gone away.
611*7c478bd9Sstevel@tonic-gate 		 */
612*7c478bd9Sstevel@tonic-gate 		if ((zoneid = getzoneidbyname(zone_name)) == -1 ||
613*7c478bd9Sstevel@tonic-gate 		    zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
614*7c478bd9Sstevel@tonic-gate 		    sizeof (uniqid)) == -1 || uniqid != zargp->uniqid) {
615*7c478bd9Sstevel@tonic-gate 			/*
616*7c478bd9Sstevel@tonic-gate 			 * We're not talking about the same zone. The request
617*7c478bd9Sstevel@tonic-gate 			 * must have arrived too late.  Return error.
618*7c478bd9Sstevel@tonic-gate 			 */
619*7c478bd9Sstevel@tonic-gate 			rval = -1;
620*7c478bd9Sstevel@tonic-gate 			goto out;
621*7c478bd9Sstevel@tonic-gate 		}
622*7c478bd9Sstevel@tonic-gate 		zlogp = &logsys;	/* Log errors to syslog */
623*7c478bd9Sstevel@tonic-gate 	}
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	switch (zstate) {
626*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_CONFIGURED:
627*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_INCOMPLETE:
628*7c478bd9Sstevel@tonic-gate 		/*
629*7c478bd9Sstevel@tonic-gate 		 * Not our area of expertise; we just print a nice message
630*7c478bd9Sstevel@tonic-gate 		 * and die off.
631*7c478bd9Sstevel@tonic-gate 		 */
632*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
633*7c478bd9Sstevel@tonic-gate 		case Z_READY:
634*7c478bd9Sstevel@tonic-gate 			cmd_str = "ready";
635*7c478bd9Sstevel@tonic-gate 			break;
636*7c478bd9Sstevel@tonic-gate 		case Z_BOOT:
637*7c478bd9Sstevel@tonic-gate 			cmd_str = "boot";
638*7c478bd9Sstevel@tonic-gate 			break;
639*7c478bd9Sstevel@tonic-gate 		case Z_HALT:
640*7c478bd9Sstevel@tonic-gate 			cmd_str = "halt";
641*7c478bd9Sstevel@tonic-gate 			break;
642*7c478bd9Sstevel@tonic-gate 		case Z_REBOOT:
643*7c478bd9Sstevel@tonic-gate 			cmd_str = "reboot";
644*7c478bd9Sstevel@tonic-gate 			break;
645*7c478bd9Sstevel@tonic-gate 		}
646*7c478bd9Sstevel@tonic-gate 		assert(cmd_str != NULL);
647*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE,
648*7c478bd9Sstevel@tonic-gate 		    "%s operation is invalid for zones in state '%s'",
649*7c478bd9Sstevel@tonic-gate 		    cmd_str, zone_state_str(zstate));
650*7c478bd9Sstevel@tonic-gate 		break;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_INSTALLED:
653*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
654*7c478bd9Sstevel@tonic-gate 		case Z_READY:
655*7c478bd9Sstevel@tonic-gate 			rval = zone_ready(zlogp);
656*7c478bd9Sstevel@tonic-gate 			if (rval == 0)
657*7c478bd9Sstevel@tonic-gate 				eventstream_write(Z_EVT_ZONE_READIED);
658*7c478bd9Sstevel@tonic-gate 			break;
659*7c478bd9Sstevel@tonic-gate 		case Z_BOOT:
660*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_BOOTING);
661*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_ready(zlogp)) == 0)
662*7c478bd9Sstevel@tonic-gate 				rval = zone_bootup(zlogp, zargp->bootbuf);
663*7c478bd9Sstevel@tonic-gate 			audit_put_record(zlogp, uc, rval, "boot");
664*7c478bd9Sstevel@tonic-gate 			if (rval != 0) {
665*7c478bd9Sstevel@tonic-gate 				bringup_failure_recovery = B_TRUE;
666*7c478bd9Sstevel@tonic-gate 				(void) zone_halt(zlogp);
667*7c478bd9Sstevel@tonic-gate 			}
668*7c478bd9Sstevel@tonic-gate 			break;
669*7c478bd9Sstevel@tonic-gate 		case Z_HALT:
670*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
671*7c478bd9Sstevel@tonic-gate 				abort();
672*7c478bd9Sstevel@tonic-gate 			/*
673*7c478bd9Sstevel@tonic-gate 			 * We could have two clients racing to halt this
674*7c478bd9Sstevel@tonic-gate 			 * zone; the second client loses, but his request
675*7c478bd9Sstevel@tonic-gate 			 * doesn't fail, since the zone is now in the desired
676*7c478bd9Sstevel@tonic-gate 			 * state.
677*7c478bd9Sstevel@tonic-gate 			 */
678*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "zone is already halted");
679*7c478bd9Sstevel@tonic-gate 			rval = 0;
680*7c478bd9Sstevel@tonic-gate 			break;
681*7c478bd9Sstevel@tonic-gate 		case Z_REBOOT:
682*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
683*7c478bd9Sstevel@tonic-gate 				abort();
684*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "%s operation is invalid "
685*7c478bd9Sstevel@tonic-gate 			    "for zones in state '%s'", "reboot",
686*7c478bd9Sstevel@tonic-gate 			    zone_state_str(zstate));
687*7c478bd9Sstevel@tonic-gate 			rval = -1;
688*7c478bd9Sstevel@tonic-gate 			break;
689*7c478bd9Sstevel@tonic-gate 		case Z_NOTE_UNINSTALLING:
690*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
691*7c478bd9Sstevel@tonic-gate 				abort();
692*7c478bd9Sstevel@tonic-gate 			/*
693*7c478bd9Sstevel@tonic-gate 			 * Tell the console to print out a message about this.
694*7c478bd9Sstevel@tonic-gate 			 * Once it does, we will be in_death_throes.
695*7c478bd9Sstevel@tonic-gate 			 */
696*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_UNINSTALLING);
697*7c478bd9Sstevel@tonic-gate 			break;
698*7c478bd9Sstevel@tonic-gate 		}
699*7c478bd9Sstevel@tonic-gate 		break;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_READY:
702*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
703*7c478bd9Sstevel@tonic-gate 		case Z_READY:
704*7c478bd9Sstevel@tonic-gate 			/*
705*7c478bd9Sstevel@tonic-gate 			 * We could have two clients racing to ready this
706*7c478bd9Sstevel@tonic-gate 			 * zone; the second client loses, but his request
707*7c478bd9Sstevel@tonic-gate 			 * doesn't fail, since the zone is now in the desired
708*7c478bd9Sstevel@tonic-gate 			 * state.
709*7c478bd9Sstevel@tonic-gate 			 */
710*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "zone is already ready");
711*7c478bd9Sstevel@tonic-gate 			rval = 0;
712*7c478bd9Sstevel@tonic-gate 			break;
713*7c478bd9Sstevel@tonic-gate 		case Z_BOOT:
714*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_BOOTING);
715*7c478bd9Sstevel@tonic-gate 			rval = zone_bootup(zlogp, zargp->bootbuf);
716*7c478bd9Sstevel@tonic-gate 			audit_put_record(zlogp, uc, rval, "boot");
717*7c478bd9Sstevel@tonic-gate 			if (rval != 0) {
718*7c478bd9Sstevel@tonic-gate 				bringup_failure_recovery = B_TRUE;
719*7c478bd9Sstevel@tonic-gate 				(void) zone_halt(zlogp);
720*7c478bd9Sstevel@tonic-gate 			}
721*7c478bd9Sstevel@tonic-gate 			break;
722*7c478bd9Sstevel@tonic-gate 		case Z_HALT:
723*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
724*7c478bd9Sstevel@tonic-gate 				abort();
725*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_halt(zlogp)) != 0)
726*7c478bd9Sstevel@tonic-gate 				break;
727*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_HALTED);
728*7c478bd9Sstevel@tonic-gate 			break;
729*7c478bd9Sstevel@tonic-gate 		case Z_REBOOT:
730*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
731*7c478bd9Sstevel@tonic-gate 				abort();
732*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "%s operation is invalid "
733*7c478bd9Sstevel@tonic-gate 			    "for zones in state '%s'", "reboot",
734*7c478bd9Sstevel@tonic-gate 			    zone_state_str(zstate));
735*7c478bd9Sstevel@tonic-gate 			rval = -1;
736*7c478bd9Sstevel@tonic-gate 			break;
737*7c478bd9Sstevel@tonic-gate 		case Z_NOTE_UNINSTALLING:
738*7c478bd9Sstevel@tonic-gate 			if (kernelcall)	/* Invalid; can't happen */
739*7c478bd9Sstevel@tonic-gate 				abort();
740*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "%s operation is "
741*7c478bd9Sstevel@tonic-gate 			    "invalid for zones in state '%s'",
742*7c478bd9Sstevel@tonic-gate 			    "note_uninstall", zone_state_str(zstate));
743*7c478bd9Sstevel@tonic-gate 			rval = -1;
744*7c478bd9Sstevel@tonic-gate 			break;
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 		break;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_RUNNING:
749*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_SHUTTING_DOWN:
750*7c478bd9Sstevel@tonic-gate 	case ZONE_STATE_DOWN:
751*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
752*7c478bd9Sstevel@tonic-gate 		case Z_READY:
753*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_halt(zlogp)) != 0)
754*7c478bd9Sstevel@tonic-gate 				break;
755*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_ready(zlogp)) == 0)
756*7c478bd9Sstevel@tonic-gate 				eventstream_write(Z_EVT_ZONE_READIED);
757*7c478bd9Sstevel@tonic-gate 			break;
758*7c478bd9Sstevel@tonic-gate 		case Z_BOOT:
759*7c478bd9Sstevel@tonic-gate 			/*
760*7c478bd9Sstevel@tonic-gate 			 * We could have two clients racing to boot this
761*7c478bd9Sstevel@tonic-gate 			 * zone; the second client loses, but his request
762*7c478bd9Sstevel@tonic-gate 			 * doesn't fail, since the zone is now in the desired
763*7c478bd9Sstevel@tonic-gate 			 * state.
764*7c478bd9Sstevel@tonic-gate 			 */
765*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "zone is already booted");
766*7c478bd9Sstevel@tonic-gate 			rval = 0;
767*7c478bd9Sstevel@tonic-gate 			break;
768*7c478bd9Sstevel@tonic-gate 		case Z_HALT:
769*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_halt(zlogp)) != 0)
770*7c478bd9Sstevel@tonic-gate 				break;
771*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_HALTED);
772*7c478bd9Sstevel@tonic-gate 			break;
773*7c478bd9Sstevel@tonic-gate 		case Z_REBOOT:
774*7c478bd9Sstevel@tonic-gate 			eventstream_write(Z_EVT_ZONE_REBOOTING);
775*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_halt(zlogp)) != 0)
776*7c478bd9Sstevel@tonic-gate 				break;
777*7c478bd9Sstevel@tonic-gate 			if ((rval = zone_ready(zlogp)) == 0) {
778*7c478bd9Sstevel@tonic-gate 				rval = zone_bootup(zlogp, "");
779*7c478bd9Sstevel@tonic-gate 				audit_put_record(zlogp, uc, rval, "reboot");
780*7c478bd9Sstevel@tonic-gate 				if (rval != 0)
781*7c478bd9Sstevel@tonic-gate 					(void) zone_halt(zlogp);
782*7c478bd9Sstevel@tonic-gate 			}
783*7c478bd9Sstevel@tonic-gate 			break;
784*7c478bd9Sstevel@tonic-gate 		case Z_NOTE_UNINSTALLING:
785*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE, "%s operation is "
786*7c478bd9Sstevel@tonic-gate 			    "invalid for zones in state '%s'",
787*7c478bd9Sstevel@tonic-gate 			    "note_uninstall", zone_state_str(zstate));
788*7c478bd9Sstevel@tonic-gate 			rval = -1;
789*7c478bd9Sstevel@tonic-gate 			break;
790*7c478bd9Sstevel@tonic-gate 		}
791*7c478bd9Sstevel@tonic-gate 		break;
792*7c478bd9Sstevel@tonic-gate 	default:
793*7c478bd9Sstevel@tonic-gate 		abort();
794*7c478bd9Sstevel@tonic-gate 	}
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	/*
797*7c478bd9Sstevel@tonic-gate 	 * Because the state of the zone may have changed, we make sure
798*7c478bd9Sstevel@tonic-gate 	 * to wake the console poller, which is in charge of initiating
799*7c478bd9Sstevel@tonic-gate 	 * the shutdown procedure as necessary.
800*7c478bd9Sstevel@tonic-gate 	 */
801*7c478bd9Sstevel@tonic-gate 	eventstream_write(Z_EVT_NULL);
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate out:
804*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lock);
805*7c478bd9Sstevel@tonic-gate 	if (kernelcall) {
806*7c478bd9Sstevel@tonic-gate 		rvalp = NULL;
807*7c478bd9Sstevel@tonic-gate 		rlen = 0;
808*7c478bd9Sstevel@tonic-gate 	} else {
809*7c478bd9Sstevel@tonic-gate 		rvalp->rval = rval;
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 	if (uc != NULL)
812*7c478bd9Sstevel@tonic-gate 		ucred_free(uc);
813*7c478bd9Sstevel@tonic-gate 	(void) door_return((char *)rvalp, rlen, NULL, 0);
814*7c478bd9Sstevel@tonic-gate 	thr_exit(NULL);
815*7c478bd9Sstevel@tonic-gate }
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate static int
818*7c478bd9Sstevel@tonic-gate setup_door(zlog_t *zlogp)
819*7c478bd9Sstevel@tonic-gate {
820*7c478bd9Sstevel@tonic-gate 	if ((zone_door = door_create(server, NULL,
821*7c478bd9Sstevel@tonic-gate 	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
822*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "%s failed", "door_create");
823*7c478bd9Sstevel@tonic-gate 		return (-1);
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 	(void) fdetach(zone_door_path);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	if (fattach(zone_door, zone_door_path) != 0) {
828*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "fattach to %s failed", zone_door_path);
829*7c478bd9Sstevel@tonic-gate 		(void) door_revoke(zone_door);
830*7c478bd9Sstevel@tonic-gate 		(void) fdetach(zone_door_path);
831*7c478bd9Sstevel@tonic-gate 		zone_door = -1;
832*7c478bd9Sstevel@tonic-gate 		return (-1);
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 	return (0);
835*7c478bd9Sstevel@tonic-gate }
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate /*
838*7c478bd9Sstevel@tonic-gate  * zoneadm(1m) will start zoneadmd if it thinks it isn't running; this
839*7c478bd9Sstevel@tonic-gate  * is where zoneadmd itself will check to see that another instance of
840*7c478bd9Sstevel@tonic-gate  * zoneadmd isn't already controlling this zone.
841*7c478bd9Sstevel@tonic-gate  *
842*7c478bd9Sstevel@tonic-gate  * The idea here is that we want to open the path to which we will
843*7c478bd9Sstevel@tonic-gate  * attach our door, lock it, and then make sure that no-one has beat us
844*7c478bd9Sstevel@tonic-gate  * to fattach(3c)ing onto it.
845*7c478bd9Sstevel@tonic-gate  *
846*7c478bd9Sstevel@tonic-gate  * fattach(3c) is really a mount, so there are actually two possible
847*7c478bd9Sstevel@tonic-gate  * vnodes we could be dealing with.  Our strategy is as follows:
848*7c478bd9Sstevel@tonic-gate  *
849*7c478bd9Sstevel@tonic-gate  * - If the file we opened is a regular file (common case):
850*7c478bd9Sstevel@tonic-gate  * 	There is no fattach(3c)ed door, so we have a chance of becoming
851*7c478bd9Sstevel@tonic-gate  * 	the managing zoneadmd. We attempt to lock the file: if it is
852*7c478bd9Sstevel@tonic-gate  * 	already locked, that means someone else raced us here, so we
853*7c478bd9Sstevel@tonic-gate  * 	lose and give up.  zoneadm(1m) will try to contact the zoneadmd
854*7c478bd9Sstevel@tonic-gate  * 	that beat us to it.
855*7c478bd9Sstevel@tonic-gate  *
856*7c478bd9Sstevel@tonic-gate  * - If the file we opened is a namefs file:
857*7c478bd9Sstevel@tonic-gate  * 	This means there is already an established door fattach(3c)'ed
858*7c478bd9Sstevel@tonic-gate  * 	to the rendezvous path.  We've lost the race, so we give up.
859*7c478bd9Sstevel@tonic-gate  * 	Note that in this case we also try to grab the file lock, and
860*7c478bd9Sstevel@tonic-gate  * 	will succeed in acquiring it since the vnode locked by the
861*7c478bd9Sstevel@tonic-gate  * 	"winning" zoneadmd was a regular one, and the one we locked was
862*7c478bd9Sstevel@tonic-gate  * 	the fattach(3c)'ed door node.  At any rate, no harm is done, and
863*7c478bd9Sstevel@tonic-gate  * 	we just return to zoneadm(1m) which knows to retry.
864*7c478bd9Sstevel@tonic-gate  */
865*7c478bd9Sstevel@tonic-gate static int
866*7c478bd9Sstevel@tonic-gate make_daemon_exclusive(zlog_t *zlogp)
867*7c478bd9Sstevel@tonic-gate {
868*7c478bd9Sstevel@tonic-gate 	int doorfd = -1;
869*7c478bd9Sstevel@tonic-gate 	int err, ret = -1;
870*7c478bd9Sstevel@tonic-gate 	struct stat st;
871*7c478bd9Sstevel@tonic-gate 	struct flock flock;
872*7c478bd9Sstevel@tonic-gate 	zone_state_t zstate;
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate top:
875*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_state(zone_name, &zstate)) != Z_OK) {
876*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "failed to get zone state: %s\n",
877*7c478bd9Sstevel@tonic-gate 		    zonecfg_strerror(err));
878*7c478bd9Sstevel@tonic-gate 		goto out;
879*7c478bd9Sstevel@tonic-gate 	}
880*7c478bd9Sstevel@tonic-gate 	if ((doorfd = open(zone_door_path, O_CREAT|O_RDWR,
881*7c478bd9Sstevel@tonic-gate 	    S_IREAD|S_IWRITE)) < 0) {
882*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "failed to open %s", zone_door_path);
883*7c478bd9Sstevel@tonic-gate 		goto out;
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate 	if (fstat(doorfd, &st) < 0) {
886*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "failed to stat %s", zone_door_path);
887*7c478bd9Sstevel@tonic-gate 		goto out;
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 	/*
890*7c478bd9Sstevel@tonic-gate 	 * Lock the file to synchronize with other zoneadmd
891*7c478bd9Sstevel@tonic-gate 	 */
892*7c478bd9Sstevel@tonic-gate 	flock.l_type = F_WRLCK;
893*7c478bd9Sstevel@tonic-gate 	flock.l_whence = SEEK_SET;
894*7c478bd9Sstevel@tonic-gate 	flock.l_start = (off_t)0;
895*7c478bd9Sstevel@tonic-gate 	flock.l_len = (off_t)0;
896*7c478bd9Sstevel@tonic-gate 	if (fcntl(doorfd, F_SETLK, &flock) < 0) {
897*7c478bd9Sstevel@tonic-gate 		/*
898*7c478bd9Sstevel@tonic-gate 		 * Someone else raced us here and grabbed the lock file
899*7c478bd9Sstevel@tonic-gate 		 * first.  A warning here is inappropriate since nothing
900*7c478bd9Sstevel@tonic-gate 		 * went wrong.
901*7c478bd9Sstevel@tonic-gate 		 */
902*7c478bd9Sstevel@tonic-gate 		goto out;
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	if (strcmp(st.st_fstype, "namefs") == 0) {
906*7c478bd9Sstevel@tonic-gate 		struct door_info info;
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 		/*
909*7c478bd9Sstevel@tonic-gate 		 * There is already something fattach()'ed to this file.
910*7c478bd9Sstevel@tonic-gate 		 * Lets see what the door is up to.
911*7c478bd9Sstevel@tonic-gate 		 */
912*7c478bd9Sstevel@tonic-gate 		if (door_info(doorfd, &info) == 0 && info.di_target != -1) {
913*7c478bd9Sstevel@tonic-gate 			/*
914*7c478bd9Sstevel@tonic-gate 			 * Another zoneadmd process seems to be in
915*7c478bd9Sstevel@tonic-gate 			 * control of the situation and we don't need to
916*7c478bd9Sstevel@tonic-gate 			 * be here.  A warning here is inappropriate
917*7c478bd9Sstevel@tonic-gate 			 * since nothing went wrong.
918*7c478bd9Sstevel@tonic-gate 			 *
919*7c478bd9Sstevel@tonic-gate 			 * If the door has been revoked, the zoneadmd
920*7c478bd9Sstevel@tonic-gate 			 * process currently managing the zone is going
921*7c478bd9Sstevel@tonic-gate 			 * away.  We'll return control to zoneadm(1m)
922*7c478bd9Sstevel@tonic-gate 			 * which will try again (by which time zoneadmd
923*7c478bd9Sstevel@tonic-gate 			 * will hopefully have exited).
924*7c478bd9Sstevel@tonic-gate 			 */
925*7c478bd9Sstevel@tonic-gate 			goto out;
926*7c478bd9Sstevel@tonic-gate 		}
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 		/*
929*7c478bd9Sstevel@tonic-gate 		 * If we got this far, there's a fattach(3c)'ed door
930*7c478bd9Sstevel@tonic-gate 		 * that belongs to a process that has exited, which can
931*7c478bd9Sstevel@tonic-gate 		 * happen if the previous zoneadmd died unexpectedly.
932*7c478bd9Sstevel@tonic-gate 		 *
933*7c478bd9Sstevel@tonic-gate 		 * Let user know that something is amiss, but that we can
934*7c478bd9Sstevel@tonic-gate 		 * recover; if the zone is in the installed state, then don't
935*7c478bd9Sstevel@tonic-gate 		 * message, since having a running zoneadmd isn't really
936*7c478bd9Sstevel@tonic-gate 		 * expected/needed.  We want to keep occurences of this message
937*7c478bd9Sstevel@tonic-gate 		 * limited to times when zoneadmd is picking back up from a
938*7c478bd9Sstevel@tonic-gate 		 * zoneadmd that died while the zone was in some non-trivial
939*7c478bd9Sstevel@tonic-gate 		 * state.
940*7c478bd9Sstevel@tonic-gate 		 */
941*7c478bd9Sstevel@tonic-gate 		if (zstate > ZONE_STATE_INSTALLED) {
942*7c478bd9Sstevel@tonic-gate 			zerror(zlogp, B_FALSE,
943*7c478bd9Sstevel@tonic-gate 			    "zone '%s': WARNING: zone is in state '%s', but "
944*7c478bd9Sstevel@tonic-gate 			    "zoneadmd does not appear to be available; "
945*7c478bd9Sstevel@tonic-gate 			    "restarted zoneadmd to recover.",
946*7c478bd9Sstevel@tonic-gate 			    zone_name, zone_state_str(zstate));
947*7c478bd9Sstevel@tonic-gate 		}
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 		(void) fdetach(zone_door_path);
950*7c478bd9Sstevel@tonic-gate 		(void) close(doorfd);
951*7c478bd9Sstevel@tonic-gate 		goto top;
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 	ret = 0;
954*7c478bd9Sstevel@tonic-gate out:
955*7c478bd9Sstevel@tonic-gate 	(void) close(doorfd);
956*7c478bd9Sstevel@tonic-gate 	return (ret);
957*7c478bd9Sstevel@tonic-gate }
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate int
960*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
961*7c478bd9Sstevel@tonic-gate {
962*7c478bd9Sstevel@tonic-gate 	int opt;
963*7c478bd9Sstevel@tonic-gate 	zoneid_t zid;
964*7c478bd9Sstevel@tonic-gate 	priv_set_t *privset;
965*7c478bd9Sstevel@tonic-gate 	zone_state_t zstate;
966*7c478bd9Sstevel@tonic-gate 	char parents_locale[MAXPATHLEN];
967*7c478bd9Sstevel@tonic-gate 	int err;
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	pid_t pid;
970*7c478bd9Sstevel@tonic-gate 	sigset_t blockset;
971*7c478bd9Sstevel@tonic-gate 	sigset_t block_cld;
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	struct {
974*7c478bd9Sstevel@tonic-gate 		sema_t sem;
975*7c478bd9Sstevel@tonic-gate 		int status;
976*7c478bd9Sstevel@tonic-gate 		zlog_t log;
977*7c478bd9Sstevel@tonic-gate 	} *shstate;
978*7c478bd9Sstevel@tonic-gate 	size_t shstatelen = getpagesize();
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	zlog_t errlog;
981*7c478bd9Sstevel@tonic-gate 	zlog_t *zlogp;
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	progname = get_execbasename(argv[0]);
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 	/*
986*7c478bd9Sstevel@tonic-gate 	 * Make sure stderr is unbuffered
987*7c478bd9Sstevel@tonic-gate 	 */
988*7c478bd9Sstevel@tonic-gate 	(void) setbuffer(stderr, NULL, 0);
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	/*
991*7c478bd9Sstevel@tonic-gate 	 * Get out of the way of mounted filesystems, since we will daemonize
992*7c478bd9Sstevel@tonic-gate 	 * soon.
993*7c478bd9Sstevel@tonic-gate 	 */
994*7c478bd9Sstevel@tonic-gate 	(void) chdir("/");
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	/*
997*7c478bd9Sstevel@tonic-gate 	 * Use the default system umask per PSARC 1998/110 rather than
998*7c478bd9Sstevel@tonic-gate 	 * anything that may have been set by the caller.
999*7c478bd9Sstevel@tonic-gate 	 */
1000*7c478bd9Sstevel@tonic-gate 	(void) umask(CMASK);
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	/*
1003*7c478bd9Sstevel@tonic-gate 	 * Initially we want to use our parent's locale.
1004*7c478bd9Sstevel@tonic-gate 	 */
1005*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1006*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1007*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(parents_locale, setlocale(LC_MESSAGES, NULL),
1008*7c478bd9Sstevel@tonic-gate 	    sizeof (parents_locale));
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	/*
1011*7c478bd9Sstevel@tonic-gate 	 * This zlog_t is used for writing to stderr
1012*7c478bd9Sstevel@tonic-gate 	 */
1013*7c478bd9Sstevel@tonic-gate 	errlog.logfile = stderr;
1014*7c478bd9Sstevel@tonic-gate 	errlog.buflen = errlog.loglen = 0;
1015*7c478bd9Sstevel@tonic-gate 	errlog.buf = errlog.log = NULL;
1016*7c478bd9Sstevel@tonic-gate 	errlog.locale = parents_locale;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	/*
1019*7c478bd9Sstevel@tonic-gate 	 * We start off writing to stderr until we're ready to daemonize.
1020*7c478bd9Sstevel@tonic-gate 	 */
1021*7c478bd9Sstevel@tonic-gate 	zlogp = &errlog;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	/*
1024*7c478bd9Sstevel@tonic-gate 	 * Process options.
1025*7c478bd9Sstevel@tonic-gate 	 */
1026*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "z:")) != EOF) {
1027*7c478bd9Sstevel@tonic-gate 		switch (opt) {
1028*7c478bd9Sstevel@tonic-gate 		case 'z':
1029*7c478bd9Sstevel@tonic-gate 			zone_name = optarg;
1030*7c478bd9Sstevel@tonic-gate 			break;
1031*7c478bd9Sstevel@tonic-gate 		default:
1032*7c478bd9Sstevel@tonic-gate 			usage();
1033*7c478bd9Sstevel@tonic-gate 		}
1034*7c478bd9Sstevel@tonic-gate 	}
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	if (zone_name == NULL)
1037*7c478bd9Sstevel@tonic-gate 		usage();
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	/*
1040*7c478bd9Sstevel@tonic-gate 	 * Because usage() prints directly to stderr, it has gettext()
1041*7c478bd9Sstevel@tonic-gate 	 * wrapping, which depends on the locale.  But since zerror() calls
1042*7c478bd9Sstevel@tonic-gate 	 * localize() which tweaks the locale, it is not safe to call zerror()
1043*7c478bd9Sstevel@tonic-gate 	 * until after the last call to usage().  Fortunately, the last call
1044*7c478bd9Sstevel@tonic-gate 	 * to usage() is just above and the first call to zerror() is just
1045*7c478bd9Sstevel@tonic-gate 	 * below.  Don't mess this up.
1046*7c478bd9Sstevel@tonic-gate 	 */
1047*7c478bd9Sstevel@tonic-gate 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
1048*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "cannot manage the %s zone",
1049*7c478bd9Sstevel@tonic-gate 		    GLOBAL_ZONENAME);
1050*7c478bd9Sstevel@tonic-gate 		return (1);
1051*7c478bd9Sstevel@tonic-gate 	}
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	if (zone_get_id(zone_name, &zid) != 0) {
1054*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "could not manage %s: %s\n", zone_name,
1055*7c478bd9Sstevel@tonic-gate 		    zonecfg_strerror(Z_NO_ZONE));
1056*7c478bd9Sstevel@tonic-gate 		return (1);
1057*7c478bd9Sstevel@tonic-gate 	}
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_state(zone_name, &zstate)) != Z_OK) {
1060*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "failed to get zone state: %s\n",
1061*7c478bd9Sstevel@tonic-gate 		    zonecfg_strerror(err));
1062*7c478bd9Sstevel@tonic-gate 		return (1);
1063*7c478bd9Sstevel@tonic-gate 	}
1064*7c478bd9Sstevel@tonic-gate 	if (zstate < ZONE_STATE_INSTALLED) {
1065*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE,
1066*7c478bd9Sstevel@tonic-gate 		    "cannot manage a zone which is in state '%s'",
1067*7c478bd9Sstevel@tonic-gate 		    zone_state_str(zstate));
1068*7c478bd9Sstevel@tonic-gate 		return (1);
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	/*
1072*7c478bd9Sstevel@tonic-gate 	 * Check that we have all privileges.  It would be nice to pare
1073*7c478bd9Sstevel@tonic-gate 	 * this down, but this is at least a first cut.
1074*7c478bd9Sstevel@tonic-gate 	 */
1075*7c478bd9Sstevel@tonic-gate 	if ((privset = priv_allocset()) == NULL) {
1076*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
1077*7c478bd9Sstevel@tonic-gate 		return (1);
1078*7c478bd9Sstevel@tonic-gate 	}
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1081*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "%s failed", "getppriv");
1082*7c478bd9Sstevel@tonic-gate 		priv_freeset(privset);
1083*7c478bd9Sstevel@tonic-gate 		return (1);
1084*7c478bd9Sstevel@tonic-gate 	}
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	if (priv_isfullset(privset) == B_FALSE) {
1087*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_FALSE, "You lack sufficient privilege to "
1088*7c478bd9Sstevel@tonic-gate 		    "run this command (all privs required)\n");
1089*7c478bd9Sstevel@tonic-gate 		priv_freeset(privset);
1090*7c478bd9Sstevel@tonic-gate 		return (1);
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate 	priv_freeset(privset);
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	if (mkzonedir(zlogp) != 0)
1095*7c478bd9Sstevel@tonic-gate 		return (1);
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 	/*
1098*7c478bd9Sstevel@tonic-gate 	 * Pre-fork: setup shared state
1099*7c478bd9Sstevel@tonic-gate 	 */
1100*7c478bd9Sstevel@tonic-gate 	if ((shstate = (void *)mmap(NULL, shstatelen,
1101*7c478bd9Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, (off_t)0)) ==
1102*7c478bd9Sstevel@tonic-gate 	    MAP_FAILED) {
1103*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "%s failed", "mmap");
1104*7c478bd9Sstevel@tonic-gate 		return (1);
1105*7c478bd9Sstevel@tonic-gate 	}
1106*7c478bd9Sstevel@tonic-gate 	if (sema_init(&shstate->sem, 0, USYNC_PROCESS, NULL) != 0) {
1107*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "%s failed", "sema_init()");
1108*7c478bd9Sstevel@tonic-gate 		(void) munmap((char *)shstate, shstatelen);
1109*7c478bd9Sstevel@tonic-gate 		return (1);
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 	shstate->log.logfile = NULL;
1112*7c478bd9Sstevel@tonic-gate 	shstate->log.buflen = shstatelen - sizeof (*shstate);
1113*7c478bd9Sstevel@tonic-gate 	shstate->log.loglen = shstate->log.buflen;
1114*7c478bd9Sstevel@tonic-gate 	shstate->log.buf = (char *)shstate + sizeof (*shstate);
1115*7c478bd9Sstevel@tonic-gate 	shstate->log.log = shstate->log.buf;
1116*7c478bd9Sstevel@tonic-gate 	shstate->log.locale = parents_locale;
1117*7c478bd9Sstevel@tonic-gate 	shstate->status = -1;
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/*
1120*7c478bd9Sstevel@tonic-gate 	 * We need a SIGCHLD handler so the sema_wait() below will wake
1121*7c478bd9Sstevel@tonic-gate 	 * up if the child dies without doing a sema_post().
1122*7c478bd9Sstevel@tonic-gate 	 */
1123*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCHLD, sigchld);
1124*7c478bd9Sstevel@tonic-gate 	/*
1125*7c478bd9Sstevel@tonic-gate 	 * We must mask SIGCHLD until after we've coped with the fork
1126*7c478bd9Sstevel@tonic-gate 	 * sufficiently to deal with it; otherwise we can race and
1127*7c478bd9Sstevel@tonic-gate 	 * receive the signal before pid has been initialized
1128*7c478bd9Sstevel@tonic-gate 	 * (yes, this really happens).
1129*7c478bd9Sstevel@tonic-gate 	 */
1130*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&block_cld);
1131*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&block_cld, SIGCHLD);
1132*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block_cld, NULL);
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	/*
1135*7c478bd9Sstevel@tonic-gate 	 * Do not let another thread localize a message while we are forking.
1136*7c478bd9Sstevel@tonic-gate 	 */
1137*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&msglock);
1138*7c478bd9Sstevel@tonic-gate 	pid = fork();
1139*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&msglock);
1140*7c478bd9Sstevel@tonic-gate 	if (pid == -1) {
1141*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "could not fork");
1142*7c478bd9Sstevel@tonic-gate 		return (1);
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 	} else if (pid > 0) { /* parent */
1145*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1146*7c478bd9Sstevel@tonic-gate 		/*
1147*7c478bd9Sstevel@tonic-gate 		 * This marks a window of vulnerability in which we receive
1148*7c478bd9Sstevel@tonic-gate 		 * the SIGCLD before falling into sema_wait (normally we would
1149*7c478bd9Sstevel@tonic-gate 		 * get woken up from sema_wait with EINTR upon receipt of
1150*7c478bd9Sstevel@tonic-gate 		 * SIGCLD).  So we may need to use some other scheme like
1151*7c478bd9Sstevel@tonic-gate 		 * sema_posting in the sigcld handler.
1152*7c478bd9Sstevel@tonic-gate 		 * blech
1153*7c478bd9Sstevel@tonic-gate 		 */
1154*7c478bd9Sstevel@tonic-gate 		(void) sema_wait(&shstate->sem);
1155*7c478bd9Sstevel@tonic-gate 		(void) sema_destroy(&shstate->sem);
1156*7c478bd9Sstevel@tonic-gate 		if (shstate->status != 0)
1157*7c478bd9Sstevel@tonic-gate 			(void) waitpid(pid, NULL, WNOHANG);
1158*7c478bd9Sstevel@tonic-gate 		/*
1159*7c478bd9Sstevel@tonic-gate 		 * It's ok if we die with SIGPIPE.  It's not like we could have
1160*7c478bd9Sstevel@tonic-gate 		 * done anything about it.
1161*7c478bd9Sstevel@tonic-gate 		 */
1162*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s", shstate->log.buf);
1163*7c478bd9Sstevel@tonic-gate 		_exit(shstate->status == 0 ? 0 : 1);
1164*7c478bd9Sstevel@tonic-gate 	}
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	/*
1167*7c478bd9Sstevel@tonic-gate 	 * The child charges on.
1168*7c478bd9Sstevel@tonic-gate 	 */
1169*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCHLD, SIG_DFL);
1170*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	/*
1173*7c478bd9Sstevel@tonic-gate 	 * SIGPIPE can be delivered if we write to a socket for which the
1174*7c478bd9Sstevel@tonic-gate 	 * peer endpoint is gone.  That can lead to too-early termination
1175*7c478bd9Sstevel@tonic-gate 	 * of zoneadmd, and that's not good eats.
1176*7c478bd9Sstevel@tonic-gate 	 */
1177*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPIPE, SIG_IGN);
1178*7c478bd9Sstevel@tonic-gate 	/*
1179*7c478bd9Sstevel@tonic-gate 	 * Stop using stderr
1180*7c478bd9Sstevel@tonic-gate 	 */
1181*7c478bd9Sstevel@tonic-gate 	zlogp = &shstate->log;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	/*
1184*7c478bd9Sstevel@tonic-gate 	 * We don't need stdout/stderr from now on.
1185*7c478bd9Sstevel@tonic-gate 	 */
1186*7c478bd9Sstevel@tonic-gate 	closefrom(0);
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	/*
1189*7c478bd9Sstevel@tonic-gate 	 * Initialize the syslog zlog_t.  This needs to be done after
1190*7c478bd9Sstevel@tonic-gate 	 * the call to closefrom().
1191*7c478bd9Sstevel@tonic-gate 	 */
1192*7c478bd9Sstevel@tonic-gate 	logsys.buf = logsys.log = NULL;
1193*7c478bd9Sstevel@tonic-gate 	logsys.buflen = logsys.loglen = 0;
1194*7c478bd9Sstevel@tonic-gate 	logsys.logfile = NULL;
1195*7c478bd9Sstevel@tonic-gate 	logsys.locale = DEFAULT_LOCALE;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	openlog("zoneadmd", LOG_PID, LOG_DAEMON);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	/*
1200*7c478bd9Sstevel@tonic-gate 	 * The eventstream is used to publish state changes in the zone
1201*7c478bd9Sstevel@tonic-gate 	 * from the door threads to the console I/O poller.
1202*7c478bd9Sstevel@tonic-gate 	 */
1203*7c478bd9Sstevel@tonic-gate 	if (eventstream_init() == -1) {
1204*7c478bd9Sstevel@tonic-gate 		zerror(zlogp, B_TRUE, "unable to create eventstream");
1205*7c478bd9Sstevel@tonic-gate 		goto child_out;
1206*7c478bd9Sstevel@tonic-gate 	}
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	(void) snprintf(zone_door_path, sizeof (zone_door_path),
1209*7c478bd9Sstevel@tonic-gate 	    ZONE_DOOR_PATH, zone_name);
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 	/*
1212*7c478bd9Sstevel@tonic-gate 	 * See if another zoneadmd is running for this zone.  If not, then we
1213*7c478bd9Sstevel@tonic-gate 	 * can now modify system state.
1214*7c478bd9Sstevel@tonic-gate 	 */
1215*7c478bd9Sstevel@tonic-gate 	if (make_daemon_exclusive(zlogp) == -1)
1216*7c478bd9Sstevel@tonic-gate 		goto child_out;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	/*
1220*7c478bd9Sstevel@tonic-gate 	 * Create/join a new session; we need to be careful of what we do with
1221*7c478bd9Sstevel@tonic-gate 	 * the console from now on so we don't end up being the session leader
1222*7c478bd9Sstevel@tonic-gate 	 * for the terminal we're going to be handing out.
1223*7c478bd9Sstevel@tonic-gate 	 */
1224*7c478bd9Sstevel@tonic-gate 	(void) setsid();
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	/*
1227*7c478bd9Sstevel@tonic-gate 	 * This thread shouldn't be receiving any signals; in particular,
1228*7c478bd9Sstevel@tonic-gate 	 * SIGCHLD should be received by the thread doing the fork().
1229*7c478bd9Sstevel@tonic-gate 	 */
1230*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&blockset);
1231*7c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_BLOCK, &blockset, NULL);
1232*7c478bd9Sstevel@tonic-gate 
1233*7c478bd9Sstevel@tonic-gate 	/*
1234*7c478bd9Sstevel@tonic-gate 	 * Setup the console device and get ready to serve the console;
1235*7c478bd9Sstevel@tonic-gate 	 * once this has completed, we're ready to let console clients
1236*7c478bd9Sstevel@tonic-gate 	 * make an attempt to connect (they will block until
1237*7c478bd9Sstevel@tonic-gate 	 * serve_console_sock() below gets called, and any pending
1238*7c478bd9Sstevel@tonic-gate 	 * connection is accept()ed).
1239*7c478bd9Sstevel@tonic-gate 	 */
1240*7c478bd9Sstevel@tonic-gate 	if (init_console(zlogp) == -1)
1241*7c478bd9Sstevel@tonic-gate 		goto child_out;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	/*
1244*7c478bd9Sstevel@tonic-gate 	 * Take the lock now, so that when the door server gets going, we
1245*7c478bd9Sstevel@tonic-gate 	 * are guaranteed that it won't take a request until we are sure
1246*7c478bd9Sstevel@tonic-gate 	 * that everything is completely set up.  See the child_out: label
1247*7c478bd9Sstevel@tonic-gate 	 * below to see why this matters.
1248*7c478bd9Sstevel@tonic-gate 	 */
1249*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lock);
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	/*
1252*7c478bd9Sstevel@tonic-gate 	 * Note: door setup must occur *after* the console is setup.
1253*7c478bd9Sstevel@tonic-gate 	 * This is so that as zlogin tests the door to see if zoneadmd
1254*7c478bd9Sstevel@tonic-gate 	 * is ready yet, we know that the console will get serviced
1255*7c478bd9Sstevel@tonic-gate 	 * once door_info() indicates that the door is "up".
1256*7c478bd9Sstevel@tonic-gate 	 */
1257*7c478bd9Sstevel@tonic-gate 	if (setup_door(zlogp) == -1)
1258*7c478bd9Sstevel@tonic-gate 		goto child_out;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	/*
1261*7c478bd9Sstevel@tonic-gate 	 * Things seem OK so far; tell the parent process that we're done
1262*7c478bd9Sstevel@tonic-gate 	 * with setup tasks.  This will cause the parent to exit, signalling
1263*7c478bd9Sstevel@tonic-gate 	 * to zoneadm, zlogin, or whatever forked it that we are ready to
1264*7c478bd9Sstevel@tonic-gate 	 * service requests.
1265*7c478bd9Sstevel@tonic-gate 	 */
1266*7c478bd9Sstevel@tonic-gate 	shstate->status = 0;
1267*7c478bd9Sstevel@tonic-gate 	(void) sema_post(&shstate->sem);
1268*7c478bd9Sstevel@tonic-gate 	(void) munmap((char *)shstate, shstatelen);
1269*7c478bd9Sstevel@tonic-gate 	shstate = NULL;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lock);
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	/*
1274*7c478bd9Sstevel@tonic-gate 	 * zlogp is now invalid, so reset it to the syslog logger.
1275*7c478bd9Sstevel@tonic-gate 	 */
1276*7c478bd9Sstevel@tonic-gate 	zlogp = &logsys;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	/*
1279*7c478bd9Sstevel@tonic-gate 	 * Now that we are free of any parents, switch to the default locale.
1280*7c478bd9Sstevel@tonic-gate 	 */
1281*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, DEFAULT_LOCALE);
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/*
1284*7c478bd9Sstevel@tonic-gate 	 * At this point the setup portion of main() is basically done, so
1285*7c478bd9Sstevel@tonic-gate 	 * we reuse this thread to manage the zone console.  When
1286*7c478bd9Sstevel@tonic-gate 	 * serve_console() has returned, we are past the point of no return
1287*7c478bd9Sstevel@tonic-gate 	 * in the life of this zoneadmd.
1288*7c478bd9Sstevel@tonic-gate 	 */
1289*7c478bd9Sstevel@tonic-gate 	serve_console(zlogp);
1290*7c478bd9Sstevel@tonic-gate 	assert(in_death_throes);
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	/*
1293*7c478bd9Sstevel@tonic-gate 	 * This is the next-to-last part of the exit interlock.  Upon calling
1294*7c478bd9Sstevel@tonic-gate 	 * fdetach(), the door will go unreferenced; once any
1295*7c478bd9Sstevel@tonic-gate 	 * outstanding requests (like the door thread doing Z_HALT) are
1296*7c478bd9Sstevel@tonic-gate 	 * done, the door will get an UNREF notification; when it handles
1297*7c478bd9Sstevel@tonic-gate 	 * the UNREF, the door server will cause the exit.
1298*7c478bd9Sstevel@tonic-gate 	 */
1299*7c478bd9Sstevel@tonic-gate 	assert(!MUTEX_HELD(&lock));
1300*7c478bd9Sstevel@tonic-gate 	(void) fdetach(zone_door_path);
1301*7c478bd9Sstevel@tonic-gate 	for (;;)
1302*7c478bd9Sstevel@tonic-gate 		(void) pause();
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate child_out:
1305*7c478bd9Sstevel@tonic-gate 	assert(pid == 0);
1306*7c478bd9Sstevel@tonic-gate 	if (shstate != NULL) {
1307*7c478bd9Sstevel@tonic-gate 		shstate->status = -1;
1308*7c478bd9Sstevel@tonic-gate 		(void) sema_post(&shstate->sem);
1309*7c478bd9Sstevel@tonic-gate 		(void) munmap((char *)shstate, shstatelen);
1310*7c478bd9Sstevel@tonic-gate 	}
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	/*
1313*7c478bd9Sstevel@tonic-gate 	 * This might trigger an unref notification, but if so,
1314*7c478bd9Sstevel@tonic-gate 	 * we are still holding the lock, so our call to exit will
1315*7c478bd9Sstevel@tonic-gate 	 * ultimately win the race and will publish the right exit
1316*7c478bd9Sstevel@tonic-gate 	 * code.
1317*7c478bd9Sstevel@tonic-gate 	 */
1318*7c478bd9Sstevel@tonic-gate 	if (zone_door != -1) {
1319*7c478bd9Sstevel@tonic-gate 		assert(MUTEX_HELD(&lock));
1320*7c478bd9Sstevel@tonic-gate 		(void) door_revoke(zone_door);
1321*7c478bd9Sstevel@tonic-gate 		(void) fdetach(zone_door_path);
1322*7c478bd9Sstevel@tonic-gate 	}
1323*7c478bd9Sstevel@tonic-gate 	return (1); /* return from main() forcibly exits an MT process */
1324*7c478bd9Sstevel@tonic-gate }
1325