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