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