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