xref: /titanic_44/usr/src/cmd/zoneadm/zoneadm.c (revision ffbafc5382b8d46def826aec8c419ad31dff8ebd)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 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 #include <libzfs.h>
68 
69 #include <fcntl.h>
70 #include <door.h>
71 #include <macros.h>
72 #include <libgen.h>
73 #include <fnmatch.h>
74 
75 #include <pool.h>
76 #include <sys/pool.h>
77 
78 #define	MAXARGS	8
79 
80 /* Reflects kernel zone entries */
81 typedef struct zone_entry {
82 	zoneid_t	zid;
83 	char		zname[ZONENAME_MAX];
84 	char		*zstate_str;
85 	zone_state_t	zstate_num;
86 	char		zroot[MAXPATHLEN];
87 } zone_entry_t;
88 
89 static zone_entry_t *zents;
90 static size_t nzents;
91 
92 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
93 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
94 #endif
95 
96 #define	Z_ERR	1
97 #define	Z_USAGE	2
98 
99 /* 0755 is the default directory mode. */
100 #define	DEFAULT_DIR_MODE \
101 	(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
102 
103 #define	CMD_HELP	0
104 #define	CMD_BOOT	1
105 #define	CMD_HALT	2
106 #define	CMD_READY	3
107 #define	CMD_REBOOT	4
108 #define	CMD_LIST	5
109 #define	CMD_VERIFY	6
110 #define	CMD_INSTALL	7
111 #define	CMD_UNINSTALL	8
112 #define	CMD_MOUNT	9
113 #define	CMD_UNMOUNT	10
114 #define	CMD_CLONE	11
115 #define	CMD_MOVE	12
116 #define	CMD_DETACH	13
117 #define	CMD_ATTACH	14
118 
119 #define	CMD_MIN		CMD_HELP
120 #define	CMD_MAX		CMD_ATTACH
121 
122 struct cmd {
123 	uint_t	cmd_num;				/* command number */
124 	char	*cmd_name;				/* command name */
125 	char	*short_usage;				/* short form help */
126 	int	(*handler)(int argc, char *argv[]);	/* function to call */
127 
128 };
129 
130 #define	SHELP_HELP	"help"
131 #define	SHELP_BOOT	"boot [-s]"
132 #define	SHELP_HALT	"halt"
133 #define	SHELP_READY	"ready"
134 #define	SHELP_REBOOT	"reboot"
135 #define	SHELP_LIST	"list [-cipv]"
136 #define	SHELP_VERIFY	"verify"
137 #define	SHELP_INSTALL	"install"
138 #define	SHELP_UNINSTALL	"uninstall [-F]"
139 #define	SHELP_CLONE	"clone [-m method] zonename"
140 #define	SHELP_MOVE	"move zonepath"
141 #define	SHELP_DETACH	"detach"
142 #define	SHELP_ATTACH	"attach [-F]"
143 
144 static int help_func(int argc, char *argv[]);
145 static int ready_func(int argc, char *argv[]);
146 static int boot_func(int argc, char *argv[]);
147 static int halt_func(int argc, char *argv[]);
148 static int reboot_func(int argc, char *argv[]);
149 static int list_func(int argc, char *argv[]);
150 static int verify_func(int argc, char *argv[]);
151 static int install_func(int argc, char *argv[]);
152 static int uninstall_func(int argc, char *argv[]);
153 static int mount_func(int argc, char *argv[]);
154 static int unmount_func(int argc, char *argv[]);
155 static int clone_func(int argc, char *argv[]);
156 static int move_func(int argc, char *argv[]);
157 static int detach_func(int argc, char *argv[]);
158 static int attach_func(int argc, char *argv[]);
159 static int sanity_check(char *zone, int cmd_num, boolean_t running,
160     boolean_t unsafe_when_running);
161 static int cmd_match(char *cmd);
162 static int verify_details(int);
163 
164 static struct cmd cmdtab[] = {
165 	{ CMD_HELP,		"help",		SHELP_HELP,	help_func },
166 	{ CMD_BOOT,		"boot",		SHELP_BOOT,	boot_func },
167 	{ CMD_HALT,		"halt",		SHELP_HALT,	halt_func },
168 	{ CMD_READY,		"ready",	SHELP_READY,	ready_func },
169 	{ CMD_REBOOT,		"reboot",	SHELP_REBOOT,	reboot_func },
170 	{ CMD_LIST,		"list",		SHELP_LIST,	list_func },
171 	{ CMD_VERIFY,		"verify",	SHELP_VERIFY,	verify_func },
172 	{ CMD_INSTALL,		"install",	SHELP_INSTALL,	install_func },
173 	{ CMD_UNINSTALL,	"uninstall",	SHELP_UNINSTALL,
174 	    uninstall_func },
175 	/* mount and unmount are private commands for admin/install */
176 	{ CMD_MOUNT,		"mount",	NULL,		mount_func },
177 	{ CMD_UNMOUNT,		"unmount",	NULL,		unmount_func },
178 	{ CMD_CLONE,		"clone",	SHELP_CLONE,	clone_func },
179 	{ CMD_MOVE,		"move",		SHELP_MOVE,	move_func },
180 	{ CMD_DETACH,		"detach",	SHELP_DETACH,	detach_func },
181 	{ CMD_ATTACH,		"attach",	SHELP_ATTACH,	attach_func }
182 };
183 
184 /* global variables */
185 
186 /* set early in main(), never modified thereafter, used all over the place */
187 static char *execname;
188 static char *target_zone;
189 static char *locale;
190 
191 /* used in do_subproc() and signal handler */
192 static volatile boolean_t child_killed;
193 
194 static char *
195 cmd_to_str(int cmd_num)
196 {
197 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
198 	return (cmdtab[cmd_num].cmd_name);
199 }
200 
201 /* This is a separate function because of gettext() wrapping. */
202 static char *
203 long_help(int cmd_num)
204 {
205 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
206 	switch (cmd_num) {
207 	case CMD_HELP:
208 		return (gettext("Print usage message."));
209 	case CMD_BOOT:
210 		return (gettext("Activates (boots) specified zone.  "
211 		    "The -s flag can be used\n\tto boot the zone in "
212 		    "the single-user state."));
213 	case CMD_HALT:
214 		return (gettext("Halts specified zone, bypassing shutdown "
215 		    "scripts and removing runtime\n\tresources of the zone."));
216 	case CMD_READY:
217 		return (gettext("Prepares a zone for running applications but "
218 		    "does not start any user\n\tprocesses in the zone."));
219 	case CMD_REBOOT:
220 		return (gettext("Restarts the zone (equivalent to a halt / "
221 		    "boot sequence).\n\tFails if the zone is not active."));
222 	case CMD_LIST:
223 		return (gettext("Lists the current zones, or a "
224 		    "specific zone if indicated.  By default,\n\tall "
225 		    "running zones are listed, though this can be "
226 		    "expanded to all\n\tinstalled zones with the -i "
227 		    "option or all configured zones with the\n\t-c "
228 		    "option.  When used with the general -z <zone> "
229 		    "option, lists only the\n\tspecified zone, but "
230 		    "lists it regardless of its state, and the -i "
231 		    "and -c\n\toptions are disallowed.  The -v option "
232 		    "can be used to display verbose\n\tinformation: "
233 		    "zone name, id, current state, root directory and "
234 		    "options.\n\tThe -p option can be used to request "
235 		    "machine-parsable output.  The -v\n\tand -p "
236 		    "options are mutually exclusive.  If neither -v "
237 		    "nor -p is used,\n\tjust the zone name is listed."));
238 	case CMD_VERIFY:
239 		return (gettext("Check to make sure the configuration "
240 		    "can safely be instantiated\n\ton the machine: "
241 		    "physical network interfaces exist, etc."));
242 	case CMD_INSTALL:
243 		return (gettext("Install the configuration on to the system."));
244 	case CMD_UNINSTALL:
245 		return (gettext("Uninstall the configuration from the system.  "
246 		    "The -F flag can be used\n\tto force the action."));
247 	case CMD_CLONE:
248 		return (gettext("Clone the installation of another zone."));
249 	case CMD_MOVE:
250 		return (gettext("Move the zone to a new zonepath."));
251 	case CMD_DETACH:
252 		return (gettext("Detach the zone from the system. The zone "
253 		    "state is changed to\n\t'configured' (but the files under "
254 		    "the zonepath are untouched).\n\tThe zone can subsequently "
255 		    "be attached, or can be moved to another\n\tsystem and "
256 		    "attached there."));
257 	case CMD_ATTACH:
258 		return (gettext("Attach the zone to the system.  The zone "
259 		    "state must be 'configured'\n\tprior to attach; upon "
260 		    "successful completion, the zone state will be\n\t"
261 		    "'installed'.  The system software on the current "
262 		    "system must be\n\tcompatible with the software on the "
263 		    "zone's original system.\n\tSpecify -F to force the attach "
264 		    "and skip software compatibility tests."));
265 	default:
266 		return ("");
267 	}
268 	/* NOTREACHED */
269 	return (NULL);
270 }
271 
272 /*
273  * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for
274  * unexpected errors.
275  */
276 
277 static int
278 usage(boolean_t explicit)
279 {
280 	int i;
281 	FILE *fd = explicit ? stdout : stderr;
282 
283 	(void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname);
284 	(void) fprintf(fd, "\t%s [-z <zone>] list\n", execname);
285 	(void) fprintf(fd, "\t%s -z <zone> <%s>\n", execname,
286 	    gettext("subcommand"));
287 	(void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands"));
288 	for (i = CMD_MIN; i <= CMD_MAX; i++) {
289 		if (cmdtab[i].short_usage == NULL)
290 			continue;
291 		(void) fprintf(fd, "%s\n", cmdtab[i].short_usage);
292 		if (explicit)
293 			(void) fprintf(fd, "\t%s\n\n", long_help(i));
294 	}
295 	if (!explicit)
296 		(void) fputs("\n", fd);
297 	return (Z_USAGE);
298 }
299 
300 static void
301 sub_usage(char *short_usage, int cmd_num)
302 {
303 	(void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage);
304 	(void) fprintf(stderr, "\t%s\n", long_help(cmd_num));
305 }
306 
307 /*
308  * zperror() is like perror(3c) except that this also prints the executable
309  * name at the start of the message, and takes a boolean indicating whether
310  * to call libc'c strerror() or that from libzonecfg.
311  */
312 
313 static void
314 zperror(const char *str, boolean_t zonecfg_error)
315 {
316 	(void) fprintf(stderr, "%s: %s: %s\n", execname, str,
317 	    zonecfg_error ? zonecfg_strerror(errno) : strerror(errno));
318 }
319 
320 /*
321  * zperror2() is very similar to zperror() above, except it also prints a
322  * supplied zone name after the executable.
323  *
324  * All current consumers of this function want libzonecfg's strerror() rather
325  * than libc's; if this ever changes, this function can be made more generic
326  * like zperror() above.
327  */
328 
329 static void
330 zperror2(const char *zone, const char *str)
331 {
332 	(void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str,
333 	    zonecfg_strerror(errno));
334 }
335 
336 /* PRINTFLIKE1 */
337 static void
338 zerror(const char *fmt, ...)
339 {
340 	va_list alist;
341 
342 	va_start(alist, fmt);
343 	(void) fprintf(stderr, "%s: ", execname);
344 	if (target_zone != NULL)
345 		(void) fprintf(stderr, "zone '%s': ", target_zone);
346 	(void) vfprintf(stderr, fmt, alist);
347 	(void) fprintf(stderr, "\n");
348 	va_end(alist);
349 }
350 
351 static void *
352 safe_calloc(size_t nelem, size_t elsize)
353 {
354 	void *r = calloc(nelem, elsize);
355 
356 	if (r == NULL) {
357 		zerror(gettext("failed to allocate %lu bytes: %s"),
358 		    (ulong_t)nelem * elsize, strerror(errno));
359 		exit(Z_ERR);
360 	}
361 	return (r);
362 }
363 
364 static void
365 zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
366 {
367 	static boolean_t firsttime = B_TRUE;
368 
369 	assert(!(verbose && parsable));
370 	if (firsttime && verbose) {
371 		firsttime = B_FALSE;
372 		(void) printf("%*s %-16s %-14s %-30s\n", ZONEID_WIDTH, "ID",
373 		    "NAME", "STATUS", "PATH");
374 	}
375 	if (!verbose) {
376 		if (!parsable) {
377 			(void) printf("%s\n", zent->zname);
378 			return;
379 		}
380 		if (zent->zid == ZONE_ID_UNDEFINED)
381 			(void) printf("-");
382 		else
383 			(void) printf("%lu", zent->zid);
384 		(void) printf(":%s:%s:%s\n", zent->zname, zent->zstate_str,
385 		    zent->zroot);
386 		return;
387 	}
388 	if (zent->zstate_str != NULL) {
389 		if (zent->zid == ZONE_ID_UNDEFINED)
390 			(void) printf("%*s", ZONEID_WIDTH, "-");
391 		else
392 			(void) printf("%*lu", ZONEID_WIDTH, zent->zid);
393 		(void) printf(" %-16s %-14s %-30s\n", zent->zname,
394 		    zent->zstate_str, zent->zroot);
395 	}
396 }
397 
398 static int
399 lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
400 {
401 	char root[MAXPATHLEN];
402 	int err;
403 
404 	(void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
405 	(void) strlcpy(zent->zroot, "???", sizeof (zent->zroot));
406 	zent->zstate_str = "???";
407 
408 	zent->zid = zid;
409 
410 	if ((err = zone_get_zonepath(zent->zname, root, sizeof (root))) !=
411 	    Z_OK) {
412 		errno = err;
413 		zperror2(zent->zname, gettext("could not get zone path"));
414 		return (Z_ERR);
415 	}
416 	(void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
417 
418 	if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) {
419 		errno = err;
420 		zperror2(zent->zname, gettext("could not get state"));
421 		return (Z_ERR);
422 	}
423 	zent->zstate_str = zone_state_str(zent->zstate_num);
424 
425 	return (Z_OK);
426 }
427 
428 /*
429  * fetch_zents() calls zone_list(2) to find out how many zones are running
430  * (which is stored in the global nzents), then calls zone_list(2) again
431  * to fetch the list of running zones (stored in the global zents).  This
432  * function may be called multiple times, so if zents is already set, we
433  * return immediately to save work.
434  */
435 
436 static int
437 fetch_zents(void)
438 {
439 	zoneid_t *zids = NULL;
440 	uint_t nzents_saved;
441 	int i, retv;
442 	FILE *fp;
443 	boolean_t inaltroot;
444 	zone_entry_t *zentp;
445 
446 	if (nzents > 0)
447 		return (Z_OK);
448 
449 	if (zone_list(NULL, &nzents) != 0) {
450 		zperror(gettext("failed to get zoneid list"), B_FALSE);
451 		return (Z_ERR);
452 	}
453 
454 again:
455 	if (nzents == 0)
456 		return (Z_OK);
457 
458 	zids = safe_calloc(nzents, sizeof (zoneid_t));
459 	nzents_saved = nzents;
460 
461 	if (zone_list(zids, &nzents) != 0) {
462 		zperror(gettext("failed to get zone list"), B_FALSE);
463 		free(zids);
464 		return (Z_ERR);
465 	}
466 	if (nzents != nzents_saved) {
467 		/* list changed, try again */
468 		free(zids);
469 		goto again;
470 	}
471 
472 	zents = safe_calloc(nzents, sizeof (zone_entry_t));
473 
474 	inaltroot = zonecfg_in_alt_root();
475 	if (inaltroot)
476 		fp = zonecfg_open_scratch("", B_FALSE);
477 	else
478 		fp = NULL;
479 	zentp = zents;
480 	retv = Z_OK;
481 	for (i = 0; i < nzents; i++) {
482 		char name[ZONENAME_MAX];
483 		char altname[ZONENAME_MAX];
484 
485 		if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
486 			zperror(gettext("failed to get zone name"), B_FALSE);
487 			retv = Z_ERR;
488 			continue;
489 		}
490 		if (zonecfg_is_scratch(name)) {
491 			/* Ignore scratch zones by default */
492 			if (!inaltroot)
493 				continue;
494 			if (fp == NULL ||
495 			    zonecfg_reverse_scratch(fp, name, altname,
496 			    sizeof (altname), NULL, 0) == -1) {
497 				zerror(gettext("could not resolve scratch "
498 				    "zone %s"), name);
499 				retv = Z_ERR;
500 				continue;
501 			}
502 			(void) strcpy(name, altname);
503 		} else {
504 			/* Ignore non-scratch when in an alternate root */
505 			if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0)
506 				continue;
507 		}
508 		if (lookup_zone_info(name, zids[i], zentp) != Z_OK) {
509 			zerror(gettext("failed to get zone data"));
510 			retv = Z_ERR;
511 			continue;
512 		}
513 		zentp++;
514 	}
515 	nzents = zentp - zents;
516 	if (fp != NULL)
517 		zonecfg_close_scratch(fp);
518 
519 	free(zids);
520 	return (retv);
521 }
522 
523 static int
524 zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
525 {
526 	int i;
527 	zone_entry_t zent;
528 	FILE *cookie;
529 	char *name;
530 
531 	/*
532 	 * First get the list of running zones from the kernel and print them.
533 	 * If that is all we need, then return.
534 	 */
535 	if ((i = fetch_zents()) != Z_OK) {
536 		/*
537 		 * No need for error messages; fetch_zents() has already taken
538 		 * care of this.
539 		 */
540 		return (i);
541 	}
542 	for (i = 0; i < nzents; i++)
543 		zone_print(&zents[i], verbose, parsable);
544 	if (min_state >= ZONE_STATE_RUNNING)
545 		return (Z_OK);
546 	/*
547 	 * Next, get the full list of zones from the configuration, skipping
548 	 * any we have already printed.
549 	 */
550 	cookie = setzoneent();
551 	while ((name = getzoneent(cookie)) != NULL) {
552 		for (i = 0; i < nzents; i++) {
553 			if (strcmp(zents[i].zname, name) == 0)
554 				break;
555 		}
556 		if (i < nzents) {
557 			free(name);
558 			continue;
559 		}
560 		if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
561 			free(name);
562 			continue;
563 		}
564 		free(name);
565 		if (zent.zstate_num >= min_state)
566 			zone_print(&zent, verbose, parsable);
567 	}
568 	endzoneent(cookie);
569 	return (Z_OK);
570 }
571 
572 static zone_entry_t *
573 lookup_running_zone(char *str)
574 {
575 	zoneid_t zoneid;
576 	char *cp;
577 	int i;
578 
579 	if (fetch_zents() != Z_OK)
580 		return (NULL);
581 
582 	for (i = 0; i < nzents; i++) {
583 		if (strcmp(str, zents[i].zname) == 0)
584 			return (&zents[i]);
585 	}
586 	errno = 0;
587 	zoneid = strtol(str, &cp, 0);
588 	if (zoneid < MIN_ZONEID || zoneid > MAX_ZONEID ||
589 	    errno != 0 || *cp != '\0')
590 		return (NULL);
591 	for (i = 0; i < nzents; i++) {
592 		if (zoneid == zents[i].zid)
593 			return (&zents[i]);
594 	}
595 	return (NULL);
596 }
597 
598 /*
599  * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
600  * B_FALSE, it should be off.  Return B_TRUE if the mode is bad (incorrect).
601  */
602 static boolean_t
603 bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file)
604 {
605 	char *str;
606 
607 	assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR ||
608 	    bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP ||
609 	    bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH);
610 	/*
611 	 * TRANSLATION_NOTE
612 	 * The strings below will be used as part of a larger message,
613 	 * either:
614 	 * (file name) must be (owner|group|world) (read|writ|execut)able
615 	 * or
616 	 * (file name) must not be (owner|group|world) (read|writ|execut)able
617 	 */
618 	switch (bit) {
619 	case S_IRUSR:
620 		str = gettext("owner readable");
621 		break;
622 	case S_IWUSR:
623 		str = gettext("owner writable");
624 		break;
625 	case S_IXUSR:
626 		str = gettext("owner executable");
627 		break;
628 	case S_IRGRP:
629 		str = gettext("group readable");
630 		break;
631 	case S_IWGRP:
632 		str = gettext("group writable");
633 		break;
634 	case S_IXGRP:
635 		str = gettext("group executable");
636 		break;
637 	case S_IROTH:
638 		str = gettext("world readable");
639 		break;
640 	case S_IWOTH:
641 		str = gettext("world writable");
642 		break;
643 	case S_IXOTH:
644 		str = gettext("world executable");
645 		break;
646 	}
647 	if ((mode & bit) == (on ? 0 : bit)) {
648 		/*
649 		 * TRANSLATION_NOTE
650 		 * The first parameter below is a file name; the second
651 		 * is one of the "(owner|group|world) (read|writ|execut)able"
652 		 * strings from above.
653 		 */
654 		/*
655 		 * The code below could be simplified but not in a way
656 		 * that would easily translate to non-English locales.
657 		 */
658 		if (on) {
659 			(void) fprintf(stderr, gettext("%s must be %s.\n"),
660 			    file, str);
661 		} else {
662 			(void) fprintf(stderr, gettext("%s must not be %s.\n"),
663 			    file, str);
664 		}
665 		return (B_TRUE);
666 	}
667 	return (B_FALSE);
668 }
669 
670 /*
671  * We want to make sure that no zone has its zone path as a child node
672  * (in the directory sense) of any other.  We do that by comparing this
673  * zone's path to the path of all other (non-global) zones.  The comparison
674  * in each case is simple: add '/' to the end of the path, then do a
675  * strncmp() of the two paths, using the length of the shorter one.
676  */
677 
678 static int
679 crosscheck_zonepaths(char *path)
680 {
681 	char rpath[MAXPATHLEN];		/* resolved path */
682 	char path_copy[MAXPATHLEN];	/* copy of original path */
683 	char rpath_copy[MAXPATHLEN];	/* copy of original rpath */
684 	struct zoneent *ze;
685 	int res, err;
686 	FILE *cookie;
687 
688 	cookie = setzoneent();
689 	while ((ze = getzoneent_private(cookie)) != NULL) {
690 		/* Skip zones which are not installed. */
691 		if (ze->zone_state < ZONE_STATE_INSTALLED) {
692 			free(ze);
693 			continue;
694 		}
695 		/* Skip the global zone and the current target zone. */
696 		if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 ||
697 		    strcmp(ze->zone_name, target_zone) == 0) {
698 			free(ze);
699 			continue;
700 		}
701 		if (strlen(ze->zone_path) == 0) {
702 			/* old index file without path, fall back */
703 			if ((err = zone_get_zonepath(ze->zone_name,
704 			    ze->zone_path, sizeof (ze->zone_path))) != Z_OK) {
705 				errno = err;
706 				zperror2(ze->zone_name,
707 				    gettext("could not get zone path"));
708 				free(ze);
709 				continue;
710 			}
711 		}
712 		(void) snprintf(path_copy, sizeof (path_copy), "%s%s",
713 		    zonecfg_get_root(), ze->zone_path);
714 		res = resolvepath(path_copy, rpath, sizeof (rpath));
715 		if (res == -1) {
716 			if (errno != ENOENT) {
717 				zperror(path_copy, B_FALSE);
718 				free(ze);
719 				return (Z_ERR);
720 			}
721 			(void) printf(gettext("WARNING: zone %s is installed, "
722 			    "but its %s %s does not exist.\n"), ze->zone_name,
723 			    "zonepath", path_copy);
724 			free(ze);
725 			continue;
726 		}
727 		rpath[res] = '\0';
728 		(void) snprintf(path_copy, sizeof (path_copy), "%s/", path);
729 		(void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath);
730 		if (strncmp(path_copy, rpath_copy,
731 		    min(strlen(path_copy), strlen(rpath_copy))) == 0) {
732 			/*
733 			 * TRANSLATION_NOTE
734 			 * zonepath is a literal that should not be translated.
735 			 */
736 			(void) fprintf(stderr, gettext("%s zonepath (%s) and "
737 			    "%s zonepath (%s) overlap.\n"),
738 			    target_zone, path, ze->zone_name, rpath);
739 			free(ze);
740 			return (Z_ERR);
741 		}
742 		free(ze);
743 	}
744 	endzoneent(cookie);
745 	return (Z_OK);
746 }
747 
748 static int
749 validate_zonepath(char *path, int cmd_num)
750 {
751 	int res;			/* result of last library/system call */
752 	boolean_t err = B_FALSE;	/* have we run into an error? */
753 	struct stat stbuf;
754 	struct statvfs vfsbuf;
755 	char rpath[MAXPATHLEN];		/* resolved path */
756 	char ppath[MAXPATHLEN];		/* parent path */
757 	char rppath[MAXPATHLEN];	/* resolved parent path */
758 	char rootpath[MAXPATHLEN];	/* root path */
759 	zone_state_t state;
760 
761 	if (path[0] != '/') {
762 		(void) fprintf(stderr,
763 		    gettext("%s is not an absolute path.\n"), path);
764 		return (Z_ERR);
765 	}
766 	if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) {
767 		if ((errno != ENOENT) ||
768 		    (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL &&
769 		    cmd_num != CMD_CLONE && cmd_num != CMD_MOVE)) {
770 			zperror(path, B_FALSE);
771 			return (Z_ERR);
772 		}
773 		if (cmd_num == CMD_VERIFY) {
774 			/*
775 			 * TRANSLATION_NOTE
776 			 * zoneadm is a literal that should not be translated.
777 			 */
778 			(void) fprintf(stderr, gettext("WARNING: %s does not "
779 			    "exist, so it could not be verified.\nWhen "
780 			    "'zoneadm %s' is run, '%s' will try to create\n%s, "
781 			    "and '%s' will be tried again,\nbut the '%s' may "
782 			    "fail if:\nthe parent directory of %s is group- or "
783 			    "other-writable\nor\n%s overlaps with any other "
784 			    "installed zones.\n"), path,
785 			    cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL),
786 			    path, cmd_to_str(CMD_VERIFY),
787 			    cmd_to_str(CMD_VERIFY), path, path);
788 			return (Z_OK);
789 		}
790 		/*
791 		 * The zonepath is supposed to be mode 700 but its
792 		 * parent(s) 755.  So use 755 on the mkdirp() then
793 		 * chmod() the zonepath itself to 700.
794 		 */
795 		if (mkdirp(path, DEFAULT_DIR_MODE) < 0) {
796 			zperror(path, B_FALSE);
797 			return (Z_ERR);
798 		}
799 		/*
800 		 * If the chmod() fails, report the error, but might
801 		 * as well continue the verify procedure.
802 		 */
803 		if (chmod(path, S_IRWXU) != 0)
804 			zperror(path, B_FALSE);
805 		/*
806 		 * Since the mkdir() succeeded, we should not have to
807 		 * worry about a subsequent ENOENT, thus this should
808 		 * only recurse once.
809 		 */
810 		return (validate_zonepath(path, cmd_num));
811 	}
812 	rpath[res] = '\0';
813 	if (strcmp(path, rpath) != 0) {
814 		errno = Z_RESOLVED_PATH;
815 		zperror(path, B_TRUE);
816 		return (Z_ERR);
817 	}
818 	if ((res = stat(rpath, &stbuf)) != 0) {
819 		zperror(rpath, B_FALSE);
820 		return (Z_ERR);
821 	}
822 	if (!S_ISDIR(stbuf.st_mode)) {
823 		(void) fprintf(stderr, gettext("%s is not a directory.\n"),
824 		    rpath);
825 		return (Z_ERR);
826 	}
827 	if ((strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) ||
828 	    (strcmp(stbuf.st_fstype, MNTTYPE_XMEMFS) == 0)) {
829 		(void) printf(gettext("WARNING: %s is on a temporary "
830 		    "file-system.\n"), rpath);
831 	}
832 	if (crosscheck_zonepaths(rpath) != Z_OK)
833 		return (Z_ERR);
834 	/*
835 	 * Try to collect and report as many minor errors as possible
836 	 * before returning, so the user can learn everything that needs
837 	 * to be fixed up front.
838 	 */
839 	if (stbuf.st_uid != 0) {
840 		(void) fprintf(stderr, gettext("%s is not owned by root.\n"),
841 		    rpath);
842 		err = B_TRUE;
843 	}
844 	err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath);
845 	err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath);
846 	err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath);
847 	err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath);
848 	err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath);
849 	err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath);
850 	err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath);
851 	err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath);
852 	err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath);
853 
854 	(void) snprintf(ppath, sizeof (ppath), "%s/..", path);
855 	if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) {
856 		zperror(ppath, B_FALSE);
857 		return (Z_ERR);
858 	}
859 	rppath[res] = '\0';
860 	if ((res = stat(rppath, &stbuf)) != 0) {
861 		zperror(rppath, B_FALSE);
862 		return (Z_ERR);
863 	}
864 	/* theoretically impossible */
865 	if (!S_ISDIR(stbuf.st_mode)) {
866 		(void) fprintf(stderr, gettext("%s is not a directory.\n"),
867 		    rppath);
868 		return (Z_ERR);
869 	}
870 	if (stbuf.st_uid != 0) {
871 		(void) fprintf(stderr, gettext("%s is not owned by root.\n"),
872 		    rppath);
873 		err = B_TRUE;
874 	}
875 	err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath);
876 	err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath);
877 	err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath);
878 	err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath);
879 	err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath);
880 	if (strcmp(rpath, rppath) == 0) {
881 		(void) fprintf(stderr, gettext("%s is its own parent.\n"),
882 		    rppath);
883 		err = B_TRUE;
884 	}
885 
886 	if (statvfs(rpath, &vfsbuf) != 0) {
887 		zperror(rpath, B_FALSE);
888 		return (Z_ERR);
889 	}
890 	if (strcmp(vfsbuf.f_basetype, MNTTYPE_NFS) == 0) {
891 		/*
892 		 * TRANSLATION_NOTE
893 		 * Zonepath and NFS are literals that should not be translated.
894 		 */
895 		(void) fprintf(stderr, gettext("Zonepath %s is on an NFS "
896 		    "mounted file-system.\n"
897 		    "\tA local file-system must be used.\n"), rpath);
898 		return (Z_ERR);
899 	}
900 	if (vfsbuf.f_flag & ST_NOSUID) {
901 		/*
902 		 * TRANSLATION_NOTE
903 		 * Zonepath and nosuid are literals that should not be
904 		 * translated.
905 		 */
906 		(void) fprintf(stderr, gettext("Zonepath %s is on a nosuid "
907 		    "file-system.\n"), rpath);
908 		return (Z_ERR);
909 	}
910 
911 	if ((res = zone_get_state(target_zone, &state)) != Z_OK) {
912 		errno = res;
913 		zperror2(target_zone, gettext("could not get state"));
914 		return (Z_ERR);
915 	}
916 	/*
917 	 * The existence of the root path is only bad in the configured state,
918 	 * as it is *supposed* to be there at the installed and later states.
919 	 * However, the root path is expected to be there if the zone is
920 	 * detached.
921 	 * State/command mismatches are caught earlier in verify_details().
922 	 */
923 	if (state == ZONE_STATE_CONFIGURED && cmd_num != CMD_ATTACH) {
924 		if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >=
925 		    sizeof (rootpath)) {
926 			/*
927 			 * TRANSLATION_NOTE
928 			 * Zonepath is a literal that should not be translated.
929 			 */
930 			(void) fprintf(stderr,
931 			    gettext("Zonepath %s is too long.\n"), rpath);
932 			return (Z_ERR);
933 		}
934 		if ((res = stat(rootpath, &stbuf)) == 0) {
935 			if (zonecfg_detached(rpath))
936 				(void) fprintf(stderr,
937 				    gettext("Cannot %s detached "
938 				    "zone.\nUse attach or remove %s "
939 				    "directory.\n"), cmd_to_str(cmd_num),
940 				    rpath);
941 			else
942 				(void) fprintf(stderr,
943 				    gettext("Rootpath %s exists; "
944 				    "remove or move aside prior to %s.\n"),
945 				    rootpath, cmd_to_str(cmd_num));
946 			return (Z_ERR);
947 		}
948 	}
949 
950 	return (err ? Z_ERR : Z_OK);
951 }
952 
953 static void
954 release_lock_file(int lockfd)
955 {
956 	(void) close(lockfd);
957 }
958 
959 static int
960 grab_lock_file(const char *zone_name, int *lockfd)
961 {
962 	char pathbuf[PATH_MAX];
963 	struct flock flock;
964 
965 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
966 	    ZONES_TMPDIR) >= sizeof (pathbuf)) {
967 		zerror(gettext("alternate root path is too long"));
968 		return (Z_ERR);
969 	}
970 	if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
971 		zerror(gettext("could not mkdir %s: %s"), pathbuf,
972 		    strerror(errno));
973 		return (Z_ERR);
974 	}
975 	(void) chmod(pathbuf, S_IRWXU);
976 
977 	/*
978 	 * One of these lock files is created for each zone (when needed).
979 	 * The lock files are not cleaned up (except on system reboot),
980 	 * but since there is only one per zone, there is no resource
981 	 * starvation issue.
982 	 */
983 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
984 	    zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
985 		zerror(gettext("alternate root path is too long"));
986 		return (Z_ERR);
987 	}
988 	if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
989 		zerror(gettext("could not open %s: %s"), pathbuf,
990 		    strerror(errno));
991 		return (Z_ERR);
992 	}
993 	/*
994 	 * Lock the file to synchronize with other zoneadmds
995 	 */
996 	flock.l_type = F_WRLCK;
997 	flock.l_whence = SEEK_SET;
998 	flock.l_start = (off_t)0;
999 	flock.l_len = (off_t)0;
1000 	if (fcntl(*lockfd, F_SETLKW, &flock) < 0) {
1001 		zerror(gettext("unable to lock %s: %s"), pathbuf,
1002 		    strerror(errno));
1003 		release_lock_file(*lockfd);
1004 		return (Z_ERR);
1005 	}
1006 	return (Z_OK);
1007 }
1008 
1009 static boolean_t
1010 get_doorname(const char *zone_name, char *buffer)
1011 {
1012 	return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
1013 	    zonecfg_get_root(), zone_name) < PATH_MAX);
1014 }
1015 
1016 /*
1017  * system daemons are not audited.  For the global zone, this occurs
1018  * "naturally" since init is started with the default audit
1019  * characteristics.  Since zoneadmd is a system daemon and it starts
1020  * init for a zone, it is necessary to clear out the audit
1021  * characteristics inherited from whomever started zoneadmd.  This is
1022  * indicated by the audit id, which is set from the ruid parameter of
1023  * adt_set_user(), below.
1024  */
1025 
1026 static void
1027 prepare_audit_context()
1028 {
1029 	adt_session_data_t	*ah;
1030 	char			*failure = gettext("audit failure: %s");
1031 
1032 	if (adt_start_session(&ah, NULL, 0)) {
1033 		zerror(failure, strerror(errno));
1034 		return;
1035 	}
1036 	if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
1037 	    ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
1038 		zerror(failure, strerror(errno));
1039 		(void) adt_end_session(ah);
1040 		return;
1041 	}
1042 	if (adt_set_proc(ah))
1043 		zerror(failure, strerror(errno));
1044 
1045 	(void) adt_end_session(ah);
1046 }
1047 
1048 static int
1049 start_zoneadmd(const char *zone_name)
1050 {
1051 	char doorpath[PATH_MAX];
1052 	pid_t child_pid;
1053 	int error = Z_ERR;
1054 	int doorfd, lockfd;
1055 	struct door_info info;
1056 
1057 	if (!get_doorname(zone_name, doorpath))
1058 		return (Z_ERR);
1059 
1060 	if (grab_lock_file(zone_name, &lockfd) != Z_OK)
1061 		return (Z_ERR);
1062 
1063 	/*
1064 	 * Now that we have the lock, re-confirm that the daemon is
1065 	 * *not* up and working fine.  If it is still down, we have a green
1066 	 * light to start it.
1067 	 */
1068 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1069 		if (errno != ENOENT) {
1070 			zperror(doorpath, B_FALSE);
1071 			goto out;
1072 		}
1073 	} else {
1074 		if (door_info(doorfd, &info) == 0 &&
1075 		    ((info.di_attributes & DOOR_REVOKED) == 0)) {
1076 			error = Z_OK;
1077 			(void) close(doorfd);
1078 			goto out;
1079 		}
1080 		(void) close(doorfd);
1081 	}
1082 
1083 	if ((child_pid = fork()) == -1) {
1084 		zperror(gettext("could not fork"), B_FALSE);
1085 		goto out;
1086 	} else if (child_pid == 0) {
1087 		const char *argv[6], **ap;
1088 
1089 		/* child process */
1090 		prepare_audit_context();
1091 
1092 		ap = argv;
1093 		*ap++ = "zoneadmd";
1094 		*ap++ = "-z";
1095 		*ap++ = zone_name;
1096 		if (zonecfg_in_alt_root()) {
1097 			*ap++ = "-R";
1098 			*ap++ = zonecfg_get_root();
1099 		}
1100 		*ap = NULL;
1101 
1102 		(void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv);
1103 		/*
1104 		 * TRANSLATION_NOTE
1105 		 * zoneadmd is a literal that should not be translated.
1106 		 */
1107 		zperror(gettext("could not exec zoneadmd"), B_FALSE);
1108 		_exit(Z_ERR);
1109 	} else {
1110 		/* parent process */
1111 		pid_t retval;
1112 		int pstatus = 0;
1113 
1114 		do {
1115 			retval = waitpid(child_pid, &pstatus, 0);
1116 		} while (retval != child_pid);
1117 		if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
1118 		    WEXITSTATUS(pstatus) != 0)) {
1119 			zerror(gettext("could not start %s"), "zoneadmd");
1120 			goto out;
1121 		}
1122 	}
1123 	error = Z_OK;
1124 out:
1125 	release_lock_file(lockfd);
1126 	return (error);
1127 }
1128 
1129 static int
1130 ping_zoneadmd(const char *zone_name)
1131 {
1132 	char doorpath[PATH_MAX];
1133 	int doorfd;
1134 	struct door_info info;
1135 
1136 	if (!get_doorname(zone_name, doorpath))
1137 		return (Z_ERR);
1138 
1139 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1140 		return (Z_ERR);
1141 	}
1142 	if (door_info(doorfd, &info) == 0 &&
1143 	    ((info.di_attributes & DOOR_REVOKED) == 0)) {
1144 		(void) close(doorfd);
1145 		return (Z_OK);
1146 	}
1147 	(void) close(doorfd);
1148 	return (Z_ERR);
1149 }
1150 
1151 static int
1152 call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg)
1153 {
1154 	char doorpath[PATH_MAX];
1155 	int doorfd, result;
1156 	door_arg_t darg;
1157 
1158 	zoneid_t zoneid;
1159 	uint64_t uniqid = 0;
1160 
1161 	zone_cmd_rval_t *rvalp;
1162 	size_t rlen;
1163 	char *cp, *errbuf;
1164 
1165 	rlen = getpagesize();
1166 	if ((rvalp = malloc(rlen)) == NULL) {
1167 		zerror(gettext("failed to allocate %lu bytes: %s"), rlen,
1168 		    strerror(errno));
1169 		return (-1);
1170 	}
1171 
1172 	if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
1173 		(void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
1174 		    sizeof (uniqid));
1175 	}
1176 	arg->uniqid = uniqid;
1177 	(void) strlcpy(arg->locale, locale, sizeof (arg->locale));
1178 	if (!get_doorname(zone_name, doorpath)) {
1179 		zerror(gettext("alternate root path is too long"));
1180 		free(rvalp);
1181 		return (-1);
1182 	}
1183 
1184 	/*
1185 	 * Loop trying to start zoneadmd; if something goes seriously
1186 	 * wrong we break out and fail.
1187 	 */
1188 	for (;;) {
1189 		if (start_zoneadmd(zone_name) != Z_OK)
1190 			break;
1191 
1192 		if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1193 			zperror(gettext("failed to open zone door"), B_FALSE);
1194 			break;
1195 		}
1196 
1197 		darg.data_ptr = (char *)arg;
1198 		darg.data_size = sizeof (*arg);
1199 		darg.desc_ptr = NULL;
1200 		darg.desc_num = 0;
1201 		darg.rbuf = (char *)rvalp;
1202 		darg.rsize = rlen;
1203 		if (door_call(doorfd, &darg) != 0) {
1204 			(void) close(doorfd);
1205 			/*
1206 			 * We'll get EBADF if the door has been revoked.
1207 			 */
1208 			if (errno != EBADF) {
1209 				zperror(gettext("door_call failed"), B_FALSE);
1210 				break;
1211 			}
1212 			continue;	/* take another lap */
1213 		}
1214 		(void) close(doorfd);
1215 
1216 		if (darg.data_size == 0) {
1217 			/* Door server is going away; kick it again. */
1218 			continue;
1219 		}
1220 
1221 		errbuf = rvalp->errbuf;
1222 		while (*errbuf != '\0') {
1223 			/*
1224 			 * Remove any newlines since zerror()
1225 			 * will append one automatically.
1226 			 */
1227 			cp = strchr(errbuf, '\n');
1228 			if (cp != NULL)
1229 				*cp = '\0';
1230 			zerror("%s", errbuf);
1231 			if (cp == NULL)
1232 				break;
1233 			errbuf = cp + 1;
1234 		}
1235 		result = rvalp->rval == 0 ? 0 : -1;
1236 		free(rvalp);
1237 		return (result);
1238 	}
1239 
1240 	free(rvalp);
1241 	return (-1);
1242 }
1243 
1244 static int
1245 ready_func(int argc, char *argv[])
1246 {
1247 	zone_cmd_arg_t zarg;
1248 	int arg;
1249 
1250 	if (zonecfg_in_alt_root()) {
1251 		zerror(gettext("cannot ready zone in alternate root"));
1252 		return (Z_ERR);
1253 	}
1254 
1255 	optind = 0;
1256 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1257 		switch (arg) {
1258 		case '?':
1259 			sub_usage(SHELP_READY, CMD_READY);
1260 			return (optopt == '?' ? Z_OK : Z_USAGE);
1261 		default:
1262 			sub_usage(SHELP_READY, CMD_READY);
1263 			return (Z_USAGE);
1264 		}
1265 	}
1266 	if (argc > optind) {
1267 		sub_usage(SHELP_READY, CMD_READY);
1268 		return (Z_USAGE);
1269 	}
1270 	if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE) != Z_OK)
1271 		return (Z_ERR);
1272 	if (verify_details(CMD_READY) != Z_OK)
1273 		return (Z_ERR);
1274 
1275 	zarg.cmd = Z_READY;
1276 	if (call_zoneadmd(target_zone, &zarg) != 0) {
1277 		zerror(gettext("call to %s failed"), "zoneadmd");
1278 		return (Z_ERR);
1279 	}
1280 	return (Z_OK);
1281 }
1282 
1283 static int
1284 boot_func(int argc, char *argv[])
1285 {
1286 	zone_cmd_arg_t zarg;
1287 	int arg;
1288 
1289 	if (zonecfg_in_alt_root()) {
1290 		zerror(gettext("cannot boot zone in alternate root"));
1291 		return (Z_ERR);
1292 	}
1293 
1294 	zarg.bootbuf[0] = '\0';
1295 
1296 	/*
1297 	 * At the current time, the only supported subargument to the
1298 	 * "boot" subcommand is "-s" which specifies a single-user boot.
1299 	 * In the future, other boot arguments should be supported
1300 	 * including "-m" for specifying alternate smf(5) milestones.
1301 	 */
1302 	optind = 0;
1303 	if ((arg = getopt(argc, argv, "?s")) != EOF) {
1304 		switch (arg) {
1305 		case '?':
1306 			sub_usage(SHELP_BOOT, CMD_BOOT);
1307 			return (optopt == '?' ? Z_OK : Z_USAGE);
1308 		case 's':
1309 			(void) strlcpy(zarg.bootbuf, "-s",
1310 			    sizeof (zarg.bootbuf));
1311 			break;
1312 		default:
1313 			sub_usage(SHELP_BOOT, CMD_BOOT);
1314 			return (Z_USAGE);
1315 		}
1316 	}
1317 	if (argc > optind) {
1318 		sub_usage(SHELP_BOOT, CMD_BOOT);
1319 		return (Z_USAGE);
1320 	}
1321 	if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE) != Z_OK)
1322 		return (Z_ERR);
1323 	if (verify_details(CMD_BOOT) != Z_OK)
1324 		return (Z_ERR);
1325 	zarg.cmd = Z_BOOT;
1326 	if (call_zoneadmd(target_zone, &zarg) != 0) {
1327 		zerror(gettext("call to %s failed"), "zoneadmd");
1328 		return (Z_ERR);
1329 	}
1330 	return (Z_OK);
1331 }
1332 
1333 static void
1334 fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr)
1335 {
1336 	ssize_t result;
1337 
1338 	zeptr->zid = zid;
1339 	/*
1340 	 * Since we're looking up our own (non-global) zone name,
1341 	 * we can be assured that it will succeed.
1342 	 */
1343 	result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname));
1344 	assert(result >= 0);
1345 	(void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
1346 	zeptr->zstate_str = "running";
1347 }
1348 
1349 static int
1350 list_func(int argc, char *argv[])
1351 {
1352 	zone_entry_t *zentp, zent;
1353 	int arg, retv;
1354 	boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE;
1355 	zone_state_t min_state = ZONE_STATE_RUNNING;
1356 	zoneid_t zone_id = getzoneid();
1357 
1358 	if (target_zone == NULL) {
1359 		/* all zones: default view to running but allow override */
1360 		optind = 0;
1361 		while ((arg = getopt(argc, argv, "?cipv")) != EOF) {
1362 			switch (arg) {
1363 			case '?':
1364 				sub_usage(SHELP_LIST, CMD_LIST);
1365 				return (optopt == '?' ? Z_OK : Z_USAGE);
1366 				/*
1367 				 * The 'i' and 'c' options are not mutually
1368 				 * exclusive so if 'c' is given, then min_state
1369 				 * is set to 0 (ZONE_STATE_CONFIGURED) which is
1370 				 * the lowest possible state.  If 'i' is given,
1371 				 * then min_state is set to be the lowest state
1372 				 * so far.
1373 				 */
1374 			case 'c':
1375 				min_state = ZONE_STATE_CONFIGURED;
1376 				break;
1377 			case 'i':
1378 				min_state = min(ZONE_STATE_INSTALLED,
1379 				    min_state);
1380 
1381 				break;
1382 			case 'p':
1383 				parsable = B_TRUE;
1384 				break;
1385 			case 'v':
1386 				verbose = B_TRUE;
1387 				break;
1388 			default:
1389 				sub_usage(SHELP_LIST, CMD_LIST);
1390 				return (Z_USAGE);
1391 			}
1392 		}
1393 		if (parsable && verbose) {
1394 			zerror(gettext("%s -p and -v are mutually exclusive."),
1395 			    cmd_to_str(CMD_LIST));
1396 			return (Z_ERR);
1397 		}
1398 		if (zone_id == GLOBAL_ZONEID) {
1399 			retv = zone_print_list(min_state, verbose, parsable);
1400 		} else {
1401 			retv = Z_OK;
1402 			fake_up_local_zone(zone_id, &zent);
1403 			zone_print(&zent, verbose, parsable);
1404 		}
1405 		return (retv);
1406 	}
1407 
1408 	/*
1409 	 * Specific target zone: disallow -i/-c suboptions.
1410 	 */
1411 	optind = 0;
1412 	while ((arg = getopt(argc, argv, "?pv")) != EOF) {
1413 		switch (arg) {
1414 		case '?':
1415 			sub_usage(SHELP_LIST, CMD_LIST);
1416 			return (optopt == '?' ? Z_OK : Z_USAGE);
1417 		case 'p':
1418 			parsable = B_TRUE;
1419 			break;
1420 		case 'v':
1421 			verbose = B_TRUE;
1422 			break;
1423 		default:
1424 			sub_usage(SHELP_LIST, CMD_LIST);
1425 			return (Z_USAGE);
1426 		}
1427 	}
1428 	if (parsable && verbose) {
1429 		zerror(gettext("%s -p and -v are mutually exclusive."),
1430 		    cmd_to_str(CMD_LIST));
1431 		return (Z_ERR);
1432 	}
1433 	if (argc > optind) {
1434 		sub_usage(SHELP_LIST, CMD_LIST);
1435 		return (Z_USAGE);
1436 	}
1437 	if (zone_id != GLOBAL_ZONEID) {
1438 		fake_up_local_zone(zone_id, &zent);
1439 		/*
1440 		 * main() will issue a Z_NO_ZONE error if it cannot get an
1441 		 * id for target_zone, which in a non-global zone should
1442 		 * happen for any zone name except `zonename`.  Thus we
1443 		 * assert() that here but don't otherwise check.
1444 		 */
1445 		assert(strcmp(zent.zname, target_zone) == 0);
1446 		zone_print(&zent, verbose, parsable);
1447 		output = B_TRUE;
1448 	} else if ((zentp = lookup_running_zone(target_zone)) != NULL) {
1449 		zone_print(zentp, verbose, parsable);
1450 		output = B_TRUE;
1451 	} else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED,
1452 	    &zent) == Z_OK) {
1453 		zone_print(&zent, verbose, parsable);
1454 		output = B_TRUE;
1455 	}
1456 	return (output ? Z_OK : Z_ERR);
1457 }
1458 
1459 static void
1460 sigterm(int sig)
1461 {
1462 	/*
1463 	 * Ignore SIG{INT,TERM}, so we don't end up in an infinite loop,
1464 	 * then propagate the signal to our process group.
1465 	 */
1466 	(void) sigset(SIGINT, SIG_IGN);
1467 	(void) sigset(SIGTERM, SIG_IGN);
1468 	(void) kill(0, sig);
1469 	child_killed = B_TRUE;
1470 }
1471 
1472 static int
1473 do_subproc(char *cmdbuf)
1474 {
1475 	char inbuf[1024];	/* arbitrary large amount */
1476 	FILE *file;
1477 
1478 	child_killed = B_FALSE;
1479 	/*
1480 	 * We use popen(3c) to launch child processes for [un]install;
1481 	 * this library call does not return a PID, so we have to kill
1482 	 * the whole process group.  To avoid killing our parent, we
1483 	 * become a process group leader here.  But doing so can wreak
1484 	 * havoc with reading from stdin when launched by a non-job-control
1485 	 * shell, so we close stdin and reopen it as /dev/null first.
1486 	 */
1487 	(void) close(STDIN_FILENO);
1488 	(void) open("/dev/null", O_RDONLY);
1489 	(void) setpgid(0, 0);
1490 	(void) sigset(SIGINT, sigterm);
1491 	(void) sigset(SIGTERM, sigterm);
1492 	file = popen(cmdbuf, "r");
1493 	for (;;) {
1494 		if (child_killed || fgets(inbuf, sizeof (inbuf), file) == NULL)
1495 			break;
1496 		(void) fputs(inbuf, stdout);
1497 	}
1498 	(void) sigset(SIGINT, SIG_DFL);
1499 	(void) sigset(SIGTERM, SIG_DFL);
1500 	return (pclose(file));
1501 }
1502 
1503 static int
1504 subproc_status(const char *cmd, int status)
1505 {
1506 	if (WIFEXITED(status)) {
1507 		int exit_code = WEXITSTATUS(status);
1508 
1509 		if (exit_code == 0)
1510 			return (Z_OK);
1511 		zerror(gettext("'%s' failed with exit code %d."), cmd,
1512 		    exit_code);
1513 	} else if (WIFSIGNALED(status)) {
1514 		int signal = WTERMSIG(status);
1515 		char sigstr[SIG2STR_MAX];
1516 
1517 		if (sig2str(signal, sigstr) == 0) {
1518 			zerror(gettext("'%s' terminated by signal SIG%s."), cmd,
1519 			    sigstr);
1520 		} else {
1521 			zerror(gettext("'%s' terminated by an unknown signal."),
1522 			    cmd);
1523 		}
1524 	} else {
1525 		zerror(gettext("'%s' failed for unknown reasons."), cmd);
1526 	}
1527 	return (Z_ERR);
1528 }
1529 
1530 /*
1531  * Various sanity checks; make sure:
1532  * 1. We're in the global zone.
1533  * 2. The calling user has sufficient privilege.
1534  * 3. The target zone is neither the global zone nor anything starting with
1535  *    "SUNW".
1536  * 4a. If we're looking for a 'not running' (i.e., configured or installed)
1537  *     zone, the name service knows about it.
1538  * 4b. For some operations which expect a zone not to be running, that it is
1539  *     not already running (or ready).
1540  */
1541 static int
1542 sanity_check(char *zone, int cmd_num, boolean_t running,
1543     boolean_t unsafe_when_running)
1544 {
1545 	zone_entry_t *zent;
1546 	priv_set_t *privset;
1547 	zone_state_t state;
1548 	char kernzone[ZONENAME_MAX];
1549 	FILE *fp;
1550 
1551 	if (getzoneid() != GLOBAL_ZONEID) {
1552 		switch (cmd_num) {
1553 		case CMD_HALT:
1554 			zerror(gettext("use %s to %s this zone."), "halt(1M)",
1555 			    cmd_to_str(cmd_num));
1556 			break;
1557 		case CMD_REBOOT:
1558 			zerror(gettext("use %s to %s this zone."),
1559 			    "reboot(1M)", cmd_to_str(cmd_num));
1560 			break;
1561 		default:
1562 			zerror(gettext("must be in the global zone to %s a "
1563 			    "zone."), cmd_to_str(cmd_num));
1564 			break;
1565 		}
1566 		return (Z_ERR);
1567 	}
1568 
1569 	if ((privset = priv_allocset()) == NULL) {
1570 		zerror(gettext("%s failed"), "priv_allocset");
1571 		return (Z_ERR);
1572 	}
1573 
1574 	if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1575 		zerror(gettext("%s failed"), "getppriv");
1576 		priv_freeset(privset);
1577 		return (Z_ERR);
1578 	}
1579 
1580 	if (priv_isfullset(privset) == B_FALSE) {
1581 		zerror(gettext("only a privileged user may %s a zone."),
1582 		    cmd_to_str(cmd_num));
1583 		priv_freeset(privset);
1584 		return (Z_ERR);
1585 	}
1586 	priv_freeset(privset);
1587 
1588 	if (zone == NULL) {
1589 		zerror(gettext("no zone specified"));
1590 		return (Z_ERR);
1591 	}
1592 
1593 	if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
1594 		zerror(gettext("%s operation is invalid for the global zone."),
1595 		    cmd_to_str(cmd_num));
1596 		return (Z_ERR);
1597 	}
1598 
1599 	if (strncmp(zone, "SUNW", 4) == 0) {
1600 		zerror(gettext("%s operation is invalid for zones starting "
1601 		    "with SUNW."), cmd_to_str(cmd_num));
1602 		return (Z_ERR);
1603 	}
1604 
1605 	if (!zonecfg_in_alt_root()) {
1606 		zent = lookup_running_zone(zone);
1607 	} else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) {
1608 		zent = NULL;
1609 	} else {
1610 		if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(),
1611 		    kernzone, sizeof (kernzone)) == 0)
1612 			zent = lookup_running_zone(kernzone);
1613 		else
1614 			zent = NULL;
1615 		zonecfg_close_scratch(fp);
1616 	}
1617 
1618 	/*
1619 	 * Look up from the kernel for 'running' zones.
1620 	 */
1621 	if (running) {
1622 		if (zent == NULL) {
1623 			zerror(gettext("not running"));
1624 			return (Z_ERR);
1625 		}
1626 	} else {
1627 		int err;
1628 
1629 		if (unsafe_when_running && zent != NULL) {
1630 			/* check whether the zone is ready or running */
1631 			if ((err = zone_get_state(zent->zname,
1632 			    &zent->zstate_num)) != Z_OK) {
1633 				errno = err;
1634 				zperror2(zent->zname,
1635 				    gettext("could not get state"));
1636 				/* can't tell, so hedge */
1637 				zent->zstate_str = "ready/running";
1638 			} else {
1639 				zent->zstate_str =
1640 				    zone_state_str(zent->zstate_num);
1641 			}
1642 			zerror(gettext("%s operation is invalid for %s zones."),
1643 			    cmd_to_str(cmd_num), zent->zstate_str);
1644 			return (Z_ERR);
1645 		}
1646 		if ((err = zone_get_state(zone, &state)) != Z_OK) {
1647 			errno = err;
1648 			zperror2(zone, gettext("could not get state"));
1649 			return (Z_ERR);
1650 		}
1651 		switch (cmd_num) {
1652 		case CMD_UNINSTALL:
1653 			if (state == ZONE_STATE_CONFIGURED) {
1654 				zerror(gettext("is already in state '%s'."),
1655 				    zone_state_str(ZONE_STATE_CONFIGURED));
1656 				return (Z_ERR);
1657 			}
1658 			break;
1659 		case CMD_ATTACH:
1660 		case CMD_CLONE:
1661 		case CMD_INSTALL:
1662 			if (state == ZONE_STATE_INSTALLED) {
1663 				zerror(gettext("is already %s."),
1664 				    zone_state_str(ZONE_STATE_INSTALLED));
1665 				return (Z_ERR);
1666 			} else if (state == ZONE_STATE_INCOMPLETE) {
1667 				zerror(gettext("zone is %s; %s required."),
1668 				    zone_state_str(ZONE_STATE_INCOMPLETE),
1669 				    cmd_to_str(CMD_UNINSTALL));
1670 				return (Z_ERR);
1671 			}
1672 			break;
1673 		case CMD_DETACH:
1674 		case CMD_MOVE:
1675 		case CMD_READY:
1676 		case CMD_BOOT:
1677 		case CMD_MOUNT:
1678 			if (state < ZONE_STATE_INSTALLED) {
1679 				zerror(gettext("must be %s before %s."),
1680 				    zone_state_str(ZONE_STATE_INSTALLED),
1681 				    cmd_to_str(cmd_num));
1682 				return (Z_ERR);
1683 			}
1684 			break;
1685 		case CMD_VERIFY:
1686 			if (state == ZONE_STATE_INCOMPLETE) {
1687 				zerror(gettext("zone is %s; %s required."),
1688 				    zone_state_str(ZONE_STATE_INCOMPLETE),
1689 				    cmd_to_str(CMD_UNINSTALL));
1690 				return (Z_ERR);
1691 			}
1692 			break;
1693 		case CMD_UNMOUNT:
1694 			if (state != ZONE_STATE_MOUNTED) {
1695 				zerror(gettext("must be %s before %s."),
1696 				    zone_state_str(ZONE_STATE_MOUNTED),
1697 				    cmd_to_str(cmd_num));
1698 				return (Z_ERR);
1699 			}
1700 			break;
1701 		}
1702 	}
1703 	return (Z_OK);
1704 }
1705 
1706 static int
1707 halt_func(int argc, char *argv[])
1708 {
1709 	zone_cmd_arg_t zarg;
1710 	int arg;
1711 
1712 	if (zonecfg_in_alt_root()) {
1713 		zerror(gettext("cannot halt zone in alternate root"));
1714 		return (Z_ERR);
1715 	}
1716 
1717 	optind = 0;
1718 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1719 		switch (arg) {
1720 		case '?':
1721 			sub_usage(SHELP_HALT, CMD_HALT);
1722 			return (optopt == '?' ? Z_OK : Z_USAGE);
1723 		default:
1724 			sub_usage(SHELP_HALT, CMD_HALT);
1725 			return (Z_USAGE);
1726 		}
1727 	}
1728 	if (argc > optind) {
1729 		sub_usage(SHELP_HALT, CMD_HALT);
1730 		return (Z_USAGE);
1731 	}
1732 	/*
1733 	 * zoneadmd should be the one to decide whether or not to proceed,
1734 	 * so even though it seems that the fourth parameter below should
1735 	 * perhaps be B_TRUE, it really shouldn't be.
1736 	 */
1737 	if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE) != Z_OK)
1738 		return (Z_ERR);
1739 
1740 	zarg.cmd = Z_HALT;
1741 	return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
1742 }
1743 
1744 static int
1745 reboot_func(int argc, char *argv[])
1746 {
1747 	zone_cmd_arg_t zarg;
1748 	int arg;
1749 
1750 	if (zonecfg_in_alt_root()) {
1751 		zerror(gettext("cannot reboot zone in alternate root"));
1752 		return (Z_ERR);
1753 	}
1754 
1755 	optind = 0;
1756 	if ((arg = getopt(argc, argv, "?")) != EOF) {
1757 		switch (arg) {
1758 		case '?':
1759 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
1760 			return (optopt == '?' ? Z_OK : Z_USAGE);
1761 		default:
1762 			sub_usage(SHELP_REBOOT, CMD_REBOOT);
1763 			return (Z_USAGE);
1764 		}
1765 	}
1766 	if (argc > 0) {
1767 		sub_usage(SHELP_REBOOT, CMD_REBOOT);
1768 		return (Z_USAGE);
1769 	}
1770 	/*
1771 	 * zoneadmd should be the one to decide whether or not to proceed,
1772 	 * so even though it seems that the fourth parameter below should
1773 	 * perhaps be B_TRUE, it really shouldn't be.
1774 	 */
1775 	if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE) != Z_OK)
1776 		return (Z_ERR);
1777 	if (verify_details(CMD_REBOOT) != Z_OK)
1778 		return (Z_ERR);
1779 
1780 	zarg.cmd = Z_REBOOT;
1781 	return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR);
1782 }
1783 
1784 static int
1785 verify_rctls(zone_dochandle_t handle)
1786 {
1787 	struct zone_rctltab rctltab;
1788 	size_t rbs = rctlblk_size();
1789 	rctlblk_t *rctlblk;
1790 	int error = Z_INVAL;
1791 
1792 	if ((rctlblk = malloc(rbs)) == NULL) {
1793 		zerror(gettext("failed to allocate %lu bytes: %s"), rbs,
1794 		    strerror(errno));
1795 		return (Z_NOMEM);
1796 	}
1797 
1798 	if (zonecfg_setrctlent(handle) != Z_OK) {
1799 		zerror(gettext("zonecfg_setrctlent failed"));
1800 		free(rctlblk);
1801 		return (error);
1802 	}
1803 
1804 	rctltab.zone_rctl_valptr = NULL;
1805 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
1806 		struct zone_rctlvaltab *rctlval;
1807 		const char *name = rctltab.zone_rctl_name;
1808 
1809 		if (!zonecfg_is_rctl(name)) {
1810 			zerror(gettext("WARNING: Ignoring unrecognized rctl "
1811 			    "'%s'."),  name);
1812 			zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1813 			rctltab.zone_rctl_valptr = NULL;
1814 			continue;
1815 		}
1816 
1817 		for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL;
1818 		    rctlval = rctlval->zone_rctlval_next) {
1819 			if (zonecfg_construct_rctlblk(rctlval, rctlblk)
1820 			    != Z_OK) {
1821 				zerror(gettext("invalid rctl value: "
1822 				    "(priv=%s,limit=%s,action%s)"),
1823 				    rctlval->zone_rctlval_priv,
1824 				    rctlval->zone_rctlval_limit,
1825 				    rctlval->zone_rctlval_action);
1826 				goto out;
1827 			}
1828 			if (!zonecfg_valid_rctl(name, rctlblk)) {
1829 				zerror(gettext("(priv=%s,limit=%s,action=%s) "
1830 				    "is not a valid value for rctl '%s'"),
1831 				    rctlval->zone_rctlval_priv,
1832 				    rctlval->zone_rctlval_limit,
1833 				    rctlval->zone_rctlval_action,
1834 				    name);
1835 				goto out;
1836 			}
1837 		}
1838 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1839 	}
1840 	rctltab.zone_rctl_valptr = NULL;
1841 	error = Z_OK;
1842 out:
1843 	zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1844 	(void) zonecfg_endrctlent(handle);
1845 	free(rctlblk);
1846 	return (error);
1847 }
1848 
1849 static int
1850 verify_pool(zone_dochandle_t handle)
1851 {
1852 	char poolname[MAXPATHLEN];
1853 	pool_conf_t *poolconf;
1854 	pool_t *pool;
1855 	int status;
1856 	int error;
1857 
1858 	/*
1859 	 * This ends up being very similar to the check done in zoneadmd.
1860 	 */
1861 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
1862 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
1863 		/*
1864 		 * No pool specified.
1865 		 */
1866 		return (0);
1867 	}
1868 	if (error != Z_OK) {
1869 		zperror(gettext("Unable to retrieve pool name from "
1870 		    "configuration"), B_TRUE);
1871 		return (error);
1872 	}
1873 	/*
1874 	 * Don't do anything if pools aren't enabled.
1875 	 */
1876 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
1877 		zerror(gettext("WARNING: pools facility not active; "
1878 		    "zone will not be bound to pool '%s'."), poolname);
1879 		return (Z_OK);
1880 	}
1881 	/*
1882 	 * Try to provide a sane error message if the requested pool doesn't
1883 	 * exist.  It isn't clear that pools-related failures should
1884 	 * necessarily translate to a failure to verify the zone configuration,
1885 	 * hence they are not considered errors.
1886 	 */
1887 	if ((poolconf = pool_conf_alloc()) == NULL) {
1888 		zerror(gettext("WARNING: pool_conf_alloc failed; "
1889 		    "using default pool"));
1890 		return (Z_OK);
1891 	}
1892 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
1893 	    PO_SUCCESS) {
1894 		zerror(gettext("WARNING: pool_conf_open failed; "
1895 		    "using default pool"));
1896 		pool_conf_free(poolconf);
1897 		return (Z_OK);
1898 	}
1899 	pool = pool_get_pool(poolconf, poolname);
1900 	(void) pool_conf_close(poolconf);
1901 	pool_conf_free(poolconf);
1902 	if (pool == NULL) {
1903 		zerror(gettext("WARNING: pool '%s' not found. "
1904 		    "using default pool"), poolname);
1905 	}
1906 
1907 	return (Z_OK);
1908 }
1909 
1910 static int
1911 verify_ipd(zone_dochandle_t handle)
1912 {
1913 	int return_code = Z_OK;
1914 	struct zone_fstab fstab;
1915 	struct stat st;
1916 	char specdir[MAXPATHLEN];
1917 
1918 	if (zonecfg_setipdent(handle) != Z_OK) {
1919 		/*
1920 		 * TRANSLATION_NOTE
1921 		 * inherit-pkg-dirs is a literal that should not be translated.
1922 		 */
1923 		(void) fprintf(stderr, gettext("could not verify "
1924 		    "inherit-pkg-dirs: unable to enumerate mounts\n"));
1925 		return (Z_ERR);
1926 	}
1927 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
1928 		/*
1929 		 * Verify fs_dir exists.
1930 		 */
1931 		(void) snprintf(specdir, sizeof (specdir), "%s%s",
1932 		    zonecfg_get_root(), fstab.zone_fs_dir);
1933 		if (stat(specdir, &st) != 0) {
1934 			/*
1935 			 * TRANSLATION_NOTE
1936 			 * inherit-pkg-dir is a literal that should not be
1937 			 * translated.
1938 			 */
1939 			(void) fprintf(stderr, gettext("could not verify "
1940 			    "inherit-pkg-dir %s: %s\n"),
1941 			    fstab.zone_fs_dir, strerror(errno));
1942 			return_code = Z_ERR;
1943 		}
1944 		if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
1945 			/*
1946 			 * TRANSLATION_NOTE
1947 			 * inherit-pkg-dir and NFS are literals that should
1948 			 * not be translated.
1949 			 */
1950 			(void) fprintf(stderr, gettext("cannot verify "
1951 			    "inherit-pkg-dir %s: NFS mounted file-system.\n"
1952 			    "\tA local file-system must be used.\n"),
1953 			    fstab.zone_fs_dir);
1954 			return_code = Z_ERR;
1955 		}
1956 	}
1957 	(void) zonecfg_endipdent(handle);
1958 
1959 	return (return_code);
1960 }
1961 
1962 /* ARGSUSED */
1963 static void
1964 zfs_fs_err_handler(const char *fmt, va_list ap)
1965 {
1966 	/*
1967 	 * Do nothing - do not print the libzfs error messages.
1968 	 */
1969 }
1970 
1971 /*
1972  * Verify that the ZFS dataset exists, and its mountpoint
1973  * property is set to "legacy".
1974  */
1975 static int
1976 verify_fs_zfs(struct zone_fstab *fstab)
1977 {
1978 	zfs_handle_t *zhp;
1979 	char propbuf[ZFS_MAXPROPLEN];
1980 
1981 	zfs_set_error_handler(zfs_fs_err_handler);
1982 
1983 	if ((zhp = zfs_open(fstab->zone_fs_special, ZFS_TYPE_ANY)) == NULL) {
1984 		(void) fprintf(stderr, gettext("could not verify fs %s: "
1985 		    "could not access zfs dataset '%s'\n"),
1986 		    fstab->zone_fs_dir, fstab->zone_fs_special);
1987 		return (Z_ERR);
1988 	}
1989 
1990 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1991 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
1992 		    "'%s' is not a filesystem\n"),
1993 		    fstab->zone_fs_dir, fstab->zone_fs_special);
1994 		zfs_close(zhp);
1995 		return (Z_ERR);
1996 	}
1997 
1998 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1999 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
2000 		(void) fprintf(stderr, gettext("could not verify fs %s: "
2001 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
2002 		    fstab->zone_fs_dir, fstab->zone_fs_special);
2003 		zfs_close(zhp);
2004 		return (Z_ERR);
2005 	}
2006 
2007 	zfs_close(zhp);
2008 	return (Z_OK);
2009 }
2010 
2011 /*
2012  * Verify that the special device/filesystem exists and is valid.
2013  */
2014 static int
2015 verify_fs_special(struct zone_fstab *fstab)
2016 {
2017 	struct stat st;
2018 
2019 	if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
2020 		return (verify_fs_zfs(fstab));
2021 
2022 	if (stat(fstab->zone_fs_special, &st) != 0) {
2023 		(void) fprintf(stderr, gettext("could not verify fs "
2024 		    "%s: could not access %s: %s\n"), fstab->zone_fs_dir,
2025 		    fstab->zone_fs_special, strerror(errno));
2026 		return (Z_ERR);
2027 	}
2028 
2029 	if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
2030 		/*
2031 		 * TRANSLATION_NOTE
2032 		 * fs and NFS are literals that should
2033 		 * not be translated.
2034 		 */
2035 		(void) fprintf(stderr, gettext("cannot verify "
2036 		    "fs %s: NFS mounted file-system.\n"
2037 		    "\tA local file-system must be used.\n"),
2038 		    fstab->zone_fs_special);
2039 		return (Z_ERR);
2040 	}
2041 
2042 	return (Z_OK);
2043 }
2044 
2045 static int
2046 verify_filesystems(zone_dochandle_t handle)
2047 {
2048 	int return_code = Z_OK;
2049 	struct zone_fstab fstab;
2050 	char cmdbuf[MAXPATHLEN];
2051 	struct stat st;
2052 
2053 	/*
2054 	 * No need to verify inherit-pkg-dir fs types, as their type is
2055 	 * implicitly lofs, which is known.  Therefore, the types are only
2056 	 * verified for regular filesystems below.
2057 	 *
2058 	 * Since the actual mount point is not known until the dependent mounts
2059 	 * are performed, we don't attempt any path validation here: that will
2060 	 * happen later when zoneadmd actually does the mounts.
2061 	 */
2062 	if (zonecfg_setfsent(handle) != Z_OK) {
2063 		(void) fprintf(stderr, gettext("could not verify file-systems: "
2064 		    "unable to enumerate mounts\n"));
2065 		return (Z_ERR);
2066 	}
2067 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
2068 		if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) {
2069 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
2070 			    "type %s is not allowed.\n"), fstab.zone_fs_dir,
2071 			    fstab.zone_fs_type);
2072 			return_code = Z_ERR;
2073 			goto next_fs;
2074 		}
2075 		/*
2076 		 * Verify /usr/lib/fs/<fstype>/mount exists.
2077 		 */
2078 		if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount",
2079 		    fstab.zone_fs_type) > sizeof (cmdbuf)) {
2080 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
2081 			    "type %s is too long.\n"), fstab.zone_fs_dir,
2082 			    fstab.zone_fs_type);
2083 			return_code = Z_ERR;
2084 			goto next_fs;
2085 		}
2086 		if (stat(cmdbuf, &st) != 0) {
2087 			(void) fprintf(stderr, gettext("could not verify fs "
2088 			    "%s: could not access %s: %s\n"), fstab.zone_fs_dir,
2089 			    cmdbuf, strerror(errno));
2090 			return_code = Z_ERR;
2091 			goto next_fs;
2092 		}
2093 		if (!S_ISREG(st.st_mode)) {
2094 			(void) fprintf(stderr, gettext("could not verify fs "
2095 			    "%s: %s is not a regular file\n"),
2096 			    fstab.zone_fs_dir, cmdbuf);
2097 			return_code = Z_ERR;
2098 			goto next_fs;
2099 		}
2100 		/*
2101 		 * Verify /usr/lib/fs/<fstype>/fsck exists iff zone_fs_raw is
2102 		 * set.
2103 		 */
2104 		if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck",
2105 		    fstab.zone_fs_type) > sizeof (cmdbuf)) {
2106 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
2107 			    "type %s is too long.\n"), fstab.zone_fs_dir,
2108 			    fstab.zone_fs_type);
2109 			return_code = Z_ERR;
2110 			goto next_fs;
2111 		}
2112 		if (fstab.zone_fs_raw[0] == '\0' && stat(cmdbuf, &st) == 0) {
2113 			(void) fprintf(stderr, gettext("could not verify fs "
2114 			    "%s: must specify 'raw' device for %s "
2115 			    "file-systems\n"),
2116 			    fstab.zone_fs_dir, fstab.zone_fs_type);
2117 			return_code = Z_ERR;
2118 			goto next_fs;
2119 		}
2120 		if (fstab.zone_fs_raw[0] != '\0' &&
2121 		    (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) {
2122 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
2123 			    "'raw' device specified but "
2124 			    "no fsck executable exists for %s\n"),
2125 			    fstab.zone_fs_dir, fstab.zone_fs_type);
2126 			return_code = Z_ERR;
2127 			goto next_fs;
2128 		}
2129 
2130 		/* Verify fs_special. */
2131 		if ((return_code = verify_fs_special(&fstab)) != Z_OK)
2132 			goto next_fs;
2133 
2134 		/* Verify fs_raw. */
2135 		if (fstab.zone_fs_raw[0] != '\0' &&
2136 		    stat(fstab.zone_fs_raw, &st) != 0) {
2137 			/*
2138 			 * TRANSLATION_NOTE
2139 			 * fs is a literal that should not be translated.
2140 			 */
2141 			(void) fprintf(stderr, gettext("could not verify fs "
2142 			    "%s: could not access %s: %s\n"), fstab.zone_fs_dir,
2143 			    fstab.zone_fs_raw, strerror(errno));
2144 			return_code = Z_ERR;
2145 			goto next_fs;
2146 		}
2147 next_fs:
2148 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
2149 	}
2150 	(void) zonecfg_endfsent(handle);
2151 
2152 	return (return_code);
2153 }
2154 
2155 const char *current_dataset;
2156 
2157 /*
2158  * Custom error handler for errors incurred as part of the checks below.  We
2159  * want to trim off the leading 'cannot open ...' to create a better error
2160  * message.  The only other way this can fail is if we fail to set the 'zoned'
2161  * property.  In this case we just pass the error on verbatim.
2162  */
2163 static void
2164 zfs_error_handler(const char *fmt, va_list ap)
2165 {
2166 	char buf[1024];
2167 
2168 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
2169 
2170 	if (strncmp(gettext("cannot open "), buf,
2171 	    strlen(gettext("cannot open "))) == 0)
2172 		/*
2173 		 * TRANSLATION_NOTE
2174 		 * zfs and dataset are literals that should not be translated.
2175 		 */
2176 		(void) fprintf(stderr, gettext("could not verify zfs "
2177 		    "dataset %s%s\n"), current_dataset, strchr(buf, ':'));
2178 	else
2179 		(void) fprintf(stderr, gettext("could not verify zfs dataset "
2180 		    "%s: %s\n"), current_dataset, buf);
2181 }
2182 
2183 /* ARGSUSED */
2184 static int
2185 check_zvol(zfs_handle_t *zhp, void *unused)
2186 {
2187 	int ret;
2188 
2189 	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
2190 		/*
2191 		 * TRANSLATION_NOTE
2192 		 * zfs and dataset are literals that should not be translated.
2193 		 */
2194 		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
2195 		    "volumes cannot be specified as a zone dataset resource\n"),
2196 		    zfs_get_name(zhp));
2197 		ret = -1;
2198 	} else {
2199 		ret = zfs_iter_children(zhp, check_zvol, NULL);
2200 	}
2201 
2202 	zfs_close(zhp);
2203 
2204 	return (ret);
2205 }
2206 
2207 /*
2208  * Validate that the given dataset exists on the system, and that neither it nor
2209  * its children are zvols.
2210  *
2211  * Note that we don't do anything with the 'zoned' property here.  All
2212  * management is done in zoneadmd when the zone is actually rebooted.  This
2213  * allows us to automatically set the zoned property even when a zone is
2214  * rebooted by the administrator.
2215  */
2216 static int
2217 verify_datasets(zone_dochandle_t handle)
2218 {
2219 	int return_code = Z_OK;
2220 	struct zone_dstab dstab;
2221 	zfs_handle_t *zhp;
2222 	char propbuf[ZFS_MAXPROPLEN];
2223 	char source[ZFS_MAXNAMELEN];
2224 	zfs_source_t srctype;
2225 
2226 	if (zonecfg_setdsent(handle) != Z_OK) {
2227 		/*
2228 		 * TRANSLATION_NOTE
2229 		 * zfs and dataset are literals that should not be translated.
2230 		 */
2231 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
2232 		    "unable to enumerate datasets\n"));
2233 		return (Z_ERR);
2234 	}
2235 
2236 	zfs_set_error_handler(zfs_error_handler);
2237 
2238 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
2239 
2240 		current_dataset = dstab.zone_dataset_name;
2241 
2242 		if ((zhp = zfs_open(dstab.zone_dataset_name,
2243 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
2244 			return_code = Z_ERR;
2245 			continue;
2246 		}
2247 
2248 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
2249 		    sizeof (propbuf), &srctype, source,
2250 		    sizeof (source), 0) == 0 &&
2251 		    (srctype == ZFS_SRC_INHERITED)) {
2252 			(void) fprintf(stderr, gettext("could not verify zfs "
2253 			    "dataset %s: mountpoint cannot be inherited\n"),
2254 			    dstab.zone_dataset_name);
2255 			return_code = Z_ERR;
2256 			zfs_close(zhp);
2257 			continue;
2258 		}
2259 
2260 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
2261 			(void) fprintf(stderr, gettext("cannot verify zfs "
2262 			    "dataset %s: volumes cannot be specified as a "
2263 			    "zone dataset resource\n"),
2264 			    dstab.zone_dataset_name);
2265 			return_code = Z_ERR;
2266 		}
2267 
2268 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
2269 			return_code = Z_ERR;
2270 
2271 		zfs_close(zhp);
2272 	}
2273 	(void) zonecfg_enddsent(handle);
2274 
2275 	return (return_code);
2276 }
2277 
2278 static int
2279 verify_limitpriv(zone_dochandle_t handle)
2280 {
2281 	char *privname = NULL;
2282 	int err;
2283 	priv_set_t *privs;
2284 
2285 	if ((privs = priv_allocset()) == NULL) {
2286 		zperror(gettext("failed to allocate privilege set"), B_FALSE);
2287 		return (Z_NOMEM);
2288 	}
2289 	err = zonecfg_get_privset(handle, privs, &privname);
2290 	switch (err) {
2291 	case Z_OK:
2292 		break;
2293 	case Z_PRIV_PROHIBITED:
2294 		(void) fprintf(stderr, gettext("privilege \"%s\" is not "
2295 		    "permitted within the zone's privilege set\n"), privname);
2296 		break;
2297 	case Z_PRIV_REQUIRED:
2298 		(void) fprintf(stderr, gettext("required privilege \"%s\" is "
2299 		    "missing from the zone's privilege set\n"), privname);
2300 		break;
2301 	case Z_PRIV_UNKNOWN:
2302 		(void) fprintf(stderr, gettext("unknown privilege \"%s\" "
2303 		    "specified in the zone's privilege set\n"), privname);
2304 		break;
2305 	default:
2306 		zperror(
2307 		    gettext("failed to determine the zone's privilege set"),
2308 		    B_TRUE);
2309 		break;
2310 	}
2311 	free(privname);
2312 	priv_freeset(privs);
2313 	return (err);
2314 }
2315 
2316 static int
2317 verify_details(int cmd_num)
2318 {
2319 	zone_dochandle_t handle;
2320 	struct zone_nwiftab nwiftab;
2321 	char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN];
2322 	int return_code = Z_OK;
2323 	int err;
2324 	boolean_t in_alt_root;
2325 
2326 	if ((handle = zonecfg_init_handle()) == NULL) {
2327 		zperror(cmd_to_str(cmd_num), B_TRUE);
2328 		return (Z_ERR);
2329 	}
2330 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
2331 		errno = err;
2332 		zperror(cmd_to_str(cmd_num), B_TRUE);
2333 		zonecfg_fini_handle(handle);
2334 		return (Z_ERR);
2335 	}
2336 	if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) !=
2337 	    Z_OK) {
2338 		errno = err;
2339 		zperror(cmd_to_str(cmd_num), B_TRUE);
2340 		zonecfg_fini_handle(handle);
2341 		return (Z_ERR);
2342 	}
2343 	/*
2344 	 * zonecfg_get_zonepath() gets its data from the XML repository.
2345 	 * Verify this against the index file, which is checked first by
2346 	 * zone_get_zonepath().  If they don't match, bail out.
2347 	 */
2348 	if ((err = zone_get_zonepath(target_zone, checkpath,
2349 	    sizeof (checkpath))) != Z_OK) {
2350 		errno = err;
2351 		zperror2(target_zone, gettext("could not get zone path"));
2352 		return (Z_ERR);
2353 	}
2354 	if (strcmp(zonepath, checkpath) != 0) {
2355 		/*
2356 		 * TRANSLATION_NOTE
2357 		 * XML and zonepath are literals that should not be translated.
2358 		 */
2359 		(void) fprintf(stderr, gettext("The XML repository has "
2360 		    "zonepath '%s',\nbut the index file has zonepath '%s'.\n"
2361 		    "These must match, so fix the incorrect entry.\n"),
2362 		    zonepath, checkpath);
2363 		return (Z_ERR);
2364 	}
2365 	if (validate_zonepath(zonepath, cmd_num) != Z_OK) {
2366 		(void) fprintf(stderr, gettext("could not verify zonepath %s "
2367 		    "because of the above errors.\n"), zonepath);
2368 		return_code = Z_ERR;
2369 	}
2370 
2371 	in_alt_root = zonecfg_in_alt_root();
2372 	if (in_alt_root)
2373 		goto no_net;
2374 
2375 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2376 		errno = err;
2377 		zperror(cmd_to_str(cmd_num), B_TRUE);
2378 		zonecfg_fini_handle(handle);
2379 		return (Z_ERR);
2380 	}
2381 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2382 		struct lifreq lifr;
2383 		sa_family_t af;
2384 		int so, res;
2385 
2386 		/* skip any loopback interfaces */
2387 		if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0)
2388 			continue;
2389 		if ((res = zonecfg_valid_net_address(nwiftab.zone_nwif_address,
2390 		    &lifr)) != Z_OK) {
2391 			(void) fprintf(stderr, gettext("could not verify %s "
2392 			    "%s=%s %s=%s: %s\n"), "net", "address",
2393 			    nwiftab.zone_nwif_address, "physical",
2394 			    nwiftab.zone_nwif_physical, zonecfg_strerror(res));
2395 			return_code = Z_ERR;
2396 			continue;
2397 		}
2398 		af = lifr.lifr_addr.ss_family;
2399 		(void) memset(&lifr, 0, sizeof (lifr));
2400 		(void) strlcpy(lifr.lifr_name, nwiftab.zone_nwif_physical,
2401 		    sizeof (lifr.lifr_name));
2402 		lifr.lifr_addr.ss_family = af;
2403 		if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2404 			(void) fprintf(stderr, gettext("could not verify %s "
2405 			    "%s=%s %s=%s: could not get socket: %s\n"), "net",
2406 			    "address", nwiftab.zone_nwif_address, "physical",
2407 			    nwiftab.zone_nwif_physical, strerror(errno));
2408 			return_code = Z_ERR;
2409 			continue;
2410 		}
2411 		if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2412 			(void) fprintf(stderr,
2413 			    gettext("could not verify %s %s=%s %s=%s: %s\n"),
2414 			    "net", "address", nwiftab.zone_nwif_address,
2415 			    "physical", nwiftab.zone_nwif_physical,
2416 			    strerror(errno));
2417 			return_code = Z_ERR;
2418 		}
2419 		(void) close(so);
2420 	}
2421 	(void) zonecfg_endnwifent(handle);
2422 no_net:
2423 
2424 	if (verify_filesystems(handle) != Z_OK)
2425 		return_code = Z_ERR;
2426 	if (verify_ipd(handle) != Z_OK)
2427 		return_code = Z_ERR;
2428 	if (!in_alt_root && verify_rctls(handle) != Z_OK)
2429 		return_code = Z_ERR;
2430 	if (!in_alt_root && verify_pool(handle) != Z_OK)
2431 		return_code = Z_ERR;
2432 	if (!in_alt_root && verify_datasets(handle) != Z_OK)
2433 		return_code = Z_ERR;
2434 
2435 	/*
2436 	 * As the "mount" command is used for patching/upgrading of zones
2437 	 * or other maintenance processes, the zone's privilege set is not
2438 	 * checked in this case.  Instead, the default, safe set of
2439 	 * privileges will be used when this zone is created in the
2440 	 * kernel.
2441 	 */
2442 	if (!in_alt_root && cmd_num != CMD_MOUNT &&
2443 	    verify_limitpriv(handle) != Z_OK)
2444 		return_code = Z_ERR;
2445 	zonecfg_fini_handle(handle);
2446 	if (return_code == Z_ERR)
2447 		(void) fprintf(stderr,
2448 		    gettext("%s: zone %s failed to verify\n"),
2449 		    execname, target_zone);
2450 	return (return_code);
2451 }
2452 
2453 static int
2454 verify_func(int argc, char *argv[])
2455 {
2456 	int arg;
2457 
2458 	optind = 0;
2459 	if ((arg = getopt(argc, argv, "?")) != EOF) {
2460 		switch (arg) {
2461 		case '?':
2462 			sub_usage(SHELP_VERIFY, CMD_VERIFY);
2463 			return (optopt == '?' ? Z_OK : Z_USAGE);
2464 		default:
2465 			sub_usage(SHELP_VERIFY, CMD_VERIFY);
2466 			return (Z_USAGE);
2467 		}
2468 	}
2469 	if (argc > optind) {
2470 		sub_usage(SHELP_VERIFY, CMD_VERIFY);
2471 		return (Z_USAGE);
2472 	}
2473 	if (sanity_check(target_zone, CMD_VERIFY, B_FALSE, B_FALSE) != Z_OK)
2474 		return (Z_ERR);
2475 	return (verify_details(CMD_VERIFY));
2476 }
2477 
2478 #define	LUCREATEZONE	"/usr/lib/lu/lucreatezone"
2479 
2480 static int
2481 install_func(int argc, char *argv[])
2482 {
2483 	/* 9: "exec " and " -z " */
2484 	char cmdbuf[sizeof (LUCREATEZONE) + ZONENAME_MAX + 9];
2485 	int lockfd;
2486 	int err, arg;
2487 	char zonepath[MAXPATHLEN];
2488 	int status;
2489 
2490 	if (zonecfg_in_alt_root()) {
2491 		zerror(gettext("cannot install zone in alternate root"));
2492 		return (Z_ERR);
2493 	}
2494 
2495 	optind = 0;
2496 	if ((arg = getopt(argc, argv, "?")) != EOF) {
2497 		switch (arg) {
2498 		case '?':
2499 			sub_usage(SHELP_INSTALL, CMD_INSTALL);
2500 			return (optopt == '?' ? Z_OK : Z_USAGE);
2501 		default:
2502 			sub_usage(SHELP_INSTALL, CMD_INSTALL);
2503 			return (Z_USAGE);
2504 		}
2505 	}
2506 	if (argc > optind) {
2507 		sub_usage(SHELP_INSTALL, CMD_INSTALL);
2508 		return (Z_USAGE);
2509 	}
2510 	if (sanity_check(target_zone, CMD_INSTALL, B_FALSE, B_TRUE) != Z_OK)
2511 		return (Z_ERR);
2512 	if (verify_details(CMD_INSTALL) != Z_OK)
2513 		return (Z_ERR);
2514 
2515 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
2516 		zerror(gettext("another %s may have an operation in progress."),
2517 		    "zoneadm");
2518 		return (Z_ERR);
2519 	}
2520 	err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
2521 	if (err != Z_OK) {
2522 		errno = err;
2523 		zperror2(target_zone, gettext("could not set state"));
2524 		goto done;
2525 	}
2526 
2527 	/*
2528 	 * According to the Application Packaging Developer's Guide, a
2529 	 * "checkinstall" script when included in a package is executed as
2530 	 * the user "install", if such a user exists, or by the user
2531 	 * "nobody".  In order to support this dubious behavior, the path
2532 	 * to the zone being constructed is opened up during the life of
2533 	 * the command laying down the zone's root file system.  Once this
2534 	 * has completed, regardless of whether it was successful, the
2535 	 * path to the zone is again restricted.
2536 	 */
2537 	if ((err = zone_get_zonepath(target_zone, zonepath,
2538 	    sizeof (zonepath))) != Z_OK) {
2539 		errno = err;
2540 		zperror2(target_zone, gettext("could not get zone path"));
2541 		goto done;
2542 	}
2543 	if (chmod(zonepath, DEFAULT_DIR_MODE) != 0) {
2544 		zperror(zonepath, B_FALSE);
2545 		err = Z_ERR;
2546 		goto done;
2547 	}
2548 
2549 	/*
2550 	 * "exec" the command so that the returned status is that of
2551 	 * LUCREATEZONE and not the shell.
2552 	 */
2553 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " LUCREATEZONE " -z %s",
2554 	    target_zone);
2555 	status = do_subproc(cmdbuf);
2556 	if (chmod(zonepath, S_IRWXU) != 0) {
2557 		zperror(zonepath, B_FALSE);
2558 		err = Z_ERR;
2559 		goto done;
2560 	}
2561 	if ((err = subproc_status(LUCREATEZONE, status)) != Z_OK)
2562 		goto done;
2563 
2564 	if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
2565 		errno = err;
2566 		zperror2(target_zone, gettext("could not set state"));
2567 		goto done;
2568 	}
2569 
2570 done:
2571 	release_lock_file(lockfd);
2572 	return ((err == Z_OK) ? Z_OK : Z_ERR);
2573 }
2574 
2575 /*
2576  * Check that the inherited pkg dirs are the same for the clone and its source.
2577  * The easiest way to do that is check that the list of ipds is the same
2578  * by matching each one against the other.  This algorithm should be fine since
2579  * the list of ipds should not be that long.
2580  */
2581 static int
2582 valid_ipd_clone(zone_dochandle_t s_handle, char *source_zone,
2583 	zone_dochandle_t t_handle, char *target_zone)
2584 {
2585 	int err;
2586 	int res = Z_OK;
2587 	int s_cnt = 0;
2588 	int t_cnt = 0;
2589 	struct zone_fstab s_fstab;
2590 	struct zone_fstab t_fstab;
2591 
2592 	/*
2593 	 * First check the source of the clone against the target.
2594 	 */
2595 	if ((err = zonecfg_setipdent(s_handle)) != Z_OK) {
2596 		errno = err;
2597 		zperror2(source_zone, gettext("could not enumerate "
2598 		    "inherit-pkg-dirs"));
2599 		return (Z_ERR);
2600 	}
2601 
2602 	while (zonecfg_getipdent(s_handle, &s_fstab) == Z_OK) {
2603 		boolean_t match = B_FALSE;
2604 
2605 		s_cnt++;
2606 
2607 		if ((err = zonecfg_setipdent(t_handle)) != Z_OK) {
2608 			errno = err;
2609 			zperror2(target_zone, gettext("could not enumerate "
2610 			    "inherit-pkg-dirs"));
2611 			(void) zonecfg_endipdent(s_handle);
2612 			return (Z_ERR);
2613 		}
2614 
2615 		while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK) {
2616 			if (strcmp(s_fstab.zone_fs_dir, t_fstab.zone_fs_dir)
2617 			    == 0) {
2618 				match = B_TRUE;
2619 				break;
2620 			}
2621 		}
2622 		(void) zonecfg_endipdent(t_handle);
2623 
2624 		if (!match) {
2625 			(void) fprintf(stderr, gettext("inherit-pkg-dir "
2626 			    "'%s' is not configured in zone %s.\n"),
2627 			    s_fstab.zone_fs_dir, target_zone);
2628 			res = Z_ERR;
2629 		}
2630 	}
2631 
2632 	(void) zonecfg_endipdent(s_handle);
2633 
2634 	/* skip the next check if we already have errors */
2635 	if (res == Z_ERR)
2636 		return (res);
2637 
2638 	/*
2639 	 * Now check the number of ipds in the target so we can verify
2640 	 * that the source is not a subset of the target.
2641 	 */
2642 	if ((err = zonecfg_setipdent(t_handle)) != Z_OK) {
2643 		errno = err;
2644 		zperror2(target_zone, gettext("could not enumerate "
2645 		    "inherit-pkg-dirs"));
2646 		return (Z_ERR);
2647 	}
2648 
2649 	while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK)
2650 		t_cnt++;
2651 
2652 	(void) zonecfg_endipdent(t_handle);
2653 
2654 	if (t_cnt != s_cnt) {
2655 		(void) fprintf(stderr, gettext("Zone %s is configured "
2656 		    "with inherit-pkg-dirs that are not configured in zone "
2657 		    "%s.\n"), target_zone, source_zone);
2658 		res = Z_ERR;
2659 	}
2660 
2661 	return (res);
2662 }
2663 
2664 static void
2665 warn_dev_match(zone_dochandle_t s_handle, char *source_zone,
2666 	zone_dochandle_t t_handle, char *target_zone)
2667 {
2668 	int err;
2669 	struct zone_devtab s_devtab;
2670 	struct zone_devtab t_devtab;
2671 
2672 	if ((err = zonecfg_setdevent(t_handle)) != Z_OK) {
2673 		errno = err;
2674 		zperror2(target_zone, gettext("could not enumerate devices"));
2675 		return;
2676 	}
2677 
2678 	while (zonecfg_getdevent(t_handle, &t_devtab) == Z_OK) {
2679 		if ((err = zonecfg_setdevent(s_handle)) != Z_OK) {
2680 			errno = err;
2681 			zperror2(source_zone,
2682 			    gettext("could not enumerate devices"));
2683 			(void) zonecfg_enddevent(t_handle);
2684 			return;
2685 		}
2686 
2687 		while (zonecfg_getdevent(s_handle, &s_devtab) == Z_OK) {
2688 			/*
2689 			 * Use fnmatch to catch the case where wildcards
2690 			 * were used in one zone and the other has an
2691 			 * explicit entry (e.g. /dev/dsk/c0t0d0s6 vs.
2692 			 * /dev/\*dsk/c0t0d0s6).
2693 			 */
2694 			if (fnmatch(t_devtab.zone_dev_match,
2695 			    s_devtab.zone_dev_match, FNM_PATHNAME) == 0 ||
2696 			    fnmatch(s_devtab.zone_dev_match,
2697 			    t_devtab.zone_dev_match, FNM_PATHNAME) == 0) {
2698 				(void) fprintf(stderr,
2699 				    gettext("WARNING: device '%s' "
2700 				    "is configured in both zones.\n"),
2701 				    t_devtab.zone_dev_match);
2702 				break;
2703 			}
2704 		}
2705 		(void) zonecfg_enddevent(s_handle);
2706 	}
2707 
2708 	(void) zonecfg_enddevent(t_handle);
2709 }
2710 
2711 /*
2712  * Check if the specified mount option (opt) is contained within the
2713  * options string.
2714  */
2715 static boolean_t
2716 opt_match(char *opt, char *options)
2717 {
2718 	char *p;
2719 	char *lastp;
2720 
2721 	if ((p = strtok_r(options, ",", &lastp)) != NULL) {
2722 		if (strcmp(p, opt) == 0)
2723 			return (B_TRUE);
2724 		while ((p = strtok_r(NULL, ",", &lastp)) != NULL) {
2725 			if (strcmp(p, opt) == 0)
2726 				return (B_TRUE);
2727 		}
2728 	}
2729 
2730 	return (B_FALSE);
2731 }
2732 
2733 #define	RW_LOFS	"WARNING: read-write lofs file-system on '%s' is configured " \
2734 	"in both zones.\n"
2735 
2736 static void
2737 print_fs_warnings(struct zone_fstab *s_fstab, struct zone_fstab *t_fstab)
2738 {
2739 	/*
2740 	 * It is ok to have shared lofs mounted fs but we want to warn if
2741 	 * either is rw since this will effect the other zone.
2742 	 */
2743 	if (strcmp(t_fstab->zone_fs_type, "lofs") == 0) {
2744 		zone_fsopt_t *optp;
2745 
2746 		/* The default is rw so no options means rw */
2747 		if (t_fstab->zone_fs_options == NULL ||
2748 		    s_fstab->zone_fs_options == NULL) {
2749 			(void) fprintf(stderr, gettext(RW_LOFS),
2750 			    t_fstab->zone_fs_special);
2751 			return;
2752 		}
2753 
2754 		for (optp = s_fstab->zone_fs_options; optp != NULL;
2755 		    optp = optp->zone_fsopt_next) {
2756 			if (opt_match("rw", optp->zone_fsopt_opt)) {
2757 				(void) fprintf(stderr, gettext(RW_LOFS),
2758 				    s_fstab->zone_fs_special);
2759 				return;
2760 			}
2761 		}
2762 
2763 		for (optp = t_fstab->zone_fs_options; optp != NULL;
2764 		    optp = optp->zone_fsopt_next) {
2765 			if (opt_match("rw", optp->zone_fsopt_opt)) {
2766 				(void) fprintf(stderr, gettext(RW_LOFS),
2767 				    t_fstab->zone_fs_special);
2768 				return;
2769 			}
2770 		}
2771 
2772 		return;
2773 	}
2774 
2775 	/*
2776 	 * TRANSLATION_NOTE
2777 	 * The first variable is the file-system type and the second is
2778 	 * the file-system special device.  For example,
2779 	 * WARNING: ufs file-system on '/dev/dsk/c0t0d0s0' ...
2780 	 */
2781 	(void) fprintf(stderr, gettext("WARNING: %s file-system on '%s' "
2782 	    "is configured in both zones.\n"), t_fstab->zone_fs_type,
2783 	    t_fstab->zone_fs_special);
2784 }
2785 
2786 static void
2787 warn_fs_match(zone_dochandle_t s_handle, char *source_zone,
2788 	zone_dochandle_t t_handle, char *target_zone)
2789 {
2790 	int err;
2791 	struct zone_fstab s_fstab;
2792 	struct zone_fstab t_fstab;
2793 
2794 	if ((err = zonecfg_setfsent(t_handle)) != Z_OK) {
2795 		errno = err;
2796 		zperror2(target_zone,
2797 		    gettext("could not enumerate file-systems"));
2798 		return;
2799 	}
2800 
2801 	while (zonecfg_getfsent(t_handle, &t_fstab) == Z_OK) {
2802 		if ((err = zonecfg_setfsent(s_handle)) != Z_OK) {
2803 			errno = err;
2804 			zperror2(source_zone,
2805 			    gettext("could not enumerate file-systems"));
2806 			(void) zonecfg_endfsent(t_handle);
2807 			return;
2808 		}
2809 
2810 		while (zonecfg_getfsent(s_handle, &s_fstab) == Z_OK) {
2811 			if (strcmp(t_fstab.zone_fs_special,
2812 			    s_fstab.zone_fs_special) == 0) {
2813 				print_fs_warnings(&s_fstab, &t_fstab);
2814 				break;
2815 			}
2816 		}
2817 		(void) zonecfg_endfsent(s_handle);
2818 	}
2819 
2820 	(void) zonecfg_endfsent(t_handle);
2821 }
2822 
2823 /*
2824  * We don't catch the case where you used the same IP address but
2825  * it is not an exact string match.  For example, 192.9.0.128 vs. 192.09.0.128.
2826  * However, we're not going to worry about that but we will check for
2827  * a possible netmask on one of the addresses (e.g. 10.0.0.1 and 10.0.0.1/24)
2828  * and handle that case as a match.
2829  */
2830 static void
2831 warn_ip_match(zone_dochandle_t s_handle, char *source_zone,
2832 	zone_dochandle_t t_handle, char *target_zone)
2833 {
2834 	int err;
2835 	struct zone_nwiftab s_nwiftab;
2836 	struct zone_nwiftab t_nwiftab;
2837 
2838 	if ((err = zonecfg_setnwifent(t_handle)) != Z_OK) {
2839 		errno = err;
2840 		zperror2(target_zone,
2841 		    gettext("could not enumerate network interfaces"));
2842 		return;
2843 	}
2844 
2845 	while (zonecfg_getnwifent(t_handle, &t_nwiftab) == Z_OK) {
2846 		char *p;
2847 
2848 		/* remove an (optional) netmask from the address */
2849 		if ((p = strchr(t_nwiftab.zone_nwif_address, '/')) != NULL)
2850 			*p = '\0';
2851 
2852 		if ((err = zonecfg_setnwifent(s_handle)) != Z_OK) {
2853 			errno = err;
2854 			zperror2(source_zone,
2855 			    gettext("could not enumerate network interfaces"));
2856 			(void) zonecfg_endnwifent(t_handle);
2857 			return;
2858 		}
2859 
2860 		while (zonecfg_getnwifent(s_handle, &s_nwiftab) == Z_OK) {
2861 			/* remove an (optional) netmask from the address */
2862 			if ((p = strchr(s_nwiftab.zone_nwif_address, '/'))
2863 			    != NULL)
2864 				*p = '\0';
2865 
2866 			if (strcmp(t_nwiftab.zone_nwif_address,
2867 			    s_nwiftab.zone_nwif_address) == 0) {
2868 				(void) fprintf(stderr,
2869 				    gettext("WARNING: network address '%s' "
2870 				    "is configured in both zones.\n"),
2871 				    t_nwiftab.zone_nwif_address);
2872 				break;
2873 			}
2874 		}
2875 		(void) zonecfg_endnwifent(s_handle);
2876 	}
2877 
2878 	(void) zonecfg_endnwifent(t_handle);
2879 }
2880 
2881 static void
2882 warn_dataset_match(zone_dochandle_t s_handle, char *source_zone,
2883 	zone_dochandle_t t_handle, char *target_zone)
2884 {
2885 	int err;
2886 	struct zone_dstab s_dstab;
2887 	struct zone_dstab t_dstab;
2888 
2889 	if ((err = zonecfg_setdsent(t_handle)) != Z_OK) {
2890 		errno = err;
2891 		zperror2(target_zone, gettext("could not enumerate datasets"));
2892 		return;
2893 	}
2894 
2895 	while (zonecfg_getdsent(t_handle, &t_dstab) == Z_OK) {
2896 		if ((err = zonecfg_setdsent(s_handle)) != Z_OK) {
2897 			errno = err;
2898 			zperror2(source_zone,
2899 			    gettext("could not enumerate datasets"));
2900 			(void) zonecfg_enddsent(t_handle);
2901 			return;
2902 		}
2903 
2904 		while (zonecfg_getdsent(s_handle, &s_dstab) == Z_OK) {
2905 			if (strcmp(t_dstab.zone_dataset_name,
2906 			    s_dstab.zone_dataset_name) == 0) {
2907 				(void) fprintf(stderr,
2908 				    gettext("WARNING: dataset '%s' "
2909 				    "is configured in both zones.\n"),
2910 				    t_dstab.zone_dataset_name);
2911 				break;
2912 			}
2913 		}
2914 		(void) zonecfg_enddsent(s_handle);
2915 	}
2916 
2917 	(void) zonecfg_enddsent(t_handle);
2918 }
2919 
2920 static int
2921 validate_clone(char *source_zone, char *target_zone)
2922 {
2923 	int err = Z_OK;
2924 	zone_dochandle_t s_handle;
2925 	zone_dochandle_t t_handle;
2926 
2927 	if ((t_handle = zonecfg_init_handle()) == NULL) {
2928 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2929 		return (Z_ERR);
2930 	}
2931 	if ((err = zonecfg_get_handle(target_zone, t_handle)) != Z_OK) {
2932 		errno = err;
2933 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2934 		zonecfg_fini_handle(t_handle);
2935 		return (Z_ERR);
2936 	}
2937 
2938 	if ((s_handle = zonecfg_init_handle()) == NULL) {
2939 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2940 		zonecfg_fini_handle(t_handle);
2941 		return (Z_ERR);
2942 	}
2943 	if ((err = zonecfg_get_handle(source_zone, s_handle)) != Z_OK) {
2944 		errno = err;
2945 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2946 		goto done;
2947 	}
2948 
2949 	/* verify new zone has same inherit-pkg-dirs */
2950 	err = valid_ipd_clone(s_handle, source_zone, t_handle, target_zone);
2951 
2952 	/* warn about imported fs's which are the same */
2953 	warn_fs_match(s_handle, source_zone, t_handle, target_zone);
2954 
2955 	/* warn about imported IP addresses which are the same */
2956 	warn_ip_match(s_handle, source_zone, t_handle, target_zone);
2957 
2958 	/* warn about imported devices which are the same */
2959 	warn_dev_match(s_handle, source_zone, t_handle, target_zone);
2960 
2961 	/* warn about imported datasets which are the same */
2962 	warn_dataset_match(s_handle, source_zone, t_handle, target_zone);
2963 
2964 done:
2965 	zonecfg_fini_handle(t_handle);
2966 	zonecfg_fini_handle(s_handle);
2967 
2968 	return ((err == Z_OK) ? Z_OK : Z_ERR);
2969 }
2970 
2971 static int
2972 copy_zone(char *src, char *dst)
2973 {
2974 	boolean_t out_null = B_FALSE;
2975 	int status;
2976 	int err;
2977 	char *outfile;
2978 	char cmdbuf[MAXPATHLEN * 2 + 128];
2979 
2980 	if ((outfile = tempnam("/var/log", "zone")) == NULL) {
2981 		outfile = "/dev/null";
2982 		out_null = B_TRUE;
2983 	}
2984 
2985 	(void) snprintf(cmdbuf, sizeof (cmdbuf),
2986 	    "cd %s && /usr/bin/find . -depth -print | "
2987 	    "/usr/bin/egrep -v '^\\./\\.zfs$|^\\./\\.zfs/' | "
2988 	    "/usr/bin/cpio -pdmuP@ %s > %s 2>&1",
2989 	    src, dst, outfile);
2990 
2991 	status = do_subproc(cmdbuf);
2992 
2993 	if ((err = subproc_status("copy", status)) != Z_OK) {
2994 		if (!out_null)
2995 			(void) fprintf(stderr, gettext("\nThe copy failed.\n"
2996 			    "More information can be found in %s\n"), outfile);
2997 		return (err);
2998 	}
2999 
3000 	if (!out_null)
3001 		(void) unlink(outfile);
3002 
3003 	return (Z_OK);
3004 }
3005 
3006 /*
3007  * Run sys-unconfig on a zone.  This will leave the zone in the installed
3008  * state as long as there were no errors during the sys-unconfig.
3009  */
3010 static int
3011 unconfigure_zone(char *zonepath)
3012 {
3013 	int		err;
3014 	int		status;
3015 	struct stat	unconfig_buf;
3016 	zone_cmd_arg_t	zarg;
3017 	char		cmdbuf[MAXPATHLEN + 51];
3018 
3019 	/* The zone has to be installed in order to mount the scratch zone. */
3020 	if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
3021 		errno = err;
3022 		zperror2(target_zone, gettext("could not set state"));
3023 		return (Z_ERR);
3024 	}
3025 
3026 	/*
3027 	 * Check if the zone is already sys-unconfiged.  This saves us
3028 	 * the work of bringing up the scratch zone so we can unconfigure it.
3029 	 */
3030 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "%s/root/etc/.UNCONFIGURED",
3031 	    zonepath);
3032 	if (stat(cmdbuf, &unconfig_buf) == 0)
3033 		return (Z_OK);
3034 
3035 	zarg.cmd = Z_MOUNT;
3036 	if (call_zoneadmd(target_zone, &zarg) != 0) {
3037 		zerror(gettext("call to %s failed"), "zoneadmd");
3038 		(void) zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
3039 		return (Z_ERR);
3040 	}
3041 
3042 	(void) snprintf(cmdbuf, sizeof (cmdbuf),
3043 	    "/usr/sbin/zlogin -S %s /usr/sbin/sys-unconfig -R /a", target_zone);
3044 
3045 	status = do_subproc(cmdbuf);
3046 	if ((err = subproc_status("sys-unconfig", status)) != Z_OK) {
3047 		errno = err;
3048 		zperror2(target_zone, gettext("sys-unconfig failed\n"));
3049 		(void) zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
3050 	}
3051 
3052 	zarg.cmd = Z_UNMOUNT;
3053 	if (call_zoneadmd(target_zone, &zarg) != 0) {
3054 		zerror(gettext("call to %s failed"), "zoneadmd");
3055 		(void) fprintf(stderr, gettext("could not unmount zone\n"));
3056 		return (Z_ERR);
3057 	}
3058 
3059 	return ((err == Z_OK) ? Z_OK : Z_ERR);
3060 }
3061 
3062 /* ARGSUSED */
3063 int
3064 zfm_print(const char *p, void *r) {
3065 	zerror("  %s\n", p);
3066 	return (0);
3067 }
3068 
3069 static int
3070 clone_func(int argc, char *argv[])
3071 {
3072 	char *source_zone = NULL;
3073 	int lockfd;
3074 	int err, arg;
3075 	char zonepath[MAXPATHLEN];
3076 	char source_zonepath[MAXPATHLEN];
3077 	zone_state_t state;
3078 	zone_entry_t *zent;
3079 	char *method = "copy";
3080 
3081 	if (zonecfg_in_alt_root()) {
3082 		zerror(gettext("cannot clone zone in alternate root"));
3083 		return (Z_ERR);
3084 	}
3085 
3086 	optind = 0;
3087 	if ((arg = getopt(argc, argv, "?m:")) != EOF) {
3088 		switch (arg) {
3089 		case '?':
3090 			sub_usage(SHELP_CLONE, CMD_CLONE);
3091 			return (optopt == '?' ? Z_OK : Z_USAGE);
3092 		case 'm':
3093 			method = optarg;
3094 			break;
3095 		default:
3096 			sub_usage(SHELP_CLONE, CMD_CLONE);
3097 			return (Z_USAGE);
3098 		}
3099 	}
3100 	if (argc != (optind + 1) || strcmp(method, "copy") != 0) {
3101 		sub_usage(SHELP_CLONE, CMD_CLONE);
3102 		return (Z_USAGE);
3103 	}
3104 	source_zone = argv[optind];
3105 	if (sanity_check(target_zone, CMD_CLONE, B_FALSE, B_TRUE) != Z_OK)
3106 		return (Z_ERR);
3107 	if (verify_details(CMD_CLONE) != Z_OK)
3108 		return (Z_ERR);
3109 
3110 	/*
3111 	 * We also need to do some extra validation on the source zone.
3112 	 */
3113 
3114 	if (strcmp(source_zone, GLOBAL_ZONENAME) == 0) {
3115 		zerror(gettext("%s operation is invalid for the global zone."),
3116 		    cmd_to_str(CMD_CLONE));
3117 		return (Z_ERR);
3118 	}
3119 
3120 	if (strncmp(source_zone, "SUNW", 4) == 0) {
3121 		zerror(gettext("%s operation is invalid for zones starting "
3122 		    "with SUNW."), cmd_to_str(CMD_CLONE));
3123 		return (Z_ERR);
3124 	}
3125 
3126 	zent = lookup_running_zone(source_zone);
3127 	if (zent != NULL) {
3128 		/* check whether the zone is ready or running */
3129 		if ((err = zone_get_state(zent->zname, &zent->zstate_num))
3130 		    != Z_OK) {
3131 			errno = err;
3132 			zperror2(zent->zname, gettext("could not get state"));
3133 			/* can't tell, so hedge */
3134 			zent->zstate_str = "ready/running";
3135 		} else {
3136 			zent->zstate_str = zone_state_str(zent->zstate_num);
3137 		}
3138 		zerror(gettext("%s operation is invalid for %s zones."),
3139 		    cmd_to_str(CMD_CLONE), zent->zstate_str);
3140 		return (Z_ERR);
3141 	}
3142 
3143 	if ((err = zone_get_state(source_zone, &state)) != Z_OK) {
3144 		errno = err;
3145 		zperror2(source_zone, gettext("could not get state"));
3146 		return (Z_ERR);
3147 	}
3148 	if (state != ZONE_STATE_INSTALLED) {
3149 		(void) fprintf(stderr,
3150 		    gettext("%s: zone %s is %s; %s is required.\n"),
3151 		    execname, source_zone, zone_state_str(state),
3152 		    zone_state_str(ZONE_STATE_INSTALLED));
3153 		return (Z_ERR);
3154 	}
3155 
3156 	/*
3157 	 * The source zone checks out ok, continue with the clone.
3158 	 */
3159 
3160 	if (validate_clone(source_zone, target_zone) != Z_OK)
3161 		return (Z_ERR);
3162 
3163 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
3164 		zerror(gettext("another %s may have an operation in progress."),
3165 		    "zoneadm");
3166 		return (Z_ERR);
3167 	}
3168 
3169 	if ((err = zone_get_zonepath(source_zone, source_zonepath,
3170 	    sizeof (source_zonepath))) != Z_OK) {
3171 		errno = err;
3172 		zperror2(source_zone, gettext("could not get zone path"));
3173 		goto done;
3174 	}
3175 
3176 	if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
3177 	    != Z_OK) {
3178 		errno = err;
3179 		zperror2(target_zone, gettext("could not get zone path"));
3180 		goto done;
3181 	}
3182 
3183 	/* Don't clone the zone if anything is still mounted there */
3184 	if (zonecfg_find_mounts(source_zonepath, NULL, NULL)) {
3185 		zerror(gettext("These file-systems are mounted on "
3186 		    "subdirectories of %s.\n"), source_zonepath);
3187 		(void) zonecfg_find_mounts(source_zonepath, zfm_print, NULL);
3188 		err = Z_ERR;
3189 		goto done;
3190 	}
3191 
3192 	if ((err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE))
3193 	    != Z_OK) {
3194 		errno = err;
3195 		zperror2(target_zone, gettext("could not set state"));
3196 		goto done;
3197 	}
3198 
3199 	(void) printf(gettext("Cloning zonepath %s..."), source_zonepath);
3200 	(void) fflush(stdout);
3201 
3202 	err = copy_zone(source_zonepath, zonepath);
3203 	(void) printf("\n");
3204 	if (err != Z_OK)
3205 		goto done;
3206 
3207 	err = unconfigure_zone(zonepath);
3208 
3209 done:
3210 	release_lock_file(lockfd);
3211 	return ((err == Z_OK) ? Z_OK : Z_ERR);
3212 }
3213 
3214 #define	RMCOMMAND	"/usr/bin/rm -rf"
3215 
3216 /*
3217  * Used when moving a zonepath (via copying) to clean up the old path or
3218  * the new path if there was an error.
3219  *
3220  * This function handles the case of a zonepath being a zfs filesystem.
3221  * If it is a zfs filesystem, we cannot just remove the whole zonepath
3222  * since we can't remove the filesystem itself.  Instead, we have to remove
3223  * the contents of the filesystem, but not the .zfs directory.
3224  */
3225 static int
3226 remove_zonepath(char *zonepath)
3227 {
3228 	int status;
3229 	boolean_t is_zfs = B_FALSE;
3230 	struct stat buf;
3231 	char cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 128];
3232 
3233 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "%s/.zfs", zonepath);
3234 
3235 	if (stat(cmdbuf, &buf) == 0 && S_ISDIR(buf.st_mode))
3236 		is_zfs = B_TRUE;
3237 
3238 	if (is_zfs) {
3239 		/*
3240 		 * This doesn't handle the (unlikely) case that there are
3241 		 * directories or files in the top-level zonepath with white
3242 		 * space in the names.
3243 		 */
3244 		(void) snprintf(cmdbuf, sizeof (cmdbuf),
3245 		    "cd %s && /usr/bin/ls -A | /usr/bin/egrep -v '^\\.zfs$' | "
3246 		    "/usr/bin/xargs " RMCOMMAND, zonepath);
3247 	} else {
3248 		/*
3249 		 * "exec" the command so that the returned status is
3250 		 * that of rm and not the shell.
3251 		 */
3252 		(void) snprintf(cmdbuf, sizeof (cmdbuf),
3253 		    "exec " RMCOMMAND " %s", zonepath);
3254 	}
3255 
3256 	status = do_subproc(cmdbuf);
3257 
3258 	return (subproc_status("rm", status));
3259 
3260 }
3261 
3262 static int
3263 move_func(int argc, char *argv[])
3264 {
3265 	char *new_zonepath = NULL;
3266 	int lockfd;
3267 	int err, arg;
3268 	char zonepath[MAXPATHLEN];
3269 	zone_dochandle_t handle;
3270 	boolean_t fast;
3271 	boolean_t revert;
3272 	struct stat zonepath_buf;
3273 	struct stat new_zonepath_buf;
3274 
3275 	if (zonecfg_in_alt_root()) {
3276 		zerror(gettext("cannot move zone in alternate root"));
3277 		return (Z_ERR);
3278 	}
3279 
3280 	optind = 0;
3281 	if ((arg = getopt(argc, argv, "?")) != EOF) {
3282 		switch (arg) {
3283 		case '?':
3284 			sub_usage(SHELP_MOVE, CMD_MOVE);
3285 			return (optopt == '?' ? Z_OK : Z_USAGE);
3286 		default:
3287 			sub_usage(SHELP_MOVE, CMD_MOVE);
3288 			return (Z_USAGE);
3289 		}
3290 	}
3291 	if (argc != (optind + 1)) {
3292 		sub_usage(SHELP_MOVE, CMD_MOVE);
3293 		return (Z_USAGE);
3294 	}
3295 	new_zonepath = argv[optind];
3296 	if (sanity_check(target_zone, CMD_MOVE, B_FALSE, B_TRUE) != Z_OK)
3297 		return (Z_ERR);
3298 	if (verify_details(CMD_MOVE) != Z_OK)
3299 		return (Z_ERR);
3300 
3301 	/*
3302 	 * Check out the new zonepath.  This has the side effect of creating
3303 	 * a directory for the new zonepath.  We depend on this later when we
3304 	 * stat to see if we are doing a cross file-system move or not.
3305 	 */
3306 	if (validate_zonepath(new_zonepath, CMD_MOVE) != Z_OK)
3307 		return (Z_ERR);
3308 
3309 	if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
3310 	    != Z_OK) {
3311 		errno = err;
3312 		zperror2(target_zone, gettext("could not get zone path"));
3313 		return (Z_ERR);
3314 	}
3315 
3316 	if (stat(zonepath, &zonepath_buf) == -1) {
3317 		zperror(gettext("could not stat zone path"), B_FALSE);
3318 		return (Z_ERR);
3319 	}
3320 
3321 	if (stat(new_zonepath, &new_zonepath_buf) == -1) {
3322 		zperror(gettext("could not stat new zone path"), B_FALSE);
3323 		return (Z_ERR);
3324 	}
3325 
3326 	/* Don't move the zone if anything is still mounted there */
3327 	if (zonecfg_find_mounts(zonepath, NULL, NULL)) {
3328 		zerror(gettext("These file-systems are mounted on "
3329 		    "subdirectories of %s.\n"), zonepath);
3330 		(void) zonecfg_find_mounts(zonepath, zfm_print, NULL);
3331 		return (Z_ERR);
3332 	}
3333 
3334 	/*
3335 	 * Check if we are moving in the same filesystem and can do a fast
3336 	 * move or if we are crossing filesystems and have to copy the data.
3337 	 */
3338 	fast = (zonepath_buf.st_dev == new_zonepath_buf.st_dev);
3339 
3340 	if ((handle = zonecfg_init_handle()) == NULL) {
3341 		zperror(cmd_to_str(CMD_MOVE), B_TRUE);
3342 		return (Z_ERR);
3343 	}
3344 
3345 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3346 		errno = err;
3347 		zperror(cmd_to_str(CMD_MOVE), B_TRUE);
3348 		zonecfg_fini_handle(handle);
3349 		return (Z_ERR);
3350 	}
3351 
3352 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
3353 		zerror(gettext("another %s may have an operation in progress."),
3354 		    "zoneadm");
3355 		zonecfg_fini_handle(handle);
3356 		return (Z_ERR);
3357 	}
3358 
3359 	/*
3360 	 * We're making some file-system changes now so we have to clean up
3361 	 * the file-system before we are done.  This will either clean up the
3362 	 * new zonepath if the zonecfg update failed or it will clean up the
3363 	 * old zonepath if everything is ok.
3364 	 */
3365 	revert = B_TRUE;
3366 
3367 	if (fast) {
3368 		/* same filesystem, use rename for a quick move */
3369 
3370 		/*
3371 		 * Remove the new_zonepath directory that got created above
3372 		 * during the validation.  It gets in the way of the rename.
3373 		 */
3374 		if (rmdir(new_zonepath) != 0) {
3375 			zperror(gettext("could not rmdir new zone path"),
3376 			    B_FALSE);
3377 			zonecfg_fini_handle(handle);
3378 			release_lock_file(lockfd);
3379 			return (Z_ERR);
3380 		}
3381 
3382 		if (rename(zonepath, new_zonepath) != 0) {
3383 			/*
3384 			 * If this fails we don't need to do all of the
3385 			 * cleanup that happens for the rest of the code
3386 			 * so just return from this error.
3387 			 */
3388 			zperror(gettext("could not move zone"), B_FALSE);
3389 			zonecfg_fini_handle(handle);
3390 			release_lock_file(lockfd);
3391 			return (Z_ERR);
3392 		}
3393 
3394 	} else {
3395 		(void) printf(gettext(
3396 		    "Moving across file-systems; copying zonepath %s..."),
3397 		    zonepath);
3398 		(void) fflush(stdout);
3399 
3400 		err = copy_zone(zonepath, new_zonepath);
3401 
3402 		(void) printf("\n");
3403 		if (err != Z_OK)
3404 			goto done;
3405 	}
3406 
3407 	if ((err = zonecfg_set_zonepath(handle, new_zonepath)) != Z_OK) {
3408 		errno = err;
3409 		zperror(gettext("could not set new zonepath"), B_TRUE);
3410 		goto done;
3411 	}
3412 
3413 	if ((err = zonecfg_save(handle)) != Z_OK) {
3414 		errno = err;
3415 		zperror(gettext("zonecfg save failed"), B_TRUE);
3416 		goto done;
3417 	}
3418 
3419 	revert = B_FALSE;
3420 
3421 done:
3422 	zonecfg_fini_handle(handle);
3423 	release_lock_file(lockfd);
3424 
3425 	/*
3426 	 * Clean up the file-system based on how things went.  We either
3427 	 * clean up the new zonepath if the operation failed for some reason
3428 	 * or we clean up the old zonepath if everything is ok.
3429 	 */
3430 	if (revert) {
3431 		/* The zonecfg update failed, cleanup the new zonepath. */
3432 		if (fast) {
3433 			if (rename(new_zonepath, zonepath) != 0) {
3434 				zperror(gettext("could not restore zonepath"),
3435 				    B_FALSE);
3436 				/*
3437 				 * err is already != Z_OK since we're reverting
3438 				 */
3439 			}
3440 		} else {
3441 			(void) printf(gettext("Cleaning up zonepath %s..."),
3442 			    new_zonepath);
3443 			(void) fflush(stdout);
3444 			err = remove_zonepath(new_zonepath);
3445 			(void) printf("\n");
3446 
3447 			if (err != Z_OK) {
3448 				errno = err;
3449 				zperror(gettext("could not remove new "
3450 				    "zonepath"), B_TRUE);
3451 			} else {
3452 				/*
3453 				 * Because we're reverting we know the mainline
3454 				 * code failed but we just reused the err
3455 				 * variable so we reset it back to Z_ERR.
3456 				 */
3457 				err = Z_ERR;
3458 			}
3459 		}
3460 
3461 	} else {
3462 		/* The move was successful, cleanup the old zonepath. */
3463 		if (!fast) {
3464 			(void) printf(
3465 			    gettext("Cleaning up zonepath %s..."), zonepath);
3466 			(void) fflush(stdout);
3467 			err = remove_zonepath(zonepath);
3468 			(void) printf("\n");
3469 
3470 			if (err != Z_OK) {
3471 				errno = err;
3472 				zperror(gettext("could not remove zonepath"),
3473 				    B_TRUE);
3474 			}
3475 		}
3476 	}
3477 
3478 	return ((err == Z_OK) ? Z_OK : Z_ERR);
3479 }
3480 
3481 static int
3482 detach_func(int argc, char *argv[])
3483 {
3484 	int lockfd;
3485 	int err, arg;
3486 	char zonepath[MAXPATHLEN];
3487 	zone_dochandle_t handle;
3488 
3489 	if (zonecfg_in_alt_root()) {
3490 		zerror(gettext("cannot detach zone in alternate root"));
3491 		return (Z_ERR);
3492 	}
3493 
3494 	optind = 0;
3495 	if ((arg = getopt(argc, argv, "?")) != EOF) {
3496 		switch (arg) {
3497 		case '?':
3498 			sub_usage(SHELP_DETACH, CMD_DETACH);
3499 			return (optopt == '?' ? Z_OK : Z_USAGE);
3500 		default:
3501 			sub_usage(SHELP_DETACH, CMD_DETACH);
3502 			return (Z_USAGE);
3503 		}
3504 	}
3505 	if (sanity_check(target_zone, CMD_DETACH, B_FALSE, B_TRUE) != Z_OK)
3506 		return (Z_ERR);
3507 	if (verify_details(CMD_DETACH) != Z_OK)
3508 		return (Z_ERR);
3509 
3510 	if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
3511 	    != Z_OK) {
3512 		errno = err;
3513 		zperror2(target_zone, gettext("could not get zone path"));
3514 		return (Z_ERR);
3515 	}
3516 
3517 	/* Don't detach the zone if anything is still mounted there */
3518 	if (zonecfg_find_mounts(zonepath, NULL, NULL)) {
3519 		zerror(gettext("These file-systems are mounted on "
3520 		    "subdirectories of %s.\n"), zonepath);
3521 		(void) zonecfg_find_mounts(zonepath, zfm_print, NULL);
3522 		return (Z_ERR);
3523 	}
3524 
3525 	if ((handle = zonecfg_init_handle()) == NULL) {
3526 		zperror(cmd_to_str(CMD_DETACH), B_TRUE);
3527 		return (Z_ERR);
3528 	}
3529 
3530 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3531 		errno = err;
3532 		zperror(cmd_to_str(CMD_DETACH), B_TRUE);
3533 		zonecfg_fini_handle(handle);
3534 		return (Z_ERR);
3535 	}
3536 
3537 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
3538 		zerror(gettext("another %s may have an operation in progress."),
3539 		    "zoneadm");
3540 		zonecfg_fini_handle(handle);
3541 		return (Z_ERR);
3542 	}
3543 
3544 	if ((err = zonecfg_get_detach_info(handle, B_TRUE)) != Z_OK) {
3545 		errno = err;
3546 		zperror(gettext("getting the detach information failed"),
3547 		    B_TRUE);
3548 		goto done;
3549 	}
3550 
3551 	if ((err = zonecfg_detach_save(handle)) != Z_OK) {
3552 		errno = err;
3553 		zperror(gettext("saving the detach manifest failed"), B_TRUE);
3554 		goto done;
3555 	}
3556 
3557 	if ((err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED))
3558 	    != Z_OK) {
3559 		errno = err;
3560 		zperror(gettext("could not reset state"), B_TRUE);
3561 	}
3562 
3563 done:
3564 	zonecfg_fini_handle(handle);
3565 	release_lock_file(lockfd);
3566 
3567 	return ((err == Z_OK) ? Z_OK : Z_ERR);
3568 }
3569 
3570 /*
3571  * Find the specified package in the sw inventory on the handle and check
3572  * if the version matches what is passed in.
3573  * Return 0 if the packages match
3574  *        1 if the package is found but we have a version mismatch
3575  *        -1 if the package is not found
3576  */
3577 static int
3578 pkg_cmp(zone_dochandle_t handle, char *pkg_name, char *pkg_vers,
3579     char *return_vers, int vers_size)
3580 {
3581 	int res = -1;
3582 	struct zone_pkgtab pkgtab;
3583 
3584 	if (zonecfg_setpkgent(handle) != Z_OK) {
3585 		(void) fprintf(stderr,
3586 		    gettext("unable to enumerate packages\n"));
3587 		return (Z_ERR);
3588 	}
3589 
3590 	while (zonecfg_getpkgent(handle, &pkgtab) == Z_OK) {
3591 		if (strcmp(pkg_name, pkgtab.zone_pkg_name) != 0)
3592 			continue;
3593 
3594 		if (strcmp(pkg_vers, pkgtab.zone_pkg_version) == 0) {
3595 			res = 0;
3596 			break;
3597 		}
3598 
3599 		(void) strlcpy(return_vers, pkgtab.zone_pkg_version, vers_size);
3600 		res = 1;
3601 		break;
3602 	}
3603 
3604 	(void) zonecfg_endpkgent(handle);
3605 	return (res);
3606 }
3607 
3608 /*
3609  * Used in software comparisons to check the packages between the two zone
3610  * handles.  The packages have to match or we print a message telling the
3611  * user what is out of sync.  The src_cmp flag tells us if the first handle
3612  * is the source machine global zone or not.  This is used to enable the
3613  * right messages to be printed and also to enable extra version checking
3614  * that is not needed for the opposite comparison.
3615  */
3616 static int
3617 pkg_check(char *header, zone_dochandle_t handle1, zone_dochandle_t handle2,
3618     boolean_t src_cmp)
3619 {
3620 	int			err;
3621 	int			res = Z_OK;
3622 	boolean_t		do_header = B_TRUE;
3623 	char			other_vers[ZONE_PKG_VERSMAX];
3624 	struct zone_pkgtab	pkgtab;
3625 
3626 	if (zonecfg_setpkgent(handle1) != Z_OK) {
3627 		(void) fprintf(stderr,
3628 		    gettext("unable to enumerate packages\n"));
3629 		return (Z_ERR);
3630 	}
3631 
3632 	while (zonecfg_getpkgent(handle1, &pkgtab) == Z_OK) {
3633 		if ((err = pkg_cmp(handle2, pkgtab.zone_pkg_name,
3634 		    pkgtab.zone_pkg_version, other_vers, sizeof (other_vers)))
3635 		    != 0) {
3636 			if (do_header && (err < 0 || src_cmp)) {
3637 				/* LINTED E_SEC_PRINTF_VAR_FMT */
3638 				(void) fprintf(stderr, header);
3639 				do_header = B_FALSE;
3640 			}
3641 			if (err < 0) {
3642 				(void) fprintf(stderr,
3643 				    (src_cmp == B_TRUE) ?
3644 				    gettext("\t%s: not installed\n\t\t(%s)\n") :
3645 				    gettext("\t%s (%s)\n"),
3646 				    pkgtab.zone_pkg_name,
3647 				    pkgtab.zone_pkg_version);
3648 				res = Z_ERR;
3649 			} else if (src_cmp) {
3650 				(void) fprintf(stderr, gettext(
3651 				    "\t%s: version mismatch\n\t\t(%s)"
3652 				    "\n\t\t(%s)\n"),
3653 				    pkgtab.zone_pkg_name,
3654 				    pkgtab.zone_pkg_version, other_vers);
3655 				res = Z_ERR;
3656 			}
3657 		}
3658 	}
3659 
3660 	(void) zonecfg_endpkgent(handle1);
3661 
3662 	return (res);
3663 }
3664 
3665 /*
3666  * Find the specified patch in the sw inventory on the handle and check
3667  * if the version matches what is passed in.
3668  * Return 0 if the patches match
3669  *        1 if the patches is found but we have a version mismatch
3670  *        -1 if the patches is not found
3671  */
3672 static int
3673 patch_cmp(zone_dochandle_t handle, char *patch_id, char *patch_vers,
3674     char *return_vers, int vers_size)
3675 {
3676 	int			res = -1;
3677 	struct zone_patchtab	patchtab;
3678 
3679 	if (zonecfg_setpatchent(handle) != Z_OK) {
3680 		(void) fprintf(stderr,
3681 		    gettext("unable to enumerate patches\n"));
3682 		return (Z_ERR);
3683 	}
3684 
3685 	while (zonecfg_getpatchent(handle, &patchtab) == Z_OK) {
3686 		char *p;
3687 
3688 		if ((p = strchr(patchtab.zone_patch_id, '-')) != NULL)
3689 			*p++ = '\0';
3690 		else
3691 			p = "";
3692 
3693 		if (strcmp(patch_id, patchtab.zone_patch_id) != 0)
3694 			continue;
3695 
3696 		if (strcmp(patch_vers, p) == 0) {
3697 			res = 0;
3698 			break;
3699 		}
3700 
3701 		(void) strlcpy(return_vers, p, vers_size);
3702 		/*
3703 		 * Keep checking.  This handles the case where multiple
3704 		 * versions of the same patch is installed.
3705 		 */
3706 		res = 1;
3707 	}
3708 
3709 	(void) zonecfg_endpatchent(handle);
3710 	return (res);
3711 }
3712 
3713 /*
3714  * Used in software comparisons to check the patches between the two zone
3715  * handles.  The patches have to match or we print a message telling the
3716  * user what is out of sync.  The src_cmp flag tells us if the first handle
3717  * is the source machine global zone or not.  This is used to enable the
3718  * right messages to be printed and also to enable extra version checking
3719  * that is not needed for the opposite comparison.
3720  */
3721 static int
3722 patch_check(char *header, zone_dochandle_t handle1, zone_dochandle_t handle2,
3723     boolean_t src_cmp)
3724 {
3725 	int			err;
3726 	int			res = Z_OK;
3727 	boolean_t		do_header = B_TRUE;
3728 	char			other_vers[MAXNAMELEN];
3729 	struct zone_patchtab	patchtab;
3730 
3731 	if (zonecfg_setpatchent(handle1) != Z_OK) {
3732 		(void) fprintf(stderr,
3733 		    gettext("unable to enumerate patches\n"));
3734 		return (Z_ERR);
3735 	}
3736 
3737 	while (zonecfg_getpatchent(handle1, &patchtab) == Z_OK) {
3738 		char *patch_vers;
3739 
3740 		if ((patch_vers = strchr(patchtab.zone_patch_id, '-')) != NULL)
3741 			*patch_vers++ = '\0';
3742 		else
3743 			patch_vers = "";
3744 
3745 		if ((err = patch_cmp(handle2, patchtab.zone_patch_id,
3746 		    patch_vers, other_vers, sizeof (other_vers))) != 0) {
3747 			if (do_header && (err < 0 || src_cmp)) {
3748 				/* LINTED E_SEC_PRINTF_VAR_FMT */
3749 				(void) fprintf(stderr, header);
3750 				do_header = B_FALSE;
3751 			}
3752 			if (err < 0) {
3753 				(void) fprintf(stderr,
3754 				    (src_cmp == B_TRUE) ?
3755 				    gettext("\t%s: not installed\n") :
3756 				    gettext("\t%s\n"),
3757 				    patchtab.zone_patch_id);
3758 				res = Z_ERR;
3759 			} else if (src_cmp) {
3760 				(void) fprintf(stderr,
3761 				    gettext("\t%s: version mismatch\n\t\t(%s) "
3762 				    "(%s)\n"), patchtab.zone_patch_id,
3763 				    patch_vers, other_vers);
3764 				res = Z_ERR;
3765 			}
3766 		}
3767 	}
3768 
3769 	(void) zonecfg_endpatchent(handle1);
3770 
3771 	return (res);
3772 }
3773 
3774 /*
3775  * Compare the software on the local global zone and source system global
3776  * zone.  Used when we are trying to attach a zone during migration.
3777  * l_handle is for the local system and s_handle is for the source system.
3778  * These have a snapshot of the appropriate packages and patches in the global
3779  * zone for the two machines.
3780  * The functions called here will print any messages that are needed to
3781  * inform the user about package or patch problems.
3782  */
3783 static int
3784 sw_cmp(zone_dochandle_t l_handle, zone_dochandle_t s_handle)
3785 {
3786 	char		*hdr;
3787 	int		res = Z_OK;
3788 
3789 	/*
3790 	 * Check the source host for pkgs (and versions) that are not on the
3791 	 * local host.
3792 	 */
3793 	hdr = gettext("These packages installed on the source system are "
3794 	    "inconsistent with this system:\n");
3795 	if (pkg_check(hdr, s_handle, l_handle, B_TRUE) != Z_OK)
3796 		res = Z_ERR;
3797 
3798 	/*
3799 	 * Now check the local host for pkgs that were not on the source host.
3800 	 * We already handled version mismatches in the loop above.
3801 	 */
3802 	hdr = gettext("These packages installed on this system were "
3803 	    "not installed on the source system:\n");
3804 	if (pkg_check(hdr, l_handle, s_handle, B_FALSE) != Z_OK)
3805 		res = Z_ERR;
3806 
3807 	/*
3808 	 * Check the source host for patches that are not on the local host.
3809 	 */
3810 	hdr = gettext("These patches installed on the source system are "
3811 	    "inconsistent with this system:\n");
3812 	if (patch_check(hdr, s_handle, l_handle, B_TRUE) != Z_OK)
3813 		res = Z_ERR;
3814 
3815 	/*
3816 	 * Check the local host for patches that were not on the source host.
3817 	 * We already handled version mismatches in the loop above.
3818 	 */
3819 	hdr = gettext("These patches installed on this system were "
3820 	    "not installed on the source system:\n");
3821 	if (patch_check(hdr, l_handle, s_handle, B_FALSE) != Z_OK)
3822 		res = Z_ERR;
3823 
3824 	return (res);
3825 }
3826 
3827 /*
3828  * During attach we go through and fix up the /dev entries for the zone
3829  * we are attaching.  In order to regenerate /dev with the correct devices,
3830  * the old /dev will be removed, the zone readied (which generates a new
3831  * /dev) then halted, then we use the info from the manifest to update
3832  * the modes, owners, etc. on the new /dev.
3833  */
3834 static int
3835 dev_fix(zone_dochandle_t handle)
3836 {
3837 	int			res;
3838 	int			err;
3839 	int			status;
3840 	struct zone_devpermtab	devtab;
3841 	zone_cmd_arg_t		zarg;
3842 	char			devpath[MAXPATHLEN];
3843 				/* 6: "exec " and " " */
3844 	char			cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 6];
3845 
3846 	if ((res = zonecfg_get_zonepath(handle, devpath, sizeof (devpath)))
3847 	    != Z_OK)
3848 		return (res);
3849 
3850 	if (strlcat(devpath, "/dev", sizeof (devpath)) >= sizeof (devpath))
3851 		return (Z_TOO_BIG);
3852 
3853 	/*
3854 	 * "exec" the command so that the returned status is that of
3855 	 * RMCOMMAND and not the shell.
3856 	 */
3857 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
3858 	    devpath);
3859 	status = do_subproc(cmdbuf);
3860 	if ((err = subproc_status(RMCOMMAND, status)) != Z_OK) {
3861 		(void) fprintf(stderr,
3862 		    gettext("could not remove existing /dev\n"));
3863 		return (Z_ERR);
3864 	}
3865 
3866 	/* In order to ready the zone, it must be in the installed state */
3867 	if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
3868 		errno = err;
3869 		zperror(gettext("could not reset state"), B_TRUE);
3870 		return (Z_ERR);
3871 	}
3872 
3873 	/* We have to ready the zone to regen the dev tree */
3874 	zarg.cmd = Z_READY;
3875 	if (call_zoneadmd(target_zone, &zarg) != 0) {
3876 		zerror(gettext("call to %s failed"), "zoneadmd");
3877 		return (Z_ERR);
3878 	}
3879 
3880 	zarg.cmd = Z_HALT;
3881 	if (call_zoneadmd(target_zone, &zarg) != 0) {
3882 		zerror(gettext("call to %s failed"), "zoneadmd");
3883 		return (Z_ERR);
3884 	}
3885 
3886 	if (zonecfg_setdevperment(handle) != Z_OK) {
3887 		(void) fprintf(stderr,
3888 		    gettext("unable to enumerate device entries\n"));
3889 		return (Z_ERR);
3890 	}
3891 
3892 	while (zonecfg_getdevperment(handle, &devtab) == Z_OK) {
3893 		int err;
3894 
3895 		if ((err = zonecfg_devperms_apply(handle,
3896 		    devtab.zone_devperm_name, devtab.zone_devperm_uid,
3897 		    devtab.zone_devperm_gid, devtab.zone_devperm_mode,
3898 		    devtab.zone_devperm_acl)) != Z_OK && err != Z_INVAL)
3899 			(void) fprintf(stderr, gettext("error updating device "
3900 			    "%s: %s\n"), devtab.zone_devperm_name,
3901 			    zonecfg_strerror(err));
3902 
3903 		free(devtab.zone_devperm_acl);
3904 	}
3905 
3906 	(void) zonecfg_enddevperment(handle);
3907 
3908 	return (Z_OK);
3909 }
3910 
3911 static int
3912 attach_func(int argc, char *argv[])
3913 {
3914 	int lockfd;
3915 	int err, arg;
3916 	boolean_t force = B_FALSE;
3917 	zone_dochandle_t handle;
3918 	zone_dochandle_t athandle = NULL;
3919 	char zonepath[MAXPATHLEN];
3920 
3921 	if (zonecfg_in_alt_root()) {
3922 		zerror(gettext("cannot attach zone in alternate root"));
3923 		return (Z_ERR);
3924 	}
3925 
3926 	optind = 0;
3927 	if ((arg = getopt(argc, argv, "?F")) != EOF) {
3928 		switch (arg) {
3929 		case '?':
3930 			sub_usage(SHELP_ATTACH, CMD_ATTACH);
3931 			return (optopt == '?' ? Z_OK : Z_USAGE);
3932 		case 'F':
3933 			force = B_TRUE;
3934 			break;
3935 		default:
3936 			sub_usage(SHELP_ATTACH, CMD_ATTACH);
3937 			return (Z_USAGE);
3938 		}
3939 	}
3940 	if (sanity_check(target_zone, CMD_ATTACH, B_FALSE, B_TRUE) != Z_OK)
3941 		return (Z_ERR);
3942 	if (verify_details(CMD_ATTACH) != Z_OK)
3943 		return (Z_ERR);
3944 
3945 	if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
3946 	    != Z_OK) {
3947 		errno = err;
3948 		zperror2(target_zone, gettext("could not get zone path"));
3949 		return (Z_ERR);
3950 	}
3951 
3952 	if ((handle = zonecfg_init_handle()) == NULL) {
3953 		zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
3954 		return (Z_ERR);
3955 	}
3956 
3957 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3958 		errno = err;
3959 		zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
3960 		zonecfg_fini_handle(handle);
3961 		return (Z_ERR);
3962 	}
3963 
3964 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
3965 		zerror(gettext("another %s may have an operation in progress."),
3966 		    "zoneadm");
3967 		zonecfg_fini_handle(handle);
3968 		return (Z_ERR);
3969 	}
3970 
3971 	if (force)
3972 		goto forced;
3973 
3974 	if ((athandle = zonecfg_init_handle()) == NULL) {
3975 		zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
3976 		goto done;
3977 	}
3978 
3979 	if ((err = zonecfg_get_attach_handle(zonepath, target_zone, B_TRUE,
3980 	    athandle)) != Z_OK) {
3981 		if (err == Z_NO_ZONE)
3982 			zerror(gettext("Not a detached zone"));
3983 		else if (err == Z_INVALID_DOCUMENT)
3984 			zerror(gettext("Cannot attach to an earlier release "
3985 			    "of the operating system"));
3986 		else
3987 			zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
3988 		goto done;
3989 	}
3990 
3991 	/* Get the detach information for the locally defined zone. */
3992 	if ((err = zonecfg_get_detach_info(handle, B_FALSE)) != Z_OK) {
3993 		errno = err;
3994 		zperror(gettext("getting the attach information failed"),
3995 		    B_TRUE);
3996 		goto done;
3997 	}
3998 
3999 	/* sw_cmp prints error msgs as necessary */
4000 	if ((err = sw_cmp(handle, athandle)) != Z_OK)
4001 		goto done;
4002 
4003 	if ((err = dev_fix(athandle)) != Z_OK)
4004 		goto done;
4005 
4006 forced:
4007 
4008 	zonecfg_rm_detached(handle, force);
4009 
4010 	if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
4011 		errno = err;
4012 		zperror(gettext("could not reset state"), B_TRUE);
4013 	}
4014 
4015 done:
4016 	zonecfg_fini_handle(handle);
4017 	release_lock_file(lockfd);
4018 	if (athandle != NULL)
4019 		zonecfg_fini_handle(athandle);
4020 
4021 	return ((err == Z_OK) ? Z_OK : Z_ERR);
4022 }
4023 
4024 /*
4025  * On input, TRUE => yes, FALSE => no.
4026  * On return, TRUE => 1, FALSE => 0, could not ask => -1.
4027  */
4028 
4029 static int
4030 ask_yesno(boolean_t default_answer, const char *question)
4031 {
4032 	char line[64];	/* should be large enough to answer yes or no */
4033 
4034 	if (!isatty(STDIN_FILENO))
4035 		return (-1);
4036 	for (;;) {
4037 		(void) printf("%s (%s)? ", question,
4038 		    default_answer ? "[y]/n" : "y/[n]");
4039 		if (fgets(line, sizeof (line), stdin) == NULL ||
4040 		    line[0] == '\n')
4041 			return (default_answer ? 1 : 0);
4042 		if (tolower(line[0]) == 'y')
4043 			return (1);
4044 		if (tolower(line[0]) == 'n')
4045 			return (0);
4046 	}
4047 }
4048 
4049 static int
4050 uninstall_func(int argc, char *argv[])
4051 {
4052 	/* 6: "exec " and " " */
4053 	char cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 6];
4054 	char line[ZONENAME_MAX + 128];	/* Enough for "Are you sure ..." */
4055 	char rootpath[MAXPATHLEN], devpath[MAXPATHLEN];
4056 	boolean_t force = B_FALSE;
4057 	int lockfd, answer;
4058 	int err, arg;
4059 	int status;
4060 
4061 	if (zonecfg_in_alt_root()) {
4062 		zerror(gettext("cannot uninstall zone in alternate root"));
4063 		return (Z_ERR);
4064 	}
4065 
4066 	optind = 0;
4067 	while ((arg = getopt(argc, argv, "?F")) != EOF) {
4068 		switch (arg) {
4069 		case '?':
4070 			sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
4071 			return (optopt == '?' ? Z_OK : Z_USAGE);
4072 		case 'F':
4073 			force = B_TRUE;
4074 			break;
4075 		default:
4076 			sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
4077 			return (Z_USAGE);
4078 		}
4079 	}
4080 	if (argc > optind) {
4081 		sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
4082 		return (Z_USAGE);
4083 	}
4084 
4085 	if (sanity_check(target_zone, CMD_UNINSTALL, B_FALSE, B_TRUE) != Z_OK)
4086 		return (Z_ERR);
4087 
4088 	if (!force) {
4089 		(void) snprintf(line, sizeof (line),
4090 		    gettext("Are you sure you want to %s zone %s"),
4091 		    cmd_to_str(CMD_UNINSTALL), target_zone);
4092 		if ((answer = ask_yesno(B_FALSE, line)) == 0) {
4093 			return (Z_OK);
4094 		} else if (answer == -1) {
4095 			zerror(gettext("Input not from terminal and -F "
4096 			    "not specified: %s not done."),
4097 			    cmd_to_str(CMD_UNINSTALL));
4098 			return (Z_ERR);
4099 		}
4100 	}
4101 
4102 	if ((err = zone_get_zonepath(target_zone, devpath,
4103 	    sizeof (devpath))) != Z_OK) {
4104 		errno = err;
4105 		zperror2(target_zone, gettext("could not get zone path"));
4106 		return (Z_ERR);
4107 	}
4108 	(void) strlcat(devpath, "/dev", sizeof (devpath));
4109 	if ((err = zone_get_rootpath(target_zone, rootpath,
4110 	    sizeof (rootpath))) != Z_OK) {
4111 		errno = err;
4112 		zperror2(target_zone, gettext("could not get root path"));
4113 		return (Z_ERR);
4114 	}
4115 
4116 	/*
4117 	 * If there seems to be a zoneadmd running for this zone, call it
4118 	 * to tell it that an uninstall is happening; if all goes well it
4119 	 * will then shut itself down.
4120 	 */
4121 	if (ping_zoneadmd(target_zone) == Z_OK) {
4122 		zone_cmd_arg_t zarg;
4123 		zarg.cmd = Z_NOTE_UNINSTALLING;
4124 		/* we don't care too much if this fails... just plow on */
4125 		(void) call_zoneadmd(target_zone, &zarg);
4126 	}
4127 
4128 	if (grab_lock_file(target_zone, &lockfd) != Z_OK) {
4129 		zerror(gettext("another %s may have an operation in progress."),
4130 		    "zoneadm");
4131 		return (Z_ERR);
4132 	}
4133 
4134 	/* Don't uninstall the zone if anything is mounted there */
4135 	err = zonecfg_find_mounts(rootpath, NULL, NULL);
4136 	if (err) {
4137 		zerror(gettext("These file-systems are mounted on "
4138 		    "subdirectories of %s.\n"), rootpath);
4139 		(void) zonecfg_find_mounts(rootpath, zfm_print, NULL);
4140 		return (Z_ERR);
4141 	}
4142 
4143 	err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
4144 	if (err != Z_OK) {
4145 		errno = err;
4146 		zperror2(target_zone, gettext("could not set state"));
4147 		goto bad;
4148 	}
4149 
4150 	/*
4151 	 * "exec" the command so that the returned status is that of
4152 	 * RMCOMMAND and not the shell.
4153 	 */
4154 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
4155 	    devpath);
4156 	status = do_subproc(cmdbuf);
4157 	if ((err = subproc_status(RMCOMMAND, status)) != Z_OK)
4158 		goto bad;
4159 	(void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
4160 	    rootpath);
4161 	status = do_subproc(cmdbuf);
4162 	if ((err = subproc_status(RMCOMMAND, status)) != Z_OK)
4163 		goto bad;
4164 	err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED);
4165 	if (err != Z_OK) {
4166 		errno = err;
4167 		zperror2(target_zone, gettext("could not reset state"));
4168 	}
4169 bad:
4170 	release_lock_file(lockfd);
4171 	return (err);
4172 }
4173 
4174 /* ARGSUSED */
4175 static int
4176 mount_func(int argc, char *argv[])
4177 {
4178 	zone_cmd_arg_t zarg;
4179 
4180 	if (argc > 0)
4181 		return (Z_USAGE);
4182 	if (sanity_check(target_zone, CMD_MOUNT, B_FALSE, B_FALSE) != Z_OK)
4183 		return (Z_ERR);
4184 	if (verify_details(CMD_MOUNT) != Z_OK)
4185 		return (Z_ERR);
4186 
4187 	zarg.cmd = Z_MOUNT;
4188 	if (call_zoneadmd(target_zone, &zarg) != 0) {
4189 		zerror(gettext("call to %s failed"), "zoneadmd");
4190 		return (Z_ERR);
4191 	}
4192 	return (Z_OK);
4193 }
4194 
4195 /* ARGSUSED */
4196 static int
4197 unmount_func(int argc, char *argv[])
4198 {
4199 	zone_cmd_arg_t zarg;
4200 
4201 	if (argc > 0)
4202 		return (Z_USAGE);
4203 	if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE) != Z_OK)
4204 		return (Z_ERR);
4205 
4206 	zarg.cmd = Z_UNMOUNT;
4207 	if (call_zoneadmd(target_zone, &zarg) != 0) {
4208 		zerror(gettext("call to %s failed"), "zoneadmd");
4209 		return (Z_ERR);
4210 	}
4211 	return (Z_OK);
4212 }
4213 
4214 static int
4215 help_func(int argc, char *argv[])
4216 {
4217 	int arg, cmd_num;
4218 
4219 	if (argc == 0) {
4220 		(void) usage(B_TRUE);
4221 		return (Z_OK);
4222 	}
4223 	optind = 0;
4224 	if ((arg = getopt(argc, argv, "?")) != EOF) {
4225 		switch (arg) {
4226 		case '?':
4227 			sub_usage(SHELP_HELP, CMD_HELP);
4228 			return (optopt == '?' ? Z_OK : Z_USAGE);
4229 		default:
4230 			sub_usage(SHELP_HELP, CMD_HELP);
4231 			return (Z_USAGE);
4232 		}
4233 	}
4234 	while (optind < argc) {
4235 		/* Private commands have NULL short_usage; omit them */
4236 		if ((cmd_num = cmd_match(argv[optind])) < 0 ||
4237 		    cmdtab[cmd_num].short_usage == NULL) {
4238 			sub_usage(SHELP_HELP, CMD_HELP);
4239 			return (Z_USAGE);
4240 		}
4241 		sub_usage(cmdtab[cmd_num].short_usage, cmd_num);
4242 		optind++;
4243 	}
4244 	return (Z_OK);
4245 }
4246 
4247 /*
4248  * Returns: CMD_MIN thru CMD_MAX on success, -1 on error
4249  */
4250 
4251 static int
4252 cmd_match(char *cmd)
4253 {
4254 	int i;
4255 
4256 	for (i = CMD_MIN; i <= CMD_MAX; i++) {
4257 		/* return only if there is an exact match */
4258 		if (strcmp(cmd, cmdtab[i].cmd_name) == 0)
4259 			return (cmdtab[i].cmd_num);
4260 	}
4261 	return (-1);
4262 }
4263 
4264 static int
4265 parse_and_run(int argc, char *argv[])
4266 {
4267 	int i = cmd_match(argv[0]);
4268 
4269 	if (i < 0)
4270 		return (usage(B_FALSE));
4271 	return (cmdtab[i].handler(argc - 1, &(argv[1])));
4272 }
4273 
4274 static char *
4275 get_execbasename(char *execfullname)
4276 {
4277 	char *last_slash, *execbasename;
4278 
4279 	/* guard against '/' at end of command invocation */
4280 	for (;;) {
4281 		last_slash = strrchr(execfullname, '/');
4282 		if (last_slash == NULL) {
4283 			execbasename = execfullname;
4284 			break;
4285 		} else {
4286 			execbasename = last_slash + 1;
4287 			if (*execbasename == '\0') {
4288 				*last_slash = '\0';
4289 				continue;
4290 			}
4291 			break;
4292 		}
4293 	}
4294 	return (execbasename);
4295 }
4296 
4297 int
4298 main(int argc, char **argv)
4299 {
4300 	int arg;
4301 	zoneid_t zid;
4302 	struct stat st;
4303 
4304 	if ((locale = setlocale(LC_ALL, "")) == NULL)
4305 		locale = "C";
4306 	(void) textdomain(TEXT_DOMAIN);
4307 	setbuf(stdout, NULL);
4308 	(void) sigset(SIGHUP, SIG_IGN);
4309 	execname = get_execbasename(argv[0]);
4310 	target_zone = NULL;
4311 	if (chdir("/") != 0) {
4312 		zerror(gettext("could not change directory to /."));
4313 		exit(Z_ERR);
4314 	}
4315 
4316 	while ((arg = getopt(argc, argv, "?z:R:")) != EOF) {
4317 		switch (arg) {
4318 		case '?':
4319 			return (usage(B_TRUE));
4320 		case 'z':
4321 			target_zone = optarg;
4322 			break;
4323 		case 'R':	/* private option for admin/install use */
4324 			if (*optarg != '/') {
4325 				zerror(gettext("root path must be absolute."));
4326 				exit(Z_ERR);
4327 			}
4328 			if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
4329 				zerror(
4330 				    gettext("root path must be a directory."));
4331 				exit(Z_ERR);
4332 			}
4333 			zonecfg_set_root(optarg);
4334 			break;
4335 		default:
4336 			return (usage(B_FALSE));
4337 		}
4338 	}
4339 
4340 	if (optind >= argc)
4341 		return (usage(B_FALSE));
4342 	if (target_zone != NULL && zone_get_id(target_zone, &zid) != 0) {
4343 		errno = Z_NO_ZONE;
4344 		zperror(target_zone, B_TRUE);
4345 		exit(Z_ERR);
4346 	}
4347 	return (parse_and_run(argc - optind, &argv[optind]));
4348 }
4349