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