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