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