xref: /illumos-gate/usr/src/cmd/zoneadm/zoneadm.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  * zoneadm is a command interpreter for zone administration.  It is all in
31*7c478bd9Sstevel@tonic-gate  * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
32*7c478bd9Sstevel@tonic-gate  * main() calls parse_and_run() which calls cmd_match(), then invokes the
33*7c478bd9Sstevel@tonic-gate  * appropriate command's handler function.  The rest of the program is the
34*7c478bd9Sstevel@tonic-gate  * handler functions and their helper functions.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * Some of the helper functions are used largely to simplify I18N: reducing
37*7c478bd9Sstevel@tonic-gate  * the need for translation notes.  This is particularly true of many of
38*7c478bd9Sstevel@tonic-gate  * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather
39*7c478bd9Sstevel@tonic-gate  * than zerror(gettext("foo failed")) with a translation note indicating
40*7c478bd9Sstevel@tonic-gate  * that "foo" need not be translated.
41*7c478bd9Sstevel@tonic-gate  */
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <stdio.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <unistd.h>
46*7c478bd9Sstevel@tonic-gate #include <signal.h>
47*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
48*7c478bd9Sstevel@tonic-gate #include <ctype.h>
49*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
50*7c478bd9Sstevel@tonic-gate #include <string.h>
51*7c478bd9Sstevel@tonic-gate #include <wait.h>
52*7c478bd9Sstevel@tonic-gate #include <zone.h>
53*7c478bd9Sstevel@tonic-gate #include <priv.h>
54*7c478bd9Sstevel@tonic-gate #include <locale.h>
55*7c478bd9Sstevel@tonic-gate #include <libintl.h>
56*7c478bd9Sstevel@tonic-gate #include <libzonecfg.h>
57*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
63*7c478bd9Sstevel@tonic-gate #include <assert.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
66*7c478bd9Sstevel@tonic-gate #include <limits.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
69*7c478bd9Sstevel@tonic-gate #include <door.h>
70*7c478bd9Sstevel@tonic-gate #include <macros.h>
71*7c478bd9Sstevel@tonic-gate #include <libgen.h>
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #include <pool.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/pool.h>
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #define	MAXARGS	8
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /* Reflects kernel zone entries */
79*7c478bd9Sstevel@tonic-gate typedef struct zone_entry {
80*7c478bd9Sstevel@tonic-gate 	zoneid_t	zid;
81*7c478bd9Sstevel@tonic-gate 	char		zname[ZONENAME_MAX];
82*7c478bd9Sstevel@tonic-gate 	char		*zstate_str;
83*7c478bd9Sstevel@tonic-gate 	zone_state_t	zstate_num;
84*7c478bd9Sstevel@tonic-gate 	char		zroot[MAXPATHLEN];
85*7c478bd9Sstevel@tonic-gate } zone_entry_t;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate static zone_entry_t *zents;
88*7c478bd9Sstevel@tonic-gate static size_t nzents;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
91*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate #define	Z_ERR	1
95*7c478bd9Sstevel@tonic-gate #define	Z_USAGE	2
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /* 0755 is the default directory mode. */
98*7c478bd9Sstevel@tonic-gate #define	DEFAULT_DIR_MODE \
99*7c478bd9Sstevel@tonic-gate 	(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate #define	CMD_HELP	0
102*7c478bd9Sstevel@tonic-gate #define	CMD_BOOT	1
103*7c478bd9Sstevel@tonic-gate #define	CMD_HALT	2
104*7c478bd9Sstevel@tonic-gate #define	CMD_READY	3
105*7c478bd9Sstevel@tonic-gate #define	CMD_REBOOT	4
106*7c478bd9Sstevel@tonic-gate #define	CMD_LIST	5
107*7c478bd9Sstevel@tonic-gate #define	CMD_VERIFY	6
108*7c478bd9Sstevel@tonic-gate #define	CMD_INSTALL	7
109*7c478bd9Sstevel@tonic-gate #define	CMD_UNINSTALL	8
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #define	CMD_MIN		CMD_HELP
112*7c478bd9Sstevel@tonic-gate #define	CMD_MAX		CMD_UNINSTALL
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate struct cmd {
115*7c478bd9Sstevel@tonic-gate 	uint_t	cmd_num;				/* command number */
116*7c478bd9Sstevel@tonic-gate 	char	*cmd_name;				/* command name */
117*7c478bd9Sstevel@tonic-gate 	char	*short_usage;				/* short form help */
118*7c478bd9Sstevel@tonic-gate 	int	(*handler)(int argc, char *argv[]);	/* function to call */
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate };
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate #define	SHELP_HELP	"help"
123*7c478bd9Sstevel@tonic-gate #define	SHELP_BOOT	"boot [-s]"
124*7c478bd9Sstevel@tonic-gate #define	SHELP_HALT	"halt"
125*7c478bd9Sstevel@tonic-gate #define	SHELP_READY	"ready"
126*7c478bd9Sstevel@tonic-gate #define	SHELP_REBOOT	"reboot"
127*7c478bd9Sstevel@tonic-gate #define	SHELP_LIST	"list [-cipv]"
128*7c478bd9Sstevel@tonic-gate #define	SHELP_VERIFY	"verify"
129*7c478bd9Sstevel@tonic-gate #define	SHELP_INSTALL	"install"
130*7c478bd9Sstevel@tonic-gate #define	SHELP_UNINSTALL	"uninstall [-F]"
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static int help_func(int argc, char *argv[]);
133*7c478bd9Sstevel@tonic-gate static int ready_func(int argc, char *argv[]);
134*7c478bd9Sstevel@tonic-gate static int boot_func(int argc, char *argv[]);
135*7c478bd9Sstevel@tonic-gate static int halt_func(int argc, char *argv[]);
136*7c478bd9Sstevel@tonic-gate static int reboot_func(int argc, char *argv[]);
137*7c478bd9Sstevel@tonic-gate static int list_func(int argc, char *argv[]);
138*7c478bd9Sstevel@tonic-gate static int verify_func(int argc, char *argv[]);
139*7c478bd9Sstevel@tonic-gate static int install_func(int argc, char *argv[]);
140*7c478bd9Sstevel@tonic-gate static int uninstall_func(int argc, char *argv[]);
141*7c478bd9Sstevel@tonic-gate static int sanity_check(char *zone, int cmd_num, boolean_t running,
142*7c478bd9Sstevel@tonic-gate     boolean_t unsafe_when_running);
143*7c478bd9Sstevel@tonic-gate static int cmd_match(char *cmd);
144*7c478bd9Sstevel@tonic-gate static int verify_details(int);
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate static struct cmd cmdtab[] = {
147*7c478bd9Sstevel@tonic-gate 	{ CMD_HELP,		"help",		SHELP_HELP,	help_func },
148*7c478bd9Sstevel@tonic-gate 	{ CMD_BOOT,		"boot",		SHELP_BOOT,	boot_func },
149*7c478bd9Sstevel@tonic-gate 	{ CMD_HALT,		"halt",		SHELP_HALT,	halt_func },
150*7c478bd9Sstevel@tonic-gate 	{ CMD_READY,		"ready",	SHELP_READY,	ready_func },
151*7c478bd9Sstevel@tonic-gate 	{ CMD_REBOOT,		"reboot",	SHELP_REBOOT,	reboot_func },
152*7c478bd9Sstevel@tonic-gate 	{ CMD_LIST,		"list",		SHELP_LIST,	list_func },
153*7c478bd9Sstevel@tonic-gate 	{ CMD_VERIFY,		"verify",	SHELP_VERIFY,	verify_func },
154*7c478bd9Sstevel@tonic-gate 	{ CMD_INSTALL,		"install",	SHELP_INSTALL,	install_func },
155*7c478bd9Sstevel@tonic-gate 	{ CMD_UNINSTALL,	"uninstall",	SHELP_UNINSTALL,
156*7c478bd9Sstevel@tonic-gate 	    uninstall_func }
157*7c478bd9Sstevel@tonic-gate };
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate /* global variables */
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate /* set early in main(), never modified thereafter, used all over the place */
162*7c478bd9Sstevel@tonic-gate static char *execname;
163*7c478bd9Sstevel@tonic-gate static char *target_zone;
164*7c478bd9Sstevel@tonic-gate static char *locale;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate /* used in do_subproc() and signal handler */
167*7c478bd9Sstevel@tonic-gate static volatile boolean_t child_killed;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate static char *
170*7c478bd9Sstevel@tonic-gate cmd_to_str(int cmd_num)
171*7c478bd9Sstevel@tonic-gate {
172*7c478bd9Sstevel@tonic-gate 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
173*7c478bd9Sstevel@tonic-gate 	return (cmdtab[cmd_num].cmd_name);
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate /* This is a separate function because of gettext() wrapping. */
177*7c478bd9Sstevel@tonic-gate static char *
178*7c478bd9Sstevel@tonic-gate long_help(int cmd_num)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	if (cmd_num < CMD_MIN || cmd_num > CMD_MAX)
181*7c478bd9Sstevel@tonic-gate 		return ("");
182*7c478bd9Sstevel@tonic-gate 	switch (cmd_num) {
183*7c478bd9Sstevel@tonic-gate 		case CMD_HELP:
184*7c478bd9Sstevel@tonic-gate 			return (gettext("Print usage message."));
185*7c478bd9Sstevel@tonic-gate 		case CMD_BOOT:
186*7c478bd9Sstevel@tonic-gate 			return (gettext("Activates (boots) specified zone.  "
187*7c478bd9Sstevel@tonic-gate 			    "The -s flag can be used\n\tto boot the zone in "
188*7c478bd9Sstevel@tonic-gate 			    "the single-user state."));
189*7c478bd9Sstevel@tonic-gate 		case CMD_HALT:
190*7c478bd9Sstevel@tonic-gate 			return (gettext("Halts specified zone, bypassing "
191*7c478bd9Sstevel@tonic-gate 			    "shutdown scripts and removing runtime\n\t"
192*7c478bd9Sstevel@tonic-gate 			    "resources of the zone."));
193*7c478bd9Sstevel@tonic-gate 		case CMD_READY:
194*7c478bd9Sstevel@tonic-gate 			return (gettext("Prepares a zone for running "
195*7c478bd9Sstevel@tonic-gate 			    "applications but does not start any user\n\t"
196*7c478bd9Sstevel@tonic-gate 			    "processes in the zone."));
197*7c478bd9Sstevel@tonic-gate 		case CMD_REBOOT:
198*7c478bd9Sstevel@tonic-gate 			return (gettext("Restarts the zone (equivalent to a "
199*7c478bd9Sstevel@tonic-gate 			    "halt / boot sequence).\n\tFails if the zone is "
200*7c478bd9Sstevel@tonic-gate 			    "not active."));
201*7c478bd9Sstevel@tonic-gate 		case CMD_LIST:
202*7c478bd9Sstevel@tonic-gate 			return (gettext("Lists the current zones, or a "
203*7c478bd9Sstevel@tonic-gate 			    "specific zone if indicated.  By default,\n\tall "
204*7c478bd9Sstevel@tonic-gate 			    "running zones are listed, though this can be "
205*7c478bd9Sstevel@tonic-gate 			    "expanded to all\n\tinstalled zones with the -i "
206*7c478bd9Sstevel@tonic-gate 			    "option or all configured zones with the\n\t-c "
207*7c478bd9Sstevel@tonic-gate 			    "option.  When used with the general -z <zone> "
208*7c478bd9Sstevel@tonic-gate 			    "option, lists only the\n\tspecified zone, but "
209*7c478bd9Sstevel@tonic-gate 			    "lists it regardless of its state, and the -i "
210*7c478bd9Sstevel@tonic-gate 			    "and -c\n\toptions are disallowed.  The -v option "
211*7c478bd9Sstevel@tonic-gate 			    "can be used to display verbose\n\tinformation: "
212*7c478bd9Sstevel@tonic-gate 			    "zone name, id, current state, root directory and "
213*7c478bd9Sstevel@tonic-gate 			    "options.\n\tThe -p option can be used to request "
214*7c478bd9Sstevel@tonic-gate 			    "machine-parsable output.  The -v\n\tand -p "
215*7c478bd9Sstevel@tonic-gate 			    "options are mutually exclusive.  If neither -v "
216*7c478bd9Sstevel@tonic-gate 			    "nor -p is used,\n\tjust the zone name is "
217*7c478bd9Sstevel@tonic-gate 			    "listed."));
218*7c478bd9Sstevel@tonic-gate 		case CMD_VERIFY:
219*7c478bd9Sstevel@tonic-gate 			return (gettext("Check to make sure the configuration "
220*7c478bd9Sstevel@tonic-gate 			    "can safely be instantiated\n\ton the machine: "
221*7c478bd9Sstevel@tonic-gate 			    "physical network interfaces exist, etc."));
222*7c478bd9Sstevel@tonic-gate 		case CMD_INSTALL:
223*7c478bd9Sstevel@tonic-gate 			return (gettext("Install the configuration on to the "
224*7c478bd9Sstevel@tonic-gate 			    "system."));
225*7c478bd9Sstevel@tonic-gate 		case CMD_UNINSTALL:
226*7c478bd9Sstevel@tonic-gate 			return (gettext("Uninstall the configuration from the "
227*7c478bd9Sstevel@tonic-gate 			    "system.  The -F flag can be used\n\tto force the "
228*7c478bd9Sstevel@tonic-gate 			    "action."));
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
231*7c478bd9Sstevel@tonic-gate }
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate /*
234*7c478bd9Sstevel@tonic-gate  * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for
235*7c478bd9Sstevel@tonic-gate  * unexpected errors.
236*7c478bd9Sstevel@tonic-gate  */
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate static int
239*7c478bd9Sstevel@tonic-gate usage(boolean_t explicit)
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	int i;
242*7c478bd9Sstevel@tonic-gate 	FILE *fd = explicit ? stdout : stderr;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname);
245*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fd, "\t%s [-z <zone>] list\n", execname);
246*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fd, "\t%s -z <zone> <%s>\n", execname,
247*7c478bd9Sstevel@tonic-gate 	    gettext("subcommand"));
248*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands"));
249*7c478bd9Sstevel@tonic-gate 	for (i = CMD_MIN; i <= CMD_MAX; i++) {
250*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fd, "%s\n", cmdtab[i].short_usage);
251*7c478bd9Sstevel@tonic-gate 		if (explicit)
252*7c478bd9Sstevel@tonic-gate 			(void) fprintf(fd, "\t%s\n\n", long_help(i));
253*7c478bd9Sstevel@tonic-gate 	}
254*7c478bd9Sstevel@tonic-gate 	if (!explicit)
255*7c478bd9Sstevel@tonic-gate 		(void) fputs("\n", fd);
256*7c478bd9Sstevel@tonic-gate 	return (Z_USAGE);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate static void
260*7c478bd9Sstevel@tonic-gate sub_usage(char *short_usage, int cmd_num)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage);
263*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\t%s\n", long_help(cmd_num));
264*7c478bd9Sstevel@tonic-gate }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate /*
267*7c478bd9Sstevel@tonic-gate  * zperror() is like perror(3c) except that this also prints the executable
268*7c478bd9Sstevel@tonic-gate  * name at the start of the message, and takes a boolean indicating whether
269*7c478bd9Sstevel@tonic-gate  * to call libc'c strerror() or that from libzonecfg.
270*7c478bd9Sstevel@tonic-gate  */
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate static void
273*7c478bd9Sstevel@tonic-gate zperror(const char *str, boolean_t zonecfg_error)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: %s: %s\n", execname, str,
276*7c478bd9Sstevel@tonic-gate 	    zonecfg_error ? zonecfg_strerror(errno) : strerror(errno));
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * zperror2() is very similar to zperror() above, except it also prints a
281*7c478bd9Sstevel@tonic-gate  * supplied zone name after the executable.
282*7c478bd9Sstevel@tonic-gate  *
283*7c478bd9Sstevel@tonic-gate  * All current consumers of this function want libzonecfg's strerror() rather
284*7c478bd9Sstevel@tonic-gate  * than libc's; if this ever changes, this function can be made more generic
285*7c478bd9Sstevel@tonic-gate  * like zperror() above.
286*7c478bd9Sstevel@tonic-gate  */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate static void
289*7c478bd9Sstevel@tonic-gate zperror2(const char *zone, const char *str)
290*7c478bd9Sstevel@tonic-gate {
291*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str,
292*7c478bd9Sstevel@tonic-gate 	    zonecfg_strerror(errno));
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */
296*7c478bd9Sstevel@tonic-gate static void
297*7c478bd9Sstevel@tonic-gate zerror(const char *fmt, ...)
298*7c478bd9Sstevel@tonic-gate {
299*7c478bd9Sstevel@tonic-gate 	va_list alist;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	va_start(alist, fmt);
302*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", execname);
303*7c478bd9Sstevel@tonic-gate 	if (target_zone != NULL)
304*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "zone '%s': ", target_zone);
305*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, alist);
306*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
307*7c478bd9Sstevel@tonic-gate 	va_end(alist);
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate static void *
311*7c478bd9Sstevel@tonic-gate safe_calloc(size_t nelem, size_t elsize)
312*7c478bd9Sstevel@tonic-gate {
313*7c478bd9Sstevel@tonic-gate 	void *r = calloc(nelem, elsize);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	if (r == NULL) {
316*7c478bd9Sstevel@tonic-gate 		zerror(gettext("failed to allocate %lu bytes: %s"),
317*7c478bd9Sstevel@tonic-gate 		    (ulong_t)nelem * elsize, strerror(errno));
318*7c478bd9Sstevel@tonic-gate 		exit(Z_ERR);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 	return (r);
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate static void
324*7c478bd9Sstevel@tonic-gate zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate 	static boolean_t firsttime = B_TRUE;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	assert(!(verbose && parsable));
329*7c478bd9Sstevel@tonic-gate 	if (firsttime && verbose) {
330*7c478bd9Sstevel@tonic-gate 		firsttime = B_FALSE;
331*7c478bd9Sstevel@tonic-gate 		(void) printf("%*s %-16s %-14s %-30s\n", ZONEID_WIDTH, "ID",
332*7c478bd9Sstevel@tonic-gate 		    "NAME", "STATUS", "PATH");
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 	if (!verbose) {
335*7c478bd9Sstevel@tonic-gate 		if (!parsable) {
336*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", zent->zname);
337*7c478bd9Sstevel@tonic-gate 			return;
338*7c478bd9Sstevel@tonic-gate 		}
339*7c478bd9Sstevel@tonic-gate 		if (zent->zid == ZONE_ID_UNDEFINED)
340*7c478bd9Sstevel@tonic-gate 			(void) printf("-");
341*7c478bd9Sstevel@tonic-gate 		else
342*7c478bd9Sstevel@tonic-gate 			(void) printf("%lu", zent->zid);
343*7c478bd9Sstevel@tonic-gate 		(void) printf(":%s:%s:%s\n", zent->zname, zent->zstate_str,
344*7c478bd9Sstevel@tonic-gate 		    zent->zroot);
345*7c478bd9Sstevel@tonic-gate 		return;
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 	if (zent->zstate_str != NULL) {
348*7c478bd9Sstevel@tonic-gate 		if (zent->zid == ZONE_ID_UNDEFINED)
349*7c478bd9Sstevel@tonic-gate 			(void) printf("%*s", ZONEID_WIDTH, "-");
350*7c478bd9Sstevel@tonic-gate 		else
351*7c478bd9Sstevel@tonic-gate 			(void) printf("%*lu", ZONEID_WIDTH, zent->zid);
352*7c478bd9Sstevel@tonic-gate 		(void) printf(" %-16s %-14s %-30s\n", zent->zname,
353*7c478bd9Sstevel@tonic-gate 		    zent->zstate_str, zent->zroot);
354*7c478bd9Sstevel@tonic-gate 	}
355*7c478bd9Sstevel@tonic-gate }
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate static int
358*7c478bd9Sstevel@tonic-gate lookup_zone_info(char *zone_name, zone_entry_t *zent)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	char root[MAXPATHLEN];
361*7c478bd9Sstevel@tonic-gate 	int err;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
364*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(zent->zroot, "???", sizeof (zent->zroot));
365*7c478bd9Sstevel@tonic-gate 	zent->zstate_str = "???";
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	if ((zent->zid = getzoneidbyname(zone_name)) == -1)
368*7c478bd9Sstevel@tonic-gate 		zent->zid = ZONE_ID_UNDEFINED;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_zonepath(zent->zname, root, sizeof (root))) !=
371*7c478bd9Sstevel@tonic-gate 	    Z_OK) {
372*7c478bd9Sstevel@tonic-gate 		errno = err;
373*7c478bd9Sstevel@tonic-gate 		zperror2(zent->zname, gettext("could not get zone path"));
374*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) {
379*7c478bd9Sstevel@tonic-gate 		errno = err;
380*7c478bd9Sstevel@tonic-gate 		zperror2(zent->zname, gettext("could not get state"));
381*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	zent->zstate_str = zone_state_str(zent->zstate_num);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
386*7c478bd9Sstevel@tonic-gate }
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate /*
389*7c478bd9Sstevel@tonic-gate  * fetch_zents() calls zone_list(2) to find out how many zones are running
390*7c478bd9Sstevel@tonic-gate  * (which is stored in the global nzents), then calls zone_list(2) again
391*7c478bd9Sstevel@tonic-gate  * to fetch the list of running zones (stored in the global zents).  This
392*7c478bd9Sstevel@tonic-gate  * function may be called multiple times, so if zents is already set, we
393*7c478bd9Sstevel@tonic-gate  * return immediately to save work.
394*7c478bd9Sstevel@tonic-gate  */
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate static int
397*7c478bd9Sstevel@tonic-gate fetch_zents()
398*7c478bd9Sstevel@tonic-gate {
399*7c478bd9Sstevel@tonic-gate 	zoneid_t *zids = NULL;
400*7c478bd9Sstevel@tonic-gate 	uint_t nzents_saved;
401*7c478bd9Sstevel@tonic-gate 	int i;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	if (nzents > 0)
404*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	if (zone_list(NULL, &nzents) != 0) {
407*7c478bd9Sstevel@tonic-gate 		zperror(gettext("failed to get zoneid list"), B_FALSE);
408*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate again:
412*7c478bd9Sstevel@tonic-gate 	if (nzents == 0)
413*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	zids = safe_calloc(nzents, sizeof (zoneid_t));
416*7c478bd9Sstevel@tonic-gate 	nzents_saved = nzents;
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	if (zone_list(zids, &nzents) != 0) {
419*7c478bd9Sstevel@tonic-gate 		zperror(gettext("failed to get zone list"), B_FALSE);
420*7c478bd9Sstevel@tonic-gate 		free(zids);
421*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 	if (nzents != nzents_saved) {
424*7c478bd9Sstevel@tonic-gate 		/* list changed, try again */
425*7c478bd9Sstevel@tonic-gate 		free(zids);
426*7c478bd9Sstevel@tonic-gate 		goto again;
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	zents = safe_calloc(nzents, sizeof (zone_entry_t));
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nzents; i++) {
432*7c478bd9Sstevel@tonic-gate 		char name[ZONENAME_MAX];
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if (getzonenamebyid(zids[i], name, sizeof (name)) < 0)
435*7c478bd9Sstevel@tonic-gate 			zperror(gettext("failed to get zone name"), B_FALSE);
436*7c478bd9Sstevel@tonic-gate 		else if (lookup_zone_info(name, &zents[i]) != Z_OK)
437*7c478bd9Sstevel@tonic-gate 			zerror(gettext("failed to get zone list"));
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	free(zids);
441*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate static void
445*7c478bd9Sstevel@tonic-gate zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	int i;
448*7c478bd9Sstevel@tonic-gate 	zone_entry_t zent;
449*7c478bd9Sstevel@tonic-gate 	FILE *cookie;
450*7c478bd9Sstevel@tonic-gate 	char *name;
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	/*
453*7c478bd9Sstevel@tonic-gate 	 * First get the list of running zones from the kernel and print them.
454*7c478bd9Sstevel@tonic-gate 	 * If that is all we need, then return.
455*7c478bd9Sstevel@tonic-gate 	 */
456*7c478bd9Sstevel@tonic-gate 	if (fetch_zents() != Z_OK) {
457*7c478bd9Sstevel@tonic-gate 		/*
458*7c478bd9Sstevel@tonic-gate 		 * No need for error messages; fetch_zents() has already taken
459*7c478bd9Sstevel@tonic-gate 		 * care of this.
460*7c478bd9Sstevel@tonic-gate 		 */
461*7c478bd9Sstevel@tonic-gate 		return;
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nzents; i++) {
464*7c478bd9Sstevel@tonic-gate 		if (!verbose && !parsable) {
465*7c478bd9Sstevel@tonic-gate 			zone_print(&zents[i], verbose, parsable);
466*7c478bd9Sstevel@tonic-gate 			continue;
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 		zone_print(&zents[i], verbose, parsable);
469*7c478bd9Sstevel@tonic-gate 	}
470*7c478bd9Sstevel@tonic-gate 	if (min_state >= ZONE_STATE_RUNNING)
471*7c478bd9Sstevel@tonic-gate 		return;
472*7c478bd9Sstevel@tonic-gate 	/*
473*7c478bd9Sstevel@tonic-gate 	 * Next, get the full list of zones from the configuration, skipping
474*7c478bd9Sstevel@tonic-gate 	 * any we have already printed.
475*7c478bd9Sstevel@tonic-gate 	 */
476*7c478bd9Sstevel@tonic-gate 	cookie = setzoneent();
477*7c478bd9Sstevel@tonic-gate 	while ((name = getzoneent(cookie)) != NULL) {
478*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nzents; i++) {
479*7c478bd9Sstevel@tonic-gate 			if (strcmp(zents[i].zname, name) == 0)
480*7c478bd9Sstevel@tonic-gate 				break;
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 		if (i < nzents) {
483*7c478bd9Sstevel@tonic-gate 			free(name);
484*7c478bd9Sstevel@tonic-gate 			continue;
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 		if (lookup_zone_info(name, &zent) != Z_OK) {
487*7c478bd9Sstevel@tonic-gate 			free(name);
488*7c478bd9Sstevel@tonic-gate 			continue;
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 		free(name);
491*7c478bd9Sstevel@tonic-gate 		if (zent.zstate_num >= min_state)
492*7c478bd9Sstevel@tonic-gate 			zone_print(&zent, verbose, parsable);
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 	endzoneent(cookie);
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate static zone_entry_t *
498*7c478bd9Sstevel@tonic-gate lookup_running_zone(char *str)
499*7c478bd9Sstevel@tonic-gate {
500*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
501*7c478bd9Sstevel@tonic-gate 	char *cp;
502*7c478bd9Sstevel@tonic-gate 	int i;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	if (fetch_zents() != Z_OK)
505*7c478bd9Sstevel@tonic-gate 		return (NULL);
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nzents; i++) {
508*7c478bd9Sstevel@tonic-gate 		if (strcmp(str, zents[i].zname) == 0)
509*7c478bd9Sstevel@tonic-gate 			return (&zents[i]);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 	errno = 0;
512*7c478bd9Sstevel@tonic-gate 	zoneid = strtol(str, &cp, 0);
513*7c478bd9Sstevel@tonic-gate 	if (zoneid < MIN_ZONEID || zoneid > MAX_ZONEID ||
514*7c478bd9Sstevel@tonic-gate 	    errno != 0 || *cp != '\0')
515*7c478bd9Sstevel@tonic-gate 		return (NULL);
516*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nzents; i++) {
517*7c478bd9Sstevel@tonic-gate 		if (zoneid == zents[i].zid)
518*7c478bd9Sstevel@tonic-gate 			return (&zents[i]);
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 	return (NULL);
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
525*7c478bd9Sstevel@tonic-gate  * B_FALSE, it should be off.  Return B_TRUE if the mode is bad (incorrect).
526*7c478bd9Sstevel@tonic-gate  */
527*7c478bd9Sstevel@tonic-gate static boolean_t
528*7c478bd9Sstevel@tonic-gate bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file)
529*7c478bd9Sstevel@tonic-gate {
530*7c478bd9Sstevel@tonic-gate 	char *str;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR ||
533*7c478bd9Sstevel@tonic-gate 	    bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP ||
534*7c478bd9Sstevel@tonic-gate 	    bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH);
535*7c478bd9Sstevel@tonic-gate 	/*
536*7c478bd9Sstevel@tonic-gate 	 * TRANSLATION_NOTE
537*7c478bd9Sstevel@tonic-gate 	 * The strings below will be used as part of a larger message,
538*7c478bd9Sstevel@tonic-gate 	 * either:
539*7c478bd9Sstevel@tonic-gate 	 * (file name) must be (owner|group|world) (read|writ|execut)able
540*7c478bd9Sstevel@tonic-gate 	 * or
541*7c478bd9Sstevel@tonic-gate 	 * (file name) must not be (owner|group|world) (read|writ|execut)able
542*7c478bd9Sstevel@tonic-gate 	 */
543*7c478bd9Sstevel@tonic-gate 	switch (bit) {
544*7c478bd9Sstevel@tonic-gate 	case S_IRUSR:
545*7c478bd9Sstevel@tonic-gate 		str = gettext("owner readable");
546*7c478bd9Sstevel@tonic-gate 		break;
547*7c478bd9Sstevel@tonic-gate 	case S_IWUSR:
548*7c478bd9Sstevel@tonic-gate 		str = gettext("owner writable");
549*7c478bd9Sstevel@tonic-gate 		break;
550*7c478bd9Sstevel@tonic-gate 	case S_IXUSR:
551*7c478bd9Sstevel@tonic-gate 		str = gettext("owner executable");
552*7c478bd9Sstevel@tonic-gate 		break;
553*7c478bd9Sstevel@tonic-gate 	case S_IRGRP:
554*7c478bd9Sstevel@tonic-gate 		str = gettext("group readable");
555*7c478bd9Sstevel@tonic-gate 		break;
556*7c478bd9Sstevel@tonic-gate 	case S_IWGRP:
557*7c478bd9Sstevel@tonic-gate 		str = gettext("group writable");
558*7c478bd9Sstevel@tonic-gate 		break;
559*7c478bd9Sstevel@tonic-gate 	case S_IXGRP:
560*7c478bd9Sstevel@tonic-gate 		str = gettext("group executable");
561*7c478bd9Sstevel@tonic-gate 		break;
562*7c478bd9Sstevel@tonic-gate 	case S_IROTH:
563*7c478bd9Sstevel@tonic-gate 		str = gettext("world readable");
564*7c478bd9Sstevel@tonic-gate 		break;
565*7c478bd9Sstevel@tonic-gate 	case S_IWOTH:
566*7c478bd9Sstevel@tonic-gate 		str = gettext("world writable");
567*7c478bd9Sstevel@tonic-gate 		break;
568*7c478bd9Sstevel@tonic-gate 	case S_IXOTH:
569*7c478bd9Sstevel@tonic-gate 		str = gettext("world executable");
570*7c478bd9Sstevel@tonic-gate 		break;
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 	if ((mode & bit) == (on ? 0 : bit)) {
573*7c478bd9Sstevel@tonic-gate 		/*
574*7c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
575*7c478bd9Sstevel@tonic-gate 		 * The first parameter below is a file name; the second
576*7c478bd9Sstevel@tonic-gate 		 * is one of the "(owner|group|world) (read|writ|execut)able"
577*7c478bd9Sstevel@tonic-gate 		 * strings from above.
578*7c478bd9Sstevel@tonic-gate 		 */
579*7c478bd9Sstevel@tonic-gate 		/*
580*7c478bd9Sstevel@tonic-gate 		 * The code below could be simplified but not in a way
581*7c478bd9Sstevel@tonic-gate 		 * that would easily translate to non-English locales.
582*7c478bd9Sstevel@tonic-gate 		 */
583*7c478bd9Sstevel@tonic-gate 		if (on) {
584*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s must be %s.\n"),
585*7c478bd9Sstevel@tonic-gate 			    file, str);
586*7c478bd9Sstevel@tonic-gate 		} else {
587*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s must not be %s.\n"),
588*7c478bd9Sstevel@tonic-gate 			    file, str);
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
591*7c478bd9Sstevel@tonic-gate 	}
592*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
593*7c478bd9Sstevel@tonic-gate }
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate /*
596*7c478bd9Sstevel@tonic-gate  * We want to make sure that no zone has its zone path as a child node
597*7c478bd9Sstevel@tonic-gate  * (in the directory sense) of any other.  We do that by comparing this
598*7c478bd9Sstevel@tonic-gate  * zone's path to the path of all other (non-global) zones.  The comparison
599*7c478bd9Sstevel@tonic-gate  * in each case is simple: add '/' to the end of the path, then do a
600*7c478bd9Sstevel@tonic-gate  * strncmp() of the two paths, using the length of the shorter one.
601*7c478bd9Sstevel@tonic-gate  */
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate static int
604*7c478bd9Sstevel@tonic-gate crosscheck_zonepaths(char *path)
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 	char rpath[MAXPATHLEN];		/* resolved path */
607*7c478bd9Sstevel@tonic-gate 	char path_copy[MAXPATHLEN];	/* copy of original path */
608*7c478bd9Sstevel@tonic-gate 	char rpath_copy[MAXPATHLEN];	/* copy of original rpath */
609*7c478bd9Sstevel@tonic-gate 	struct zoneent *ze;
610*7c478bd9Sstevel@tonic-gate 	int res, err;
611*7c478bd9Sstevel@tonic-gate 	FILE *cookie;
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	cookie = setzoneent();
614*7c478bd9Sstevel@tonic-gate 	while ((ze = getzoneent_private(cookie)) != NULL) {
615*7c478bd9Sstevel@tonic-gate 		/* Skip zones which are not installed. */
616*7c478bd9Sstevel@tonic-gate 		if (ze->zone_state < ZONE_STATE_INSTALLED) {
617*7c478bd9Sstevel@tonic-gate 			free(ze);
618*7c478bd9Sstevel@tonic-gate 			continue;
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 		/* Skip the global zone and the current target zone. */
621*7c478bd9Sstevel@tonic-gate 		if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 ||
622*7c478bd9Sstevel@tonic-gate 		    strcmp(ze->zone_name, target_zone) == 0) {
623*7c478bd9Sstevel@tonic-gate 			free(ze);
624*7c478bd9Sstevel@tonic-gate 			continue;
625*7c478bd9Sstevel@tonic-gate 		}
626*7c478bd9Sstevel@tonic-gate 		if (strlen(ze->zone_path) == 0) {
627*7c478bd9Sstevel@tonic-gate 			/* old index file without path, fall back */
628*7c478bd9Sstevel@tonic-gate 			if ((err = zone_get_zonepath(ze->zone_name,
629*7c478bd9Sstevel@tonic-gate 			    ze->zone_path, sizeof (ze->zone_path))) != Z_OK) {
630*7c478bd9Sstevel@tonic-gate 				errno = err;
631*7c478bd9Sstevel@tonic-gate 				zperror2(ze->zone_name,
632*7c478bd9Sstevel@tonic-gate 				    gettext("could not get zone path"));
633*7c478bd9Sstevel@tonic-gate 				free(ze);
634*7c478bd9Sstevel@tonic-gate 				continue;
635*7c478bd9Sstevel@tonic-gate 			}
636*7c478bd9Sstevel@tonic-gate 		}
637*7c478bd9Sstevel@tonic-gate 		res = resolvepath(ze->zone_path, rpath, sizeof (rpath));
638*7c478bd9Sstevel@tonic-gate 		if (res == -1) {
639*7c478bd9Sstevel@tonic-gate 			if (errno != ENOENT) {
640*7c478bd9Sstevel@tonic-gate 				zperror(ze->zone_path, B_FALSE);
641*7c478bd9Sstevel@tonic-gate 				free(ze);
642*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
643*7c478bd9Sstevel@tonic-gate 			}
644*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("WARNING: zone %s is installed, "
645*7c478bd9Sstevel@tonic-gate 			    "but its %s %s does not exist.\n"), ze->zone_name,
646*7c478bd9Sstevel@tonic-gate 			    "zonepath", ze->zone_path);
647*7c478bd9Sstevel@tonic-gate 			free(ze);
648*7c478bd9Sstevel@tonic-gate 			continue;
649*7c478bd9Sstevel@tonic-gate 		}
650*7c478bd9Sstevel@tonic-gate 		rpath[res] = '\0';
651*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path_copy, sizeof (path_copy), "%s/", path);
652*7c478bd9Sstevel@tonic-gate 		(void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath);
653*7c478bd9Sstevel@tonic-gate 		if (strncmp(path_copy, rpath_copy,
654*7c478bd9Sstevel@tonic-gate 		    min(strlen(path_copy), strlen(rpath_copy))) == 0) {
655*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s zonepath (%s) and "
656*7c478bd9Sstevel@tonic-gate 			    "%s zonepath (%s) overlap.\n"),
657*7c478bd9Sstevel@tonic-gate 			    target_zone, path, ze->zone_name, rpath);
658*7c478bd9Sstevel@tonic-gate 			free(ze);
659*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
660*7c478bd9Sstevel@tonic-gate 		}
661*7c478bd9Sstevel@tonic-gate 		free(ze);
662*7c478bd9Sstevel@tonic-gate 	}
663*7c478bd9Sstevel@tonic-gate 	endzoneent(cookie);
664*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
665*7c478bd9Sstevel@tonic-gate }
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate static int
668*7c478bd9Sstevel@tonic-gate validate_zonepath(char *path, int cmd_num)
669*7c478bd9Sstevel@tonic-gate {
670*7c478bd9Sstevel@tonic-gate 	int res;			/* result of last library/system call */
671*7c478bd9Sstevel@tonic-gate 	boolean_t err = B_FALSE;	/* have we run into an error? */
672*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
673*7c478bd9Sstevel@tonic-gate 	struct statvfs vfsbuf;
674*7c478bd9Sstevel@tonic-gate 	char rpath[MAXPATHLEN];		/* resolved path */
675*7c478bd9Sstevel@tonic-gate 	char ppath[MAXPATHLEN];		/* parent path */
676*7c478bd9Sstevel@tonic-gate 	char rppath[MAXPATHLEN];	/* resolved parent path */
677*7c478bd9Sstevel@tonic-gate 	char rootpath[MAXPATHLEN];	/* root path */
678*7c478bd9Sstevel@tonic-gate 	zone_state_t state;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	if (path[0] != '/') {
681*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
682*7c478bd9Sstevel@tonic-gate 		    gettext("%s is not an absolute path.\n"), path);
683*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
684*7c478bd9Sstevel@tonic-gate 	}
685*7c478bd9Sstevel@tonic-gate 	if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) {
686*7c478bd9Sstevel@tonic-gate 		if ((errno != ENOENT) ||
687*7c478bd9Sstevel@tonic-gate 		    (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL)) {
688*7c478bd9Sstevel@tonic-gate 			zperror(path, B_FALSE);
689*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
690*7c478bd9Sstevel@tonic-gate 		}
691*7c478bd9Sstevel@tonic-gate 		if (cmd_num == CMD_VERIFY) {
692*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("WARNING: %s does not "
693*7c478bd9Sstevel@tonic-gate 			    "exist, so it cannot be verified.\nWhen 'zoneadm "
694*7c478bd9Sstevel@tonic-gate 			    "%s' is run, '%s' will try to create\n%s, and '%s' "
695*7c478bd9Sstevel@tonic-gate 			    "will be tried again,\nbut the '%s' may fail if:\n"
696*7c478bd9Sstevel@tonic-gate 			    "the parent directory of %s is group- or other-"
697*7c478bd9Sstevel@tonic-gate 			    "writable\nor\n%s overlaps with any other "
698*7c478bd9Sstevel@tonic-gate 			    "installed zones.\n"), path,
699*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL),
700*7c478bd9Sstevel@tonic-gate 			    path, cmd_to_str(CMD_VERIFY),
701*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(CMD_VERIFY), path, path);
702*7c478bd9Sstevel@tonic-gate 			return (Z_OK);
703*7c478bd9Sstevel@tonic-gate 		}
704*7c478bd9Sstevel@tonic-gate 		/*
705*7c478bd9Sstevel@tonic-gate 		 * The zonepath is supposed to be mode 700 but its
706*7c478bd9Sstevel@tonic-gate 		 * parent(s) 755.  So use 755 on the mkdirp() then
707*7c478bd9Sstevel@tonic-gate 		 * chmod() the zonepath itself to 700.
708*7c478bd9Sstevel@tonic-gate 		 */
709*7c478bd9Sstevel@tonic-gate 		if (mkdirp(path, DEFAULT_DIR_MODE) < 0) {
710*7c478bd9Sstevel@tonic-gate 			zperror(path, B_FALSE);
711*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
712*7c478bd9Sstevel@tonic-gate 		}
713*7c478bd9Sstevel@tonic-gate 		/*
714*7c478bd9Sstevel@tonic-gate 		 * If the chmod() fails, report the error, but might
715*7c478bd9Sstevel@tonic-gate 		 * as well continue the verify procedure.
716*7c478bd9Sstevel@tonic-gate 		 */
717*7c478bd9Sstevel@tonic-gate 		if (chmod(path, S_IRWXU) != 0)
718*7c478bd9Sstevel@tonic-gate 			zperror(path, B_FALSE);
719*7c478bd9Sstevel@tonic-gate 		/*
720*7c478bd9Sstevel@tonic-gate 		 * Since the mkdir() succeeded, we should not have to
721*7c478bd9Sstevel@tonic-gate 		 * worry about a subsequent ENOENT, thus this should
722*7c478bd9Sstevel@tonic-gate 		 * only recurse once.
723*7c478bd9Sstevel@tonic-gate 		 */
724*7c478bd9Sstevel@tonic-gate 		return (validate_zonepath(path, CMD_INSTALL));
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 	rpath[res] = '\0';
727*7c478bd9Sstevel@tonic-gate 	if (strcmp(path, rpath) != 0) {
728*7c478bd9Sstevel@tonic-gate 		errno = Z_RESOLVED_PATH;
729*7c478bd9Sstevel@tonic-gate 		zperror(path, B_TRUE);
730*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 	if ((res = stat(rpath, &stbuf)) != 0) {
733*7c478bd9Sstevel@tonic-gate 		zperror(rpath, B_FALSE);
734*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 	if (!S_ISDIR(stbuf.st_mode)) {
737*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is not a directory.\n"),
738*7c478bd9Sstevel@tonic-gate 		    rpath);
739*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
740*7c478bd9Sstevel@tonic-gate 	}
741*7c478bd9Sstevel@tonic-gate 	if ((strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) ||
742*7c478bd9Sstevel@tonic-gate 	    (strcmp(stbuf.st_fstype, MNTTYPE_XMEMFS) == 0)) {
743*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("WARNING: %s is on a temporary "
744*7c478bd9Sstevel@tonic-gate 		    "file-system.\n"), rpath);
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 	if (crosscheck_zonepaths(rpath) != Z_OK)
747*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
748*7c478bd9Sstevel@tonic-gate 	/*
749*7c478bd9Sstevel@tonic-gate 	 * Try to collect and report as many minor errors as possible
750*7c478bd9Sstevel@tonic-gate 	 * before returning, so the user can learn everything that needs
751*7c478bd9Sstevel@tonic-gate 	 * to be fixed up front.
752*7c478bd9Sstevel@tonic-gate 	 */
753*7c478bd9Sstevel@tonic-gate 	if (stbuf.st_uid != 0) {
754*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is not owned by root.\n"),
755*7c478bd9Sstevel@tonic-gate 		    rpath);
756*7c478bd9Sstevel@tonic-gate 		err = B_TRUE;
757*7c478bd9Sstevel@tonic-gate 	}
758*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath);
759*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath);
760*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath);
761*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath);
762*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath);
763*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath);
764*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath);
765*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath);
766*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath);
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ppath, sizeof (ppath), "%s/..", path);
769*7c478bd9Sstevel@tonic-gate 	if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) {
770*7c478bd9Sstevel@tonic-gate 		zperror(ppath, B_FALSE);
771*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate 	rppath[res] = '\0';
774*7c478bd9Sstevel@tonic-gate 	if ((res = stat(rppath, &stbuf)) != 0) {
775*7c478bd9Sstevel@tonic-gate 		zperror(rppath, B_FALSE);
776*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
777*7c478bd9Sstevel@tonic-gate 	}
778*7c478bd9Sstevel@tonic-gate 	/* theoretically impossible */
779*7c478bd9Sstevel@tonic-gate 	if (!S_ISDIR(stbuf.st_mode)) {
780*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is not a directory.\n"),
781*7c478bd9Sstevel@tonic-gate 		    rppath);
782*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
783*7c478bd9Sstevel@tonic-gate 	}
784*7c478bd9Sstevel@tonic-gate 	if (stbuf.st_uid != 0) {
785*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is not owned by root.\n"),
786*7c478bd9Sstevel@tonic-gate 		    rppath);
787*7c478bd9Sstevel@tonic-gate 		err = B_TRUE;
788*7c478bd9Sstevel@tonic-gate 	}
789*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath);
790*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath);
791*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath);
792*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath);
793*7c478bd9Sstevel@tonic-gate 	err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath);
794*7c478bd9Sstevel@tonic-gate 	if (strcmp(rpath, rppath) == 0) {
795*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is its own parent.\n"),
796*7c478bd9Sstevel@tonic-gate 		    rppath);
797*7c478bd9Sstevel@tonic-gate 		err = B_TRUE;
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	if (statvfs(rpath, &vfsbuf) != 0) {
801*7c478bd9Sstevel@tonic-gate 		zperror(rpath, B_FALSE);
802*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
803*7c478bd9Sstevel@tonic-gate 	}
804*7c478bd9Sstevel@tonic-gate 	if (strncmp(vfsbuf.f_basetype, "nfs", 3) == 0) {
805*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Zonepath %s is over NFS, "
806*7c478bd9Sstevel@tonic-gate 		    "which is not currently supported.\n"), rpath);
807*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	if ((res = zone_get_state(target_zone, &state)) != Z_OK) {
811*7c478bd9Sstevel@tonic-gate 		errno = res;
812*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not get state"));
813*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 	/*
816*7c478bd9Sstevel@tonic-gate 	 * The existence of the root path is only bad in the configured state,
817*7c478bd9Sstevel@tonic-gate 	 * as it is *supposed* to be there at the installed and later states.
818*7c478bd9Sstevel@tonic-gate 	 * State/command mismatches are caught earlier in verify_details().
819*7c478bd9Sstevel@tonic-gate 	 */
820*7c478bd9Sstevel@tonic-gate 	if (state == ZONE_STATE_CONFIGURED) {
821*7c478bd9Sstevel@tonic-gate 		if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >=
822*7c478bd9Sstevel@tonic-gate 		    sizeof (rootpath)) {
823*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
824*7c478bd9Sstevel@tonic-gate 			    gettext("Zonepath %s is too long.\n"), rpath);
825*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
826*7c478bd9Sstevel@tonic-gate 		}
827*7c478bd9Sstevel@tonic-gate 		if ((res = stat(rootpath, &stbuf)) == 0) {
828*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Rootpath %s exists; "
829*7c478bd9Sstevel@tonic-gate 			    "remove or move aside prior to %s.\n"), rootpath,
830*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(CMD_INSTALL));
831*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	return (err ? Z_ERR : Z_OK);
836*7c478bd9Sstevel@tonic-gate }
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate static void
839*7c478bd9Sstevel@tonic-gate release_lock_file(int lockfd)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	(void) close(lockfd);
842*7c478bd9Sstevel@tonic-gate }
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate static int
845*7c478bd9Sstevel@tonic-gate grab_lock_file(const char *zone_name, int *lockfd)
846*7c478bd9Sstevel@tonic-gate {
847*7c478bd9Sstevel@tonic-gate 	char pathbuf[PATH_MAX];
848*7c478bd9Sstevel@tonic-gate 	struct flock flock;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) {
851*7c478bd9Sstevel@tonic-gate 		zerror(gettext("could not mkdir %s: %s"), ZONES_TMPDIR,
852*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
853*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
854*7c478bd9Sstevel@tonic-gate 	}
855*7c478bd9Sstevel@tonic-gate 	(void) chmod(ZONES_TMPDIR, S_IRWXU);
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * One of these lock files is created for each zone (when needed).
859*7c478bd9Sstevel@tonic-gate 	 * The lock files are not cleaned up (except on system reboot),
860*7c478bd9Sstevel@tonic-gate 	 * but since there is only one per zone, there is no resource
861*7c478bd9Sstevel@tonic-gate 	 * starvation issue.
862*7c478bd9Sstevel@tonic-gate 	 */
863*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pathbuf, sizeof (pathbuf), "%s/%s.zoneadm.lock",
864*7c478bd9Sstevel@tonic-gate 	    ZONES_TMPDIR, zone_name);
865*7c478bd9Sstevel@tonic-gate 	if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
866*7c478bd9Sstevel@tonic-gate 		zerror(gettext("could not open %s: %s"), pathbuf,
867*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
868*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
869*7c478bd9Sstevel@tonic-gate 	}
870*7c478bd9Sstevel@tonic-gate 	/*
871*7c478bd9Sstevel@tonic-gate 	 * Lock the file to synchronize with other zoneadmds
872*7c478bd9Sstevel@tonic-gate 	 */
873*7c478bd9Sstevel@tonic-gate 	flock.l_type = F_WRLCK;
874*7c478bd9Sstevel@tonic-gate 	flock.l_whence = SEEK_SET;
875*7c478bd9Sstevel@tonic-gate 	flock.l_start = (off_t)0;
876*7c478bd9Sstevel@tonic-gate 	flock.l_len = (off_t)0;
877*7c478bd9Sstevel@tonic-gate 	if (fcntl(*lockfd, F_SETLKW, &flock) < 0) {
878*7c478bd9Sstevel@tonic-gate 		zerror(gettext("unable to lock %s: %s"), pathbuf,
879*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
880*7c478bd9Sstevel@tonic-gate 		release_lock_file(*lockfd);
881*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
882*7c478bd9Sstevel@tonic-gate 	}
883*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
884*7c478bd9Sstevel@tonic-gate }
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate static void
887*7c478bd9Sstevel@tonic-gate get_doorname(const char *zone_name, char *buffer)
888*7c478bd9Sstevel@tonic-gate {
889*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buffer, PATH_MAX, ZONE_DOOR_PATH, zone_name);
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate /*
893*7c478bd9Sstevel@tonic-gate  * system daemons are not audited.  For the global zone, this occurs
894*7c478bd9Sstevel@tonic-gate  * "naturally" since init is started with the default audit
895*7c478bd9Sstevel@tonic-gate  * characteristics.  Since zoneadmd is a system daemon and it starts
896*7c478bd9Sstevel@tonic-gate  * init for a zone, it is necessary to clear out the audit
897*7c478bd9Sstevel@tonic-gate  * characteristics inherited from whomever started zoneadmd.  This is
898*7c478bd9Sstevel@tonic-gate  * indicated by the audit id, which is set from the ruid parameter of
899*7c478bd9Sstevel@tonic-gate  * adt_set_user(), below.
900*7c478bd9Sstevel@tonic-gate  */
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate static void
903*7c478bd9Sstevel@tonic-gate prepare_audit_context()
904*7c478bd9Sstevel@tonic-gate {
905*7c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;
906*7c478bd9Sstevel@tonic-gate 	char			*failure = gettext("audit failure: %s");
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, 0)) {
909*7c478bd9Sstevel@tonic-gate 		zerror(failure, strerror(errno));
910*7c478bd9Sstevel@tonic-gate 		return;
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 	if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
913*7c478bd9Sstevel@tonic-gate 	    ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
914*7c478bd9Sstevel@tonic-gate 		zerror(failure, strerror(errno));
915*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
916*7c478bd9Sstevel@tonic-gate 		return;
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 	if (adt_set_proc(ah))
919*7c478bd9Sstevel@tonic-gate 		zerror(failure, strerror(errno));
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
922*7c478bd9Sstevel@tonic-gate }
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate static int
925*7c478bd9Sstevel@tonic-gate start_zoneadmd(const char *zone_name)
926*7c478bd9Sstevel@tonic-gate {
927*7c478bd9Sstevel@tonic-gate 	char doorpath[PATH_MAX];
928*7c478bd9Sstevel@tonic-gate 	pid_t child_pid;
929*7c478bd9Sstevel@tonic-gate 	int error = Z_ERR;
930*7c478bd9Sstevel@tonic-gate 	int doorfd, lockfd;
931*7c478bd9Sstevel@tonic-gate 	struct door_info info;
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 	get_doorname(zone_name, doorpath);
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	if (grab_lock_file(zone_name, &lockfd) != Z_OK)
936*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	/*
939*7c478bd9Sstevel@tonic-gate 	 * Now that we have the lock, re-confirm that the daemon is
940*7c478bd9Sstevel@tonic-gate 	 * *not* up and working fine.  If it is still down, we have a green
941*7c478bd9Sstevel@tonic-gate 	 * light to start it.
942*7c478bd9Sstevel@tonic-gate 	 */
943*7c478bd9Sstevel@tonic-gate 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
944*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) {
945*7c478bd9Sstevel@tonic-gate 			zperror(doorpath, B_FALSE);
946*7c478bd9Sstevel@tonic-gate 			goto out;
947*7c478bd9Sstevel@tonic-gate 		}
948*7c478bd9Sstevel@tonic-gate 	} else {
949*7c478bd9Sstevel@tonic-gate 		if (door_info(doorfd, &info) == 0 &&
950*7c478bd9Sstevel@tonic-gate 		    ((info.di_attributes & DOOR_REVOKED) == 0)) {
951*7c478bd9Sstevel@tonic-gate 			error = Z_OK;
952*7c478bd9Sstevel@tonic-gate 			(void) close(doorfd);
953*7c478bd9Sstevel@tonic-gate 			goto out;
954*7c478bd9Sstevel@tonic-gate 		}
955*7c478bd9Sstevel@tonic-gate 		(void) close(doorfd);
956*7c478bd9Sstevel@tonic-gate 	}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if ((child_pid = fork()) == -1) {
959*7c478bd9Sstevel@tonic-gate 		zperror(gettext("could not fork"), B_FALSE);
960*7c478bd9Sstevel@tonic-gate 		goto out;
961*7c478bd9Sstevel@tonic-gate 	} else if (child_pid == 0) {
962*7c478bd9Sstevel@tonic-gate 		/* child process */
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 		prepare_audit_context();
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 		(void) execl("/usr/lib/zones/zoneadmd", "zoneadmd", "-z",
967*7c478bd9Sstevel@tonic-gate 		    zone_name, NULL);
968*7c478bd9Sstevel@tonic-gate 		zperror(gettext("could not exec zoneadmd"), B_FALSE);
969*7c478bd9Sstevel@tonic-gate 		_exit(Z_ERR);
970*7c478bd9Sstevel@tonic-gate 	} else {
971*7c478bd9Sstevel@tonic-gate 		/* parent process */
972*7c478bd9Sstevel@tonic-gate 		pid_t retval;
973*7c478bd9Sstevel@tonic-gate 		int pstatus = 0;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 		do {
976*7c478bd9Sstevel@tonic-gate 			retval = waitpid(child_pid, &pstatus, 0);
977*7c478bd9Sstevel@tonic-gate 		} while (retval != child_pid);
978*7c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
979*7c478bd9Sstevel@tonic-gate 		    WEXITSTATUS(pstatus) != 0)) {
980*7c478bd9Sstevel@tonic-gate 			zerror(gettext("could not start %s"), "zoneadmd");
981*7c478bd9Sstevel@tonic-gate 			goto out;
982*7c478bd9Sstevel@tonic-gate 		}
983*7c478bd9Sstevel@tonic-gate 	}
984*7c478bd9Sstevel@tonic-gate 	error = Z_OK;
985*7c478bd9Sstevel@tonic-gate out:
986*7c478bd9Sstevel@tonic-gate 	release_lock_file(lockfd);
987*7c478bd9Sstevel@tonic-gate 	return (error);
988*7c478bd9Sstevel@tonic-gate }
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate static int
991*7c478bd9Sstevel@tonic-gate ping_zoneadmd(const char *zone_name)
992*7c478bd9Sstevel@tonic-gate {
993*7c478bd9Sstevel@tonic-gate 	char doorpath[PATH_MAX];
994*7c478bd9Sstevel@tonic-gate 	int doorfd;
995*7c478bd9Sstevel@tonic-gate 	struct door_info info;
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	get_doorname(zone_name, doorpath);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1000*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1001*7c478bd9Sstevel@tonic-gate 	}
1002*7c478bd9Sstevel@tonic-gate 	if (door_info(doorfd, &info) == 0 &&
1003*7c478bd9Sstevel@tonic-gate 	    ((info.di_attributes & DOOR_REVOKED) == 0)) {
1004*7c478bd9Sstevel@tonic-gate 		(void) close(doorfd);
1005*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
1006*7c478bd9Sstevel@tonic-gate 	}
1007*7c478bd9Sstevel@tonic-gate 	(void) close(doorfd);
1008*7c478bd9Sstevel@tonic-gate 	return (Z_ERR);
1009*7c478bd9Sstevel@tonic-gate }
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate static int
1012*7c478bd9Sstevel@tonic-gate call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg)
1013*7c478bd9Sstevel@tonic-gate {
1014*7c478bd9Sstevel@tonic-gate 	char doorpath[PATH_MAX];
1015*7c478bd9Sstevel@tonic-gate 	int doorfd, result;
1016*7c478bd9Sstevel@tonic-gate 	door_arg_t darg;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
1019*7c478bd9Sstevel@tonic-gate 	uint64_t uniqid = 0;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	zone_cmd_rval_t *rvalp;
1022*7c478bd9Sstevel@tonic-gate 	size_t rlen;
1023*7c478bd9Sstevel@tonic-gate 	char *cp, *errbuf;
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	rlen = getpagesize();
1026*7c478bd9Sstevel@tonic-gate 	if ((rvalp = malloc(rlen)) == NULL) {
1027*7c478bd9Sstevel@tonic-gate 		zerror(gettext("failed to allocate %lu bytes: %s"), rlen,
1028*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1029*7c478bd9Sstevel@tonic-gate 		return (-1);
1030*7c478bd9Sstevel@tonic-gate 	}
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
1033*7c478bd9Sstevel@tonic-gate 		(void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
1034*7c478bd9Sstevel@tonic-gate 		    sizeof (uniqid));
1035*7c478bd9Sstevel@tonic-gate 	}
1036*7c478bd9Sstevel@tonic-gate 	arg->uniqid = uniqid;
1037*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(arg->locale, locale, sizeof (arg->locale));
1038*7c478bd9Sstevel@tonic-gate 	get_doorname(zone_name, doorpath);
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	/*
1041*7c478bd9Sstevel@tonic-gate 	 * Loop trying to start zoneadmd; if something goes seriously
1042*7c478bd9Sstevel@tonic-gate 	 * wrong we break out and fail.
1043*7c478bd9Sstevel@tonic-gate 	 */
1044*7c478bd9Sstevel@tonic-gate 	for (;;) {
1045*7c478bd9Sstevel@tonic-gate 		if (start_zoneadmd(zone_name) != Z_OK)
1046*7c478bd9Sstevel@tonic-gate 			break;
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 		if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1049*7c478bd9Sstevel@tonic-gate 			zperror(gettext("failed to open zone door"), B_FALSE);
1050*7c478bd9Sstevel@tonic-gate 			break;
1051*7c478bd9Sstevel@tonic-gate 		}
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 		darg.data_ptr = (char *)arg;
1054*7c478bd9Sstevel@tonic-gate 		darg.data_size = sizeof (*arg);
1055*7c478bd9Sstevel@tonic-gate 		darg.desc_ptr = NULL;
1056*7c478bd9Sstevel@tonic-gate 		darg.desc_num = 0;
1057*7c478bd9Sstevel@tonic-gate 		darg.rbuf = (char *)rvalp;
1058*7c478bd9Sstevel@tonic-gate 		darg.rsize = rlen;
1059*7c478bd9Sstevel@tonic-gate 		if (door_call(doorfd, &darg) != 0) {
1060*7c478bd9Sstevel@tonic-gate 			(void) close(doorfd);
1061*7c478bd9Sstevel@tonic-gate 			/*
1062*7c478bd9Sstevel@tonic-gate 			 * We'll get EBADF if the door has been revoked.
1063*7c478bd9Sstevel@tonic-gate 			 */
1064*7c478bd9Sstevel@tonic-gate 			if (errno != EBADF) {
1065*7c478bd9Sstevel@tonic-gate 				zperror(gettext("door_call failed"), B_FALSE);
1066*7c478bd9Sstevel@tonic-gate 				break;
1067*7c478bd9Sstevel@tonic-gate 			}
1068*7c478bd9Sstevel@tonic-gate 			continue;	/* take another lap */
1069*7c478bd9Sstevel@tonic-gate 		}
1070*7c478bd9Sstevel@tonic-gate 		(void) close(doorfd);
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 		if (darg.data_size == 0) {
1073*7c478bd9Sstevel@tonic-gate 			/* Door server is going away; kick it again. */
1074*7c478bd9Sstevel@tonic-gate 			continue;
1075*7c478bd9Sstevel@tonic-gate 		}
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 		errbuf = rvalp->errbuf;
1078*7c478bd9Sstevel@tonic-gate 		while (*errbuf != '\0') {
1079*7c478bd9Sstevel@tonic-gate 			/*
1080*7c478bd9Sstevel@tonic-gate 			 * Remove any newlines since zerror()
1081*7c478bd9Sstevel@tonic-gate 			 * will append one automatically.
1082*7c478bd9Sstevel@tonic-gate 			 */
1083*7c478bd9Sstevel@tonic-gate 			cp = strchr(errbuf, '\n');
1084*7c478bd9Sstevel@tonic-gate 			if (cp != NULL)
1085*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
1086*7c478bd9Sstevel@tonic-gate 			zerror("%s", errbuf);
1087*7c478bd9Sstevel@tonic-gate 			if (cp == NULL)
1088*7c478bd9Sstevel@tonic-gate 				break;
1089*7c478bd9Sstevel@tonic-gate 			errbuf = cp + 1;
1090*7c478bd9Sstevel@tonic-gate 		}
1091*7c478bd9Sstevel@tonic-gate 		result = rvalp->rval == 0 ? 0 : -1;
1092*7c478bd9Sstevel@tonic-gate 		free(rvalp);
1093*7c478bd9Sstevel@tonic-gate 		return (result);
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	free(rvalp);
1097*7c478bd9Sstevel@tonic-gate 	return (-1);
1098*7c478bd9Sstevel@tonic-gate }
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate static int
1101*7c478bd9Sstevel@tonic-gate ready_func(int argc, char *argv[])
1102*7c478bd9Sstevel@tonic-gate {
1103*7c478bd9Sstevel@tonic-gate 	zone_cmd_arg_t zarg;
1104*7c478bd9Sstevel@tonic-gate 	int arg;
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	optind = 0;
1107*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1108*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1109*7c478bd9Sstevel@tonic-gate 		case '?':
1110*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_READY, CMD_READY);
1111*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1112*7c478bd9Sstevel@tonic-gate 		default:
1113*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_READY, CMD_READY);
1114*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1115*7c478bd9Sstevel@tonic-gate 		}
1116*7c478bd9Sstevel@tonic-gate 	}
1117*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1118*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_READY, CMD_READY);
1119*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE) != Z_OK)
1122*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1123*7c478bd9Sstevel@tonic-gate 	if (verify_details(CMD_READY) != Z_OK)
1124*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	zarg.cmd = Z_READY;
1127*7c478bd9Sstevel@tonic-gate 	if (call_zoneadmd(target_zone, &zarg) != 0) {
1128*7c478bd9Sstevel@tonic-gate 		zerror(gettext("call to %s failed"), "zoneadmd");
1129*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1130*7c478bd9Sstevel@tonic-gate 	}
1131*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
1132*7c478bd9Sstevel@tonic-gate }
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate static int
1135*7c478bd9Sstevel@tonic-gate boot_func(int argc, char *argv[])
1136*7c478bd9Sstevel@tonic-gate {
1137*7c478bd9Sstevel@tonic-gate 	zone_cmd_arg_t zarg;
1138*7c478bd9Sstevel@tonic-gate 	int arg;
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	zarg.bootbuf[0] = '\0';
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	/*
1143*7c478bd9Sstevel@tonic-gate 	 * At the current time, the only supported subargument to the
1144*7c478bd9Sstevel@tonic-gate 	 * "boot" subcommand is "-s" which specifies a single-user boot.
1145*7c478bd9Sstevel@tonic-gate 	 * In the future, other boot arguments should be supported
1146*7c478bd9Sstevel@tonic-gate 	 * including "-m" for specifying alternate smf(5) milestones.
1147*7c478bd9Sstevel@tonic-gate 	 */
1148*7c478bd9Sstevel@tonic-gate 	optind = 0;
1149*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?s")) != EOF) {
1150*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1151*7c478bd9Sstevel@tonic-gate 		case '?':
1152*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_BOOT, CMD_BOOT);
1153*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1154*7c478bd9Sstevel@tonic-gate 		case 's':
1155*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(zarg.bootbuf, "-s",
1156*7c478bd9Sstevel@tonic-gate 			    sizeof (zarg.bootbuf));
1157*7c478bd9Sstevel@tonic-gate 			break;
1158*7c478bd9Sstevel@tonic-gate 		default:
1159*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_BOOT, CMD_BOOT);
1160*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1161*7c478bd9Sstevel@tonic-gate 		}
1162*7c478bd9Sstevel@tonic-gate 	}
1163*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1164*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_BOOT, CMD_BOOT);
1165*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1166*7c478bd9Sstevel@tonic-gate 	}
1167*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE) != Z_OK)
1168*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1169*7c478bd9Sstevel@tonic-gate 	if (verify_details(CMD_BOOT) != Z_OK)
1170*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1171*7c478bd9Sstevel@tonic-gate 	zarg.cmd = Z_BOOT;
1172*7c478bd9Sstevel@tonic-gate 	if (call_zoneadmd(target_zone, &zarg) != 0) {
1173*7c478bd9Sstevel@tonic-gate 		zerror(gettext("call to %s failed"), "zoneadmd");
1174*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1175*7c478bd9Sstevel@tonic-gate 	}
1176*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
1177*7c478bd9Sstevel@tonic-gate }
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate static void
1180*7c478bd9Sstevel@tonic-gate fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr)
1181*7c478bd9Sstevel@tonic-gate {
1182*7c478bd9Sstevel@tonic-gate 	ssize_t result;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	zeptr->zid = zid;
1185*7c478bd9Sstevel@tonic-gate 	/*
1186*7c478bd9Sstevel@tonic-gate 	 * Since we're looking up our own (non-global) zone name,
1187*7c478bd9Sstevel@tonic-gate 	 * we can be assured that it will succeed.
1188*7c478bd9Sstevel@tonic-gate 	 */
1189*7c478bd9Sstevel@tonic-gate 	result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname));
1190*7c478bd9Sstevel@tonic-gate 	assert(result >= 0);
1191*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
1192*7c478bd9Sstevel@tonic-gate 	zeptr->zstate_str = "running";
1193*7c478bd9Sstevel@tonic-gate }
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate static int
1196*7c478bd9Sstevel@tonic-gate list_func(int argc, char *argv[])
1197*7c478bd9Sstevel@tonic-gate {
1198*7c478bd9Sstevel@tonic-gate 	zone_entry_t *zentp, zent;
1199*7c478bd9Sstevel@tonic-gate 	int arg;
1200*7c478bd9Sstevel@tonic-gate 	boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE;
1201*7c478bd9Sstevel@tonic-gate 	zone_state_t min_state = ZONE_STATE_RUNNING;
1202*7c478bd9Sstevel@tonic-gate 	zoneid_t zone_id = getzoneid();
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	if (target_zone == NULL) {
1205*7c478bd9Sstevel@tonic-gate 		/* all zones: default view to running but allow override */
1206*7c478bd9Sstevel@tonic-gate 		optind = 0;
1207*7c478bd9Sstevel@tonic-gate 		while ((arg = getopt(argc, argv, "?cipv")) != EOF) {
1208*7c478bd9Sstevel@tonic-gate 			switch (arg) {
1209*7c478bd9Sstevel@tonic-gate 			case '?':
1210*7c478bd9Sstevel@tonic-gate 				sub_usage(SHELP_LIST, CMD_LIST);
1211*7c478bd9Sstevel@tonic-gate 				return (optopt == '?' ? Z_OK : Z_USAGE);
1212*7c478bd9Sstevel@tonic-gate 			case 'c':
1213*7c478bd9Sstevel@tonic-gate 				min_state = ZONE_STATE_CONFIGURED;
1214*7c478bd9Sstevel@tonic-gate 				break;
1215*7c478bd9Sstevel@tonic-gate 			case 'i':
1216*7c478bd9Sstevel@tonic-gate 				min_state = ZONE_STATE_INSTALLED;
1217*7c478bd9Sstevel@tonic-gate 				break;
1218*7c478bd9Sstevel@tonic-gate 			case 'p':
1219*7c478bd9Sstevel@tonic-gate 				parsable = B_TRUE;
1220*7c478bd9Sstevel@tonic-gate 				break;
1221*7c478bd9Sstevel@tonic-gate 			case 'v':
1222*7c478bd9Sstevel@tonic-gate 				verbose = B_TRUE;
1223*7c478bd9Sstevel@tonic-gate 				break;
1224*7c478bd9Sstevel@tonic-gate 			default:
1225*7c478bd9Sstevel@tonic-gate 				sub_usage(SHELP_LIST, CMD_LIST);
1226*7c478bd9Sstevel@tonic-gate 				return (Z_USAGE);
1227*7c478bd9Sstevel@tonic-gate 			}
1228*7c478bd9Sstevel@tonic-gate 		}
1229*7c478bd9Sstevel@tonic-gate 		if (parsable && verbose) {
1230*7c478bd9Sstevel@tonic-gate 			zerror(gettext("%s -p and -v are mutually exclusive."),
1231*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(CMD_LIST));
1232*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
1233*7c478bd9Sstevel@tonic-gate 		}
1234*7c478bd9Sstevel@tonic-gate 		if (zone_id == GLOBAL_ZONEID) {
1235*7c478bd9Sstevel@tonic-gate 			zone_print_list(min_state, verbose, parsable);
1236*7c478bd9Sstevel@tonic-gate 		} else {
1237*7c478bd9Sstevel@tonic-gate 			fake_up_local_zone(zone_id, &zent);
1238*7c478bd9Sstevel@tonic-gate 			zone_print(&zent, verbose, parsable);
1239*7c478bd9Sstevel@tonic-gate 		}
1240*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
1241*7c478bd9Sstevel@tonic-gate 	}
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	/*
1244*7c478bd9Sstevel@tonic-gate 	 * Specific target zone: disallow -i/-c suboptions.
1245*7c478bd9Sstevel@tonic-gate 	 */
1246*7c478bd9Sstevel@tonic-gate 	optind = 0;
1247*7c478bd9Sstevel@tonic-gate 	while ((arg = getopt(argc, argv, "?pv")) != EOF) {
1248*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1249*7c478bd9Sstevel@tonic-gate 		case '?':
1250*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_LIST, CMD_LIST);
1251*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1252*7c478bd9Sstevel@tonic-gate 		case 'p':
1253*7c478bd9Sstevel@tonic-gate 			parsable = B_TRUE;
1254*7c478bd9Sstevel@tonic-gate 			break;
1255*7c478bd9Sstevel@tonic-gate 		case 'v':
1256*7c478bd9Sstevel@tonic-gate 			verbose = B_TRUE;
1257*7c478bd9Sstevel@tonic-gate 			break;
1258*7c478bd9Sstevel@tonic-gate 		default:
1259*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_LIST, CMD_LIST);
1260*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1261*7c478bd9Sstevel@tonic-gate 		}
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 	if (parsable && verbose) {
1264*7c478bd9Sstevel@tonic-gate 		zerror(gettext("%s -p and -v are mutually exclusive."),
1265*7c478bd9Sstevel@tonic-gate 		    cmd_to_str(CMD_LIST));
1266*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1269*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_LIST, CMD_LIST);
1270*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1271*7c478bd9Sstevel@tonic-gate 	}
1272*7c478bd9Sstevel@tonic-gate 	if (zone_id != GLOBAL_ZONEID) {
1273*7c478bd9Sstevel@tonic-gate 		fake_up_local_zone(zone_id, &zent);
1274*7c478bd9Sstevel@tonic-gate 		/*
1275*7c478bd9Sstevel@tonic-gate 		 * main() will issue a Z_NO_ZONE error if it cannot get an
1276*7c478bd9Sstevel@tonic-gate 		 * id for target_zone, which in a non-global zone should
1277*7c478bd9Sstevel@tonic-gate 		 * happen for any zone name except `zonename`.  Thus we
1278*7c478bd9Sstevel@tonic-gate 		 * assert() that here but don't otherwise check.
1279*7c478bd9Sstevel@tonic-gate 		 */
1280*7c478bd9Sstevel@tonic-gate 		assert(strcmp(zent.zname, target_zone) == 0);
1281*7c478bd9Sstevel@tonic-gate 		zone_print(&zent, verbose, parsable);
1282*7c478bd9Sstevel@tonic-gate 		output = B_TRUE;
1283*7c478bd9Sstevel@tonic-gate 	} else if ((zentp = lookup_running_zone(target_zone)) != NULL) {
1284*7c478bd9Sstevel@tonic-gate 		zone_print(zentp, verbose, parsable);
1285*7c478bd9Sstevel@tonic-gate 		output = B_TRUE;
1286*7c478bd9Sstevel@tonic-gate 	} else if (lookup_zone_info(target_zone, &zent) == Z_OK) {
1287*7c478bd9Sstevel@tonic-gate 		zone_print(&zent, verbose, parsable);
1288*7c478bd9Sstevel@tonic-gate 		output = B_TRUE;
1289*7c478bd9Sstevel@tonic-gate 	}
1290*7c478bd9Sstevel@tonic-gate 	return (output ? Z_OK : Z_ERR);
1291*7c478bd9Sstevel@tonic-gate }
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate static void
1294*7c478bd9Sstevel@tonic-gate sigterm(int sig)
1295*7c478bd9Sstevel@tonic-gate {
1296*7c478bd9Sstevel@tonic-gate 	/*
1297*7c478bd9Sstevel@tonic-gate 	 * Ignore SIG{INT,TERM}, so we don't end up in an infinite loop,
1298*7c478bd9Sstevel@tonic-gate 	 * then propagate the signal to our process group.
1299*7c478bd9Sstevel@tonic-gate 	 */
1300*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, SIG_IGN);
1301*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, SIG_IGN);
1302*7c478bd9Sstevel@tonic-gate 	(void) kill(0, sig);
1303*7c478bd9Sstevel@tonic-gate 	child_killed = B_TRUE;
1304*7c478bd9Sstevel@tonic-gate }
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate static int
1307*7c478bd9Sstevel@tonic-gate do_subproc(char *cmdbuf)
1308*7c478bd9Sstevel@tonic-gate {
1309*7c478bd9Sstevel@tonic-gate 	char inbuf[1024];	/* arbitrary large amount */
1310*7c478bd9Sstevel@tonic-gate 	FILE *file;
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	child_killed = B_FALSE;
1313*7c478bd9Sstevel@tonic-gate 	/*
1314*7c478bd9Sstevel@tonic-gate 	 * We use popen(3c) to launch child processes for [un]install;
1315*7c478bd9Sstevel@tonic-gate 	 * this library call does not return a PID, so we have to kill
1316*7c478bd9Sstevel@tonic-gate 	 * the whole process group.  To avoid killing our parent, we
1317*7c478bd9Sstevel@tonic-gate 	 * become a process group leader here.  But doing so can wreak
1318*7c478bd9Sstevel@tonic-gate 	 * havoc with reading from stdin when launched by a non-job-control
1319*7c478bd9Sstevel@tonic-gate 	 * shell, so we close stdin and reopen it as /dev/null first.
1320*7c478bd9Sstevel@tonic-gate 	 */
1321*7c478bd9Sstevel@tonic-gate 	(void) close(STDIN_FILENO);
1322*7c478bd9Sstevel@tonic-gate 	(void) open("/dev/null", O_RDONLY);
1323*7c478bd9Sstevel@tonic-gate 	(void) setpgid(0, 0);
1324*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, sigterm);
1325*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, sigterm);
1326*7c478bd9Sstevel@tonic-gate 	file = popen(cmdbuf, "r");
1327*7c478bd9Sstevel@tonic-gate 	for (;;) {
1328*7c478bd9Sstevel@tonic-gate 		if (child_killed || fgets(inbuf, sizeof (inbuf), file) == NULL)
1329*7c478bd9Sstevel@tonic-gate 			break;
1330*7c478bd9Sstevel@tonic-gate 		(void) fputs(inbuf, stdout);
1331*7c478bd9Sstevel@tonic-gate 	}
1332*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, SIG_DFL);
1333*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, SIG_DFL);
1334*7c478bd9Sstevel@tonic-gate 	return (pclose(file));
1335*7c478bd9Sstevel@tonic-gate }
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate static int
1338*7c478bd9Sstevel@tonic-gate subproc_status(const char *cmd, int status)
1339*7c478bd9Sstevel@tonic-gate {
1340*7c478bd9Sstevel@tonic-gate 	if (WIFEXITED(status)) {
1341*7c478bd9Sstevel@tonic-gate 		int exit_code = WEXITSTATUS(status);
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 		if (exit_code == 0)
1344*7c478bd9Sstevel@tonic-gate 			return (Z_OK);
1345*7c478bd9Sstevel@tonic-gate 		zerror(gettext("'%s' failed with exit code %d."), cmd,
1346*7c478bd9Sstevel@tonic-gate 		    exit_code);
1347*7c478bd9Sstevel@tonic-gate 	} else if (WIFSIGNALED(status)) {
1348*7c478bd9Sstevel@tonic-gate 		int signal = WTERMSIG(status);
1349*7c478bd9Sstevel@tonic-gate 		char sigstr[SIG2STR_MAX];
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 		if (sig2str(signal, sigstr) == 0) {
1352*7c478bd9Sstevel@tonic-gate 			zerror(gettext("'%s' terminated by signal SIG%s."), cmd,
1353*7c478bd9Sstevel@tonic-gate 			    sigstr);
1354*7c478bd9Sstevel@tonic-gate 		} else {
1355*7c478bd9Sstevel@tonic-gate 			zerror(gettext("'%s' terminated by an unknown signal."),
1356*7c478bd9Sstevel@tonic-gate 			    cmd);
1357*7c478bd9Sstevel@tonic-gate 		}
1358*7c478bd9Sstevel@tonic-gate 	} else {
1359*7c478bd9Sstevel@tonic-gate 		zerror(gettext("'%s' failed for unknown reasons."), cmd);
1360*7c478bd9Sstevel@tonic-gate 	}
1361*7c478bd9Sstevel@tonic-gate 	return (Z_ERR);
1362*7c478bd9Sstevel@tonic-gate }
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate /*
1365*7c478bd9Sstevel@tonic-gate  * Various sanity checks; make sure:
1366*7c478bd9Sstevel@tonic-gate  * 1. We're in the global zone.
1367*7c478bd9Sstevel@tonic-gate  * 2. The calling user has sufficient privilege.
1368*7c478bd9Sstevel@tonic-gate  * 3. The target zone is neither the global zone nor anything starting with
1369*7c478bd9Sstevel@tonic-gate  *    "SUNW".
1370*7c478bd9Sstevel@tonic-gate  * 4a. If we're looking for a 'not running' (i.e., configured or installed)
1371*7c478bd9Sstevel@tonic-gate  *     zone, the name service knows about it.
1372*7c478bd9Sstevel@tonic-gate  * 4b. For some operations which expect a zone not to be running, that it is
1373*7c478bd9Sstevel@tonic-gate  *     not already running (or ready).
1374*7c478bd9Sstevel@tonic-gate  */
1375*7c478bd9Sstevel@tonic-gate static int
1376*7c478bd9Sstevel@tonic-gate sanity_check(char *zone, int cmd_num, boolean_t running,
1377*7c478bd9Sstevel@tonic-gate     boolean_t unsafe_when_running)
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	zone_entry_t *zent;
1380*7c478bd9Sstevel@tonic-gate 	priv_set_t *privset;
1381*7c478bd9Sstevel@tonic-gate 	zone_state_t state;
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
1384*7c478bd9Sstevel@tonic-gate 		zerror(gettext("must be in the global zone to %s a zone."),
1385*7c478bd9Sstevel@tonic-gate 		    cmd_to_str(cmd_num));
1386*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1387*7c478bd9Sstevel@tonic-gate 	}
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	if ((privset = priv_allocset()) == NULL) {
1390*7c478bd9Sstevel@tonic-gate 		zerror(gettext("%s failed"), "priv_allocset");
1391*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1392*7c478bd9Sstevel@tonic-gate 	}
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate 	if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1395*7c478bd9Sstevel@tonic-gate 		zerror(gettext("%s failed"), "getppriv");
1396*7c478bd9Sstevel@tonic-gate 		priv_freeset(privset);
1397*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1398*7c478bd9Sstevel@tonic-gate 	}
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 	if (priv_isfullset(privset) == B_FALSE) {
1401*7c478bd9Sstevel@tonic-gate 		zerror(gettext("only a privileged user may %s a zone."),
1402*7c478bd9Sstevel@tonic-gate 		    cmd_to_str(cmd_num));
1403*7c478bd9Sstevel@tonic-gate 		priv_freeset(privset);
1404*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1405*7c478bd9Sstevel@tonic-gate 	}
1406*7c478bd9Sstevel@tonic-gate 	priv_freeset(privset);
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate 	if (zone == NULL) {
1409*7c478bd9Sstevel@tonic-gate 		zerror(gettext("no zone specified"));
1410*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1411*7c478bd9Sstevel@tonic-gate 	}
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate 	zent = lookup_running_zone(zone);
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
1416*7c478bd9Sstevel@tonic-gate 		assert((zent != NULL) && (zent->zid == GLOBAL_ZONEID));
1417*7c478bd9Sstevel@tonic-gate 		zerror(gettext("%s operation is invalid for the global zone."),
1418*7c478bd9Sstevel@tonic-gate 		    cmd_to_str(cmd_num));
1419*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1420*7c478bd9Sstevel@tonic-gate 	}
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	if (strncmp(zone, "SUNW", 4) == 0) {
1423*7c478bd9Sstevel@tonic-gate 		zerror(gettext("%s operation is invalid for zones starting "
1424*7c478bd9Sstevel@tonic-gate 		    "with SUNW."), cmd_to_str(cmd_num));
1425*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1426*7c478bd9Sstevel@tonic-gate 	}
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate 	/*
1429*7c478bd9Sstevel@tonic-gate 	 * Look up from the kernel for 'running' zones.
1430*7c478bd9Sstevel@tonic-gate 	 */
1431*7c478bd9Sstevel@tonic-gate 	if (running) {
1432*7c478bd9Sstevel@tonic-gate 		if (zent == NULL) {
1433*7c478bd9Sstevel@tonic-gate 			zerror(gettext("not running"));
1434*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
1435*7c478bd9Sstevel@tonic-gate 		}
1436*7c478bd9Sstevel@tonic-gate 	} else {
1437*7c478bd9Sstevel@tonic-gate 		int err;
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate 		if (unsafe_when_running && zent != NULL) {
1440*7c478bd9Sstevel@tonic-gate 			/* check whether the zone is ready or running */
1441*7c478bd9Sstevel@tonic-gate 			if ((err = zone_get_state(zent->zname,
1442*7c478bd9Sstevel@tonic-gate 			    &zent->zstate_num)) != Z_OK) {
1443*7c478bd9Sstevel@tonic-gate 				errno = err;
1444*7c478bd9Sstevel@tonic-gate 				zperror2(zent->zname,
1445*7c478bd9Sstevel@tonic-gate 				    gettext("could not get state"));
1446*7c478bd9Sstevel@tonic-gate 				/* can't tell, so hedge */
1447*7c478bd9Sstevel@tonic-gate 				zent->zstate_str = "ready/running";
1448*7c478bd9Sstevel@tonic-gate 			} else {
1449*7c478bd9Sstevel@tonic-gate 				zent->zstate_str =
1450*7c478bd9Sstevel@tonic-gate 				    zone_state_str(zent->zstate_num);
1451*7c478bd9Sstevel@tonic-gate 			}
1452*7c478bd9Sstevel@tonic-gate 			zerror(gettext("%s operation is invalid for %s zones."),
1453*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(cmd_num), zent->zstate_str);
1454*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
1455*7c478bd9Sstevel@tonic-gate 		}
1456*7c478bd9Sstevel@tonic-gate 		if ((err = zone_get_state(zone, &state)) != Z_OK) {
1457*7c478bd9Sstevel@tonic-gate 			errno = err;
1458*7c478bd9Sstevel@tonic-gate 			zperror2(zone, gettext("could not get state"));
1459*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
1460*7c478bd9Sstevel@tonic-gate 		}
1461*7c478bd9Sstevel@tonic-gate 		switch (cmd_num) {
1462*7c478bd9Sstevel@tonic-gate 		case CMD_UNINSTALL:
1463*7c478bd9Sstevel@tonic-gate 			if (state == ZONE_STATE_CONFIGURED) {
1464*7c478bd9Sstevel@tonic-gate 				zerror(gettext("is already in state '%s'."),
1465*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ZONE_STATE_CONFIGURED));
1466*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
1467*7c478bd9Sstevel@tonic-gate 			}
1468*7c478bd9Sstevel@tonic-gate 			break;
1469*7c478bd9Sstevel@tonic-gate 		case CMD_INSTALL:
1470*7c478bd9Sstevel@tonic-gate 			if (state == ZONE_STATE_INSTALLED) {
1471*7c478bd9Sstevel@tonic-gate 				zerror(gettext("is already %s."),
1472*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ZONE_STATE_INSTALLED));
1473*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
1474*7c478bd9Sstevel@tonic-gate 			} else if (state == ZONE_STATE_INCOMPLETE) {
1475*7c478bd9Sstevel@tonic-gate 				zerror(gettext("zone is %s; %s required."),
1476*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ZONE_STATE_INCOMPLETE),
1477*7c478bd9Sstevel@tonic-gate 				    cmd_to_str(CMD_UNINSTALL));
1478*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
1479*7c478bd9Sstevel@tonic-gate 			}
1480*7c478bd9Sstevel@tonic-gate 			break;
1481*7c478bd9Sstevel@tonic-gate 		case CMD_READY:
1482*7c478bd9Sstevel@tonic-gate 		case CMD_BOOT:
1483*7c478bd9Sstevel@tonic-gate 			if (state < ZONE_STATE_INSTALLED) {
1484*7c478bd9Sstevel@tonic-gate 				zerror(gettext("must be %s before %s."),
1485*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ZONE_STATE_INSTALLED),
1486*7c478bd9Sstevel@tonic-gate 				    cmd_to_str(cmd_num));
1487*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
1488*7c478bd9Sstevel@tonic-gate 			}
1489*7c478bd9Sstevel@tonic-gate 			break;
1490*7c478bd9Sstevel@tonic-gate 		case CMD_VERIFY:
1491*7c478bd9Sstevel@tonic-gate 			if (state == ZONE_STATE_INCOMPLETE) {
1492*7c478bd9Sstevel@tonic-gate 				zerror(gettext("zone is %s; %s required."),
1493*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ZONE_STATE_INCOMPLETE),
1494*7c478bd9Sstevel@tonic-gate 				    cmd_to_str(CMD_UNINSTALL));
1495*7c478bd9Sstevel@tonic-gate 				return (Z_ERR);
1496*7c478bd9Sstevel@tonic-gate 			}
1497*7c478bd9Sstevel@tonic-gate 			break;
1498*7c478bd9Sstevel@tonic-gate 		}
1499*7c478bd9Sstevel@tonic-gate 	}
1500*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
1501*7c478bd9Sstevel@tonic-gate }
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate static int
1504*7c478bd9Sstevel@tonic-gate halt_func(int argc, char *argv[])
1505*7c478bd9Sstevel@tonic-gate {
1506*7c478bd9Sstevel@tonic-gate 	zone_cmd_arg_t zarg;
1507*7c478bd9Sstevel@tonic-gate 	int arg;
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	optind = 0;
1510*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1511*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1512*7c478bd9Sstevel@tonic-gate 		case '?':
1513*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_HALT, CMD_HALT);
1514*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1515*7c478bd9Sstevel@tonic-gate 		default:
1516*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_HALT, CMD_HALT);
1517*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1518*7c478bd9Sstevel@tonic-gate 		}
1519*7c478bd9Sstevel@tonic-gate 	}
1520*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1521*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_HALT, CMD_HALT);
1522*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1523*7c478bd9Sstevel@tonic-gate 	}
1524*7c478bd9Sstevel@tonic-gate 	/*
1525*7c478bd9Sstevel@tonic-gate 	 * zoneadmd should be the one to decide whether or not to proceed,
1526*7c478bd9Sstevel@tonic-gate 	 * so even though it seems that the fourth parameter below should
1527*7c478bd9Sstevel@tonic-gate 	 * perhaps be B_TRUE, it really shouldn't be.
1528*7c478bd9Sstevel@tonic-gate 	 */
1529*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE) != Z_OK)
1530*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate 	zarg.cmd = Z_HALT;
1533*7c478bd9Sstevel@tonic-gate 	return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
1534*7c478bd9Sstevel@tonic-gate }
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate static int
1537*7c478bd9Sstevel@tonic-gate reboot_func(int argc, char *argv[])
1538*7c478bd9Sstevel@tonic-gate {
1539*7c478bd9Sstevel@tonic-gate 	zone_cmd_arg_t zarg;
1540*7c478bd9Sstevel@tonic-gate 	int arg;
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate 	optind = 0;
1543*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1544*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1545*7c478bd9Sstevel@tonic-gate 		case '?':
1546*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
1547*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1548*7c478bd9Sstevel@tonic-gate 		default:
1549*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
1550*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1551*7c478bd9Sstevel@tonic-gate 		}
1552*7c478bd9Sstevel@tonic-gate 	}
1553*7c478bd9Sstevel@tonic-gate 	if (argc > 0) {
1554*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_REBOOT, CMD_REBOOT);
1555*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1556*7c478bd9Sstevel@tonic-gate 	}
1557*7c478bd9Sstevel@tonic-gate 	/*
1558*7c478bd9Sstevel@tonic-gate 	 * zoneadmd should be the one to decide whether or not to proceed,
1559*7c478bd9Sstevel@tonic-gate 	 * so even though it seems that the fourth parameter below should
1560*7c478bd9Sstevel@tonic-gate 	 * perhaps be B_TRUE, it really shouldn't be.
1561*7c478bd9Sstevel@tonic-gate 	 */
1562*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE) != Z_OK)
1563*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 	zarg.cmd = Z_REBOOT;
1566*7c478bd9Sstevel@tonic-gate 	return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
1567*7c478bd9Sstevel@tonic-gate }
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate static int
1570*7c478bd9Sstevel@tonic-gate verify_rctls(zone_dochandle_t handle)
1571*7c478bd9Sstevel@tonic-gate {
1572*7c478bd9Sstevel@tonic-gate 	struct zone_rctltab rctltab;
1573*7c478bd9Sstevel@tonic-gate 	size_t rbs = rctlblk_size();
1574*7c478bd9Sstevel@tonic-gate 	rctlblk_t *rctlblk;
1575*7c478bd9Sstevel@tonic-gate 	int error = Z_INVAL;
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate 	if ((rctlblk = malloc(rbs)) == NULL) {
1578*7c478bd9Sstevel@tonic-gate 		zerror(gettext("failed to allocate %lu bytes: %s"), rbs,
1579*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
1580*7c478bd9Sstevel@tonic-gate 		return (Z_NOMEM);
1581*7c478bd9Sstevel@tonic-gate 	}
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 	if (zonecfg_setrctlent(handle) != Z_OK) {
1584*7c478bd9Sstevel@tonic-gate 		zerror(gettext("zonecfg_setrctlent failed"));
1585*7c478bd9Sstevel@tonic-gate 		free(rctlblk);
1586*7c478bd9Sstevel@tonic-gate 		return (error);
1587*7c478bd9Sstevel@tonic-gate 	}
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 	rctltab.zone_rctl_valptr = NULL;
1590*7c478bd9Sstevel@tonic-gate 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
1591*7c478bd9Sstevel@tonic-gate 		struct zone_rctlvaltab *rctlval;
1592*7c478bd9Sstevel@tonic-gate 		const char *name = rctltab.zone_rctl_name;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 		if (!zonecfg_is_rctl(name)) {
1595*7c478bd9Sstevel@tonic-gate 			zerror(gettext("WARNING: Ignoring unrecognized rctl "
1596*7c478bd9Sstevel@tonic-gate 			    "'%s'."),  name);
1597*7c478bd9Sstevel@tonic-gate 			zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1598*7c478bd9Sstevel@tonic-gate 			rctltab.zone_rctl_valptr = NULL;
1599*7c478bd9Sstevel@tonic-gate 			continue;
1600*7c478bd9Sstevel@tonic-gate 		}
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 		for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL;
1603*7c478bd9Sstevel@tonic-gate 		    rctlval = rctlval->zone_rctlval_next) {
1604*7c478bd9Sstevel@tonic-gate 			if (zonecfg_construct_rctlblk(rctlval, rctlblk)
1605*7c478bd9Sstevel@tonic-gate 			    != Z_OK) {
1606*7c478bd9Sstevel@tonic-gate 				zerror(gettext("invalid rctl value: "
1607*7c478bd9Sstevel@tonic-gate 				    "(priv=%s,limit=%s,action%s)"),
1608*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_priv,
1609*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_limit,
1610*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_action);
1611*7c478bd9Sstevel@tonic-gate 				goto out;
1612*7c478bd9Sstevel@tonic-gate 			}
1613*7c478bd9Sstevel@tonic-gate 			if (!zonecfg_valid_rctl(name, rctlblk)) {
1614*7c478bd9Sstevel@tonic-gate 				zerror(gettext("(priv=%s,limit=%s,action=%s) "
1615*7c478bd9Sstevel@tonic-gate 				    "is not a valid value for rctl '%s'"),
1616*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_priv,
1617*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_limit,
1618*7c478bd9Sstevel@tonic-gate 				    rctlval->zone_rctlval_action,
1619*7c478bd9Sstevel@tonic-gate 				    name);
1620*7c478bd9Sstevel@tonic-gate 				goto out;
1621*7c478bd9Sstevel@tonic-gate 			}
1622*7c478bd9Sstevel@tonic-gate 		}
1623*7c478bd9Sstevel@tonic-gate 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1624*7c478bd9Sstevel@tonic-gate 	}
1625*7c478bd9Sstevel@tonic-gate 	rctltab.zone_rctl_valptr = NULL;
1626*7c478bd9Sstevel@tonic-gate 	error = Z_OK;
1627*7c478bd9Sstevel@tonic-gate out:
1628*7c478bd9Sstevel@tonic-gate 	zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1629*7c478bd9Sstevel@tonic-gate 	(void) zonecfg_endrctlent(handle);
1630*7c478bd9Sstevel@tonic-gate 	free(rctlblk);
1631*7c478bd9Sstevel@tonic-gate 	return (error);
1632*7c478bd9Sstevel@tonic-gate }
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate static int
1635*7c478bd9Sstevel@tonic-gate verify_pool(zone_dochandle_t handle)
1636*7c478bd9Sstevel@tonic-gate {
1637*7c478bd9Sstevel@tonic-gate 	char poolname[MAXPATHLEN];
1638*7c478bd9Sstevel@tonic-gate 	pool_conf_t *poolconf;
1639*7c478bd9Sstevel@tonic-gate 	pool_t *pool;
1640*7c478bd9Sstevel@tonic-gate 	int status;
1641*7c478bd9Sstevel@tonic-gate 	int error;
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 	/*
1644*7c478bd9Sstevel@tonic-gate 	 * This ends up being very similar to the check done in zoneadmd.
1645*7c478bd9Sstevel@tonic-gate 	 */
1646*7c478bd9Sstevel@tonic-gate 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
1647*7c478bd9Sstevel@tonic-gate 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
1648*7c478bd9Sstevel@tonic-gate 		/*
1649*7c478bd9Sstevel@tonic-gate 		 * No pool specified.
1650*7c478bd9Sstevel@tonic-gate 		 */
1651*7c478bd9Sstevel@tonic-gate 		return (0);
1652*7c478bd9Sstevel@tonic-gate 	}
1653*7c478bd9Sstevel@tonic-gate 	if (error != Z_OK) {
1654*7c478bd9Sstevel@tonic-gate 		zperror(gettext("Unable to retrieve pool name from "
1655*7c478bd9Sstevel@tonic-gate 		    "configuration"), B_TRUE);
1656*7c478bd9Sstevel@tonic-gate 		return (error);
1657*7c478bd9Sstevel@tonic-gate 	}
1658*7c478bd9Sstevel@tonic-gate 	/*
1659*7c478bd9Sstevel@tonic-gate 	 * Don't do anything if pools aren't enabled.
1660*7c478bd9Sstevel@tonic-gate 	 */
1661*7c478bd9Sstevel@tonic-gate 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
1662*7c478bd9Sstevel@tonic-gate 		zerror(gettext("WARNING: pools facility not active; "
1663*7c478bd9Sstevel@tonic-gate 		    "zone will not be bound to pool '%s'."), poolname);
1664*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
1665*7c478bd9Sstevel@tonic-gate 	}
1666*7c478bd9Sstevel@tonic-gate 	/*
1667*7c478bd9Sstevel@tonic-gate 	 * Try to provide a sane error message if the requested pool doesn't
1668*7c478bd9Sstevel@tonic-gate 	 * exist.  It isn't clear that pools-related failures should
1669*7c478bd9Sstevel@tonic-gate 	 * necessarily translate to a failure to verify the zone configuration,
1670*7c478bd9Sstevel@tonic-gate 	 * hence they are not considered errors.
1671*7c478bd9Sstevel@tonic-gate 	 */
1672*7c478bd9Sstevel@tonic-gate 	if ((poolconf = pool_conf_alloc()) == NULL) {
1673*7c478bd9Sstevel@tonic-gate 		zerror(gettext("WARNING: pool_conf_alloc failed; "
1674*7c478bd9Sstevel@tonic-gate 		    "using default pool"));
1675*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
1676*7c478bd9Sstevel@tonic-gate 	}
1677*7c478bd9Sstevel@tonic-gate 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
1678*7c478bd9Sstevel@tonic-gate 	    PO_SUCCESS) {
1679*7c478bd9Sstevel@tonic-gate 		zerror(gettext("WARNING: pool_conf_open failed; "
1680*7c478bd9Sstevel@tonic-gate 		    "using default pool"));
1681*7c478bd9Sstevel@tonic-gate 		pool_conf_free(poolconf);
1682*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
1683*7c478bd9Sstevel@tonic-gate 	}
1684*7c478bd9Sstevel@tonic-gate 	pool = pool_get_pool(poolconf, poolname);
1685*7c478bd9Sstevel@tonic-gate 	(void) pool_conf_close(poolconf);
1686*7c478bd9Sstevel@tonic-gate 	pool_conf_free(poolconf);
1687*7c478bd9Sstevel@tonic-gate 	if (pool == NULL) {
1688*7c478bd9Sstevel@tonic-gate 		zerror(gettext("WARNING: pool '%s' not found. "
1689*7c478bd9Sstevel@tonic-gate 		    "using default pool"), poolname);
1690*7c478bd9Sstevel@tonic-gate 	}
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
1693*7c478bd9Sstevel@tonic-gate }
1694*7c478bd9Sstevel@tonic-gate 
1695*7c478bd9Sstevel@tonic-gate static int
1696*7c478bd9Sstevel@tonic-gate verify_filesystems(zone_dochandle_t handle)
1697*7c478bd9Sstevel@tonic-gate {
1698*7c478bd9Sstevel@tonic-gate 	int return_code = Z_OK;
1699*7c478bd9Sstevel@tonic-gate 	struct zone_fstab fstab;
1700*7c478bd9Sstevel@tonic-gate 	char cmdbuf[MAXPATHLEN];
1701*7c478bd9Sstevel@tonic-gate 	struct stat st;
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 	/*
1704*7c478bd9Sstevel@tonic-gate 	 * No need to verify inherit-pkg-dir fs types, as their type is
1705*7c478bd9Sstevel@tonic-gate 	 * implicitly lofs, which is known.  Therefore, the types are only
1706*7c478bd9Sstevel@tonic-gate 	 * verified for regular filesystems below.
1707*7c478bd9Sstevel@tonic-gate 	 *
1708*7c478bd9Sstevel@tonic-gate 	 * Since the actual mount point is not known until the dependent mounts
1709*7c478bd9Sstevel@tonic-gate 	 * are performed, we don't attempt any path validation here: that will
1710*7c478bd9Sstevel@tonic-gate 	 * happen later when zoneadmd actually does the mounts.
1711*7c478bd9Sstevel@tonic-gate 	 */
1712*7c478bd9Sstevel@tonic-gate 	if (zonecfg_setfsent(handle) != Z_OK) {
1713*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cannot verify file-systems: "
1714*7c478bd9Sstevel@tonic-gate 		    "unable to enumerate mounts\n"));
1715*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1716*7c478bd9Sstevel@tonic-gate 	}
1717*7c478bd9Sstevel@tonic-gate 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1718*7c478bd9Sstevel@tonic-gate 		if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) {
1719*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1720*7c478bd9Sstevel@tonic-gate 			    "type %s is not allowed.\n"), fstab.zone_fs_dir,
1721*7c478bd9Sstevel@tonic-gate 			    fstab.zone_fs_type);
1722*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1723*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1724*7c478bd9Sstevel@tonic-gate 		}
1725*7c478bd9Sstevel@tonic-gate 		/*
1726*7c478bd9Sstevel@tonic-gate 		 * Verify /usr/lib/fs/<fstype>/mount exists.
1727*7c478bd9Sstevel@tonic-gate 		 */
1728*7c478bd9Sstevel@tonic-gate 		if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount",
1729*7c478bd9Sstevel@tonic-gate 		    fstab.zone_fs_type) > sizeof (cmdbuf)) {
1730*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1731*7c478bd9Sstevel@tonic-gate 			    "type %s is too long.\n"), fstab.zone_fs_dir,
1732*7c478bd9Sstevel@tonic-gate 			    fstab.zone_fs_type);
1733*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1734*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1735*7c478bd9Sstevel@tonic-gate 		}
1736*7c478bd9Sstevel@tonic-gate 		if (stat(cmdbuf, &st) != 0) {
1737*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1738*7c478bd9Sstevel@tonic-gate 			    "can't access %s: %s\n"), fstab.zone_fs_dir,
1739*7c478bd9Sstevel@tonic-gate 			    cmdbuf, strerror(errno));
1740*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1741*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1742*7c478bd9Sstevel@tonic-gate 		}
1743*7c478bd9Sstevel@tonic-gate 		if (!S_ISREG(st.st_mode)) {
1744*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1745*7c478bd9Sstevel@tonic-gate 			    "%s is not a regular file\n"), fstab.zone_fs_dir,
1746*7c478bd9Sstevel@tonic-gate 			    cmdbuf);
1747*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1748*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1749*7c478bd9Sstevel@tonic-gate 		}
1750*7c478bd9Sstevel@tonic-gate 		/*
1751*7c478bd9Sstevel@tonic-gate 		 * Verify /usr/lib/fs/<fstype>/fsck exists iff zone_fs_raw is
1752*7c478bd9Sstevel@tonic-gate 		 * set.
1753*7c478bd9Sstevel@tonic-gate 		 */
1754*7c478bd9Sstevel@tonic-gate 		if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck",
1755*7c478bd9Sstevel@tonic-gate 		    fstab.zone_fs_type) > sizeof (cmdbuf)) {
1756*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1757*7c478bd9Sstevel@tonic-gate 			    "type %s is too long.\n"), fstab.zone_fs_dir,
1758*7c478bd9Sstevel@tonic-gate 			    fstab.zone_fs_type);
1759*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1760*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1761*7c478bd9Sstevel@tonic-gate 		}
1762*7c478bd9Sstevel@tonic-gate 		if (fstab.zone_fs_raw[0] == '\0' && stat(cmdbuf, &st) == 0) {
1763*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1764*7c478bd9Sstevel@tonic-gate 			    "must specify 'raw' device for %s file-systems\n"),
1765*7c478bd9Sstevel@tonic-gate 			    fstab.zone_fs_dir, fstab.zone_fs_type);
1766*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1767*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1768*7c478bd9Sstevel@tonic-gate 		}
1769*7c478bd9Sstevel@tonic-gate 		if (fstab.zone_fs_raw[0] != '\0' &&
1770*7c478bd9Sstevel@tonic-gate 		    (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) {
1771*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
1772*7c478bd9Sstevel@tonic-gate 			    "'raw' device specified but "
1773*7c478bd9Sstevel@tonic-gate 			    "no fsck executable exists for %s\n"),
1774*7c478bd9Sstevel@tonic-gate 			    fstab.zone_fs_dir, fstab.zone_fs_type);
1775*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1776*7c478bd9Sstevel@tonic-gate 			goto next_fs;
1777*7c478bd9Sstevel@tonic-gate 		}
1778*7c478bd9Sstevel@tonic-gate next_fs:
1779*7c478bd9Sstevel@tonic-gate 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
1780*7c478bd9Sstevel@tonic-gate 	}
1781*7c478bd9Sstevel@tonic-gate 	(void) zonecfg_endfsent(handle);
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate 	return (return_code);
1784*7c478bd9Sstevel@tonic-gate }
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate static int
1787*7c478bd9Sstevel@tonic-gate verify_details(int cmd_num)
1788*7c478bd9Sstevel@tonic-gate {
1789*7c478bd9Sstevel@tonic-gate 	zone_dochandle_t handle;
1790*7c478bd9Sstevel@tonic-gate 	struct zone_nwiftab nwiftab;
1791*7c478bd9Sstevel@tonic-gate 	char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN];
1792*7c478bd9Sstevel@tonic-gate 	int return_code = Z_OK;
1793*7c478bd9Sstevel@tonic-gate 	int err;
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 	if ((handle = zonecfg_init_handle()) == NULL) {
1796*7c478bd9Sstevel@tonic-gate 		zperror(cmd_to_str(cmd_num), B_TRUE);
1797*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1798*7c478bd9Sstevel@tonic-gate 	}
1799*7c478bd9Sstevel@tonic-gate 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
1800*7c478bd9Sstevel@tonic-gate 		errno = err;
1801*7c478bd9Sstevel@tonic-gate 		zperror(cmd_to_str(cmd_num), B_TRUE);
1802*7c478bd9Sstevel@tonic-gate 		zonecfg_fini_handle(handle);
1803*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1804*7c478bd9Sstevel@tonic-gate 	}
1805*7c478bd9Sstevel@tonic-gate 	if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) !=
1806*7c478bd9Sstevel@tonic-gate 	    Z_OK) {
1807*7c478bd9Sstevel@tonic-gate 		errno = err;
1808*7c478bd9Sstevel@tonic-gate 		zperror(cmd_to_str(cmd_num), B_TRUE);
1809*7c478bd9Sstevel@tonic-gate 		zonecfg_fini_handle(handle);
1810*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1811*7c478bd9Sstevel@tonic-gate 	}
1812*7c478bd9Sstevel@tonic-gate 	/*
1813*7c478bd9Sstevel@tonic-gate 	 * zonecfg_get_zonepath() gets its data from the XML repository.
1814*7c478bd9Sstevel@tonic-gate 	 * Verify this against the index file, which is checked first by
1815*7c478bd9Sstevel@tonic-gate 	 * zone_get_zonepath().  If they don't match, bail out.
1816*7c478bd9Sstevel@tonic-gate 	 */
1817*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_zonepath(target_zone, checkpath,
1818*7c478bd9Sstevel@tonic-gate 	    sizeof (checkpath))) != Z_OK) {
1819*7c478bd9Sstevel@tonic-gate 		errno = err;
1820*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not get zone path"));
1821*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1822*7c478bd9Sstevel@tonic-gate 	}
1823*7c478bd9Sstevel@tonic-gate 	if (strcmp(zonepath, checkpath) != 0) {
1824*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("The XML repository has "
1825*7c478bd9Sstevel@tonic-gate 		    "zonepath '%s',\nbut the index file has zonepath '%s'.\n"
1826*7c478bd9Sstevel@tonic-gate 		    "These must match, so fix the incorrect entry.\n"),
1827*7c478bd9Sstevel@tonic-gate 		    zonepath, checkpath);
1828*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1829*7c478bd9Sstevel@tonic-gate 	}
1830*7c478bd9Sstevel@tonic-gate 	if (validate_zonepath(zonepath, cmd_num) != Z_OK) {
1831*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("could not verify zonepath %s "
1832*7c478bd9Sstevel@tonic-gate 		    "because of the above errors.\n"), zonepath);
1833*7c478bd9Sstevel@tonic-gate 		return_code = Z_ERR;
1834*7c478bd9Sstevel@tonic-gate 	}
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
1837*7c478bd9Sstevel@tonic-gate 		errno = err;
1838*7c478bd9Sstevel@tonic-gate 		zperror(cmd_to_str(cmd_num), B_TRUE);
1839*7c478bd9Sstevel@tonic-gate 		zonecfg_fini_handle(handle);
1840*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1841*7c478bd9Sstevel@tonic-gate 	}
1842*7c478bd9Sstevel@tonic-gate 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
1843*7c478bd9Sstevel@tonic-gate 		struct lifreq lifr;
1844*7c478bd9Sstevel@tonic-gate 		sa_family_t af;
1845*7c478bd9Sstevel@tonic-gate 		int so, res;
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 		/* skip any loopback interfaces */
1848*7c478bd9Sstevel@tonic-gate 		if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0)
1849*7c478bd9Sstevel@tonic-gate 			continue;
1850*7c478bd9Sstevel@tonic-gate 		if ((res = zonecfg_valid_net_address(nwiftab.zone_nwif_address,
1851*7c478bd9Sstevel@tonic-gate 		    &lifr)) != Z_OK) {
1852*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("could not verify %s "
1853*7c478bd9Sstevel@tonic-gate 			    "%s=%s %s=%s: %s\n"), "net", "address",
1854*7c478bd9Sstevel@tonic-gate 			    nwiftab.zone_nwif_address, "physical",
1855*7c478bd9Sstevel@tonic-gate 			    nwiftab.zone_nwif_physical, zonecfg_strerror(res));
1856*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1857*7c478bd9Sstevel@tonic-gate 			continue;
1858*7c478bd9Sstevel@tonic-gate 		}
1859*7c478bd9Sstevel@tonic-gate 		af = lifr.lifr_addr.ss_family;
1860*7c478bd9Sstevel@tonic-gate 		(void) memset(&lifr, 0, sizeof (lifr));
1861*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, nwiftab.zone_nwif_physical,
1862*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1863*7c478bd9Sstevel@tonic-gate 		lifr.lifr_addr.ss_family = af;
1864*7c478bd9Sstevel@tonic-gate 		if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
1865*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("could not verify %s "
1866*7c478bd9Sstevel@tonic-gate 			    "%s=%s %s=%s: could not get socket: %s\n"), "net",
1867*7c478bd9Sstevel@tonic-gate 			    "address", nwiftab.zone_nwif_address, "physical",
1868*7c478bd9Sstevel@tonic-gate 			    nwiftab.zone_nwif_physical, strerror(errno));
1869*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1870*7c478bd9Sstevel@tonic-gate 			continue;
1871*7c478bd9Sstevel@tonic-gate 		}
1872*7c478bd9Sstevel@tonic-gate 		if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
1873*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1874*7c478bd9Sstevel@tonic-gate 			    gettext("could not verify %s %s=%s %s=%s: %s\n"),
1875*7c478bd9Sstevel@tonic-gate 			    "net", "address", nwiftab.zone_nwif_address,
1876*7c478bd9Sstevel@tonic-gate 			    "physical", nwiftab.zone_nwif_physical,
1877*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
1878*7c478bd9Sstevel@tonic-gate 			return_code = Z_ERR;
1879*7c478bd9Sstevel@tonic-gate 		}
1880*7c478bd9Sstevel@tonic-gate 		(void) close(so);
1881*7c478bd9Sstevel@tonic-gate 	}
1882*7c478bd9Sstevel@tonic-gate 	(void) zonecfg_endnwifent(handle);
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate 	if (verify_filesystems(handle) != Z_OK)
1885*7c478bd9Sstevel@tonic-gate 		return_code = Z_ERR;
1886*7c478bd9Sstevel@tonic-gate 	if (verify_rctls(handle) != Z_OK)
1887*7c478bd9Sstevel@tonic-gate 		return_code = Z_ERR;
1888*7c478bd9Sstevel@tonic-gate 	if (verify_pool(handle) != Z_OK)
1889*7c478bd9Sstevel@tonic-gate 		return_code = Z_ERR;
1890*7c478bd9Sstevel@tonic-gate 	zonecfg_fini_handle(handle);
1891*7c478bd9Sstevel@tonic-gate 	if (return_code == Z_ERR)
1892*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1893*7c478bd9Sstevel@tonic-gate 		    gettext("%s: zone %s failed to verify\n"),
1894*7c478bd9Sstevel@tonic-gate 		    execname, target_zone);
1895*7c478bd9Sstevel@tonic-gate 	return (return_code);
1896*7c478bd9Sstevel@tonic-gate }
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate static int
1899*7c478bd9Sstevel@tonic-gate verify_func(int argc, char *argv[])
1900*7c478bd9Sstevel@tonic-gate {
1901*7c478bd9Sstevel@tonic-gate 	int arg;
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 	optind = 0;
1904*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1905*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1906*7c478bd9Sstevel@tonic-gate 		case '?':
1907*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_VERIFY, CMD_VERIFY);
1908*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1909*7c478bd9Sstevel@tonic-gate 		default:
1910*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_VERIFY, CMD_VERIFY);
1911*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1912*7c478bd9Sstevel@tonic-gate 		}
1913*7c478bd9Sstevel@tonic-gate 	}
1914*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1915*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_VERIFY, CMD_VERIFY);
1916*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1917*7c478bd9Sstevel@tonic-gate 	}
1918*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_VERIFY, B_FALSE, B_FALSE) != Z_OK)
1919*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1920*7c478bd9Sstevel@tonic-gate 	return (verify_details(CMD_VERIFY));
1921*7c478bd9Sstevel@tonic-gate }
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate #define	LUCREATEZONE	"/usr/lib/lu/lucreatezone"
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate static int
1926*7c478bd9Sstevel@tonic-gate install_func(int argc, char *argv[])
1927*7c478bd9Sstevel@tonic-gate {
1928*7c478bd9Sstevel@tonic-gate 	/* 9: "exec " and " -z " */
1929*7c478bd9Sstevel@tonic-gate 	char cmdbuf[sizeof (LUCREATEZONE) + ZONENAME_MAX + 9];
1930*7c478bd9Sstevel@tonic-gate 	int lockfd;
1931*7c478bd9Sstevel@tonic-gate 	int err, arg;
1932*7c478bd9Sstevel@tonic-gate 	char zonepath[MAXPATHLEN];
1933*7c478bd9Sstevel@tonic-gate 	int status;
1934*7c478bd9Sstevel@tonic-gate 
1935*7c478bd9Sstevel@tonic-gate 	optind = 0;
1936*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1937*7c478bd9Sstevel@tonic-gate 		switch (arg) {
1938*7c478bd9Sstevel@tonic-gate 		case '?':
1939*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_INSTALL, CMD_INSTALL);
1940*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
1941*7c478bd9Sstevel@tonic-gate 		default:
1942*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_INSTALL, CMD_INSTALL);
1943*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
1944*7c478bd9Sstevel@tonic-gate 		}
1945*7c478bd9Sstevel@tonic-gate 	}
1946*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1947*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_INSTALL, CMD_INSTALL);
1948*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
1949*7c478bd9Sstevel@tonic-gate 	}
1950*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_INSTALL, B_FALSE, B_TRUE) != Z_OK)
1951*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1952*7c478bd9Sstevel@tonic-gate 	if (verify_details(CMD_INSTALL) != Z_OK)
1953*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1954*7c478bd9Sstevel@tonic-gate 
1955*7c478bd9Sstevel@tonic-gate 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
1956*7c478bd9Sstevel@tonic-gate 		zerror(gettext("another %s may have an operation in progress."),
1957*7c478bd9Sstevel@tonic-gate 		    "zoneadmd");
1958*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
1959*7c478bd9Sstevel@tonic-gate 	}
1960*7c478bd9Sstevel@tonic-gate 	err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
1961*7c478bd9Sstevel@tonic-gate 	if (err != Z_OK) {
1962*7c478bd9Sstevel@tonic-gate 		errno = err;
1963*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not set state"));
1964*7c478bd9Sstevel@tonic-gate 		goto done;
1965*7c478bd9Sstevel@tonic-gate 	}
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate 	/*
1968*7c478bd9Sstevel@tonic-gate 	 * According to the Application Packaging Developer's Guide, a
1969*7c478bd9Sstevel@tonic-gate 	 * "checkinstall" script when included in a package is executed as
1970*7c478bd9Sstevel@tonic-gate 	 * the user "install", if such a user exists, or by the user
1971*7c478bd9Sstevel@tonic-gate 	 * "nobody".  In order to support this dubious behavior, the path
1972*7c478bd9Sstevel@tonic-gate 	 * to the zone being constructed is opened up during the life of
1973*7c478bd9Sstevel@tonic-gate 	 * the command laying down the zone's root file system.  Once this
1974*7c478bd9Sstevel@tonic-gate 	 * has completed, regardless of whether it was successful, the
1975*7c478bd9Sstevel@tonic-gate 	 * path to the zone is again restricted.
1976*7c478bd9Sstevel@tonic-gate 	 */
1977*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_zonepath(target_zone, zonepath,
1978*7c478bd9Sstevel@tonic-gate 	    sizeof (zonepath))) != Z_OK) {
1979*7c478bd9Sstevel@tonic-gate 		errno = err;
1980*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not get zone path"));
1981*7c478bd9Sstevel@tonic-gate 		goto done;
1982*7c478bd9Sstevel@tonic-gate 	}
1983*7c478bd9Sstevel@tonic-gate 	if (chmod(zonepath, DEFAULT_DIR_MODE) != 0) {
1984*7c478bd9Sstevel@tonic-gate 		zperror(zonepath, B_FALSE);
1985*7c478bd9Sstevel@tonic-gate 		err = Z_ERR;
1986*7c478bd9Sstevel@tonic-gate 		goto done;
1987*7c478bd9Sstevel@tonic-gate 	}
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	/*
1990*7c478bd9Sstevel@tonic-gate 	 * "exec" the command so that the returned status is that of
1991*7c478bd9Sstevel@tonic-gate 	 * LUCREATEZONE and not the shell.
1992*7c478bd9Sstevel@tonic-gate 	 */
1993*7c478bd9Sstevel@tonic-gate 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " LUCREATEZONE " -z %s",
1994*7c478bd9Sstevel@tonic-gate 	    target_zone);
1995*7c478bd9Sstevel@tonic-gate 	status = do_subproc(cmdbuf);
1996*7c478bd9Sstevel@tonic-gate 	if (chmod(zonepath, S_IRWXU) != 0) {
1997*7c478bd9Sstevel@tonic-gate 		zperror(zonepath, B_FALSE);
1998*7c478bd9Sstevel@tonic-gate 		err = Z_ERR;
1999*7c478bd9Sstevel@tonic-gate 		goto done;
2000*7c478bd9Sstevel@tonic-gate 	}
2001*7c478bd9Sstevel@tonic-gate 	if ((err = subproc_status(LUCREATEZONE, status)) != Z_OK)
2002*7c478bd9Sstevel@tonic-gate 		goto done;
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 	if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
2005*7c478bd9Sstevel@tonic-gate 		errno = err;
2006*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not set state"));
2007*7c478bd9Sstevel@tonic-gate 		goto done;
2008*7c478bd9Sstevel@tonic-gate 	}
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate done:
2011*7c478bd9Sstevel@tonic-gate 	release_lock_file(lockfd);
2012*7c478bd9Sstevel@tonic-gate 	return ((err == Z_OK) ? Z_OK : Z_ERR);
2013*7c478bd9Sstevel@tonic-gate }
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate /*
2016*7c478bd9Sstevel@tonic-gate  * On input, TRUE => yes, FALSE => no.
2017*7c478bd9Sstevel@tonic-gate  * On return, TRUE => 1, FALSE => 0, could not ask => -1.
2018*7c478bd9Sstevel@tonic-gate  */
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate static int
2021*7c478bd9Sstevel@tonic-gate ask_yesno(boolean_t default_answer, const char *question)
2022*7c478bd9Sstevel@tonic-gate {
2023*7c478bd9Sstevel@tonic-gate 	char line[64];	/* should be large enough to answer yes or no */
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate 	if (!isatty(STDIN_FILENO))
2026*7c478bd9Sstevel@tonic-gate 		return (-1);
2027*7c478bd9Sstevel@tonic-gate 	for (;;) {
2028*7c478bd9Sstevel@tonic-gate 		(void) printf("%s (%s)? ", question,
2029*7c478bd9Sstevel@tonic-gate 		    default_answer ? "[y]/n" : "y/[n]");
2030*7c478bd9Sstevel@tonic-gate 		if (fgets(line, sizeof (line), stdin) == NULL ||
2031*7c478bd9Sstevel@tonic-gate 		    line[0] == '\n')
2032*7c478bd9Sstevel@tonic-gate 			return (default_answer ? 1 : 0);
2033*7c478bd9Sstevel@tonic-gate 		if (tolower(line[0]) == 'y')
2034*7c478bd9Sstevel@tonic-gate 			return (1);
2035*7c478bd9Sstevel@tonic-gate 		if (tolower(line[0]) == 'n')
2036*7c478bd9Sstevel@tonic-gate 			return (0);
2037*7c478bd9Sstevel@tonic-gate 	}
2038*7c478bd9Sstevel@tonic-gate }
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate #define	RMCOMMAND	"/usr/bin/rm -rf"
2041*7c478bd9Sstevel@tonic-gate 
2042*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2043*7c478bd9Sstevel@tonic-gate int
2044*7c478bd9Sstevel@tonic-gate zfm_print(const char *p, void *r) {
2045*7c478bd9Sstevel@tonic-gate 	zerror("  %s\n", p);
2046*7c478bd9Sstevel@tonic-gate 	return (0);
2047*7c478bd9Sstevel@tonic-gate }
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate static int
2050*7c478bd9Sstevel@tonic-gate uninstall_func(int argc, char *argv[])
2051*7c478bd9Sstevel@tonic-gate {
2052*7c478bd9Sstevel@tonic-gate 	/* 6: "exec " and " " */
2053*7c478bd9Sstevel@tonic-gate 	char cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 6];
2054*7c478bd9Sstevel@tonic-gate 	char line[ZONENAME_MAX + 128];	/* Enough for "Are you sure ..." */
2055*7c478bd9Sstevel@tonic-gate 	char rootpath[MAXPATHLEN], devpath[MAXPATHLEN];
2056*7c478bd9Sstevel@tonic-gate 	boolean_t force = B_FALSE;
2057*7c478bd9Sstevel@tonic-gate 	int lockfd, answer;
2058*7c478bd9Sstevel@tonic-gate 	int err, arg;
2059*7c478bd9Sstevel@tonic-gate 	int status;
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 	optind = 0;
2062*7c478bd9Sstevel@tonic-gate 	while ((arg = getopt(argc, argv, "?F")) != EOF) {
2063*7c478bd9Sstevel@tonic-gate 		switch (arg) {
2064*7c478bd9Sstevel@tonic-gate 		case '?':
2065*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
2066*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
2067*7c478bd9Sstevel@tonic-gate 		case 'F':
2068*7c478bd9Sstevel@tonic-gate 			force = B_TRUE;
2069*7c478bd9Sstevel@tonic-gate 			break;
2070*7c478bd9Sstevel@tonic-gate 		default:
2071*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
2072*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
2073*7c478bd9Sstevel@tonic-gate 		}
2074*7c478bd9Sstevel@tonic-gate 	}
2075*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
2076*7c478bd9Sstevel@tonic-gate 		sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
2077*7c478bd9Sstevel@tonic-gate 		return (Z_USAGE);
2078*7c478bd9Sstevel@tonic-gate 	}
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 	if (sanity_check(target_zone, CMD_UNINSTALL, B_FALSE, B_TRUE) != Z_OK)
2081*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 	if (!force) {
2084*7c478bd9Sstevel@tonic-gate 		(void) snprintf(line, sizeof (line),
2085*7c478bd9Sstevel@tonic-gate 		    gettext("Are you sure you want to %s zone %s"),
2086*7c478bd9Sstevel@tonic-gate 		    cmd_to_str(CMD_UNINSTALL), target_zone);
2087*7c478bd9Sstevel@tonic-gate 		if ((answer = ask_yesno(B_FALSE, line)) == 0) {
2088*7c478bd9Sstevel@tonic-gate 			return (Z_OK);
2089*7c478bd9Sstevel@tonic-gate 		} else if (answer == -1) {
2090*7c478bd9Sstevel@tonic-gate 			zerror(gettext("Input not from terminal and -F "
2091*7c478bd9Sstevel@tonic-gate 			    "not specified: %s not done."),
2092*7c478bd9Sstevel@tonic-gate 			    cmd_to_str(CMD_UNINSTALL));
2093*7c478bd9Sstevel@tonic-gate 			return (Z_ERR);
2094*7c478bd9Sstevel@tonic-gate 		}
2095*7c478bd9Sstevel@tonic-gate 	}
2096*7c478bd9Sstevel@tonic-gate 
2097*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_zonepath(target_zone, devpath,
2098*7c478bd9Sstevel@tonic-gate 	    sizeof (devpath))) != Z_OK) {
2099*7c478bd9Sstevel@tonic-gate 		errno = err;
2100*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not get zone path"));
2101*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
2102*7c478bd9Sstevel@tonic-gate 	}
2103*7c478bd9Sstevel@tonic-gate 	(void) strlcat(devpath, "/dev", sizeof (devpath));
2104*7c478bd9Sstevel@tonic-gate 	if ((err = zone_get_rootpath(target_zone, rootpath,
2105*7c478bd9Sstevel@tonic-gate 	    sizeof (rootpath))) != Z_OK) {
2106*7c478bd9Sstevel@tonic-gate 		errno = err;
2107*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not get root path"));
2108*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
2109*7c478bd9Sstevel@tonic-gate 	}
2110*7c478bd9Sstevel@tonic-gate 
2111*7c478bd9Sstevel@tonic-gate 	/*
2112*7c478bd9Sstevel@tonic-gate 	 * If there seems to be a zoneadmd running for this zone, call it
2113*7c478bd9Sstevel@tonic-gate 	 * to tell it that an uninstall is happening; if all goes well it
2114*7c478bd9Sstevel@tonic-gate 	 * will then shut itself down.
2115*7c478bd9Sstevel@tonic-gate 	 */
2116*7c478bd9Sstevel@tonic-gate 	if (ping_zoneadmd(target_zone) == Z_OK) {
2117*7c478bd9Sstevel@tonic-gate 		zone_cmd_arg_t zarg;
2118*7c478bd9Sstevel@tonic-gate 		zarg.cmd = Z_NOTE_UNINSTALLING;
2119*7c478bd9Sstevel@tonic-gate 		/* we don't care too much if this fails... just plow on */
2120*7c478bd9Sstevel@tonic-gate 		(void) call_zoneadmd(target_zone, &zarg);
2121*7c478bd9Sstevel@tonic-gate 	}
2122*7c478bd9Sstevel@tonic-gate 
2123*7c478bd9Sstevel@tonic-gate 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
2124*7c478bd9Sstevel@tonic-gate 		zerror(gettext("another %s may have an operation in progress."),
2125*7c478bd9Sstevel@tonic-gate 		    "zoneadmd");
2126*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
2127*7c478bd9Sstevel@tonic-gate 	}
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 	/* Don't uninstall the zone if anything is mounted there */
2130*7c478bd9Sstevel@tonic-gate 	err = zonecfg_find_mounts(rootpath, NULL, NULL);
2131*7c478bd9Sstevel@tonic-gate 	if (err) {
2132*7c478bd9Sstevel@tonic-gate 		zerror(gettext("These file-systems are mounted on "
2133*7c478bd9Sstevel@tonic-gate 			"subdirectories of %s.\n"), rootpath);
2134*7c478bd9Sstevel@tonic-gate 		(void) zonecfg_find_mounts(rootpath, zfm_print, NULL);
2135*7c478bd9Sstevel@tonic-gate 		return (Z_ERR);
2136*7c478bd9Sstevel@tonic-gate 	}
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 	err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
2139*7c478bd9Sstevel@tonic-gate 	if (err != Z_OK) {
2140*7c478bd9Sstevel@tonic-gate 		errno = err;
2141*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not set state"));
2142*7c478bd9Sstevel@tonic-gate 		goto bad;
2143*7c478bd9Sstevel@tonic-gate 	}
2144*7c478bd9Sstevel@tonic-gate 
2145*7c478bd9Sstevel@tonic-gate 	/*
2146*7c478bd9Sstevel@tonic-gate 	 * "exec" the command so that the returned status is that of
2147*7c478bd9Sstevel@tonic-gate 	 * RMCOMMAND and not the shell.
2148*7c478bd9Sstevel@tonic-gate 	 */
2149*7c478bd9Sstevel@tonic-gate 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
2150*7c478bd9Sstevel@tonic-gate 	    devpath);
2151*7c478bd9Sstevel@tonic-gate 	status = do_subproc(cmdbuf);
2152*7c478bd9Sstevel@tonic-gate 	if ((err = subproc_status(RMCOMMAND, status)) != Z_OK)
2153*7c478bd9Sstevel@tonic-gate 		goto bad;
2154*7c478bd9Sstevel@tonic-gate 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
2155*7c478bd9Sstevel@tonic-gate 	    rootpath);
2156*7c478bd9Sstevel@tonic-gate 	status = do_subproc(cmdbuf);
2157*7c478bd9Sstevel@tonic-gate 	if ((err = subproc_status(RMCOMMAND, status)) != Z_OK)
2158*7c478bd9Sstevel@tonic-gate 		goto bad;
2159*7c478bd9Sstevel@tonic-gate 	err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED);
2160*7c478bd9Sstevel@tonic-gate 	if (err != Z_OK) {
2161*7c478bd9Sstevel@tonic-gate 		errno = err;
2162*7c478bd9Sstevel@tonic-gate 		zperror2(target_zone, gettext("could not reset state"));
2163*7c478bd9Sstevel@tonic-gate 	}
2164*7c478bd9Sstevel@tonic-gate bad:
2165*7c478bd9Sstevel@tonic-gate 	release_lock_file(lockfd);
2166*7c478bd9Sstevel@tonic-gate 	return (err);
2167*7c478bd9Sstevel@tonic-gate }
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate static int
2170*7c478bd9Sstevel@tonic-gate help_func(int argc, char *argv[])
2171*7c478bd9Sstevel@tonic-gate {
2172*7c478bd9Sstevel@tonic-gate 	int arg, cmd_num;
2173*7c478bd9Sstevel@tonic-gate 
2174*7c478bd9Sstevel@tonic-gate 	if (argc == 0) {
2175*7c478bd9Sstevel@tonic-gate 		(void) usage(B_TRUE);
2176*7c478bd9Sstevel@tonic-gate 		return (Z_OK);
2177*7c478bd9Sstevel@tonic-gate 	}
2178*7c478bd9Sstevel@tonic-gate 	optind = 0;
2179*7c478bd9Sstevel@tonic-gate 	if ((arg = getopt(argc, argv, "?")) != EOF) {
2180*7c478bd9Sstevel@tonic-gate 		switch (arg) {
2181*7c478bd9Sstevel@tonic-gate 		case '?':
2182*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_HELP, CMD_HELP);
2183*7c478bd9Sstevel@tonic-gate 			return (optopt == '?' ? Z_OK : Z_USAGE);
2184*7c478bd9Sstevel@tonic-gate 		default:
2185*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_HELP, CMD_HELP);
2186*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
2187*7c478bd9Sstevel@tonic-gate 		}
2188*7c478bd9Sstevel@tonic-gate 	}
2189*7c478bd9Sstevel@tonic-gate 	while (optind < argc) {
2190*7c478bd9Sstevel@tonic-gate 		if ((cmd_num = cmd_match(argv[optind])) < 0) {
2191*7c478bd9Sstevel@tonic-gate 			sub_usage(SHELP_HELP, CMD_HELP);
2192*7c478bd9Sstevel@tonic-gate 			return (Z_USAGE);
2193*7c478bd9Sstevel@tonic-gate 		}
2194*7c478bd9Sstevel@tonic-gate 		sub_usage(cmdtab[cmd_num].short_usage, cmd_num);
2195*7c478bd9Sstevel@tonic-gate 		optind++;
2196*7c478bd9Sstevel@tonic-gate 	}
2197*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
2198*7c478bd9Sstevel@tonic-gate }
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate /*
2201*7c478bd9Sstevel@tonic-gate  * Returns: CMD_MIN thru CMD_MAX on success, -1 on error
2202*7c478bd9Sstevel@tonic-gate  */
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate static int
2205*7c478bd9Sstevel@tonic-gate cmd_match(char *cmd)
2206*7c478bd9Sstevel@tonic-gate {
2207*7c478bd9Sstevel@tonic-gate 	int i;
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate 	for (i = CMD_MIN; i <= CMD_MAX; i++) {
2210*7c478bd9Sstevel@tonic-gate 		/* return only if there is an exact match */
2211*7c478bd9Sstevel@tonic-gate 		if (strcmp(cmd, cmdtab[i].cmd_name) == 0)
2212*7c478bd9Sstevel@tonic-gate 			return (cmdtab[i].cmd_num);
2213*7c478bd9Sstevel@tonic-gate 	}
2214*7c478bd9Sstevel@tonic-gate 	return (-1);
2215*7c478bd9Sstevel@tonic-gate }
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate static int
2218*7c478bd9Sstevel@tonic-gate parse_and_run(int argc, char *argv[])
2219*7c478bd9Sstevel@tonic-gate {
2220*7c478bd9Sstevel@tonic-gate 	int i = cmd_match(argv[0]);
2221*7c478bd9Sstevel@tonic-gate 
2222*7c478bd9Sstevel@tonic-gate 	if (i < 0)
2223*7c478bd9Sstevel@tonic-gate 		return (usage(B_FALSE));
2224*7c478bd9Sstevel@tonic-gate 	return (cmdtab[i].handler(argc - 1, &(argv[1])));
2225*7c478bd9Sstevel@tonic-gate }
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate static char *
2228*7c478bd9Sstevel@tonic-gate get_execbasename(char *execfullname)
2229*7c478bd9Sstevel@tonic-gate {
2230*7c478bd9Sstevel@tonic-gate 	char *last_slash, *execbasename;
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 	/* guard against '/' at end of command invocation */
2233*7c478bd9Sstevel@tonic-gate 	for (;;) {
2234*7c478bd9Sstevel@tonic-gate 		last_slash = strrchr(execfullname, '/');
2235*7c478bd9Sstevel@tonic-gate 		if (last_slash == NULL) {
2236*7c478bd9Sstevel@tonic-gate 			execbasename = execfullname;
2237*7c478bd9Sstevel@tonic-gate 			break;
2238*7c478bd9Sstevel@tonic-gate 		} else {
2239*7c478bd9Sstevel@tonic-gate 			execbasename = last_slash + 1;
2240*7c478bd9Sstevel@tonic-gate 			if (*execbasename == '\0') {
2241*7c478bd9Sstevel@tonic-gate 				*last_slash = '\0';
2242*7c478bd9Sstevel@tonic-gate 				continue;
2243*7c478bd9Sstevel@tonic-gate 			}
2244*7c478bd9Sstevel@tonic-gate 			break;
2245*7c478bd9Sstevel@tonic-gate 		}
2246*7c478bd9Sstevel@tonic-gate 	}
2247*7c478bd9Sstevel@tonic-gate 	return (execbasename);
2248*7c478bd9Sstevel@tonic-gate }
2249*7c478bd9Sstevel@tonic-gate 
2250*7c478bd9Sstevel@tonic-gate int
2251*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2252*7c478bd9Sstevel@tonic-gate {
2253*7c478bd9Sstevel@tonic-gate 	int arg;
2254*7c478bd9Sstevel@tonic-gate 	zoneid_t zid;
2255*7c478bd9Sstevel@tonic-gate 
2256*7c478bd9Sstevel@tonic-gate 	if ((locale = setlocale(LC_ALL, "")) == NULL)
2257*7c478bd9Sstevel@tonic-gate 		locale = "C";
2258*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2259*7c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
2260*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGHUP, SIG_IGN);
2261*7c478bd9Sstevel@tonic-gate 	execname = get_execbasename(argv[0]);
2262*7c478bd9Sstevel@tonic-gate 	target_zone = NULL;
2263*7c478bd9Sstevel@tonic-gate 	if (chdir("/") != 0) {
2264*7c478bd9Sstevel@tonic-gate 		zerror(gettext("could not change directory to /."));
2265*7c478bd9Sstevel@tonic-gate 		exit(Z_ERR);
2266*7c478bd9Sstevel@tonic-gate 	}
2267*7c478bd9Sstevel@tonic-gate 
2268*7c478bd9Sstevel@tonic-gate 	while ((arg = getopt(argc, argv, "?z:")) != EOF) {
2269*7c478bd9Sstevel@tonic-gate 		switch (arg) {
2270*7c478bd9Sstevel@tonic-gate 		case '?':
2271*7c478bd9Sstevel@tonic-gate 			return (usage(B_TRUE));
2272*7c478bd9Sstevel@tonic-gate 		case 'z':
2273*7c478bd9Sstevel@tonic-gate 			target_zone = optarg;
2274*7c478bd9Sstevel@tonic-gate 			break;
2275*7c478bd9Sstevel@tonic-gate 		default:
2276*7c478bd9Sstevel@tonic-gate 			return (usage(B_FALSE));
2277*7c478bd9Sstevel@tonic-gate 		}
2278*7c478bd9Sstevel@tonic-gate 	}
2279*7c478bd9Sstevel@tonic-gate 
2280*7c478bd9Sstevel@tonic-gate 	if (optind >= argc)
2281*7c478bd9Sstevel@tonic-gate 		return (usage(B_FALSE));
2282*7c478bd9Sstevel@tonic-gate 	if (target_zone != NULL && zone_get_id(target_zone, &zid) != 0) {
2283*7c478bd9Sstevel@tonic-gate 		errno = Z_NO_ZONE;
2284*7c478bd9Sstevel@tonic-gate 		zperror(target_zone, B_TRUE);
2285*7c478bd9Sstevel@tonic-gate 		exit(Z_ERR);
2286*7c478bd9Sstevel@tonic-gate 	}
2287*7c478bd9Sstevel@tonic-gate 	return (parse_and_run(argc - optind, &argv[optind]));
2288*7c478bd9Sstevel@tonic-gate }
2289