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