xref: /titanic_50/usr/src/cmd/zonecfg/zonecfg.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * zonecfg is a lex/yacc based command interpreter used to manage zone
28  * configurations.  The lexer (see zonecfg_lex.l) builds up tokens, which
29  * the grammar (see zonecfg_grammar.y) builds up into commands, some of
30  * which takes resources and/or properties as arguments.  See the block
31  * comments near the end of zonecfg_grammar.y for how the data structures
32  * which keep track of these resources and properties are built up.
33  *
34  * The resource/property data structures are inserted into a command
35  * structure (see zonecfg.h), which also keeps track of command names,
36  * miscellaneous arguments, and function handlers.  The grammar selects
37  * the appropriate function handler, each of which takes a pointer to a
38  * command structure as its sole argument, and invokes it.  The grammar
39  * itself is "entered" (a la the Matrix) by yyparse(), which is called
40  * from read_input(), our main driving function.  That in turn is called
41  * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
42  * of which is called from main() depending on how the program was invoked.
43  *
44  * The rest of this module consists of the various function handlers and
45  * their helper functions.  Some of these functions, particularly the
46  * X_to_str() functions, which maps command, resource and property numbers
47  * to strings, are used quite liberally, as doing so results in a better
48  * program w/rt I18N, reducing the need for translation notes.
49  */
50 
51 #include <sys/mntent.h>
52 #include <sys/varargs.h>
53 #include <sys/sysmacros.h>
54 
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <strings.h>
58 #include <unistd.h>
59 #include <ctype.h>
60 #include <stdlib.h>
61 #include <assert.h>
62 #include <sys/stat.h>
63 #include <zone.h>
64 #include <arpa/inet.h>
65 #include <netdb.h>
66 #include <locale.h>
67 #include <libintl.h>
68 #include <alloca.h>
69 #include <signal.h>
70 #include <wait.h>
71 #include <libtecla.h>
72 #include <libzfs.h>
73 #include <sys/brand.h>
74 #include <libbrand.h>
75 #include <sys/systeminfo.h>
76 #include <libdladm.h>
77 #include <libinetutil.h>
78 #include <pwd.h>
79 
80 #include <libzonecfg.h>
81 #include "zonecfg.h"
82 
83 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
84 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
85 #endif
86 
87 #define	PAGER	"/usr/bin/more"
88 #define	EXEC_PREFIX	"exec "
89 #define	EXEC_LEN	(strlen(EXEC_PREFIX))
90 
91 struct help {
92 	uint_t	cmd_num;
93 	char	*cmd_name;
94 	uint_t	flags;
95 	char	*short_usage;
96 };
97 
98 extern int yyparse(void);
99 extern int lex_lineno;
100 
101 #define	MAX_LINE_LEN	1024
102 #define	MAX_CMD_HIST	1024
103 #define	MAX_CMD_LEN	1024
104 
105 #define	ONE_MB		1048576
106 
107 /*
108  * Each SHELP_ should be a simple string.
109  */
110 
111 #define	SHELP_ADD	"add <resource-type>\n\t(global scope)\n" \
112 	"add <property-name> <property-value>\n\t(resource scope)"
113 #define	SHELP_CANCEL	"cancel"
114 #define	SHELP_CLEAR	"clear <property-name>"
115 #define	SHELP_COMMIT	"commit"
116 #define	SHELP_CREATE	"create [-F] [ -a <path> | -b | -t <template> ]"
117 #define	SHELP_DELETE	"delete [-F]"
118 #define	SHELP_END	"end"
119 #define	SHELP_EXIT	"exit [-F]"
120 #define	SHELP_EXPORT	"export [-f output-file]"
121 #define	SHELP_HELP	"help [commands] [syntax] [usage] [<command-name>]"
122 #define	SHELP_INFO	"info [<resource-type> [property-name=property-value]*]"
123 #define	SHELP_REMOVE	"remove [-F] <resource-type> " \
124 	"[ <property-name>=<property-value> ]*\n" \
125 	"\t(global scope)\n" \
126 	"remove <property-name> <property-value>\n" \
127 	"\t(resource scope)"
128 #define	SHELP_REVERT	"revert [-F]"
129 #define	SHELP_SELECT	"select <resource-type> { <property-name>=" \
130 	"<property-value> }"
131 #define	SHELP_SET	"set <property-name>=<property-value>"
132 #define	SHELP_VERIFY	"verify"
133 
134 static struct help helptab[] = {
135 	{ CMD_ADD,	"add",		HELP_RES_PROPS,	SHELP_ADD, },
136 	{ CMD_CANCEL,	"cancel",	0,		SHELP_CANCEL, },
137 	{ CMD_CLEAR,	"clear",	HELP_PROPS,	SHELP_CLEAR, },
138 	{ CMD_COMMIT,	"commit",	0,		SHELP_COMMIT, },
139 	{ CMD_CREATE,	"create",	0,		SHELP_CREATE, },
140 	{ CMD_DELETE,	"delete",	0,		SHELP_DELETE, },
141 	{ CMD_END,	"end",		0,		SHELP_END, },
142 	{ CMD_EXIT,	"exit",		0,		SHELP_EXIT, },
143 	{ CMD_EXPORT,	"export",	0,		SHELP_EXPORT, },
144 	{ CMD_HELP,	"help",		0,		SHELP_HELP },
145 	{ CMD_INFO,	"info",		HELP_RES_PROPS,	SHELP_INFO, },
146 	{ CMD_REMOVE,	"remove",	HELP_RES_PROPS,	SHELP_REMOVE, },
147 	{ CMD_REVERT,	"revert",	0,		SHELP_REVERT, },
148 	{ CMD_SELECT,	"select",	HELP_RES_PROPS,	SHELP_SELECT, },
149 	{ CMD_SET,	"set",		HELP_PROPS,	SHELP_SET, },
150 	{ CMD_VERIFY,	"verify",	0,		SHELP_VERIFY, },
151 	{ 0 },
152 };
153 
154 #define	MAX_RT_STRLEN	16
155 
156 /* These *must* match the order of the RT_ define's from zonecfg.h */
157 char *res_types[] = {
158 	"unknown",
159 	"zonename",
160 	"zonepath",
161 	"autoboot",
162 	"pool",
163 	"fs",
164 	"inherit-pkg-dir",
165 	"net",
166 	"device",
167 	"rctl",
168 	"attr",
169 	"dataset",
170 	"limitpriv",
171 	"bootargs",
172 	"brand",
173 	"dedicated-cpu",
174 	"capped-memory",
175 	ALIAS_MAXLWPS,
176 	ALIAS_MAXSHMMEM,
177 	ALIAS_MAXSHMIDS,
178 	ALIAS_MAXMSGIDS,
179 	ALIAS_MAXSEMIDS,
180 	ALIAS_SHARES,
181 	"scheduling-class",
182 	"ip-type",
183 	"capped-cpu",
184 	"hostid",
185 	"admin",
186 	"fs-allowed",
187 	NULL
188 };
189 
190 /* These *must* match the order of the PT_ define's from zonecfg.h */
191 char *prop_types[] = {
192 	"unknown",
193 	"zonename",
194 	"zonepath",
195 	"autoboot",
196 	"pool",
197 	"dir",
198 	"special",
199 	"type",
200 	"options",
201 	"address",
202 	"physical",
203 	"name",
204 	"value",
205 	"match",
206 	"priv",
207 	"limit",
208 	"action",
209 	"raw",
210 	"limitpriv",
211 	"bootargs",
212 	"brand",
213 	"ncpus",
214 	"importance",
215 	"swap",
216 	"locked",
217 	ALIAS_SHARES,
218 	ALIAS_MAXLWPS,
219 	ALIAS_MAXSHMMEM,
220 	ALIAS_MAXSHMIDS,
221 	ALIAS_MAXMSGIDS,
222 	ALIAS_MAXSEMIDS,
223 	ALIAS_MAXLOCKEDMEM,
224 	ALIAS_MAXSWAP,
225 	"scheduling-class",
226 	"ip-type",
227 	"defrouter",
228 	"hostid",
229 	"user",
230 	"auths",
231 	"fs-allowed",
232 	NULL
233 };
234 
235 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
236 static char *prop_val_types[] = {
237 	"simple",
238 	"complex",
239 	"list",
240 };
241 
242 /*
243  * The various _cmds[] lists below are for command tab-completion.
244  */
245 
246 /*
247  * remove has a space afterwards because it has qualifiers; the other commands
248  * that have qualifiers (add, select, etc.) don't need a space here because
249  * they have their own _cmds[] lists below.
250  */
251 static const char *global_scope_cmds[] = {
252 	"add",
253 	"clear",
254 	"commit",
255 	"create",
256 	"delete",
257 	"exit",
258 	"export",
259 	"help",
260 	"info",
261 	"remove ",
262 	"revert",
263 	"select",
264 	"set",
265 	"verify",
266 	NULL
267 };
268 
269 static const char *add_cmds[] = {
270 	"add fs",
271 	"add inherit-pkg-dir",
272 	"add net",
273 	"add device",
274 	"add rctl",
275 	"add attr",
276 	"add dataset",
277 	"add dedicated-cpu",
278 	"add capped-cpu",
279 	"add capped-memory",
280 	"add admin",
281 	NULL
282 };
283 
284 static const char *clear_cmds[] = {
285 	"clear autoboot",
286 	"clear pool",
287 	"clear limitpriv",
288 	"clear bootargs",
289 	"clear scheduling-class",
290 	"clear ip-type",
291 	"clear " ALIAS_MAXLWPS,
292 	"clear " ALIAS_MAXSHMMEM,
293 	"clear " ALIAS_MAXSHMIDS,
294 	"clear " ALIAS_MAXMSGIDS,
295 	"clear " ALIAS_MAXSEMIDS,
296 	"clear " ALIAS_SHARES,
297 	NULL
298 };
299 
300 static const char *remove_cmds[] = {
301 	"remove fs ",
302 	"remove inherit-pkg-dir ",
303 	"remove net ",
304 	"remove device ",
305 	"remove rctl ",
306 	"remove attr ",
307 	"remove dataset ",
308 	"remove dedicated-cpu ",
309 	"remove capped-cpu ",
310 	"remove capped-memory ",
311 	"remove admin ",
312 	NULL
313 };
314 
315 static const char *select_cmds[] = {
316 	"select fs ",
317 	"select inherit-pkg-dir ",
318 	"select net ",
319 	"select device ",
320 	"select rctl ",
321 	"select attr ",
322 	"select dataset ",
323 	"select dedicated-cpu",
324 	"select capped-cpu",
325 	"select capped-memory",
326 	"select admin",
327 	NULL
328 };
329 
330 static const char *set_cmds[] = {
331 	"set zonename=",
332 	"set zonepath=",
333 	"set brand=",
334 	"set autoboot=",
335 	"set pool=",
336 	"set limitpriv=",
337 	"set bootargs=",
338 	"set scheduling-class=",
339 	"set ip-type=",
340 	"set " ALIAS_MAXLWPS "=",
341 	"set " ALIAS_MAXSHMMEM "=",
342 	"set " ALIAS_MAXSHMIDS "=",
343 	"set " ALIAS_MAXMSGIDS "=",
344 	"set " ALIAS_MAXSEMIDS "=",
345 	"set " ALIAS_SHARES "=",
346 	"set hostid=",
347 	"set fs-allowed=",
348 	NULL
349 };
350 
351 static const char *info_cmds[] = {
352 	"info fs ",
353 	"info inherit-pkg-dir ",
354 	"info net ",
355 	"info device ",
356 	"info rctl ",
357 	"info attr ",
358 	"info dataset ",
359 	"info capped-memory",
360 	"info dedicated-cpu",
361 	"info capped-cpu",
362 	"info zonename",
363 	"info zonepath",
364 	"info autoboot",
365 	"info pool",
366 	"info limitpriv",
367 	"info bootargs",
368 	"info brand",
369 	"info scheduling-class",
370 	"info ip-type",
371 	"info max-lwps",
372 	"info max-shm-memory",
373 	"info max-shm-ids",
374 	"info max-msg-ids",
375 	"info max-sem-ids",
376 	"info cpu-shares",
377 	"info hostid",
378 	"info admin",
379 	"info fs-allowed",
380 	NULL
381 };
382 
383 static const char *fs_res_scope_cmds[] = {
384 	"add options ",
385 	"cancel",
386 	"end",
387 	"exit",
388 	"help",
389 	"info",
390 	"remove options ",
391 	"set dir=",
392 	"set raw=",
393 	"set special=",
394 	"set type=",
395 	"clear raw",
396 	NULL
397 };
398 
399 static const char *net_res_scope_cmds[] = {
400 	"cancel",
401 	"end",
402 	"exit",
403 	"help",
404 	"info",
405 	"set address=",
406 	"set physical=",
407 	"set defrouter=",
408 	NULL
409 };
410 
411 static const char *ipd_res_scope_cmds[] = {
412 	"cancel",
413 	"end",
414 	"exit",
415 	"help",
416 	"info",
417 	"set dir=",
418 	NULL
419 };
420 
421 static const char *device_res_scope_cmds[] = {
422 	"cancel",
423 	"end",
424 	"exit",
425 	"help",
426 	"info",
427 	"set match=",
428 	NULL
429 };
430 
431 static const char *attr_res_scope_cmds[] = {
432 	"cancel",
433 	"end",
434 	"exit",
435 	"help",
436 	"info",
437 	"set name=",
438 	"set type=",
439 	"set value=",
440 	NULL
441 };
442 
443 static const char *rctl_res_scope_cmds[] = {
444 	"add value ",
445 	"cancel",
446 	"end",
447 	"exit",
448 	"help",
449 	"info",
450 	"remove value ",
451 	"set name=",
452 	NULL
453 };
454 
455 static const char *dataset_res_scope_cmds[] = {
456 	"cancel",
457 	"end",
458 	"exit",
459 	"help",
460 	"info",
461 	"set name=",
462 	NULL
463 };
464 
465 static const char *pset_res_scope_cmds[] = {
466 	"cancel",
467 	"end",
468 	"exit",
469 	"help",
470 	"info",
471 	"set ncpus=",
472 	"set importance=",
473 	"clear importance",
474 	NULL
475 };
476 
477 static const char *pcap_res_scope_cmds[] = {
478 	"cancel",
479 	"end",
480 	"exit",
481 	"help",
482 	"info",
483 	"set ncpus=",
484 	NULL
485 };
486 
487 static const char *mcap_res_scope_cmds[] = {
488 	"cancel",
489 	"end",
490 	"exit",
491 	"help",
492 	"info",
493 	"set physical=",
494 	"set swap=",
495 	"set locked=",
496 	"clear physical",
497 	"clear swap",
498 	"clear locked",
499 	NULL
500 };
501 
502 static const char *admin_res_scope_cmds[] = {
503 	"cancel",
504 	"end",
505 	"exit",
506 	"help",
507 	"info",
508 	"set user=",
509 	"set auths=",
510 	NULL
511 };
512 
513 /* Global variables */
514 
515 /* set early in main(), never modified thereafter, used all over the place */
516 static char *execname;
517 
518 /* set in main(), used all over the place */
519 static zone_dochandle_t handle;
520 
521 /* used all over the place */
522 static char zone[ZONENAME_MAX];
523 static char revert_zone[ZONENAME_MAX];
524 
525 /* global brand operations */
526 static brand_handle_t brand;
527 
528 /* set in modifying functions, checked in read_input() */
529 static boolean_t need_to_commit = B_FALSE;
530 boolean_t saw_error;
531 
532 /* set in yacc parser, checked in read_input() */
533 boolean_t newline_terminated;
534 
535 /* set in main(), checked in lex error handler */
536 boolean_t cmd_file_mode;
537 
538 /* set in exit_func(), checked in read_input() */
539 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
540 
541 /* used in short_usage() and zerr() */
542 static char *cmd_file_name = NULL;
543 
544 /* checked in read_input() and other places */
545 static boolean_t ok_to_prompt = B_FALSE;
546 
547 /* set and checked in initialize() */
548 static boolean_t got_handle = B_FALSE;
549 
550 /* initialized in do_interactive(), checked in initialize() */
551 static boolean_t interactive_mode;
552 
553 /* set if configuring the global zone */
554 static boolean_t global_zone = B_FALSE;
555 
556 /* set in main(), checked in multiple places */
557 static boolean_t read_only_mode;
558 
559 /* scope is outer/global or inner/resource */
560 static boolean_t global_scope = B_TRUE;
561 static int resource_scope;	/* should be in the RT_ list from zonecfg.h */
562 static int end_op = -1;		/* operation on end is either add or modify */
563 
564 int num_prop_vals;		/* for grammar */
565 
566 /*
567  * These are for keeping track of resources as they are specified as part of
568  * the multi-step process.  They should be initialized by add_resource() or
569  * select_func() and filled in by add_property() or set_func().
570  */
571 static struct zone_fstab	old_fstab, in_progress_fstab;
572 static struct zone_fstab	old_ipdtab, in_progress_ipdtab;
573 static struct zone_nwiftab	old_nwiftab, in_progress_nwiftab;
574 static struct zone_devtab	old_devtab, in_progress_devtab;
575 static struct zone_rctltab	old_rctltab, in_progress_rctltab;
576 static struct zone_attrtab	old_attrtab, in_progress_attrtab;
577 static struct zone_dstab	old_dstab, in_progress_dstab;
578 static struct zone_psettab	old_psettab, in_progress_psettab;
579 static struct zone_mcaptab	old_mcaptab, in_progress_mcaptab;
580 static struct zone_admintab	old_admintab, in_progress_admintab;
581 
582 static GetLine *gl;	/* The gl_get_line() resource object */
583 
584 static void bytes_to_units(char *str, char *buf, int bufsize);
585 
586 /* Functions begin here */
587 
588 static boolean_t
589 initial_match(const char *line1, const char *line2, int word_end)
590 {
591 	if (word_end <= 0)
592 		return (B_TRUE);
593 	return (strncmp(line1, line2, word_end) == 0);
594 }
595 
596 static int
597 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
598     int word_end)
599 {
600 	int i, err;
601 
602 	for (i = 0; list[i] != NULL; i++) {
603 		if (initial_match(line1, list[i], word_end)) {
604 			err = cpl_add_completion(cpl, line1, 0, word_end,
605 			    list[i] + word_end, "", "");
606 			if (err != 0)
607 				return (err);
608 		}
609 	}
610 	return (0);
611 }
612 
613 static
614 /* ARGSUSED */
615 CPL_MATCH_FN(cmd_cpl_fn)
616 {
617 	if (global_scope) {
618 		/*
619 		 * The MAX/MIN tests below are to make sure we have at least
620 		 * enough characters to distinguish from other prefixes (MAX)
621 		 * but only check MIN(what we have, what we're checking).
622 		 */
623 		if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
624 			return (add_stuff(cpl, line, add_cmds, word_end));
625 		if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
626 			return (add_stuff(cpl, line, clear_cmds, word_end));
627 		if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
628 			return (add_stuff(cpl, line, select_cmds, word_end));
629 		if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
630 			return (add_stuff(cpl, line, set_cmds, word_end));
631 		if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
632 			return (add_stuff(cpl, line, remove_cmds, word_end));
633 		if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
634 			return (add_stuff(cpl, line, info_cmds, word_end));
635 		return (add_stuff(cpl, line, global_scope_cmds, word_end));
636 	}
637 	switch (resource_scope) {
638 	case RT_FS:
639 		return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
640 	case RT_IPD:
641 		return (add_stuff(cpl, line, ipd_res_scope_cmds, word_end));
642 	case RT_NET:
643 		return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
644 	case RT_DEVICE:
645 		return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
646 	case RT_RCTL:
647 		return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
648 	case RT_ATTR:
649 		return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
650 	case RT_DATASET:
651 		return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
652 	case RT_DCPU:
653 		return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
654 	case RT_PCAP:
655 		return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
656 	case RT_MCAP:
657 		return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
658 	case RT_ADMIN:
659 		return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
660 	}
661 	return (0);
662 }
663 
664 /*
665  * For the main CMD_func() functions below, several of them call getopt()
666  * then check optind against argc to make sure an extra parameter was not
667  * passed in.  The reason this is not caught in the grammar is that the
668  * grammar just checks for a miscellaneous TOKEN, which is *expected* to
669  * be "-F" (for example), but could be anything.  So (for example) this
670  * check will prevent "create bogus".
671  */
672 
673 cmd_t *
674 alloc_cmd(void)
675 {
676 	return (calloc(1, sizeof (cmd_t)));
677 }
678 
679 void
680 free_cmd(cmd_t *cmd)
681 {
682 	int i;
683 
684 	for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
685 		if (cmd->cmd_property_ptr[i] != NULL) {
686 			property_value_ptr_t pp = cmd->cmd_property_ptr[i];
687 
688 			switch (pp->pv_type) {
689 			case PROP_VAL_SIMPLE:
690 				free(pp->pv_simple);
691 				break;
692 			case PROP_VAL_COMPLEX:
693 				free_complex(pp->pv_complex);
694 				break;
695 			case PROP_VAL_LIST:
696 				free_list(pp->pv_list);
697 				break;
698 			}
699 		}
700 	for (i = 0; i < cmd->cmd_argc; i++)
701 		free(cmd->cmd_argv[i]);
702 	free(cmd);
703 }
704 
705 complex_property_ptr_t
706 alloc_complex(void)
707 {
708 	return (calloc(1, sizeof (complex_property_t)));
709 }
710 
711 void
712 free_complex(complex_property_ptr_t complex)
713 {
714 	if (complex == NULL)
715 		return;
716 	free_complex(complex->cp_next);
717 	if (complex->cp_value != NULL)
718 		free(complex->cp_value);
719 	free(complex);
720 }
721 
722 list_property_ptr_t
723 alloc_list(void)
724 {
725 	return (calloc(1, sizeof (list_property_t)));
726 }
727 
728 void
729 free_list(list_property_ptr_t list)
730 {
731 	if (list == NULL)
732 		return;
733 	if (list->lp_simple != NULL)
734 		free(list->lp_simple);
735 	free_complex(list->lp_complex);
736 	free_list(list->lp_next);
737 	free(list);
738 }
739 
740 void
741 free_outer_list(list_property_ptr_t list)
742 {
743 	if (list == NULL)
744 		return;
745 	free_outer_list(list->lp_next);
746 	free(list);
747 }
748 
749 static struct zone_rctlvaltab *
750 alloc_rctlvaltab(void)
751 {
752 	return (calloc(1, sizeof (struct zone_rctlvaltab)));
753 }
754 
755 static char *
756 rt_to_str(int res_type)
757 {
758 	assert(res_type >= RT_MIN && res_type <= RT_MAX);
759 	return (res_types[res_type]);
760 }
761 
762 static char *
763 pt_to_str(int prop_type)
764 {
765 	assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
766 	return (prop_types[prop_type]);
767 }
768 
769 static char *
770 pvt_to_str(int pv_type)
771 {
772 	assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
773 	return (prop_val_types[pv_type]);
774 }
775 
776 static char *
777 cmd_to_str(int cmd_num)
778 {
779 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
780 	return (helptab[cmd_num].cmd_name);
781 }
782 
783 /* PRINTFLIKE1 */
784 static void
785 zerr(const char *fmt, ...)
786 {
787 	va_list alist;
788 	static int last_lineno;
789 
790 	/* lex_lineno has already been incremented in the lexer; compensate */
791 	if (cmd_file_mode && lex_lineno > last_lineno) {
792 		if (strcmp(cmd_file_name, "-") == 0)
793 			(void) fprintf(stderr, gettext("On line %d:\n"),
794 			    lex_lineno - 1);
795 		else
796 			(void) fprintf(stderr, gettext("On line %d of %s:\n"),
797 			    lex_lineno - 1, cmd_file_name);
798 		last_lineno = lex_lineno;
799 	}
800 	va_start(alist, fmt);
801 	(void) vfprintf(stderr, fmt, alist);
802 	(void) fprintf(stderr, "\n");
803 	va_end(alist);
804 }
805 
806 /*
807  * This is a separate function rather than a set of define's because of the
808  * gettext() wrapping.
809  */
810 
811 /*
812  * TRANSLATION_NOTE
813  * Each string below should have \t follow \n whenever needed; the
814  * initial \t and the terminal \n will be provided by the calling function.
815  */
816 
817 static char *
818 long_help(int cmd_num)
819 {
820 	static char line[1024];	/* arbitrary large amount */
821 
822 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
823 	switch (cmd_num) {
824 		case CMD_HELP:
825 			return (gettext("Prints help message."));
826 		case CMD_CREATE:
827 			(void) snprintf(line, sizeof (line),
828 			    gettext("Creates a configuration for the "
829 			    "specified zone.  %s should be\n\tused to "
830 			    "begin configuring a new zone.  If overwriting an "
831 			    "existing\n\tconfiguration, the -F flag can be "
832 			    "used to force the action.  If\n\t-t template is "
833 			    "given, creates a configuration identical to the\n"
834 			    "\tspecified template, except that the zone name "
835 			    "is changed from\n\ttemplate to zonename.  '%s -a' "
836 			    "creates a configuration from a\n\tdetached "
837 			    "zonepath.  '%s -b' results in a blank "
838 			    "configuration.\n\t'%s' with no arguments applies "
839 			    "the Sun default settings."),
840 			    cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
841 			    cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
842 			return (line);
843 		case CMD_EXIT:
844 			return (gettext("Exits the program.  The -F flag can "
845 			    "be used to force the action."));
846 		case CMD_EXPORT:
847 			return (gettext("Prints configuration to standard "
848 			    "output, or to output-file if\n\tspecified, in "
849 			    "a form suitable for use in a command-file."));
850 		case CMD_ADD:
851 			return (gettext("Add specified resource to "
852 			    "configuration."));
853 		case CMD_DELETE:
854 			return (gettext("Deletes the specified zone.  The -F "
855 			    "flag can be used to force the\n\taction."));
856 		case CMD_REMOVE:
857 			return (gettext("Remove specified resource from "
858 			    "configuration.  The -F flag can be used\n\tto "
859 			    "force the action."));
860 		case CMD_SELECT:
861 			(void) snprintf(line, sizeof (line),
862 			    gettext("Selects a resource to modify.  "
863 			    "Resource modification is completed\n\twith the "
864 			    "command \"%s\".  The property name/value pairs "
865 			    "must uniquely\n\tidentify a resource.  Note that "
866 			    "the curly braces ('{', '}') mean one\n\tor more "
867 			    "of whatever is between them."),
868 			    cmd_to_str(CMD_END));
869 			return (line);
870 		case CMD_SET:
871 			return (gettext("Sets property values."));
872 		case CMD_CLEAR:
873 			return (gettext("Clears property values."));
874 		case CMD_INFO:
875 			return (gettext("Displays information about the "
876 			    "current configuration.  If resource\n\ttype is "
877 			    "specified, displays only information about "
878 			    "resources of\n\tthe relevant type.  If resource "
879 			    "id is specified, displays only\n\tinformation "
880 			    "about that resource."));
881 		case CMD_VERIFY:
882 			return (gettext("Verifies current configuration "
883 			    "for correctness (some resource types\n\thave "
884 			    "required properties)."));
885 		case CMD_COMMIT:
886 			(void) snprintf(line, sizeof (line),
887 			    gettext("Commits current configuration.  "
888 			    "Configuration must be committed to\n\tbe used by "
889 			    "%s.  Until the configuration is committed, "
890 			    "changes \n\tcan be removed with the %s "
891 			    "command.  This operation is\n\tattempted "
892 			    "automatically upon completion of a %s "
893 			    "session."), "zoneadm", cmd_to_str(CMD_REVERT),
894 			    "zonecfg");
895 			return (line);
896 		case CMD_REVERT:
897 			return (gettext("Reverts configuration back to the "
898 			    "last committed state.  The -F flag\n\tcan be "
899 			    "used to force the action."));
900 		case CMD_CANCEL:
901 			return (gettext("Cancels resource/property "
902 			    "specification."));
903 		case CMD_END:
904 			return (gettext("Ends resource/property "
905 			    "specification."));
906 	}
907 	/* NOTREACHED */
908 	return (NULL);
909 }
910 
911 /*
912  * Called with verbose TRUE when help is explicitly requested, FALSE for
913  * unexpected errors.
914  */
915 
916 void
917 usage(boolean_t verbose, uint_t flags)
918 {
919 	FILE *fp = verbose ? stdout : stderr;
920 	FILE *newfp;
921 	boolean_t need_to_close = B_FALSE;
922 	char *pager;
923 	int i;
924 	struct stat statbuf;
925 
926 	/* don't page error output */
927 	if (verbose && interactive_mode) {
928 		if ((pager = getenv("PAGER")) == NULL)
929 			pager = PAGER;
930 
931 		if (stat(pager, &statbuf) == 0) {
932 			if ((newfp = popen(pager, "w")) != NULL) {
933 				need_to_close = B_TRUE;
934 				fp = newfp;
935 			}
936 		} else {
937 			zerr(gettext("PAGER %s does not exist (%s)."),
938 			    pager, strerror(errno));
939 		}
940 	}
941 
942 	if (flags & HELP_META) {
943 		(void) fprintf(fp, gettext("More help is available for the "
944 		    "following:\n"));
945 		(void) fprintf(fp, "\n\tcommands ('%s commands')\n",
946 		    cmd_to_str(CMD_HELP));
947 		(void) fprintf(fp, "\tsyntax ('%s syntax')\n",
948 		    cmd_to_str(CMD_HELP));
949 		(void) fprintf(fp, "\tusage ('%s usage')\n\n",
950 		    cmd_to_str(CMD_HELP));
951 		(void) fprintf(fp, gettext("You may also obtain help on any "
952 		    "command by typing '%s <command-name>.'\n"),
953 		    cmd_to_str(CMD_HELP));
954 	}
955 	if (flags & HELP_RES_SCOPE) {
956 		switch (resource_scope) {
957 		case RT_FS:
958 			(void) fprintf(fp, gettext("The '%s' resource scope is "
959 			    "used to configure a file-system.\n"),
960 			    rt_to_str(resource_scope));
961 			(void) fprintf(fp, gettext("Valid commands:\n"));
962 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
963 			    pt_to_str(PT_DIR), gettext("<path>"));
964 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
965 			    pt_to_str(PT_SPECIAL), gettext("<path>"));
966 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
967 			    pt_to_str(PT_RAW), gettext("<raw-device>"));
968 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
969 			    pt_to_str(PT_TYPE), gettext("<file-system type>"));
970 			(void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
971 			    pt_to_str(PT_OPTIONS),
972 			    gettext("<file-system options>"));
973 			(void) fprintf(fp, "\t%s %s %s\n",
974 			    cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
975 			    gettext("<file-system options>"));
976 			(void) fprintf(fp, gettext("Consult the file-system "
977 			    "specific manual page, such as mount_ufs(1M), "
978 			    "for\ndetails about file-system options.  Note "
979 			    "that any file-system options with an\nembedded "
980 			    "'=' character must be enclosed in double quotes, "
981 			    /*CSTYLED*/
982 			    "such as \"%s=5\".\n"), MNTOPT_RETRY);
983 			break;
984 		case RT_IPD:
985 			(void) fprintf(fp, gettext("The '%s' resource scope is "
986 			    "used to configure a directory\ninherited from the "
987 			    "global zone into a non-global zone in read-only "
988 			    "mode.\n"), rt_to_str(resource_scope));
989 			(void) fprintf(fp, gettext("Valid commands:\n"));
990 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
991 			    pt_to_str(PT_DIR), gettext("<path>"));
992 			break;
993 		case RT_NET:
994 			(void) fprintf(fp, gettext("The '%s' resource scope is "
995 			    "used to configure a network interface.\n"),
996 			    rt_to_str(resource_scope));
997 			(void) fprintf(fp, gettext("Valid commands:\n"));
998 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
999 			    pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
1000 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1001 			    pt_to_str(PT_PHYSICAL), gettext("<interface>"));
1002 			(void) fprintf(fp, gettext("See ifconfig(1M) for "
1003 			    "details of the <interface> string.\n"));
1004 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1005 			    pt_to_str(PT_DEFROUTER), gettext("<IP-address>"));
1006 			(void) fprintf(fp, gettext("%s %s and %s %s are valid "
1007 			    "if the %s property is set to %s, otherwise they "
1008 			    "must not be set.\n"),
1009 			    cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
1010 			    cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
1011 			    pt_to_str(PT_IPTYPE), "shared");
1012 			break;
1013 		case RT_DEVICE:
1014 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1015 			    "used to configure a device node.\n"),
1016 			    rt_to_str(resource_scope));
1017 			(void) fprintf(fp, gettext("Valid commands:\n"));
1018 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1019 			    pt_to_str(PT_MATCH), gettext("<device-path>"));
1020 			break;
1021 		case RT_RCTL:
1022 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1023 			    "used to configure a resource control.\n"),
1024 			    rt_to_str(resource_scope));
1025 			(void) fprintf(fp, gettext("Valid commands:\n"));
1026 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1027 			    pt_to_str(PT_NAME), gettext("<string>"));
1028 			(void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1029 			    cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1030 			    pt_to_str(PT_PRIV), gettext("<priv-value>"),
1031 			    pt_to_str(PT_LIMIT), gettext("<number>"),
1032 			    pt_to_str(PT_ACTION), gettext("<action-value>"));
1033 			(void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1034 			    cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
1035 			    pt_to_str(PT_PRIV), gettext("<priv-value>"),
1036 			    pt_to_str(PT_LIMIT), gettext("<number>"),
1037 			    pt_to_str(PT_ACTION), gettext("<action-value>"));
1038 			(void) fprintf(fp, "%s\n\t%s := privileged\n"
1039 			    "\t%s := none | deny\n", gettext("Where"),
1040 			    gettext("<priv-value>"), gettext("<action-value>"));
1041 			break;
1042 		case RT_ATTR:
1043 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1044 			    "used to configure a generic attribute.\n"),
1045 			    rt_to_str(resource_scope));
1046 			(void) fprintf(fp, gettext("Valid commands:\n"));
1047 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1048 			    pt_to_str(PT_NAME), gettext("<name>"));
1049 			(void) fprintf(fp, "\t%s %s=boolean\n",
1050 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1051 			(void) fprintf(fp, "\t%s %s=true | false\n",
1052 			    cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
1053 			(void) fprintf(fp, gettext("or\n"));
1054 			(void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
1055 			    pt_to_str(PT_TYPE));
1056 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1057 			    pt_to_str(PT_VALUE), gettext("<integer>"));
1058 			(void) fprintf(fp, gettext("or\n"));
1059 			(void) fprintf(fp, "\t%s %s=string\n",
1060 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1061 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1062 			    pt_to_str(PT_VALUE), gettext("<string>"));
1063 			(void) fprintf(fp, gettext("or\n"));
1064 			(void) fprintf(fp, "\t%s %s=uint\n",
1065 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1066 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1067 			    pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
1068 			break;
1069 		case RT_DATASET:
1070 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1071 			    "used to export ZFS datasets.\n"),
1072 			    rt_to_str(resource_scope));
1073 			(void) fprintf(fp, gettext("Valid commands:\n"));
1074 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1075 			    pt_to_str(PT_NAME), gettext("<name>"));
1076 			break;
1077 		case RT_DCPU:
1078 			(void) fprintf(fp, gettext("The '%s' resource scope "
1079 			    "configures the 'pools' facility to dedicate\na "
1080 			    "subset of the system's processors to this zone "
1081 			    "while it is running.\n"),
1082 			    rt_to_str(resource_scope));
1083 			(void) fprintf(fp, gettext("Valid commands:\n"));
1084 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1085 			    pt_to_str(PT_NCPUS),
1086 			    gettext("<unsigned integer | range>"));
1087 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1088 			    pt_to_str(PT_IMPORTANCE),
1089 			    gettext("<unsigned integer>"));
1090 			break;
1091 		case RT_PCAP:
1092 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1093 			    "used to set an upper limit (a cap) on the\n"
1094 			    "percentage of CPU that can be used by this zone.  "
1095 			    "A '%s' value of 1\ncorresponds to one cpu.  The "
1096 			    "value can be set higher than 1, up to the total\n"
1097 			    "number of CPUs on the system.  The value can "
1098 			    "also be less than 1,\nrepresenting a fraction of "
1099 			    "a cpu.\n"),
1100 			    rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
1101 			(void) fprintf(fp, gettext("Valid commands:\n"));
1102 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1103 			    pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
1104 			break;
1105 		case RT_MCAP:
1106 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1107 			    "used to set an upper limit (a cap) on the\n"
1108 			    "amount of physical memory, swap space and locked "
1109 			    "memory that can be used by\nthis zone.\n"),
1110 			    rt_to_str(resource_scope));
1111 			(void) fprintf(fp, gettext("Valid commands:\n"));
1112 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1113 			    pt_to_str(PT_PHYSICAL),
1114 			    gettext("<qualified unsigned decimal>"));
1115 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1116 			    pt_to_str(PT_SWAP),
1117 			    gettext("<qualified unsigned decimal>"));
1118 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1119 			    pt_to_str(PT_LOCKED),
1120 			    gettext("<qualified unsigned decimal>"));
1121 			break;
1122 		case RT_ADMIN:
1123 			(void) fprintf(fp, gettext("The '%s' resource scope is "
1124 			    "used to delegate specific zone management\n"
1125 			    "rights to users and roles. These rights are "
1126 			    "only applicable to this zone.\n"),
1127 			    rt_to_str(resource_scope));
1128 			(void) fprintf(fp, gettext("Valid commands:\n"));
1129 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1130 			    pt_to_str(PT_USER),
1131 			    gettext("<single user or role name>"));
1132 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1133 			    pt_to_str(PT_AUTHS),
1134 			    gettext("<comma separated list>"));
1135 			break;
1136 		}
1137 		(void) fprintf(fp, gettext("And from any resource scope, you "
1138 		    "can:\n"));
1139 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
1140 		    gettext("(to conclude this operation)"));
1141 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
1142 		    gettext("(to cancel this operation)"));
1143 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
1144 		    gettext("(to exit the zonecfg utility)"));
1145 	}
1146 	if (flags & HELP_USAGE) {
1147 		(void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
1148 		    execname, cmd_to_str(CMD_HELP));
1149 		(void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
1150 		    execname, gettext("interactive"));
1151 		(void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
1152 		(void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
1153 		    execname);
1154 	}
1155 	if (flags & HELP_SUBCMDS) {
1156 		(void) fprintf(fp, "%s:\n\n", gettext("Commands"));
1157 		for (i = 0; i <= CMD_MAX; i++) {
1158 			(void) fprintf(fp, "%s\n", helptab[i].short_usage);
1159 			if (verbose)
1160 				(void) fprintf(fp, "\t%s\n\n", long_help(i));
1161 		}
1162 	}
1163 	if (flags & HELP_SYNTAX) {
1164 		if (!verbose)
1165 			(void) fprintf(fp, "\n");
1166 		(void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
1167 		(void) fprintf(fp, gettext("\t(except the reserved words "
1168 		    "'%s' and anything starting with '%s')\n"), "global",
1169 		    "SUNW");
1170 		(void) fprintf(fp,
1171 		    gettext("\tName must be less than %d characters.\n"),
1172 		    ZONENAME_MAX);
1173 		if (verbose)
1174 			(void) fprintf(fp, "\n");
1175 	}
1176 	if (flags & HELP_NETADDR) {
1177 		(void) fprintf(fp, gettext("\n<net-addr> :="));
1178 		(void) fprintf(fp,
1179 		    gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
1180 		(void) fprintf(fp,
1181 		    gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
1182 		(void) fprintf(fp,
1183 		    gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
1184 		(void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
1185 		    "IPv6 address syntax.\n"));
1186 		(void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
1187 		(void) fprintf(fp,
1188 		    gettext("<IPv6-prefix-length> := [0-128]\n"));
1189 		(void) fprintf(fp,
1190 		    gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
1191 	}
1192 	if (flags & HELP_RESOURCES) {
1193 		(void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t"
1194 		    "%s | %s | %s | %s | %s\n\n",
1195 		    gettext("resource type"), rt_to_str(RT_FS),
1196 		    rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
1197 		    rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
1198 		    rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
1199 		    rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
1200 		    rt_to_str(RT_ADMIN));
1201 	}
1202 	if (flags & HELP_PROPS) {
1203 		(void) fprintf(fp, gettext("For resource type ... there are "
1204 		    "property types ...:\n"));
1205 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1206 		    pt_to_str(PT_ZONENAME));
1207 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1208 		    pt_to_str(PT_ZONEPATH));
1209 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1210 		    pt_to_str(PT_BRAND));
1211 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1212 		    pt_to_str(PT_AUTOBOOT));
1213 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1214 		    pt_to_str(PT_BOOTARGS));
1215 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1216 		    pt_to_str(PT_POOL));
1217 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1218 		    pt_to_str(PT_LIMITPRIV));
1219 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1220 		    pt_to_str(PT_SCHED));
1221 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1222 		    pt_to_str(PT_IPTYPE));
1223 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1224 		    pt_to_str(PT_HOSTID));
1225 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1226 		    pt_to_str(PT_FS_ALLOWED));
1227 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1228 		    pt_to_str(PT_MAXLWPS));
1229 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1230 		    pt_to_str(PT_MAXSHMMEM));
1231 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1232 		    pt_to_str(PT_MAXSHMIDS));
1233 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1234 		    pt_to_str(PT_MAXMSGIDS));
1235 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1236 		    pt_to_str(PT_MAXSEMIDS));
1237 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1238 		    pt_to_str(PT_SHARES));
1239 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
1240 		    rt_to_str(RT_FS), pt_to_str(PT_DIR),
1241 		    pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
1242 		    pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
1243 		(void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_IPD),
1244 		    pt_to_str(PT_DIR));
1245 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_NET),
1246 		    pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL),
1247 		    pt_to_str(PT_DEFROUTER));
1248 		(void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1249 		    pt_to_str(PT_MATCH));
1250 		(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1251 		    pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1252 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1253 		    pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1254 		    pt_to_str(PT_VALUE));
1255 		(void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1256 		    pt_to_str(PT_NAME));
1257 		(void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1258 		    pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1259 		(void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1260 		    pt_to_str(PT_NCPUS));
1261 		(void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1262 		    pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1263 		    pt_to_str(PT_LOCKED));
1264 		(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1265 		    pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1266 	}
1267 	if (need_to_close)
1268 		(void) pclose(fp);
1269 }
1270 
1271 static void
1272 zone_perror(char *prefix, int err, boolean_t set_saw)
1273 {
1274 	zerr("%s: %s", prefix, zonecfg_strerror(err));
1275 	if (set_saw)
1276 		saw_error = B_TRUE;
1277 }
1278 
1279 /*
1280  * zone_perror() expects a single string, but for remove and select
1281  * we have both the command and the resource type, so this wrapper
1282  * function serves the same purpose in a slightly different way.
1283  */
1284 
1285 static void
1286 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1287 {
1288 	zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
1289 	    zonecfg_strerror(err));
1290 	if (set_saw)
1291 		saw_error = B_TRUE;
1292 }
1293 
1294 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
1295 static int
1296 initialize(boolean_t handle_expected)
1297 {
1298 	int err;
1299 	char brandname[MAXNAMELEN];
1300 
1301 	if (zonecfg_check_handle(handle) != Z_OK) {
1302 		if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
1303 			got_handle = B_TRUE;
1304 			if (zonecfg_get_brand(handle, brandname,
1305 			    sizeof (brandname)) != Z_OK) {
1306 				zerr("Zone %s is inconsistent: missing "
1307 				    "brand attribute", zone);
1308 				exit(Z_ERR);
1309 			}
1310 			if ((brand = brand_open(brandname)) == NULL) {
1311 				zerr("Zone %s uses non-existent brand \"%s\"."
1312 				    "  Unable to continue", zone, brandname);
1313 				exit(Z_ERR);
1314 			}
1315 			/*
1316 			 * If the user_attr file is newer than
1317 			 * the zone config file, the admins
1318 			 * may need to be updated since the
1319 			 * RBAC files are authoritative for
1320 			 * authorization checks.
1321 			 */
1322 			err = zonecfg_update_userauths(handle, zone);
1323 			if (err == Z_OK) {
1324 				zerr(gettext("The administrative rights "
1325 				    "were updated to match "
1326 				    "the current RBAC configuration.\n"
1327 				    "Use \"info admin\" and \"revert\" to "
1328 				    "compare with the previous settings."));
1329 				need_to_commit = B_TRUE;
1330 			} else if (err != Z_NO_ENTRY) {
1331 				zerr(gettext("failed to update "
1332 				    "admin  rights."));
1333 				exit(Z_ERR);
1334 			} else if (need_to_commit) {
1335 				zerr(gettext("admin rights were updated "
1336 				    "to match RBAC configuration."));
1337 			}
1338 
1339 		} else if (global_zone && err == Z_NO_ZONE && !got_handle &&
1340 		    !read_only_mode) {
1341 			/*
1342 			 * We implicitly create the global zone config if it
1343 			 * doesn't exist.
1344 			 */
1345 			zone_dochandle_t tmphandle;
1346 
1347 			if ((tmphandle = zonecfg_init_handle()) == NULL) {
1348 				zone_perror(execname, Z_NOMEM, B_TRUE);
1349 				exit(Z_ERR);
1350 			}
1351 
1352 			err = zonecfg_get_template_handle("SUNWblank", zone,
1353 			    tmphandle);
1354 
1355 			if (err != Z_OK) {
1356 				zonecfg_fini_handle(tmphandle);
1357 				zone_perror("SUNWblank", err, B_TRUE);
1358 				return (err);
1359 			}
1360 
1361 			need_to_commit = B_TRUE;
1362 			zonecfg_fini_handle(handle);
1363 			handle = tmphandle;
1364 			got_handle = B_TRUE;
1365 
1366 		} else {
1367 			zone_perror(zone, err, handle_expected || got_handle);
1368 			if (err == Z_NO_ZONE && !got_handle &&
1369 			    interactive_mode && !read_only_mode)
1370 				(void) printf(gettext("Use '%s' to begin "
1371 				    "configuring a new zone.\n"),
1372 				    cmd_to_str(CMD_CREATE));
1373 			return (err);
1374 		}
1375 	}
1376 	return (Z_OK);
1377 }
1378 
1379 static boolean_t
1380 state_atleast(zone_state_t state)
1381 {
1382 	zone_state_t state_num;
1383 	int err;
1384 
1385 	if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
1386 		/* all states are greater than "non-existent" */
1387 		if (err == Z_NO_ZONE)
1388 			return (B_FALSE);
1389 		zerr(gettext("Unexpectedly failed to determine state "
1390 		    "of zone %s: %s"), zone, zonecfg_strerror(err));
1391 		exit(Z_ERR);
1392 	}
1393 	return (state_num >= state);
1394 }
1395 
1396 /*
1397  * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
1398  */
1399 
1400 void
1401 short_usage(int command)
1402 {
1403 	/* lex_lineno has already been incremented in the lexer; compensate */
1404 	if (cmd_file_mode) {
1405 		if (strcmp(cmd_file_name, "-") == 0)
1406 			(void) fprintf(stderr,
1407 			    gettext("syntax error on line %d\n"),
1408 			    lex_lineno - 1);
1409 		else
1410 			(void) fprintf(stderr,
1411 			    gettext("syntax error on line %d of %s\n"),
1412 			    lex_lineno - 1, cmd_file_name);
1413 	}
1414 	(void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
1415 	    helptab[command].short_usage);
1416 	saw_error = B_TRUE;
1417 }
1418 
1419 /*
1420  * long_usage() is for bad semantics: e.g., wrong property type for a given
1421  * resource type.  It is also used by longer_usage() below.
1422  */
1423 
1424 void
1425 long_usage(uint_t cmd_num, boolean_t set_saw)
1426 {
1427 	(void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
1428 	    helptab[cmd_num].short_usage);
1429 	(void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
1430 	if (set_saw)
1431 		saw_error = B_TRUE;
1432 }
1433 
1434 /*
1435  * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
1436  * any extra usage() flags as appropriate for whatever command.
1437  */
1438 
1439 void
1440 longer_usage(uint_t cmd_num)
1441 {
1442 	long_usage(cmd_num, B_FALSE);
1443 	if (helptab[cmd_num].flags != 0) {
1444 		(void) printf("\n");
1445 		usage(B_TRUE, helptab[cmd_num].flags);
1446 	}
1447 }
1448 
1449 /*
1450  * scope_usage() is simply used when a command is called from the wrong scope.
1451  */
1452 
1453 static void
1454 scope_usage(uint_t cmd_num)
1455 {
1456 	zerr(gettext("The %s command only makes sense in the %s scope."),
1457 	    cmd_to_str(cmd_num),
1458 	    global_scope ?  gettext("resource") : gettext("global"));
1459 	saw_error = B_TRUE;
1460 }
1461 
1462 /*
1463  * On input, B_TRUE => yes, B_FALSE => no.
1464  * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
1465  */
1466 
1467 static int
1468 ask_yesno(boolean_t default_answer, const char *question)
1469 {
1470 	char line[64];	/* should be enough to answer yes or no */
1471 
1472 	if (!ok_to_prompt) {
1473 		saw_error = B_TRUE;
1474 		return (-1);
1475 	}
1476 	for (;;) {
1477 		if (printf("%s (%s)? ", question,
1478 		    default_answer ? "[y]/n" : "y/[n]") < 0)
1479 			return (-1);
1480 		if (fgets(line, sizeof (line), stdin) == NULL)
1481 			return (-1);
1482 
1483 		if (line[0] == '\n')
1484 			return (default_answer ? 1 : 0);
1485 		if (tolower(line[0]) == 'y')
1486 			return (1);
1487 		if (tolower(line[0]) == 'n')
1488 			return (0);
1489 	}
1490 }
1491 
1492 /*
1493  * Prints warning if zone already exists.
1494  * In interactive mode, prompts if we should continue anyway and returns Z_OK
1495  * if so, Z_ERR if not.  In non-interactive mode, exits with Z_ERR.
1496  *
1497  * Note that if a zone exists and its state is >= INSTALLED, an error message
1498  * will be printed and this function will return Z_ERR regardless of mode.
1499  */
1500 
1501 static int
1502 check_if_zone_already_exists(boolean_t force)
1503 {
1504 	char line[ZONENAME_MAX + 128];	/* enough to ask a question */
1505 	zone_dochandle_t tmphandle;
1506 	int res, answer;
1507 
1508 	if ((tmphandle = zonecfg_init_handle()) == NULL) {
1509 		zone_perror(execname, Z_NOMEM, B_TRUE);
1510 		exit(Z_ERR);
1511 	}
1512 	res = zonecfg_get_handle(zone, tmphandle);
1513 	zonecfg_fini_handle(tmphandle);
1514 	if (res != Z_OK)
1515 		return (Z_OK);
1516 
1517 	if (state_atleast(ZONE_STATE_INSTALLED)) {
1518 		zerr(gettext("Zone %s already installed; %s not allowed."),
1519 		    zone, cmd_to_str(CMD_CREATE));
1520 		return (Z_ERR);
1521 	}
1522 
1523 	if (force) {
1524 		(void) printf(gettext("Zone %s already exists; overwriting.\n"),
1525 		    zone);
1526 		return (Z_OK);
1527 	}
1528 	(void) snprintf(line, sizeof (line),
1529 	    gettext("Zone %s already exists; %s anyway"), zone,
1530 	    cmd_to_str(CMD_CREATE));
1531 	if ((answer = ask_yesno(B_FALSE, line)) == -1) {
1532 		zerr(gettext("Zone exists, input not from terminal and -F not "
1533 		    "specified:\n%s command ignored, exiting."),
1534 		    cmd_to_str(CMD_CREATE));
1535 		exit(Z_ERR);
1536 	}
1537 	return (answer == 1 ? Z_OK : Z_ERR);
1538 }
1539 
1540 static boolean_t
1541 zone_is_read_only(int cmd_num)
1542 {
1543 	if (strncmp(zone, "SUNW", 4) == 0) {
1544 		zerr(gettext("%s: zones beginning with SUNW are read-only."),
1545 		    zone);
1546 		saw_error = B_TRUE;
1547 		return (B_TRUE);
1548 	}
1549 	if (read_only_mode) {
1550 		zerr(gettext("%s: cannot %s in read-only mode."), zone,
1551 		    cmd_to_str(cmd_num));
1552 		saw_error = B_TRUE;
1553 		return (B_TRUE);
1554 	}
1555 	return (B_FALSE);
1556 }
1557 
1558 /*
1559  * Create a new configuration.
1560  */
1561 void
1562 create_func(cmd_t *cmd)
1563 {
1564 	int err, arg;
1565 	char zone_template[ZONENAME_MAX];
1566 	char attach_path[MAXPATHLEN];
1567 	zone_dochandle_t tmphandle;
1568 	boolean_t force = B_FALSE;
1569 	boolean_t attach = B_FALSE;
1570 	boolean_t arg_err = B_FALSE;
1571 
1572 	assert(cmd != NULL);
1573 
1574 	/* This is the default if no arguments are given. */
1575 	(void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
1576 
1577 	optind = 0;
1578 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
1579 	    != EOF) {
1580 		switch (arg) {
1581 		case '?':
1582 			if (optopt == '?')
1583 				longer_usage(CMD_CREATE);
1584 			else
1585 				short_usage(CMD_CREATE);
1586 			arg_err = B_TRUE;
1587 			break;
1588 		case 'a':
1589 			(void) strlcpy(attach_path, optarg,
1590 			    sizeof (attach_path));
1591 			attach = B_TRUE;
1592 			break;
1593 		case 'b':
1594 			(void) strlcpy(zone_template, "SUNWblank",
1595 			    sizeof (zone_template));
1596 			break;
1597 		case 'F':
1598 			force = B_TRUE;
1599 			break;
1600 		case 't':
1601 			(void) strlcpy(zone_template, optarg,
1602 			    sizeof (zone_template));
1603 			break;
1604 		default:
1605 			short_usage(CMD_CREATE);
1606 			arg_err = B_TRUE;
1607 			break;
1608 		}
1609 	}
1610 	if (arg_err)
1611 		return;
1612 
1613 	if (optind != cmd->cmd_argc) {
1614 		short_usage(CMD_CREATE);
1615 		return;
1616 	}
1617 
1618 	if (zone_is_read_only(CMD_CREATE))
1619 		return;
1620 
1621 	if (check_if_zone_already_exists(force) != Z_OK)
1622 		return;
1623 
1624 	/*
1625 	 * Get a temporary handle first.  If that fails, the old handle
1626 	 * will not be lost.  Then finish whichever one we don't need,
1627 	 * to avoid leaks.  Then get the handle for zone_template, and
1628 	 * set the name to zone: this "copy, rename" method is how
1629 	 * create -[b|t] works.
1630 	 */
1631 	if ((tmphandle = zonecfg_init_handle()) == NULL) {
1632 		zone_perror(execname, Z_NOMEM, B_TRUE);
1633 		exit(Z_ERR);
1634 	}
1635 
1636 	if (attach)
1637 		err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
1638 		    zone, B_FALSE, tmphandle);
1639 	else
1640 		err = zonecfg_get_template_handle(zone_template, zone,
1641 		    tmphandle);
1642 
1643 	if (err != Z_OK) {
1644 		zonecfg_fini_handle(tmphandle);
1645 		if (attach && err == Z_NO_ZONE)
1646 			(void) fprintf(stderr, gettext("invalid path to "
1647 			    "detached zone\n"));
1648 		else if (attach && err == Z_INVALID_DOCUMENT)
1649 			(void) fprintf(stderr, gettext("Cannot attach to an "
1650 			    "earlier release of the operating system\n"));
1651 		else
1652 			zone_perror(zone_template, err, B_TRUE);
1653 		return;
1654 	}
1655 
1656 	need_to_commit = B_TRUE;
1657 	zonecfg_fini_handle(handle);
1658 	handle = tmphandle;
1659 	got_handle = B_TRUE;
1660 }
1661 
1662 /*
1663  * This malloc()'s memory, which must be freed by the caller.
1664  */
1665 static char *
1666 quoteit(char *instr)
1667 {
1668 	char *outstr;
1669 	size_t outstrsize = strlen(instr) + 3;	/* 2 quotes + '\0' */
1670 
1671 	if ((outstr = malloc(outstrsize)) == NULL) {
1672 		zone_perror(zone, Z_NOMEM, B_FALSE);
1673 		exit(Z_ERR);
1674 	}
1675 	if (strchr(instr, ' ') == NULL) {
1676 		(void) strlcpy(outstr, instr, outstrsize);
1677 		return (outstr);
1678 	}
1679 	(void) snprintf(outstr, outstrsize, "\"%s\"", instr);
1680 	return (outstr);
1681 }
1682 
1683 static void
1684 export_prop(FILE *of, int prop_num, char *prop_id)
1685 {
1686 	char *quote_str;
1687 
1688 	if (strlen(prop_id) == 0)
1689 		return;
1690 	quote_str = quoteit(prop_id);
1691 	(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1692 	    pt_to_str(prop_num), quote_str);
1693 	free(quote_str);
1694 }
1695 
1696 void
1697 export_func(cmd_t *cmd)
1698 {
1699 	struct zone_nwiftab nwiftab;
1700 	struct zone_fstab fstab;
1701 	struct zone_devtab devtab;
1702 	struct zone_attrtab attrtab;
1703 	struct zone_rctltab rctltab;
1704 	struct zone_dstab dstab;
1705 	struct zone_psettab psettab;
1706 	struct zone_mcaptab mcaptab;
1707 	struct zone_rctlvaltab *valptr;
1708 	struct zone_admintab admintab;
1709 	int err, arg;
1710 	char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
1711 	char bootargs[BOOTARGS_MAX];
1712 	char sched[MAXNAMELEN];
1713 	char brand[MAXNAMELEN];
1714 	char hostidp[HW_HOSTID_LEN];
1715 	char fsallowedp[ZONE_FS_ALLOWED_MAX];
1716 	char *limitpriv;
1717 	FILE *of;
1718 	boolean_t autoboot;
1719 	zone_iptype_t iptype;
1720 	boolean_t need_to_close = B_FALSE;
1721 	boolean_t arg_err = B_FALSE;
1722 
1723 	assert(cmd != NULL);
1724 
1725 	outfile[0] = '\0';
1726 	optind = 0;
1727 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
1728 		switch (arg) {
1729 		case '?':
1730 			if (optopt == '?')
1731 				longer_usage(CMD_EXPORT);
1732 			else
1733 				short_usage(CMD_EXPORT);
1734 			arg_err = B_TRUE;
1735 			break;
1736 		case 'f':
1737 			(void) strlcpy(outfile, optarg, sizeof (outfile));
1738 			break;
1739 		default:
1740 			short_usage(CMD_EXPORT);
1741 			arg_err = B_TRUE;
1742 			break;
1743 		}
1744 	}
1745 	if (arg_err)
1746 		return;
1747 
1748 	if (optind != cmd->cmd_argc) {
1749 		short_usage(CMD_EXPORT);
1750 		return;
1751 	}
1752 	if (strlen(outfile) == 0) {
1753 		of = stdout;
1754 	} else {
1755 		if ((of = fopen(outfile, "w")) == NULL) {
1756 			zerr(gettext("opening file %s: %s"),
1757 			    outfile, strerror(errno));
1758 			goto done;
1759 		}
1760 		setbuf(of, NULL);
1761 		need_to_close = B_TRUE;
1762 	}
1763 
1764 	if ((err = initialize(B_TRUE)) != Z_OK)
1765 		goto done;
1766 
1767 	(void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
1768 
1769 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
1770 	    strlen(zonepath) > 0)
1771 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1772 		    pt_to_str(PT_ZONEPATH), zonepath);
1773 
1774 	if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
1775 	    (strcmp(brand, NATIVE_BRAND_NAME) != 0))
1776 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1777 		    pt_to_str(PT_BRAND), brand);
1778 
1779 	if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
1780 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1781 		    pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
1782 
1783 	if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
1784 	    strlen(bootargs) > 0) {
1785 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1786 		    pt_to_str(PT_BOOTARGS), bootargs);
1787 	}
1788 
1789 	if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
1790 	    strlen(pool) > 0)
1791 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1792 		    pt_to_str(PT_POOL), pool);
1793 
1794 	if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
1795 	    strlen(limitpriv) > 0) {
1796 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1797 		    pt_to_str(PT_LIMITPRIV), limitpriv);
1798 		free(limitpriv);
1799 	}
1800 
1801 	if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
1802 	    strlen(sched) > 0)
1803 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1804 		    pt_to_str(PT_SCHED), sched);
1805 
1806 	if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
1807 		switch (iptype) {
1808 		case ZS_SHARED:
1809 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1810 			    pt_to_str(PT_IPTYPE), "shared");
1811 			break;
1812 		case ZS_EXCLUSIVE:
1813 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1814 			    pt_to_str(PT_IPTYPE), "exclusive");
1815 			break;
1816 		}
1817 	}
1818 
1819 	if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
1820 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1821 		    pt_to_str(PT_HOSTID), hostidp);
1822 	}
1823 
1824 	if (zonecfg_get_fs_allowed(handle, fsallowedp,
1825 	    sizeof (fsallowedp)) == Z_OK) {
1826 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1827 		    pt_to_str(PT_FS_ALLOWED), fsallowedp);
1828 	}
1829 
1830 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
1831 		zone_perror(zone, err, B_FALSE);
1832 		goto done;
1833 	}
1834 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
1835 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1836 		    rt_to_str(RT_IPD));
1837 		export_prop(of, PT_DIR, fstab.zone_fs_dir);
1838 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1839 	}
1840 	(void) zonecfg_endipdent(handle);
1841 
1842 	if ((err = zonecfg_setfsent(handle)) != Z_OK) {
1843 		zone_perror(zone, err, B_FALSE);
1844 		goto done;
1845 	}
1846 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1847 		zone_fsopt_t *optptr;
1848 
1849 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1850 		    rt_to_str(RT_FS));
1851 		export_prop(of, PT_DIR, fstab.zone_fs_dir);
1852 		export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
1853 		export_prop(of, PT_RAW, fstab.zone_fs_raw);
1854 		export_prop(of, PT_TYPE, fstab.zone_fs_type);
1855 		for (optptr = fstab.zone_fs_options; optptr != NULL;
1856 		    optptr = optptr->zone_fsopt_next) {
1857 			/*
1858 			 * Simple property values with embedded equal signs
1859 			 * need to be quoted to prevent the lexer from
1860 			 * mis-parsing them as complex name=value pairs.
1861 			 */
1862 			if (strchr(optptr->zone_fsopt_opt, '='))
1863 				(void) fprintf(of, "%s %s \"%s\"\n",
1864 				    cmd_to_str(CMD_ADD),
1865 				    pt_to_str(PT_OPTIONS),
1866 				    optptr->zone_fsopt_opt);
1867 			else
1868 				(void) fprintf(of, "%s %s %s\n",
1869 				    cmd_to_str(CMD_ADD),
1870 				    pt_to_str(PT_OPTIONS),
1871 				    optptr->zone_fsopt_opt);
1872 		}
1873 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1874 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
1875 	}
1876 	(void) zonecfg_endfsent(handle);
1877 
1878 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
1879 		zone_perror(zone, err, B_FALSE);
1880 		goto done;
1881 	}
1882 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
1883 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1884 		    rt_to_str(RT_NET));
1885 		export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
1886 		export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
1887 		export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
1888 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1889 	}
1890 	(void) zonecfg_endnwifent(handle);
1891 
1892 	if ((err = zonecfg_setdevent(handle)) != Z_OK) {
1893 		zone_perror(zone, err, B_FALSE);
1894 		goto done;
1895 	}
1896 	while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
1897 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1898 		    rt_to_str(RT_DEVICE));
1899 		export_prop(of, PT_MATCH, devtab.zone_dev_match);
1900 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1901 	}
1902 	(void) zonecfg_enddevent(handle);
1903 
1904 	if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
1905 		char buf[128];
1906 
1907 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1908 		    rt_to_str(RT_MCAP));
1909 		bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
1910 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1911 		    pt_to_str(PT_PHYSICAL), buf);
1912 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1913 	}
1914 
1915 	if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
1916 		zone_perror(zone, err, B_FALSE);
1917 		goto done;
1918 	}
1919 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
1920 		(void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
1921 		export_prop(of, PT_NAME, rctltab.zone_rctl_name);
1922 		for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
1923 		    valptr = valptr->zone_rctlval_next) {
1924 			fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
1925 			    cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1926 			    pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
1927 			    pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
1928 			    pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
1929 		}
1930 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1931 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1932 	}
1933 	(void) zonecfg_endrctlent(handle);
1934 
1935 	if ((err = zonecfg_setattrent(handle)) != Z_OK) {
1936 		zone_perror(zone, err, B_FALSE);
1937 		goto done;
1938 	}
1939 	while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
1940 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1941 		    rt_to_str(RT_ATTR));
1942 		export_prop(of, PT_NAME, attrtab.zone_attr_name);
1943 		export_prop(of, PT_TYPE, attrtab.zone_attr_type);
1944 		export_prop(of, PT_VALUE, attrtab.zone_attr_value);
1945 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1946 	}
1947 	(void) zonecfg_endattrent(handle);
1948 
1949 	if ((err = zonecfg_setdsent(handle)) != Z_OK) {
1950 		zone_perror(zone, err, B_FALSE);
1951 		goto done;
1952 	}
1953 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
1954 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1955 		    rt_to_str(RT_DATASET));
1956 		export_prop(of, PT_NAME, dstab.zone_dataset_name);
1957 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1958 	}
1959 	(void) zonecfg_enddsent(handle);
1960 
1961 	if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
1962 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1963 		    rt_to_str(RT_DCPU));
1964 		if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
1965 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1966 			    pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
1967 		else
1968 			(void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
1969 			    pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
1970 			    psettab.zone_ncpu_max);
1971 		if (psettab.zone_importance[0] != '\0')
1972 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1973 			    pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
1974 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1975 	}
1976 
1977 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
1978 		zone_perror(zone, err, B_FALSE);
1979 		goto done;
1980 	}
1981 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
1982 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1983 		    rt_to_str(RT_ADMIN));
1984 		export_prop(of, PT_USER, admintab.zone_admin_user);
1985 		export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
1986 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1987 	}
1988 	(void) zonecfg_endadminent(handle);
1989 
1990 	/*
1991 	 * There is nothing to export for pcap since this resource is just
1992 	 * a container for an rctl alias.
1993 	 */
1994 
1995 done:
1996 	if (need_to_close)
1997 		(void) fclose(of);
1998 }
1999 
2000 void
2001 exit_func(cmd_t *cmd)
2002 {
2003 	int arg, answer;
2004 	boolean_t arg_err = B_FALSE;
2005 
2006 	optind = 0;
2007 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2008 		switch (arg) {
2009 		case '?':
2010 			longer_usage(CMD_EXIT);
2011 			arg_err = B_TRUE;
2012 			break;
2013 		case 'F':
2014 			force_exit = B_TRUE;
2015 			break;
2016 		default:
2017 			short_usage(CMD_EXIT);
2018 			arg_err = B_TRUE;
2019 			break;
2020 		}
2021 	}
2022 	if (arg_err)
2023 		return;
2024 
2025 	if (optind < cmd->cmd_argc) {
2026 		short_usage(CMD_EXIT);
2027 		return;
2028 	}
2029 
2030 	if (global_scope || force_exit) {
2031 		time_to_exit = B_TRUE;
2032 		return;
2033 	}
2034 
2035 	answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2036 	if (answer == -1) {
2037 		zerr(gettext("Resource incomplete, input "
2038 		    "not from terminal and -F not specified:\n%s command "
2039 		    "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2040 		exit(Z_ERR);
2041 	} else if (answer == 1) {
2042 		time_to_exit = B_TRUE;
2043 	}
2044 	/* (answer == 0) => just return */
2045 }
2046 
2047 static int
2048 validate_zonepath_syntax(char *path)
2049 {
2050 	if (path[0] != '/') {
2051 		zerr(gettext("%s is not an absolute path."), path);
2052 		return (Z_ERR);
2053 	}
2054 	if (strcmp(path, "/") == 0) {
2055 		zerr(gettext("/ is not allowed as a %s."),
2056 		    pt_to_str(PT_ZONEPATH));
2057 		return (Z_ERR);
2058 	}
2059 	return (Z_OK);
2060 }
2061 
2062 static void
2063 add_resource(cmd_t *cmd)
2064 {
2065 	int type;
2066 	struct zone_psettab tmp_psettab;
2067 	struct zone_mcaptab tmp_mcaptab;
2068 	uint64_t tmp;
2069 	uint64_t tmp_mcap;
2070 	char pool[MAXNAMELEN];
2071 
2072 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2073 		long_usage(CMD_ADD, B_TRUE);
2074 		goto bad;
2075 	}
2076 
2077 	switch (type) {
2078 	case RT_FS:
2079 		bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2080 		return;
2081 	case RT_IPD:
2082 		if (state_atleast(ZONE_STATE_INSTALLED)) {
2083 			zerr(gettext("Zone %s already installed; %s %s not "
2084 			    "allowed."), zone, cmd_to_str(CMD_ADD),
2085 			    rt_to_str(RT_IPD));
2086 			goto bad;
2087 		}
2088 		bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab));
2089 		return;
2090 	case RT_NET:
2091 		bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2092 		return;
2093 	case RT_DEVICE:
2094 		bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2095 		return;
2096 	case RT_RCTL:
2097 		if (global_zone)
2098 			zerr(gettext("WARNING: Setting a global zone resource "
2099 			    "control too low could deny\nservice "
2100 			    "to even the root user; "
2101 			    "this could render the system impossible\n"
2102 			    "to administer.  Please use caution."));
2103 		bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2104 		return;
2105 	case RT_ATTR:
2106 		bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2107 		return;
2108 	case RT_DATASET:
2109 		bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2110 		return;
2111 	case RT_DCPU:
2112 		/* Make sure there isn't already a cpu-set or cpu-cap entry. */
2113 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2114 			zerr(gettext("The %s resource already exists."),
2115 			    rt_to_str(RT_DCPU));
2116 			goto bad;
2117 		}
2118 		if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2119 		    Z_NO_ENTRY) {
2120 			zerr(gettext("The %s resource already exists."),
2121 			    rt_to_str(RT_PCAP));
2122 			goto bad;
2123 		}
2124 
2125 		/* Make sure the pool property isn't set. */
2126 		if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2127 		    strlen(pool) > 0) {
2128 			zerr(gettext("The %s property is already set.  "
2129 			    "A persistent pool is incompatible with\nthe %s "
2130 			    "resource."),
2131 			    pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2132 			goto bad;
2133 		}
2134 
2135 		bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2136 		return;
2137 	case RT_PCAP:
2138 		/*
2139 		 * Make sure there isn't already a cpu-set or incompatible
2140 		 * cpu-cap rctls.
2141 		 */
2142 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2143 			zerr(gettext("The %s resource already exists."),
2144 			    rt_to_str(RT_DCPU));
2145 			goto bad;
2146 		}
2147 
2148 		switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2149 		case Z_ALIAS_DISALLOW:
2150 			zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2151 			    B_FALSE);
2152 			goto bad;
2153 
2154 		case Z_OK:
2155 			zerr(gettext("The %s resource already exists."),
2156 			    rt_to_str(RT_PCAP));
2157 			goto bad;
2158 
2159 		default:
2160 			break;
2161 		}
2162 		return;
2163 	case RT_MCAP:
2164 		/*
2165 		 * Make sure there isn't already a mem-cap entry or max-swap
2166 		 * or max-locked rctl.
2167 		 */
2168 		if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2169 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2170 		    == Z_OK ||
2171 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2172 		    &tmp_mcap) == Z_OK) {
2173 			zerr(gettext("The %s resource or a related resource "
2174 			    "control already exists."), rt_to_str(RT_MCAP));
2175 			goto bad;
2176 		}
2177 		if (global_zone)
2178 			zerr(gettext("WARNING: Setting a global zone memory "
2179 			    "cap too low could deny\nservice "
2180 			    "to even the root user; "
2181 			    "this could render the system impossible\n"
2182 			    "to administer.  Please use caution."));
2183 		bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2184 		return;
2185 	case RT_ADMIN:
2186 		bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2187 		return;
2188 	default:
2189 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2190 		long_usage(CMD_ADD, B_TRUE);
2191 		usage(B_FALSE, HELP_RESOURCES);
2192 	}
2193 bad:
2194 	global_scope = B_TRUE;
2195 	end_op = -1;
2196 }
2197 
2198 static void
2199 do_complex_rctl_val(complex_property_ptr_t cp)
2200 {
2201 	struct zone_rctlvaltab *rctlvaltab;
2202 	complex_property_ptr_t cx;
2203 	boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2204 	    seen_action = B_FALSE;
2205 	rctlblk_t *rctlblk;
2206 	int err;
2207 
2208 	if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2209 		zone_perror(zone, Z_NOMEM, B_TRUE);
2210 		exit(Z_ERR);
2211 	}
2212 	for (cx = cp; cx != NULL; cx = cx->cp_next) {
2213 		switch (cx->cp_type) {
2214 		case PT_PRIV:
2215 			if (seen_priv) {
2216 				zerr(gettext("%s already specified"),
2217 				    pt_to_str(PT_PRIV));
2218 				goto bad;
2219 			}
2220 			(void) strlcpy(rctlvaltab->zone_rctlval_priv,
2221 			    cx->cp_value,
2222 			    sizeof (rctlvaltab->zone_rctlval_priv));
2223 			seen_priv = B_TRUE;
2224 			break;
2225 		case PT_LIMIT:
2226 			if (seen_limit) {
2227 				zerr(gettext("%s already specified"),
2228 				    pt_to_str(PT_LIMIT));
2229 				goto bad;
2230 			}
2231 			(void) strlcpy(rctlvaltab->zone_rctlval_limit,
2232 			    cx->cp_value,
2233 			    sizeof (rctlvaltab->zone_rctlval_limit));
2234 			seen_limit = B_TRUE;
2235 			break;
2236 		case PT_ACTION:
2237 			if (seen_action) {
2238 				zerr(gettext("%s already specified"),
2239 				    pt_to_str(PT_ACTION));
2240 				goto bad;
2241 			}
2242 			(void) strlcpy(rctlvaltab->zone_rctlval_action,
2243 			    cx->cp_value,
2244 			    sizeof (rctlvaltab->zone_rctlval_action));
2245 			seen_action = B_TRUE;
2246 			break;
2247 		default:
2248 			zone_perror(pt_to_str(PT_VALUE),
2249 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2250 			long_usage(CMD_ADD, B_TRUE);
2251 			usage(B_FALSE, HELP_PROPS);
2252 			zonecfg_free_rctl_value_list(rctlvaltab);
2253 			return;
2254 		}
2255 	}
2256 	if (!seen_priv)
2257 		zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2258 	if (!seen_limit)
2259 		zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2260 	if (!seen_action)
2261 		zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2262 	if (!seen_priv || !seen_limit || !seen_action)
2263 		goto bad;
2264 	rctlvaltab->zone_rctlval_next = NULL;
2265 	rctlblk = alloca(rctlblk_size());
2266 	/*
2267 	 * Make sure the rctl value looks roughly correct; we won't know if
2268 	 * it's truly OK until we verify the configuration on the target
2269 	 * system.
2270 	 */
2271 	if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2272 	    !zonecfg_valid_rctlblk(rctlblk)) {
2273 		zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2274 		    pt_to_str(PT_VALUE));
2275 		goto bad;
2276 	}
2277 	err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2278 	if (err != Z_OK)
2279 		zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2280 	return;
2281 
2282 bad:
2283 	zonecfg_free_rctl_value_list(rctlvaltab);
2284 }
2285 
2286 static void
2287 add_property(cmd_t *cmd)
2288 {
2289 	char *prop_id;
2290 	int err, res_type, prop_type;
2291 	property_value_ptr_t pp;
2292 	list_property_ptr_t l;
2293 
2294 	res_type = resource_scope;
2295 	prop_type = cmd->cmd_prop_name[0];
2296 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2297 		long_usage(CMD_ADD, B_TRUE);
2298 		return;
2299 	}
2300 
2301 	if (cmd->cmd_prop_nv_pairs != 1) {
2302 		long_usage(CMD_ADD, B_TRUE);
2303 		return;
2304 	}
2305 
2306 	if (initialize(B_TRUE) != Z_OK)
2307 		return;
2308 
2309 	switch (res_type) {
2310 	case RT_FS:
2311 		if (prop_type != PT_OPTIONS) {
2312 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2313 			    B_TRUE);
2314 			long_usage(CMD_ADD, B_TRUE);
2315 			usage(B_FALSE, HELP_PROPS);
2316 			return;
2317 		}
2318 		pp = cmd->cmd_property_ptr[0];
2319 		if (pp->pv_type != PROP_VAL_SIMPLE &&
2320 		    pp->pv_type != PROP_VAL_LIST) {
2321 			zerr(gettext("A %s or %s value was expected here."),
2322 			    pvt_to_str(PROP_VAL_SIMPLE),
2323 			    pvt_to_str(PROP_VAL_LIST));
2324 			saw_error = B_TRUE;
2325 			return;
2326 		}
2327 		if (pp->pv_type == PROP_VAL_SIMPLE) {
2328 			if (pp->pv_simple == NULL) {
2329 				long_usage(CMD_ADD, B_TRUE);
2330 				return;
2331 			}
2332 			prop_id = pp->pv_simple;
2333 			err = zonecfg_add_fs_option(&in_progress_fstab,
2334 			    prop_id);
2335 			if (err != Z_OK)
2336 				zone_perror(pt_to_str(prop_type), err, B_TRUE);
2337 		} else {
2338 			list_property_ptr_t list;
2339 
2340 			for (list = pp->pv_list; list != NULL;
2341 			    list = list->lp_next) {
2342 				prop_id = list->lp_simple;
2343 				if (prop_id == NULL)
2344 					break;
2345 				err = zonecfg_add_fs_option(
2346 				    &in_progress_fstab, prop_id);
2347 				if (err != Z_OK)
2348 					zone_perror(pt_to_str(prop_type), err,
2349 					    B_TRUE);
2350 			}
2351 		}
2352 		return;
2353 	case RT_RCTL:
2354 		if (prop_type != PT_VALUE) {
2355 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2356 			    B_TRUE);
2357 			long_usage(CMD_ADD, B_TRUE);
2358 			usage(B_FALSE, HELP_PROPS);
2359 			return;
2360 		}
2361 		pp = cmd->cmd_property_ptr[0];
2362 		if (pp->pv_type != PROP_VAL_COMPLEX &&
2363 		    pp->pv_type != PROP_VAL_LIST) {
2364 			zerr(gettext("A %s or %s value was expected here."),
2365 			    pvt_to_str(PROP_VAL_COMPLEX),
2366 			    pvt_to_str(PROP_VAL_LIST));
2367 			saw_error = B_TRUE;
2368 			return;
2369 		}
2370 		if (pp->pv_type == PROP_VAL_COMPLEX) {
2371 			do_complex_rctl_val(pp->pv_complex);
2372 			return;
2373 		}
2374 		for (l = pp->pv_list; l != NULL; l = l->lp_next)
2375 			do_complex_rctl_val(l->lp_complex);
2376 		return;
2377 	default:
2378 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2379 		long_usage(CMD_ADD, B_TRUE);
2380 		usage(B_FALSE, HELP_RESOURCES);
2381 		return;
2382 	}
2383 }
2384 
2385 static boolean_t
2386 gz_invalid_resource(int type)
2387 {
2388 	return (global_zone && (type == RT_FS || type == RT_IPD ||
2389 	    type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2390 	    type == RT_DATASET));
2391 }
2392 
2393 static boolean_t
2394 gz_invalid_rt_property(int type)
2395 {
2396 	return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2397 	    type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2398 	    type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2399 	    type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2400 }
2401 
2402 static boolean_t
2403 gz_invalid_property(int type)
2404 {
2405 	return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2406 	    type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2407 	    type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2408 	    type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2409 }
2410 
2411 void
2412 add_func(cmd_t *cmd)
2413 {
2414 	int arg;
2415 	boolean_t arg_err = B_FALSE;
2416 
2417 	assert(cmd != NULL);
2418 
2419 	optind = 0;
2420 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2421 		switch (arg) {
2422 		case '?':
2423 			longer_usage(CMD_ADD);
2424 			arg_err = B_TRUE;
2425 			break;
2426 		default:
2427 			short_usage(CMD_ADD);
2428 			arg_err = B_TRUE;
2429 			break;
2430 		}
2431 	}
2432 	if (arg_err)
2433 		return;
2434 
2435 	if (optind != cmd->cmd_argc) {
2436 		short_usage(CMD_ADD);
2437 		return;
2438 	}
2439 
2440 	if (zone_is_read_only(CMD_ADD))
2441 		return;
2442 
2443 	if (initialize(B_TRUE) != Z_OK)
2444 		return;
2445 	if (global_scope) {
2446 		if (gz_invalid_resource(cmd->cmd_res_type)) {
2447 			zerr(gettext("Cannot add a %s resource to the "
2448 			    "global zone."), rt_to_str(cmd->cmd_res_type));
2449 			saw_error = B_TRUE;
2450 			return;
2451 		}
2452 
2453 		global_scope = B_FALSE;
2454 		resource_scope = cmd->cmd_res_type;
2455 		end_op = CMD_ADD;
2456 		add_resource(cmd);
2457 	} else
2458 		add_property(cmd);
2459 }
2460 
2461 /*
2462  * This routine has an unusual implementation, because it tries very
2463  * hard to succeed in the face of a variety of failure modes.
2464  * The most common and most vexing occurs when the index file and
2465  * the /etc/zones/<zonename.xml> file are not both present.  In
2466  * this case, delete must eradicate as much of the zone state as is left
2467  * so that the user can later create a new zone with the same name.
2468  */
2469 void
2470 delete_func(cmd_t *cmd)
2471 {
2472 	int err, arg, answer;
2473 	char line[ZONENAME_MAX + 128];	/* enough to ask a question */
2474 	boolean_t force = B_FALSE;
2475 	boolean_t arg_err = B_FALSE;
2476 
2477 	optind = 0;
2478 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2479 		switch (arg) {
2480 		case '?':
2481 			longer_usage(CMD_DELETE);
2482 			arg_err = B_TRUE;
2483 			break;
2484 		case 'F':
2485 			force = B_TRUE;
2486 			break;
2487 		default:
2488 			short_usage(CMD_DELETE);
2489 			arg_err = B_TRUE;
2490 			break;
2491 		}
2492 	}
2493 	if (arg_err)
2494 		return;
2495 
2496 	if (optind != cmd->cmd_argc) {
2497 		short_usage(CMD_DELETE);
2498 		return;
2499 	}
2500 
2501 	if (zone_is_read_only(CMD_DELETE))
2502 		return;
2503 
2504 	if (!force) {
2505 		/*
2506 		 * Initialize sets up the global called "handle" and warns the
2507 		 * user if the zone is not configured.  In force mode, we don't
2508 		 * trust that evaluation, and hence skip it.  (We don't need the
2509 		 * handle to be loaded anyway, since zonecfg_destroy is done by
2510 		 * zonename). However, we also have to take care to emulate the
2511 		 * messages spit out by initialize; see below.
2512 		 */
2513 		if (initialize(B_TRUE) != Z_OK)
2514 			return;
2515 
2516 		(void) snprintf(line, sizeof (line),
2517 		    gettext("Are you sure you want to delete zone %s"), zone);
2518 		if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2519 			zerr(gettext("Input not from terminal and -F not "
2520 			    "specified:\n%s command ignored, exiting."),
2521 			    cmd_to_str(CMD_DELETE));
2522 			exit(Z_ERR);
2523 		}
2524 		if (answer != 1)
2525 			return;
2526 	}
2527 
2528 	/*
2529 	 * This function removes the authorizations from user_attr
2530 	 * that correspond to those specified in the configuration
2531 	 */
2532 	if (initialize(B_TRUE) == Z_OK) {
2533 		(void) zonecfg_deauthorize_users(handle, zone);
2534 	}
2535 	if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2536 		if ((err == Z_BAD_ZONE_STATE) && !force) {
2537 			zerr(gettext("Zone %s not in %s state; %s not "
2538 			    "allowed.  Use -F to force %s."),
2539 			    zone, zone_state_str(ZONE_STATE_CONFIGURED),
2540 			    cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2541 		} else {
2542 			zone_perror(zone, err, B_TRUE);
2543 		}
2544 	}
2545 	need_to_commit = B_FALSE;
2546 
2547 	/*
2548 	 * Emulate initialize's messaging; if there wasn't a valid handle to
2549 	 * begin with, then user had typed delete (or delete -F) multiple
2550 	 * times.  So we emit a message.
2551 	 *
2552 	 * We only do this in the 'force' case because normally, initialize()
2553 	 * takes care of this for us.
2554 	 */
2555 	if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2556 		(void) printf(gettext("Use '%s' to begin "
2557 		    "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2558 
2559 	/*
2560 	 * Time for a new handle: finish the old one off first
2561 	 * then get a new one properly to avoid leaks.
2562 	 */
2563 	if (got_handle) {
2564 		zonecfg_fini_handle(handle);
2565 		if ((handle = zonecfg_init_handle()) == NULL) {
2566 			zone_perror(execname, Z_NOMEM, B_TRUE);
2567 			exit(Z_ERR);
2568 		}
2569 		if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2570 			/* If there was no zone before, that's OK */
2571 			if (err != Z_NO_ZONE)
2572 				zone_perror(zone, err, B_TRUE);
2573 			got_handle = B_FALSE;
2574 		}
2575 	}
2576 }
2577 
2578 static int
2579 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2580 {
2581 	int err, i;
2582 	property_value_ptr_t pp;
2583 
2584 	if ((err = initialize(B_TRUE)) != Z_OK)
2585 		return (err);
2586 
2587 	bzero(fstab, sizeof (*fstab));
2588 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2589 		pp = cmd->cmd_property_ptr[i];
2590 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2591 			zerr(gettext("A simple value was expected here."));
2592 			saw_error = B_TRUE;
2593 			return (Z_INSUFFICIENT_SPEC);
2594 		}
2595 		switch (cmd->cmd_prop_name[i]) {
2596 		case PT_DIR:
2597 			(void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2598 			    sizeof (fstab->zone_fs_dir));
2599 			break;
2600 		case PT_SPECIAL:
2601 			(void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2602 			    sizeof (fstab->zone_fs_special));
2603 			break;
2604 		case PT_RAW:
2605 			(void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2606 			    sizeof (fstab->zone_fs_raw));
2607 			break;
2608 		case PT_TYPE:
2609 			(void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2610 			    sizeof (fstab->zone_fs_type));
2611 			break;
2612 		default:
2613 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2614 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2615 			return (Z_INSUFFICIENT_SPEC);
2616 		}
2617 	}
2618 	if (fill_in_only)
2619 		return (Z_OK);
2620 	return (zonecfg_lookup_filesystem(handle, fstab));
2621 }
2622 
2623 static int
2624 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, boolean_t fill_in_only)
2625 {
2626 	int err, i;
2627 	property_value_ptr_t pp;
2628 
2629 	if ((err = initialize(B_TRUE)) != Z_OK)
2630 		return (err);
2631 
2632 	bzero(ipdtab, sizeof (*ipdtab));
2633 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2634 		pp = cmd->cmd_property_ptr[i];
2635 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2636 			zerr(gettext("A simple value was expected here."));
2637 			saw_error = B_TRUE;
2638 			return (Z_INSUFFICIENT_SPEC);
2639 		}
2640 		switch (cmd->cmd_prop_name[i]) {
2641 		case PT_DIR:
2642 			(void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple,
2643 			    sizeof (ipdtab->zone_fs_dir));
2644 			break;
2645 		default:
2646 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2647 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2648 			return (Z_INSUFFICIENT_SPEC);
2649 		}
2650 	}
2651 	if (fill_in_only)
2652 		return (Z_OK);
2653 	return (zonecfg_lookup_ipd(handle, ipdtab));
2654 }
2655 
2656 static int
2657 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2658     boolean_t fill_in_only)
2659 {
2660 	int err, i;
2661 	property_value_ptr_t pp;
2662 
2663 	if ((err = initialize(B_TRUE)) != Z_OK)
2664 		return (err);
2665 
2666 	bzero(nwiftab, sizeof (*nwiftab));
2667 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2668 		pp = cmd->cmd_property_ptr[i];
2669 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2670 			zerr(gettext("A simple value was expected here."));
2671 			saw_error = B_TRUE;
2672 			return (Z_INSUFFICIENT_SPEC);
2673 		}
2674 		switch (cmd->cmd_prop_name[i]) {
2675 		case PT_ADDRESS:
2676 			(void) strlcpy(nwiftab->zone_nwif_address,
2677 			    pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2678 			break;
2679 		case PT_PHYSICAL:
2680 			(void) strlcpy(nwiftab->zone_nwif_physical,
2681 			    pp->pv_simple,
2682 			    sizeof (nwiftab->zone_nwif_physical));
2683 			break;
2684 		case PT_DEFROUTER:
2685 			(void) strlcpy(nwiftab->zone_nwif_defrouter,
2686 			    pp->pv_simple,
2687 			    sizeof (nwiftab->zone_nwif_defrouter));
2688 			break;
2689 		default:
2690 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2691 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2692 			return (Z_INSUFFICIENT_SPEC);
2693 		}
2694 	}
2695 	if (fill_in_only)
2696 		return (Z_OK);
2697 	err = zonecfg_lookup_nwif(handle, nwiftab);
2698 	return (err);
2699 }
2700 
2701 static int
2702 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2703 {
2704 	int err, i;
2705 	property_value_ptr_t pp;
2706 
2707 	if ((err = initialize(B_TRUE)) != Z_OK)
2708 		return (err);
2709 
2710 	bzero(devtab, sizeof (*devtab));
2711 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2712 		pp = cmd->cmd_property_ptr[i];
2713 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2714 			zerr(gettext("A simple value was expected here."));
2715 			saw_error = B_TRUE;
2716 			return (Z_INSUFFICIENT_SPEC);
2717 		}
2718 		switch (cmd->cmd_prop_name[i]) {
2719 		case PT_MATCH:
2720 			(void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2721 			    sizeof (devtab->zone_dev_match));
2722 			break;
2723 		default:
2724 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2725 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2726 			return (Z_INSUFFICIENT_SPEC);
2727 		}
2728 	}
2729 	if (fill_in_only)
2730 		return (Z_OK);
2731 	err = zonecfg_lookup_dev(handle, devtab);
2732 	return (err);
2733 }
2734 
2735 static int
2736 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2737     boolean_t fill_in_only)
2738 {
2739 	int err, i;
2740 	property_value_ptr_t pp;
2741 
2742 	if ((err = initialize(B_TRUE)) != Z_OK)
2743 		return (err);
2744 
2745 	bzero(rctltab, sizeof (*rctltab));
2746 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2747 		pp = cmd->cmd_property_ptr[i];
2748 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2749 			zerr(gettext("A simple value was expected here."));
2750 			saw_error = B_TRUE;
2751 			return (Z_INSUFFICIENT_SPEC);
2752 		}
2753 		switch (cmd->cmd_prop_name[i]) {
2754 		case PT_NAME:
2755 			(void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2756 			    sizeof (rctltab->zone_rctl_name));
2757 			break;
2758 		default:
2759 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2760 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2761 			return (Z_INSUFFICIENT_SPEC);
2762 		}
2763 	}
2764 	if (fill_in_only)
2765 		return (Z_OK);
2766 	err = zonecfg_lookup_rctl(handle, rctltab);
2767 	return (err);
2768 }
2769 
2770 static int
2771 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2772     boolean_t fill_in_only)
2773 {
2774 	int err, i;
2775 	property_value_ptr_t pp;
2776 
2777 	if ((err = initialize(B_TRUE)) != Z_OK)
2778 		return (err);
2779 
2780 	bzero(attrtab, sizeof (*attrtab));
2781 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2782 		pp = cmd->cmd_property_ptr[i];
2783 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2784 			zerr(gettext("A simple value was expected here."));
2785 			saw_error = B_TRUE;
2786 			return (Z_INSUFFICIENT_SPEC);
2787 		}
2788 		switch (cmd->cmd_prop_name[i]) {
2789 		case PT_NAME:
2790 			(void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2791 			    sizeof (attrtab->zone_attr_name));
2792 			break;
2793 		case PT_TYPE:
2794 			(void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2795 			    sizeof (attrtab->zone_attr_type));
2796 			break;
2797 		case PT_VALUE:
2798 			(void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2799 			    sizeof (attrtab->zone_attr_value));
2800 			break;
2801 		default:
2802 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2803 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2804 			return (Z_INSUFFICIENT_SPEC);
2805 		}
2806 	}
2807 	if (fill_in_only)
2808 		return (Z_OK);
2809 	err = zonecfg_lookup_attr(handle, attrtab);
2810 	return (err);
2811 }
2812 
2813 static int
2814 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2815 {
2816 	int err, i;
2817 	property_value_ptr_t pp;
2818 
2819 	if ((err = initialize(B_TRUE)) != Z_OK)
2820 		return (err);
2821 
2822 	dstab->zone_dataset_name[0] = '\0';
2823 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2824 		pp = cmd->cmd_property_ptr[i];
2825 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2826 			zerr(gettext("A simple value was expected here."));
2827 			saw_error = B_TRUE;
2828 			return (Z_INSUFFICIENT_SPEC);
2829 		}
2830 		switch (cmd->cmd_prop_name[i]) {
2831 		case PT_NAME:
2832 			(void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2833 			    sizeof (dstab->zone_dataset_name));
2834 			break;
2835 		default:
2836 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2837 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2838 			return (Z_INSUFFICIENT_SPEC);
2839 		}
2840 	}
2841 	if (fill_in_only)
2842 		return (Z_OK);
2843 	return (zonecfg_lookup_ds(handle, dstab));
2844 }
2845 
2846 static int
2847 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2848     boolean_t fill_in_only)
2849 {
2850 	int err, i;
2851 	property_value_ptr_t pp;
2852 
2853 	if ((err = initialize(B_TRUE)) != Z_OK)
2854 		return (err);
2855 
2856 	bzero(admintab, sizeof (*admintab));
2857 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2858 		pp = cmd->cmd_property_ptr[i];
2859 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2860 			zerr(gettext("A simple value was expected here."));
2861 			saw_error = B_TRUE;
2862 			return (Z_INSUFFICIENT_SPEC);
2863 		}
2864 		switch (cmd->cmd_prop_name[i]) {
2865 		case PT_USER:
2866 			(void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2867 			    sizeof (admintab->zone_admin_user));
2868 			break;
2869 		case PT_AUTHS:
2870 			(void) strlcpy(admintab->zone_admin_auths,
2871 			    pp->pv_simple, sizeof (admintab->zone_admin_auths));
2872 			break;
2873 		default:
2874 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2875 			    Z_NO_PROPERTY_TYPE, B_TRUE);
2876 			return (Z_INSUFFICIENT_SPEC);
2877 		}
2878 	}
2879 	if (fill_in_only)
2880 		return (Z_OK);
2881 	err = zonecfg_lookup_admin(handle, admintab);
2882 	return (err);
2883 }
2884 
2885 static void
2886 remove_aliased_rctl(int type, char *name)
2887 {
2888 	int err;
2889 	uint64_t tmp;
2890 
2891 	if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
2892 		zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
2893 		    zonecfg_strerror(err));
2894 		saw_error = B_TRUE;
2895 		return;
2896 	}
2897 	if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
2898 		zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
2899 		    zonecfg_strerror(err));
2900 		saw_error = B_TRUE;
2901 	} else {
2902 		need_to_commit = B_TRUE;
2903 	}
2904 }
2905 
2906 static boolean_t
2907 prompt_remove_resource(cmd_t *cmd, char *rsrc)
2908 {
2909 	int num;
2910 	int answer;
2911 	int arg;
2912 	boolean_t force = B_FALSE;
2913 	char prompt[128];
2914 	boolean_t arg_err = B_FALSE;
2915 
2916 	optind = 0;
2917 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
2918 		switch (arg) {
2919 		case 'F':
2920 			force = B_TRUE;
2921 			break;
2922 		default:
2923 			arg_err = B_TRUE;
2924 			break;
2925 		}
2926 	}
2927 	if (arg_err)
2928 		return (B_FALSE);
2929 
2930 
2931 	num = zonecfg_num_resources(handle, rsrc);
2932 
2933 	if (num == 0) {
2934 		z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
2935 		    B_TRUE);
2936 		return (B_FALSE);
2937 	}
2938 	if (num > 1 && !force) {
2939 		if (!interactive_mode) {
2940 			zerr(gettext("There are multiple instances of this "
2941 			    "resource.  Either qualify the resource to\n"
2942 			    "remove a single instance or use the -F option to "
2943 			    "remove all instances."));
2944 			saw_error = B_TRUE;
2945 			return (B_FALSE);
2946 		}
2947 		(void) snprintf(prompt, sizeof (prompt), gettext(
2948 		    "Are you sure you want to remove ALL '%s' resources"),
2949 		    rsrc);
2950 		answer = ask_yesno(B_FALSE, prompt);
2951 		if (answer == -1) {
2952 			zerr(gettext("Resource incomplete."));
2953 			return (B_FALSE);
2954 		}
2955 		if (answer != 1)
2956 			return (B_FALSE);
2957 	}
2958 	return (B_TRUE);
2959 }
2960 
2961 static void
2962 remove_fs(cmd_t *cmd)
2963 {
2964 	int err;
2965 
2966 	/* traditional, qualified fs removal */
2967 	if (cmd->cmd_prop_nv_pairs > 0) {
2968 		struct zone_fstab fstab;
2969 
2970 		if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
2971 			z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
2972 			return;
2973 		}
2974 		if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
2975 			z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
2976 		else
2977 			need_to_commit = B_TRUE;
2978 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
2979 		return;
2980 	}
2981 
2982 	/*
2983 	 * unqualified fs removal.  remove all fs's but prompt if more
2984 	 * than one.
2985 	 */
2986 	if (!prompt_remove_resource(cmd, "fs"))
2987 		return;
2988 
2989 	if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
2990 		z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
2991 	else
2992 		need_to_commit = B_TRUE;
2993 }
2994 
2995 static void
2996 remove_ipd(cmd_t *cmd)
2997 {
2998 	int err;
2999 
3000 	if (state_atleast(ZONE_STATE_INSTALLED)) {
3001 		zerr(gettext("Zone %s already installed; %s %s not allowed."),
3002 		    zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD));
3003 		return;
3004 	}
3005 
3006 	/* traditional, qualified ipd removal */
3007 	if (cmd->cmd_prop_nv_pairs > 0) {
3008 		struct zone_fstab fstab;
3009 
3010 		if ((err = fill_in_ipdtab(cmd, &fstab, B_FALSE)) != Z_OK) {
3011 			z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
3012 			return;
3013 		}
3014 		if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK)
3015 			z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
3016 		else
3017 			need_to_commit = B_TRUE;
3018 		return;
3019 	}
3020 
3021 	/*
3022 	 * unqualified ipd removal.  remove all ipds but prompt if more
3023 	 * than one.
3024 	 */
3025 	if (!prompt_remove_resource(cmd, "inherit-pkg-dir"))
3026 		return;
3027 
3028 	if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir"))
3029 	    != Z_OK)
3030 		z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
3031 	else
3032 		need_to_commit = B_TRUE;
3033 }
3034 
3035 static void
3036 remove_net(cmd_t *cmd)
3037 {
3038 	int err;
3039 
3040 	/* traditional, qualified net removal */
3041 	if (cmd->cmd_prop_nv_pairs > 0) {
3042 		struct zone_nwiftab nwiftab;
3043 
3044 		if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3045 			z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3046 			return;
3047 		}
3048 		if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3049 			z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3050 		else
3051 			need_to_commit = B_TRUE;
3052 		return;
3053 	}
3054 
3055 	/*
3056 	 * unqualified net removal.  remove all nets but prompt if more
3057 	 * than one.
3058 	 */
3059 	if (!prompt_remove_resource(cmd, "net"))
3060 		return;
3061 
3062 	if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3063 		z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3064 	else
3065 		need_to_commit = B_TRUE;
3066 }
3067 
3068 static void
3069 remove_device(cmd_t *cmd)
3070 {
3071 	int err;
3072 
3073 	/* traditional, qualified device removal */
3074 	if (cmd->cmd_prop_nv_pairs > 0) {
3075 		struct zone_devtab devtab;
3076 
3077 		if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3078 			z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3079 			return;
3080 		}
3081 		if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3082 			z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3083 		else
3084 			need_to_commit = B_TRUE;
3085 		return;
3086 	}
3087 
3088 	/*
3089 	 * unqualified device removal.  remove all devices but prompt if more
3090 	 * than one.
3091 	 */
3092 	if (!prompt_remove_resource(cmd, "device"))
3093 		return;
3094 
3095 	if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3096 		z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3097 	else
3098 		need_to_commit = B_TRUE;
3099 }
3100 
3101 static void
3102 remove_attr(cmd_t *cmd)
3103 {
3104 	int err;
3105 
3106 	/* traditional, qualified attr removal */
3107 	if (cmd->cmd_prop_nv_pairs > 0) {
3108 		struct zone_attrtab attrtab;
3109 
3110 		if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3111 			z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3112 			return;
3113 		}
3114 		if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3115 			z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3116 		else
3117 			need_to_commit = B_TRUE;
3118 		return;
3119 	}
3120 
3121 	/*
3122 	 * unqualified attr removal.  remove all attrs but prompt if more
3123 	 * than one.
3124 	 */
3125 	if (!prompt_remove_resource(cmd, "attr"))
3126 		return;
3127 
3128 	if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3129 		z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3130 	else
3131 		need_to_commit = B_TRUE;
3132 }
3133 
3134 static void
3135 remove_dataset(cmd_t *cmd)
3136 {
3137 	int err;
3138 
3139 	/* traditional, qualified dataset removal */
3140 	if (cmd->cmd_prop_nv_pairs > 0) {
3141 		struct zone_dstab dstab;
3142 
3143 		if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3144 			z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3145 			return;
3146 		}
3147 		if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3148 			z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3149 		else
3150 			need_to_commit = B_TRUE;
3151 		return;
3152 	}
3153 
3154 	/*
3155 	 * unqualified dataset removal.  remove all datasets but prompt if more
3156 	 * than one.
3157 	 */
3158 	if (!prompt_remove_resource(cmd, "dataset"))
3159 		return;
3160 
3161 	if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3162 		z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3163 	else
3164 		need_to_commit = B_TRUE;
3165 }
3166 
3167 static void
3168 remove_rctl(cmd_t *cmd)
3169 {
3170 	int err;
3171 
3172 	/* traditional, qualified rctl removal */
3173 	if (cmd->cmd_prop_nv_pairs > 0) {
3174 		struct zone_rctltab rctltab;
3175 
3176 		if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3177 			z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3178 			return;
3179 		}
3180 		if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3181 			z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3182 		else
3183 			need_to_commit = B_TRUE;
3184 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3185 		return;
3186 	}
3187 
3188 	/*
3189 	 * unqualified rctl removal.  remove all rctls but prompt if more
3190 	 * than one.
3191 	 */
3192 	if (!prompt_remove_resource(cmd, "rctl"))
3193 		return;
3194 
3195 	if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3196 		z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3197 	else
3198 		need_to_commit = B_TRUE;
3199 }
3200 
3201 static void
3202 remove_pset()
3203 {
3204 	int err;
3205 	struct zone_psettab psettab;
3206 
3207 	if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3208 		z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3209 		return;
3210 	}
3211 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3212 		z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3213 	else
3214 		need_to_commit = B_TRUE;
3215 }
3216 
3217 static void
3218 remove_pcap()
3219 {
3220 	int err;
3221 	uint64_t tmp;
3222 
3223 	if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3224 		zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3225 		    zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3226 		saw_error = B_TRUE;
3227 		return;
3228 	}
3229 
3230 	if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3231 		z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3232 	else
3233 		need_to_commit = B_TRUE;
3234 }
3235 
3236 static void
3237 remove_mcap()
3238 {
3239 	int err, res1, res2, res3;
3240 	uint64_t tmp;
3241 	struct zone_mcaptab mcaptab;
3242 	boolean_t revert = B_FALSE;
3243 
3244 	res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3245 	res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3246 	res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3247 
3248 	/* if none of these exist, there is no resource to remove */
3249 	if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3250 		zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3251 		    zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3252 		saw_error = B_TRUE;
3253 		return;
3254 	}
3255 	if (res1 == Z_OK) {
3256 		if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3257 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3258 			revert = B_TRUE;
3259 		} else {
3260 			need_to_commit = B_TRUE;
3261 		}
3262 	}
3263 	if (res2 == Z_OK) {
3264 		if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3265 		    != Z_OK) {
3266 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3267 			revert = B_TRUE;
3268 		} else {
3269 			need_to_commit = B_TRUE;
3270 		}
3271 	}
3272 	if (res3 == Z_OK) {
3273 		if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3274 		    != Z_OK) {
3275 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3276 			revert = B_TRUE;
3277 		} else {
3278 			need_to_commit = B_TRUE;
3279 		}
3280 	}
3281 
3282 	if (revert)
3283 		need_to_commit = B_FALSE;
3284 }
3285 
3286 static void
3287 remove_admin(cmd_t *cmd)
3288 {
3289 	int err;
3290 
3291 	/* traditional, qualified attr removal */
3292 	if (cmd->cmd_prop_nv_pairs > 0) {
3293 		struct zone_admintab admintab;
3294 
3295 		if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3296 			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3297 			    err, B_TRUE);
3298 			return;
3299 		}
3300 		if ((err = zonecfg_delete_admin(handle, &admintab,
3301 		    zone))
3302 		    != Z_OK)
3303 			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3304 			    err, B_TRUE);
3305 		else
3306 			need_to_commit = B_TRUE;
3307 		return;
3308 	} else {
3309 		/*
3310 		 * unqualified admin removal.
3311 		 * remove all admins but prompt if more
3312 		 * than one.
3313 		 */
3314 		if (!prompt_remove_resource(cmd, "admin"))
3315 			return;
3316 
3317 		if ((err = zonecfg_delete_admins(handle, zone))
3318 		    != Z_OK)
3319 			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3320 			    err, B_TRUE);
3321 		else
3322 			need_to_commit = B_TRUE;
3323 	}
3324 }
3325 
3326 static void
3327 remove_resource(cmd_t *cmd)
3328 {
3329 	int type;
3330 	int arg;
3331 	boolean_t arg_err = B_FALSE;
3332 
3333 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3334 		long_usage(CMD_REMOVE, B_TRUE);
3335 		return;
3336 	}
3337 
3338 	optind = 0;
3339 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3340 		switch (arg) {
3341 		case '?':
3342 			longer_usage(CMD_REMOVE);
3343 			arg_err = B_TRUE;
3344 			break;
3345 		case 'F':
3346 			break;
3347 		default:
3348 			short_usage(CMD_REMOVE);
3349 			arg_err = B_TRUE;
3350 			break;
3351 		}
3352 	}
3353 	if (arg_err)
3354 		return;
3355 
3356 	if (initialize(B_TRUE) != Z_OK)
3357 		return;
3358 
3359 	switch (type) {
3360 	case RT_FS:
3361 		remove_fs(cmd);
3362 		return;
3363 	case RT_IPD:
3364 		remove_ipd(cmd);
3365 		return;
3366 	case RT_NET:
3367 		remove_net(cmd);
3368 		return;
3369 	case RT_DEVICE:
3370 		remove_device(cmd);
3371 		return;
3372 	case RT_RCTL:
3373 		remove_rctl(cmd);
3374 		return;
3375 	case RT_ATTR:
3376 		remove_attr(cmd);
3377 		return;
3378 	case RT_DATASET:
3379 		remove_dataset(cmd);
3380 		return;
3381 	case RT_DCPU:
3382 		remove_pset();
3383 		return;
3384 	case RT_PCAP:
3385 		remove_pcap();
3386 		return;
3387 	case RT_MCAP:
3388 		remove_mcap();
3389 		return;
3390 	case RT_ADMIN:
3391 		remove_admin(cmd);
3392 		return;
3393 	default:
3394 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3395 		long_usage(CMD_REMOVE, B_TRUE);
3396 		usage(B_FALSE, HELP_RESOURCES);
3397 		return;
3398 	}
3399 }
3400 
3401 static void
3402 remove_property(cmd_t *cmd)
3403 {
3404 	char *prop_id;
3405 	int err, res_type, prop_type;
3406 	property_value_ptr_t pp;
3407 	struct zone_rctlvaltab *rctlvaltab;
3408 	complex_property_ptr_t cx;
3409 
3410 	res_type = resource_scope;
3411 	prop_type = cmd->cmd_prop_name[0];
3412 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3413 		long_usage(CMD_REMOVE, B_TRUE);
3414 		return;
3415 	}
3416 
3417 	if (cmd->cmd_prop_nv_pairs != 1) {
3418 		long_usage(CMD_ADD, B_TRUE);
3419 		return;
3420 	}
3421 
3422 	if (initialize(B_TRUE) != Z_OK)
3423 		return;
3424 
3425 	switch (res_type) {
3426 	case RT_FS:
3427 		if (prop_type != PT_OPTIONS) {
3428 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3429 			    B_TRUE);
3430 			long_usage(CMD_REMOVE, B_TRUE);
3431 			usage(B_FALSE, HELP_PROPS);
3432 			return;
3433 		}
3434 		pp = cmd->cmd_property_ptr[0];
3435 		if (pp->pv_type == PROP_VAL_COMPLEX) {
3436 			zerr(gettext("A %s or %s value was expected here."),
3437 			    pvt_to_str(PROP_VAL_SIMPLE),
3438 			    pvt_to_str(PROP_VAL_LIST));
3439 			saw_error = B_TRUE;
3440 			return;
3441 		}
3442 		if (pp->pv_type == PROP_VAL_SIMPLE) {
3443 			if (pp->pv_simple == NULL) {
3444 				long_usage(CMD_ADD, B_TRUE);
3445 				return;
3446 			}
3447 			prop_id = pp->pv_simple;
3448 			err = zonecfg_remove_fs_option(&in_progress_fstab,
3449 			    prop_id);
3450 			if (err != Z_OK)
3451 				zone_perror(pt_to_str(prop_type), err, B_TRUE);
3452 		} else {
3453 			list_property_ptr_t list;
3454 
3455 			for (list = pp->pv_list; list != NULL;
3456 			    list = list->lp_next) {
3457 				prop_id = list->lp_simple;
3458 				if (prop_id == NULL)
3459 					break;
3460 				err = zonecfg_remove_fs_option(
3461 				    &in_progress_fstab, prop_id);
3462 				if (err != Z_OK)
3463 					zone_perror(pt_to_str(prop_type), err,
3464 					    B_TRUE);
3465 			}
3466 		}
3467 		return;
3468 	case RT_RCTL:
3469 		if (prop_type != PT_VALUE) {
3470 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3471 			    B_TRUE);
3472 			long_usage(CMD_REMOVE, B_TRUE);
3473 			usage(B_FALSE, HELP_PROPS);
3474 			return;
3475 		}
3476 		pp = cmd->cmd_property_ptr[0];
3477 		if (pp->pv_type != PROP_VAL_COMPLEX) {
3478 			zerr(gettext("A %s value was expected here."),
3479 			    pvt_to_str(PROP_VAL_COMPLEX));
3480 			saw_error = B_TRUE;
3481 			return;
3482 		}
3483 		if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3484 			zone_perror(zone, Z_NOMEM, B_TRUE);
3485 			exit(Z_ERR);
3486 		}
3487 		for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3488 			switch (cx->cp_type) {
3489 			case PT_PRIV:
3490 				(void) strlcpy(rctlvaltab->zone_rctlval_priv,
3491 				    cx->cp_value,
3492 				    sizeof (rctlvaltab->zone_rctlval_priv));
3493 				break;
3494 			case PT_LIMIT:
3495 				(void) strlcpy(rctlvaltab->zone_rctlval_limit,
3496 				    cx->cp_value,
3497 				    sizeof (rctlvaltab->zone_rctlval_limit));
3498 				break;
3499 			case PT_ACTION:
3500 				(void) strlcpy(rctlvaltab->zone_rctlval_action,
3501 				    cx->cp_value,
3502 				    sizeof (rctlvaltab->zone_rctlval_action));
3503 				break;
3504 			default:
3505 				zone_perror(pt_to_str(prop_type),
3506 				    Z_NO_PROPERTY_TYPE, B_TRUE);
3507 				long_usage(CMD_ADD, B_TRUE);
3508 				usage(B_FALSE, HELP_PROPS);
3509 				zonecfg_free_rctl_value_list(rctlvaltab);
3510 				return;
3511 			}
3512 		}
3513 		rctlvaltab->zone_rctlval_next = NULL;
3514 		err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3515 		    rctlvaltab);
3516 		if (err != Z_OK)
3517 			zone_perror(pt_to_str(prop_type), err, B_TRUE);
3518 		zonecfg_free_rctl_value_list(rctlvaltab);
3519 		return;
3520 	case RT_NET:
3521 		if (prop_type != PT_DEFROUTER) {
3522 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3523 			    B_TRUE);
3524 			long_usage(CMD_REMOVE, B_TRUE);
3525 			usage(B_FALSE, HELP_PROPS);
3526 			return;
3527 		} else {
3528 			bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3529 			    sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3530 			return;
3531 		}
3532 	default:
3533 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3534 		long_usage(CMD_REMOVE, B_TRUE);
3535 		usage(B_FALSE, HELP_RESOURCES);
3536 		return;
3537 	}
3538 }
3539 
3540 void
3541 remove_func(cmd_t *cmd)
3542 {
3543 	if (zone_is_read_only(CMD_REMOVE))
3544 		return;
3545 
3546 	assert(cmd != NULL);
3547 
3548 	if (global_scope) {
3549 		if (gz_invalid_resource(cmd->cmd_res_type)) {
3550 			zerr(gettext("%s is not a valid resource for the "
3551 			    "global zone."), rt_to_str(cmd->cmd_res_type));
3552 			saw_error = B_TRUE;
3553 			return;
3554 		}
3555 		remove_resource(cmd);
3556 	} else {
3557 		remove_property(cmd);
3558 	}
3559 }
3560 
3561 static void
3562 clear_property(cmd_t *cmd)
3563 {
3564 	int res_type, prop_type;
3565 
3566 	res_type = resource_scope;
3567 	prop_type = cmd->cmd_res_type;
3568 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3569 		long_usage(CMD_CLEAR, B_TRUE);
3570 		return;
3571 	}
3572 
3573 	if (initialize(B_TRUE) != Z_OK)
3574 		return;
3575 
3576 	switch (res_type) {
3577 	case RT_FS:
3578 		if (prop_type == PT_RAW) {
3579 			in_progress_fstab.zone_fs_raw[0] = '\0';
3580 			need_to_commit = B_TRUE;
3581 			return;
3582 		}
3583 		break;
3584 	case RT_DCPU:
3585 		if (prop_type == PT_IMPORTANCE) {
3586 			in_progress_psettab.zone_importance[0] = '\0';
3587 			need_to_commit = B_TRUE;
3588 			return;
3589 		}
3590 		break;
3591 	case RT_MCAP:
3592 		switch (prop_type) {
3593 		case PT_PHYSICAL:
3594 			in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3595 			need_to_commit = B_TRUE;
3596 			return;
3597 		case PT_SWAP:
3598 			remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3599 			return;
3600 		case PT_LOCKED:
3601 			remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3602 			return;
3603 		}
3604 		break;
3605 	default:
3606 		break;
3607 	}
3608 
3609 	zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3610 }
3611 
3612 static void
3613 clear_global(cmd_t *cmd)
3614 {
3615 	int err, type;
3616 
3617 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3618 		long_usage(CMD_CLEAR, B_TRUE);
3619 		return;
3620 	}
3621 
3622 	if (initialize(B_TRUE) != Z_OK)
3623 		return;
3624 
3625 	switch (type) {
3626 	case PT_ZONENAME:
3627 		/* FALLTHRU */
3628 	case PT_ZONEPATH:
3629 		/* FALLTHRU */
3630 	case PT_BRAND:
3631 		zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3632 		return;
3633 	case PT_AUTOBOOT:
3634 		/* false is default; we'll treat as equivalent to clearing */
3635 		if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3636 			z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3637 		else
3638 			need_to_commit = B_TRUE;
3639 		return;
3640 	case PT_POOL:
3641 		if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3642 			z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3643 		else
3644 			need_to_commit = B_TRUE;
3645 		return;
3646 	case PT_LIMITPRIV:
3647 		if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3648 			z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3649 		else
3650 			need_to_commit = B_TRUE;
3651 		return;
3652 	case PT_BOOTARGS:
3653 		if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3654 			z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3655 		else
3656 			need_to_commit = B_TRUE;
3657 		return;
3658 	case PT_SCHED:
3659 		if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3660 			z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3661 		else
3662 			need_to_commit = B_TRUE;
3663 		return;
3664 	case PT_IPTYPE:
3665 		/* shared is default; we'll treat as equivalent to clearing */
3666 		if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3667 			z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3668 		else
3669 			need_to_commit = B_TRUE;
3670 		return;
3671 	case PT_MAXLWPS:
3672 		remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3673 		return;
3674 	case PT_MAXSHMMEM:
3675 		remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3676 		return;
3677 	case PT_MAXSHMIDS:
3678 		remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3679 		return;
3680 	case PT_MAXMSGIDS:
3681 		remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3682 		return;
3683 	case PT_MAXSEMIDS:
3684 		remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3685 		return;
3686 	case PT_SHARES:
3687 		remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3688 		return;
3689 	case PT_HOSTID:
3690 		if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3691 			z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3692 		else
3693 			need_to_commit = B_TRUE;
3694 		return;
3695 	case PT_FS_ALLOWED:
3696 		if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3697 			z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3698 		else
3699 			need_to_commit = B_TRUE;
3700 		return;
3701 	default:
3702 		zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3703 		long_usage(CMD_CLEAR, B_TRUE);
3704 		usage(B_FALSE, HELP_PROPS);
3705 		return;
3706 	}
3707 }
3708 
3709 void
3710 clear_func(cmd_t *cmd)
3711 {
3712 	if (zone_is_read_only(CMD_CLEAR))
3713 		return;
3714 
3715 	assert(cmd != NULL);
3716 
3717 	if (global_scope) {
3718 		if (gz_invalid_property(cmd->cmd_res_type)) {
3719 			zerr(gettext("%s is not a valid property for the "
3720 			    "global zone."), pt_to_str(cmd->cmd_res_type));
3721 			saw_error = B_TRUE;
3722 			return;
3723 		}
3724 
3725 		clear_global(cmd);
3726 	} else {
3727 		clear_property(cmd);
3728 	}
3729 }
3730 
3731 void
3732 select_func(cmd_t *cmd)
3733 {
3734 	int type, err, res;
3735 	uint64_t limit;
3736 	uint64_t tmp;
3737 
3738 	if (zone_is_read_only(CMD_SELECT))
3739 		return;
3740 
3741 	assert(cmd != NULL);
3742 
3743 	if (global_scope) {
3744 		global_scope = B_FALSE;
3745 		resource_scope = cmd->cmd_res_type;
3746 		end_op = CMD_SELECT;
3747 	} else {
3748 		scope_usage(CMD_SELECT);
3749 		return;
3750 	}
3751 
3752 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3753 		long_usage(CMD_SELECT, B_TRUE);
3754 		return;
3755 	}
3756 
3757 	if (initialize(B_TRUE) != Z_OK)
3758 		return;
3759 
3760 	switch (type) {
3761 	case RT_FS:
3762 		if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3763 			z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3764 			global_scope = B_TRUE;
3765 		}
3766 		bcopy(&old_fstab, &in_progress_fstab,
3767 		    sizeof (struct zone_fstab));
3768 		return;
3769 	case RT_IPD:
3770 		if (state_atleast(ZONE_STATE_INCOMPLETE)) {
3771 			zerr(gettext("Zone %s not in %s state; %s %s not "
3772 			    "allowed."), zone,
3773 			    zone_state_str(ZONE_STATE_CONFIGURED),
3774 			    cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD));
3775 			global_scope = B_TRUE;
3776 			end_op = -1;
3777 			return;
3778 		}
3779 		if ((err = fill_in_ipdtab(cmd, &old_ipdtab, B_FALSE)) != Z_OK) {
3780 			z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, B_TRUE);
3781 			global_scope = B_TRUE;
3782 		}
3783 		bcopy(&old_ipdtab, &in_progress_ipdtab,
3784 		    sizeof (struct zone_fstab));
3785 		return;
3786 	case RT_NET:
3787 		if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3788 		    != Z_OK) {
3789 			z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3790 			global_scope = B_TRUE;
3791 		}
3792 		bcopy(&old_nwiftab, &in_progress_nwiftab,
3793 		    sizeof (struct zone_nwiftab));
3794 		return;
3795 	case RT_DEVICE:
3796 		if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3797 			z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3798 			global_scope = B_TRUE;
3799 		}
3800 		bcopy(&old_devtab, &in_progress_devtab,
3801 		    sizeof (struct zone_devtab));
3802 		return;
3803 	case RT_RCTL:
3804 		if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3805 		    != Z_OK) {
3806 			z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3807 			global_scope = B_TRUE;
3808 		}
3809 		bcopy(&old_rctltab, &in_progress_rctltab,
3810 		    sizeof (struct zone_rctltab));
3811 		return;
3812 	case RT_ATTR:
3813 		if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3814 		    != Z_OK) {
3815 			z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3816 			global_scope = B_TRUE;
3817 		}
3818 		bcopy(&old_attrtab, &in_progress_attrtab,
3819 		    sizeof (struct zone_attrtab));
3820 		return;
3821 	case RT_DATASET:
3822 		if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3823 			z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3824 			global_scope = B_TRUE;
3825 		}
3826 		bcopy(&old_dstab, &in_progress_dstab,
3827 		    sizeof (struct zone_dstab));
3828 		return;
3829 	case RT_DCPU:
3830 		if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3831 			z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3832 			global_scope = B_TRUE;
3833 		}
3834 		bcopy(&old_psettab, &in_progress_psettab,
3835 		    sizeof (struct zone_psettab));
3836 		return;
3837 	case RT_PCAP:
3838 		if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3839 		    != Z_OK) {
3840 			z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3841 			global_scope = B_TRUE;
3842 		}
3843 		return;
3844 	case RT_MCAP:
3845 		/* if none of these exist, there is no resource to select */
3846 		if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3847 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3848 		    != Z_OK &&
3849 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3850 		    != Z_OK) {
3851 			z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3852 			    B_TRUE);
3853 			global_scope = B_TRUE;
3854 		}
3855 		if (res == Z_OK)
3856 			bcopy(&old_mcaptab, &in_progress_mcaptab,
3857 			    sizeof (struct zone_mcaptab));
3858 		else
3859 			bzero(&in_progress_mcaptab,
3860 			    sizeof (in_progress_mcaptab));
3861 		return;
3862 	case RT_ADMIN:
3863 		if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
3864 		    != Z_OK) {
3865 			z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
3866 			    B_TRUE);
3867 			global_scope = B_TRUE;
3868 		}
3869 		bcopy(&old_admintab, &in_progress_admintab,
3870 		    sizeof (struct zone_admintab));
3871 		return;
3872 	default:
3873 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3874 		long_usage(CMD_SELECT, B_TRUE);
3875 		usage(B_FALSE, HELP_RESOURCES);
3876 		return;
3877 	}
3878 }
3879 
3880 /*
3881  * Network "addresses" can be one of the following forms:
3882  *	<IPv4 address>
3883  *	<IPv4 address>/<prefix length>
3884  *	<IPv6 address>/<prefix length>
3885  *	<host name>
3886  *	<host name>/<prefix length>
3887  * In other words, the "/" followed by a prefix length is allowed but not
3888  * required for IPv4 addresses and host names, and required for IPv6 addresses.
3889  * If a prefix length is given, it must be in the allowable range: 0 to 32 for
3890  * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
3891  * Host names must start with an alpha-numeric character, and all subsequent
3892  * characters must be either alpha-numeric or "-".
3893  */
3894 
3895 static int
3896 validate_net_address_syntax(char *address)
3897 {
3898 	char *slashp, part1[MAXHOSTNAMELEN];
3899 	struct in6_addr in6;
3900 	struct in_addr in4;
3901 	int prefixlen, i;
3902 
3903 	/*
3904 	 * Copy the part before any '/' into part1 or copy the whole
3905 	 * thing if there is no '/'.
3906 	 */
3907 	if ((slashp = strchr(address, '/')) != NULL) {
3908 		*slashp = '\0';
3909 		(void) strlcpy(part1, address, sizeof (part1));
3910 		*slashp = '/';
3911 		prefixlen = atoi(++slashp);
3912 	} else {
3913 		(void) strlcpy(part1, address, sizeof (part1));
3914 	}
3915 
3916 	if (inet_pton(AF_INET6, part1, &in6) == 1) {
3917 		if (slashp == NULL) {
3918 			zerr(gettext("%s: IPv6 addresses "
3919 			    "require /prefix-length suffix."), address);
3920 			return (Z_ERR);
3921 		}
3922 		if (prefixlen < 0 || prefixlen > 128) {
3923 			zerr(gettext("%s: IPv6 address "
3924 			    "prefix lengths must be 0 - 128."), address);
3925 			return (Z_ERR);
3926 		}
3927 		return (Z_OK);
3928 	}
3929 
3930 	/* At this point, any /prefix must be for IPv4. */
3931 	if (slashp != NULL) {
3932 		if (prefixlen < 0 || prefixlen > 32) {
3933 			zerr(gettext("%s: IPv4 address "
3934 			    "prefix lengths must be 0 - 32."), address);
3935 			return (Z_ERR);
3936 		}
3937 	}
3938 	if (inet_pton(AF_INET, part1, &in4) == 1)
3939 		return (Z_OK);
3940 
3941 	/* address may also be a host name */
3942 	if (!isalnum(part1[0])) {
3943 		zerr(gettext("%s: bogus host name or network address syntax"),
3944 		    part1);
3945 		saw_error = B_TRUE;
3946 		usage(B_FALSE, HELP_NETADDR);
3947 		return (Z_ERR);
3948 	}
3949 	for (i = 1; part1[i]; i++)
3950 		if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
3951 			zerr(gettext("%s: bogus host name or "
3952 			    "network address syntax"), part1);
3953 			saw_error = B_TRUE;
3954 			usage(B_FALSE, HELP_NETADDR);
3955 			return (Z_ERR);
3956 		}
3957 	return (Z_OK);
3958 }
3959 
3960 static int
3961 validate_net_physical_syntax(const char *ifname)
3962 {
3963 	ifspec_t ifnameprop;
3964 	zone_iptype_t iptype;
3965 
3966 	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
3967 		zerr(gettext("zone configuration has an invalid or nonexistent "
3968 		    "ip-type property"));
3969 		return (Z_ERR);
3970 	}
3971 	switch (iptype) {
3972 	case ZS_SHARED:
3973 		if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
3974 			zerr(gettext("%s: invalid physical interface name"),
3975 			    ifname);
3976 			return (Z_ERR);
3977 		}
3978 		if (ifnameprop.ifsp_lunvalid) {
3979 			zerr(gettext("%s: LUNs not allowed in physical "
3980 			    "interface names"), ifname);
3981 			return (Z_ERR);
3982 		}
3983 		break;
3984 	case ZS_EXCLUSIVE:
3985 		if (dladm_valid_linkname(ifname) == B_FALSE) {
3986 			if (strchr(ifname, ':') != NULL)
3987 				zerr(gettext("%s: physical interface name "
3988 				    "required; logical interface name not "
3989 				    "allowed"), ifname);
3990 			else
3991 				zerr(gettext("%s: invalid physical interface "
3992 				    "name"), ifname);
3993 			return (Z_ERR);
3994 		}
3995 		break;
3996 	}
3997 	return (Z_OK);
3998 }
3999 
4000 static boolean_t
4001 valid_fs_type(const char *type)
4002 {
4003 	/*
4004 	 * Is this a valid path component?
4005 	 */
4006 	if (strlen(type) + 1 > MAXNAMELEN)
4007 		return (B_FALSE);
4008 	/*
4009 	 * Make sure a bad value for "type" doesn't make
4010 	 * /usr/lib/fs/<type>/mount turn into something else.
4011 	 */
4012 	if (strchr(type, '/') != NULL || type[0] == '\0' ||
4013 	    strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4014 		return (B_FALSE);
4015 	/*
4016 	 * More detailed verification happens later by zoneadm(1m).
4017 	 */
4018 	return (B_TRUE);
4019 }
4020 
4021 static boolean_t
4022 allow_exclusive()
4023 {
4024 	brand_handle_t	bh;
4025 	char		brand[MAXNAMELEN];
4026 	boolean_t	ret;
4027 
4028 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4029 		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4030 		return (B_FALSE);
4031 	}
4032 	if ((bh = brand_open(brand)) == NULL) {
4033 		zerr("%s: %s\n", zone, gettext("unknown brand."));
4034 		return (B_FALSE);
4035 	}
4036 	ret = brand_allow_exclusive_ip(bh);
4037 	brand_close(bh);
4038 	if (!ret)
4039 		zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4040 		    pt_to_str(PT_IPTYPE), "exclusive",
4041 		    pt_to_str(PT_BRAND), brand);
4042 	return (ret);
4043 }
4044 
4045 static void
4046 set_aliased_rctl(char *alias, int prop_type, char *s)
4047 {
4048 	uint64_t limit;
4049 	int err;
4050 	char tmp[128];
4051 
4052 	if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4053 		zerr(gettext("WARNING: Setting a global zone resource "
4054 		    "control too low could deny\nservice "
4055 		    "to even the root user; "
4056 		    "this could render the system impossible\n"
4057 		    "to administer.  Please use caution."));
4058 
4059 	/* convert memory based properties */
4060 	if (prop_type == PT_MAXSHMMEM) {
4061 		if (!zonecfg_valid_memlimit(s, &limit)) {
4062 			zerr(gettext("A non-negative number with a required "
4063 			    "scale suffix (K, M, G or T) was expected\nhere."));
4064 			saw_error = B_TRUE;
4065 			return;
4066 		}
4067 
4068 		(void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4069 		s = tmp;
4070 	}
4071 
4072 	if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4073 		zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4074 		saw_error = B_TRUE;
4075 	} else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4076 		zerr(gettext("%s property is out of range."),
4077 		    pt_to_str(prop_type));
4078 		saw_error = B_TRUE;
4079 	} else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4080 	    != Z_OK) {
4081 		zone_perror(zone, err, B_TRUE);
4082 		saw_error = B_TRUE;
4083 	} else {
4084 		need_to_commit = B_TRUE;
4085 	}
4086 }
4087 
4088 void
4089 set_func(cmd_t *cmd)
4090 {
4091 	char *prop_id;
4092 	int arg, err, res_type, prop_type;
4093 	property_value_ptr_t pp;
4094 	boolean_t autoboot;
4095 	zone_iptype_t iptype;
4096 	boolean_t force_set = B_FALSE;
4097 	size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4098 	uint64_t mem_cap, mem_limit;
4099 	float cap;
4100 	char *unitp;
4101 	struct zone_psettab tmp_psettab;
4102 	boolean_t arg_err = B_FALSE;
4103 
4104 	if (zone_is_read_only(CMD_SET))
4105 		return;
4106 
4107 	assert(cmd != NULL);
4108 
4109 	optind = opterr = 0;
4110 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4111 		switch (arg) {
4112 		case 'F':
4113 			force_set = B_TRUE;
4114 			break;
4115 		default:
4116 			if (optopt == '?')
4117 				longer_usage(CMD_SET);
4118 			else
4119 				short_usage(CMD_SET);
4120 			arg_err = B_TRUE;
4121 			break;
4122 		}
4123 	}
4124 	if (arg_err)
4125 		return;
4126 
4127 	prop_type = cmd->cmd_prop_name[0];
4128 	if (global_scope) {
4129 		if (gz_invalid_property(prop_type)) {
4130 			zerr(gettext("%s is not a valid property for the "
4131 			    "global zone."), pt_to_str(prop_type));
4132 			saw_error = B_TRUE;
4133 			return;
4134 		}
4135 
4136 		if (prop_type == PT_ZONENAME) {
4137 			res_type = RT_ZONENAME;
4138 		} else if (prop_type == PT_ZONEPATH) {
4139 			res_type = RT_ZONEPATH;
4140 		} else if (prop_type == PT_AUTOBOOT) {
4141 			res_type = RT_AUTOBOOT;
4142 		} else if (prop_type == PT_BRAND) {
4143 			res_type = RT_BRAND;
4144 		} else if (prop_type == PT_POOL) {
4145 			res_type = RT_POOL;
4146 		} else if (prop_type == PT_LIMITPRIV) {
4147 			res_type = RT_LIMITPRIV;
4148 		} else if (prop_type == PT_BOOTARGS) {
4149 			res_type = RT_BOOTARGS;
4150 		} else if (prop_type == PT_SCHED) {
4151 			res_type = RT_SCHED;
4152 		} else if (prop_type == PT_IPTYPE) {
4153 			res_type = RT_IPTYPE;
4154 		} else if (prop_type == PT_MAXLWPS) {
4155 			res_type = RT_MAXLWPS;
4156 		} else if (prop_type == PT_MAXSHMMEM) {
4157 			res_type = RT_MAXSHMMEM;
4158 		} else if (prop_type == PT_MAXSHMIDS) {
4159 			res_type = RT_MAXSHMIDS;
4160 		} else if (prop_type == PT_MAXMSGIDS) {
4161 			res_type = RT_MAXMSGIDS;
4162 		} else if (prop_type == PT_MAXSEMIDS) {
4163 			res_type = RT_MAXSEMIDS;
4164 		} else if (prop_type == PT_SHARES) {
4165 			res_type = RT_SHARES;
4166 		} else if (prop_type == PT_HOSTID) {
4167 			res_type = RT_HOSTID;
4168 		} else if (prop_type == PT_FS_ALLOWED) {
4169 			res_type = RT_FS_ALLOWED;
4170 		} else {
4171 			zerr(gettext("Cannot set a resource-specific property "
4172 			    "from the global scope."));
4173 			saw_error = B_TRUE;
4174 			return;
4175 		}
4176 	} else {
4177 		res_type = resource_scope;
4178 	}
4179 
4180 	if (force_set) {
4181 		if (res_type != RT_ZONEPATH) {
4182 			zerr(gettext("Only zonepath setting can be forced."));
4183 			saw_error = B_TRUE;
4184 			return;
4185 		}
4186 		if (!zonecfg_in_alt_root()) {
4187 			zerr(gettext("Zonepath is changeable only in an "
4188 			    "alternate root."));
4189 			saw_error = B_TRUE;
4190 			return;
4191 		}
4192 	}
4193 
4194 	pp = cmd->cmd_property_ptr[0];
4195 	/*
4196 	 * A nasty expression but not that complicated:
4197 	 * 1. fs options are simple or list (tested below)
4198 	 * 2. rctl value's are complex or list (tested below)
4199 	 * Anything else should be simple.
4200 	 */
4201 	if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4202 	    !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4203 	    (pp->pv_type != PROP_VAL_SIMPLE ||
4204 	    (prop_id = pp->pv_simple) == NULL)) {
4205 		zerr(gettext("A %s value was expected here."),
4206 		    pvt_to_str(PROP_VAL_SIMPLE));
4207 		saw_error = B_TRUE;
4208 		return;
4209 	}
4210 	if (prop_type == PT_UNKNOWN) {
4211 		long_usage(CMD_SET, B_TRUE);
4212 		return;
4213 	}
4214 
4215 	/*
4216 	 * Special case: the user can change the zone name prior to 'create';
4217 	 * if the zone already exists, we fall through letting initialize()
4218 	 * and the rest of the logic run.
4219 	 */
4220 	if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4221 	    !state_atleast(ZONE_STATE_CONFIGURED)) {
4222 		if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4223 			zone_perror(prop_id, err, B_TRUE);
4224 			usage(B_FALSE, HELP_SYNTAX);
4225 			return;
4226 		}
4227 		(void) strlcpy(zone, prop_id, sizeof (zone));
4228 		return;
4229 	}
4230 
4231 	if (initialize(B_TRUE) != Z_OK)
4232 		return;
4233 
4234 	switch (res_type) {
4235 	case RT_ZONENAME:
4236 		if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4237 			/*
4238 			 * Use prop_id instead of 'zone' here, since we're
4239 			 * reporting a problem about the *new* zonename.
4240 			 */
4241 			zone_perror(prop_id, err, B_TRUE);
4242 			usage(B_FALSE, HELP_SYNTAX);
4243 		} else {
4244 			need_to_commit = B_TRUE;
4245 			(void) strlcpy(zone, prop_id, sizeof (zone));
4246 		}
4247 		return;
4248 	case RT_ZONEPATH:
4249 		if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4250 			zerr(gettext("Zone %s already installed; %s %s not "
4251 			    "allowed."), zone, cmd_to_str(CMD_SET),
4252 			    rt_to_str(RT_ZONEPATH));
4253 			return;
4254 		}
4255 		if (validate_zonepath_syntax(prop_id) != Z_OK) {
4256 			saw_error = B_TRUE;
4257 			return;
4258 		}
4259 		if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4260 			zone_perror(zone, err, B_TRUE);
4261 		else
4262 			need_to_commit = B_TRUE;
4263 		return;
4264 	case RT_BRAND:
4265 		if (state_atleast(ZONE_STATE_INSTALLED)) {
4266 			zerr(gettext("Zone %s already installed; %s %s not "
4267 			    "allowed."), zone, cmd_to_str(CMD_SET),
4268 			    rt_to_str(RT_BRAND));
4269 			return;
4270 		}
4271 		if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4272 			zone_perror(zone, err, B_TRUE);
4273 		else
4274 			need_to_commit = B_TRUE;
4275 		return;
4276 	case RT_AUTOBOOT:
4277 		if (strcmp(prop_id, "true") == 0) {
4278 			autoboot = B_TRUE;
4279 		} else if (strcmp(prop_id, "false") == 0) {
4280 			autoboot = B_FALSE;
4281 		} else {
4282 			zerr(gettext("%s value must be '%s' or '%s'."),
4283 			    pt_to_str(PT_AUTOBOOT), "true", "false");
4284 			saw_error = B_TRUE;
4285 			return;
4286 		}
4287 		if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4288 			zone_perror(zone, err, B_TRUE);
4289 		else
4290 			need_to_commit = B_TRUE;
4291 		return;
4292 	case RT_POOL:
4293 		/* don't allow use of the reserved temporary pool names */
4294 		if (strncmp("SUNW", prop_id, 4) == 0) {
4295 			zerr(gettext("pool names starting with SUNW are "
4296 			    "reserved."));
4297 			saw_error = B_TRUE;
4298 			return;
4299 		}
4300 
4301 		/* can't set pool if dedicated-cpu exists */
4302 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4303 			zerr(gettext("The %s resource already exists.  "
4304 			    "A persistent pool is incompatible\nwith the %s "
4305 			    "resource."), rt_to_str(RT_DCPU),
4306 			    rt_to_str(RT_DCPU));
4307 			saw_error = B_TRUE;
4308 			return;
4309 		}
4310 
4311 		if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4312 			zone_perror(zone, err, B_TRUE);
4313 		else
4314 			need_to_commit = B_TRUE;
4315 		return;
4316 	case RT_LIMITPRIV:
4317 		if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4318 			zone_perror(zone, err, B_TRUE);
4319 		else
4320 			need_to_commit = B_TRUE;
4321 		return;
4322 	case RT_BOOTARGS:
4323 		if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4324 			zone_perror(zone, err, B_TRUE);
4325 		else
4326 			need_to_commit = B_TRUE;
4327 		return;
4328 	case RT_SCHED:
4329 		if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4330 			zone_perror(zone, err, B_TRUE);
4331 		else
4332 			need_to_commit = B_TRUE;
4333 		return;
4334 	case RT_IPTYPE:
4335 		if (strcmp(prop_id, "shared") == 0) {
4336 			iptype = ZS_SHARED;
4337 		} else if (strcmp(prop_id, "exclusive") == 0) {
4338 			iptype = ZS_EXCLUSIVE;
4339 		} else {
4340 			zerr(gettext("%s value must be '%s' or '%s'."),
4341 			    pt_to_str(PT_IPTYPE), "shared", "exclusive");
4342 			saw_error = B_TRUE;
4343 			return;
4344 		}
4345 		if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4346 			saw_error = B_TRUE;
4347 			return;
4348 		}
4349 		if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4350 			zone_perror(zone, err, B_TRUE);
4351 		else
4352 			need_to_commit = B_TRUE;
4353 		return;
4354 	case RT_MAXLWPS:
4355 		set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4356 		return;
4357 	case RT_MAXSHMMEM:
4358 		set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4359 		return;
4360 	case RT_MAXSHMIDS:
4361 		set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4362 		return;
4363 	case RT_MAXMSGIDS:
4364 		set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4365 		return;
4366 	case RT_MAXSEMIDS:
4367 		set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4368 		return;
4369 	case RT_SHARES:
4370 		set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4371 		return;
4372 	case RT_HOSTID:
4373 		if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4374 			if (err == Z_TOO_BIG) {
4375 				zerr(gettext("hostid string is too large: %s"),
4376 				    prop_id);
4377 				saw_error = B_TRUE;
4378 			} else {
4379 				zone_perror(pt_to_str(prop_type), err, B_TRUE);
4380 			}
4381 			return;
4382 		}
4383 		need_to_commit = B_TRUE;
4384 		return;
4385 	case RT_FS_ALLOWED:
4386 		if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4387 			zone_perror(zone, err, B_TRUE);
4388 		else
4389 			need_to_commit = B_TRUE;
4390 		return;
4391 	case RT_FS:
4392 		switch (prop_type) {
4393 		case PT_DIR:
4394 			(void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4395 			    sizeof (in_progress_fstab.zone_fs_dir));
4396 			return;
4397 		case PT_SPECIAL:
4398 			(void) strlcpy(in_progress_fstab.zone_fs_special,
4399 			    prop_id,
4400 			    sizeof (in_progress_fstab.zone_fs_special));
4401 			return;
4402 		case PT_RAW:
4403 			(void) strlcpy(in_progress_fstab.zone_fs_raw,
4404 			    prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4405 			return;
4406 		case PT_TYPE:
4407 			if (!valid_fs_type(prop_id)) {
4408 				zerr(gettext("\"%s\" is not a valid %s."),
4409 				    prop_id, pt_to_str(PT_TYPE));
4410 				saw_error = B_TRUE;
4411 				return;
4412 			}
4413 			(void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4414 			    sizeof (in_progress_fstab.zone_fs_type));
4415 			return;
4416 		case PT_OPTIONS:
4417 			if (pp->pv_type != PROP_VAL_SIMPLE &&
4418 			    pp->pv_type != PROP_VAL_LIST) {
4419 				zerr(gettext("A %s or %s value was expected "
4420 				    "here."), pvt_to_str(PROP_VAL_SIMPLE),
4421 				    pvt_to_str(PROP_VAL_LIST));
4422 				saw_error = B_TRUE;
4423 				return;
4424 			}
4425 			zonecfg_free_fs_option_list(
4426 			    in_progress_fstab.zone_fs_options);
4427 			in_progress_fstab.zone_fs_options = NULL;
4428 			if (!(pp->pv_type == PROP_VAL_LIST &&
4429 			    pp->pv_list == NULL))
4430 				add_property(cmd);
4431 			return;
4432 		default:
4433 			break;
4434 		}
4435 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4436 		long_usage(CMD_SET, B_TRUE);
4437 		usage(B_FALSE, HELP_PROPS);
4438 		return;
4439 	case RT_IPD:
4440 		switch (prop_type) {
4441 		case PT_DIR:
4442 			(void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id,
4443 			    sizeof (in_progress_ipdtab.zone_fs_dir));
4444 			return;
4445 		default:
4446 			break;
4447 		}
4448 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4449 		long_usage(CMD_SET, B_TRUE);
4450 		usage(B_FALSE, HELP_PROPS);
4451 		return;
4452 	case RT_NET:
4453 		switch (prop_type) {
4454 		case PT_ADDRESS:
4455 			if (validate_net_address_syntax(prop_id) != Z_OK) {
4456 				saw_error = B_TRUE;
4457 				return;
4458 			}
4459 			(void) strlcpy(in_progress_nwiftab.zone_nwif_address,
4460 			    prop_id,
4461 			    sizeof (in_progress_nwiftab.zone_nwif_address));
4462 			break;
4463 		case PT_PHYSICAL:
4464 			if (validate_net_physical_syntax(prop_id) != Z_OK) {
4465 				saw_error = B_TRUE;
4466 				return;
4467 			}
4468 			(void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4469 			    prop_id,
4470 			    sizeof (in_progress_nwiftab.zone_nwif_physical));
4471 			break;
4472 		case PT_DEFROUTER:
4473 			if (validate_net_address_syntax(prop_id) != Z_OK) {
4474 				saw_error = B_TRUE;
4475 				return;
4476 			}
4477 			(void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4478 			    prop_id,
4479 			    sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4480 			break;
4481 		default:
4482 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4483 			    B_TRUE);
4484 			long_usage(CMD_SET, B_TRUE);
4485 			usage(B_FALSE, HELP_PROPS);
4486 			return;
4487 		}
4488 		return;
4489 	case RT_DEVICE:
4490 		switch (prop_type) {
4491 		case PT_MATCH:
4492 			(void) strlcpy(in_progress_devtab.zone_dev_match,
4493 			    prop_id,
4494 			    sizeof (in_progress_devtab.zone_dev_match));
4495 			break;
4496 		default:
4497 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4498 			    B_TRUE);
4499 			long_usage(CMD_SET, B_TRUE);
4500 			usage(B_FALSE, HELP_PROPS);
4501 			return;
4502 		}
4503 		return;
4504 	case RT_RCTL:
4505 		switch (prop_type) {
4506 		case PT_NAME:
4507 			if (!zonecfg_valid_rctlname(prop_id)) {
4508 				zerr(gettext("'%s' is not a valid zone %s "
4509 				    "name."), prop_id, rt_to_str(RT_RCTL));
4510 				return;
4511 			}
4512 			(void) strlcpy(in_progress_rctltab.zone_rctl_name,
4513 			    prop_id,
4514 			    sizeof (in_progress_rctltab.zone_rctl_name));
4515 			break;
4516 		case PT_VALUE:
4517 			if (pp->pv_type != PROP_VAL_COMPLEX &&
4518 			    pp->pv_type != PROP_VAL_LIST) {
4519 				zerr(gettext("A %s or %s value was expected "
4520 				    "here."), pvt_to_str(PROP_VAL_COMPLEX),
4521 				    pvt_to_str(PROP_VAL_LIST));
4522 				saw_error = B_TRUE;
4523 				return;
4524 			}
4525 			zonecfg_free_rctl_value_list(
4526 			    in_progress_rctltab.zone_rctl_valptr);
4527 			in_progress_rctltab.zone_rctl_valptr = NULL;
4528 			if (!(pp->pv_type == PROP_VAL_LIST &&
4529 			    pp->pv_list == NULL))
4530 				add_property(cmd);
4531 			break;
4532 		default:
4533 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4534 			    B_TRUE);
4535 			long_usage(CMD_SET, B_TRUE);
4536 			usage(B_FALSE, HELP_PROPS);
4537 			return;
4538 		}
4539 		return;
4540 	case RT_ATTR:
4541 		switch (prop_type) {
4542 		case PT_NAME:
4543 			(void) strlcpy(in_progress_attrtab.zone_attr_name,
4544 			    prop_id,
4545 			    sizeof (in_progress_attrtab.zone_attr_name));
4546 			break;
4547 		case PT_TYPE:
4548 			(void) strlcpy(in_progress_attrtab.zone_attr_type,
4549 			    prop_id,
4550 			    sizeof (in_progress_attrtab.zone_attr_type));
4551 			break;
4552 		case PT_VALUE:
4553 			(void) strlcpy(in_progress_attrtab.zone_attr_value,
4554 			    prop_id,
4555 			    sizeof (in_progress_attrtab.zone_attr_value));
4556 			break;
4557 		default:
4558 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4559 			    B_TRUE);
4560 			long_usage(CMD_SET, B_TRUE);
4561 			usage(B_FALSE, HELP_PROPS);
4562 			return;
4563 		}
4564 		return;
4565 	case RT_DATASET:
4566 		switch (prop_type) {
4567 		case PT_NAME:
4568 			(void) strlcpy(in_progress_dstab.zone_dataset_name,
4569 			    prop_id,
4570 			    sizeof (in_progress_dstab.zone_dataset_name));
4571 			return;
4572 		default:
4573 			break;
4574 		}
4575 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4576 		long_usage(CMD_SET, B_TRUE);
4577 		usage(B_FALSE, HELP_PROPS);
4578 		return;
4579 	case RT_DCPU:
4580 		switch (prop_type) {
4581 		char *lowp, *highp;
4582 
4583 		case PT_NCPUS:
4584 			lowp = prop_id;
4585 			if ((highp = strchr(prop_id, '-')) != NULL)
4586 				*highp++ = '\0';
4587 			else
4588 				highp = lowp;
4589 
4590 			/* Make sure the input makes sense. */
4591 			if (!zonecfg_valid_ncpus(lowp, highp)) {
4592 				zerr(gettext("%s property is out of range."),
4593 				    pt_to_str(PT_NCPUS));
4594 				saw_error = B_TRUE;
4595 				return;
4596 			}
4597 
4598 			(void) strlcpy(
4599 			    in_progress_psettab.zone_ncpu_min, lowp,
4600 			    sizeof (in_progress_psettab.zone_ncpu_min));
4601 			(void) strlcpy(
4602 			    in_progress_psettab.zone_ncpu_max, highp,
4603 			    sizeof (in_progress_psettab.zone_ncpu_max));
4604 			return;
4605 		case PT_IMPORTANCE:
4606 			/* Make sure the value makes sense. */
4607 			if (!zonecfg_valid_importance(prop_id)) {
4608 				zerr(gettext("%s property is out of range."),
4609 				    pt_to_str(PT_IMPORTANCE));
4610 				saw_error = B_TRUE;
4611 				return;
4612 			}
4613 
4614 			(void) strlcpy(in_progress_psettab.zone_importance,
4615 			    prop_id,
4616 			    sizeof (in_progress_psettab.zone_importance));
4617 			return;
4618 		default:
4619 			break;
4620 		}
4621 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4622 		long_usage(CMD_SET, B_TRUE);
4623 		usage(B_FALSE, HELP_PROPS);
4624 		return;
4625 	case RT_PCAP:
4626 		if (prop_type != PT_NCPUS) {
4627 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4628 			    B_TRUE);
4629 			long_usage(CMD_SET, B_TRUE);
4630 			usage(B_FALSE, HELP_PROPS);
4631 			return;
4632 		}
4633 
4634 		/*
4635 		 * We already checked that an rctl alias is allowed in
4636 		 * the add_resource() function.
4637 		 */
4638 
4639 		if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4640 		    (int)(cap * 100) < 1) {
4641 			zerr(gettext("%s property is out of range."),
4642 			    pt_to_str(PT_NCPUS));
4643 			saw_error = B_TRUE;
4644 			return;
4645 		}
4646 
4647 		if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4648 		    (int)(cap * 100))) != Z_OK)
4649 			zone_perror(zone, err, B_TRUE);
4650 		else
4651 			need_to_commit = B_TRUE;
4652 		return;
4653 	case RT_MCAP:
4654 		switch (prop_type) {
4655 		case PT_PHYSICAL:
4656 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4657 				zerr(gettext("A positive number with a "
4658 				    "required scale suffix (K, M, G or T) was "
4659 				    "expected here."));
4660 				saw_error = B_TRUE;
4661 			} else if (mem_cap < ONE_MB) {
4662 				zerr(gettext("%s value is too small.  It must "
4663 				    "be at least 1M."), pt_to_str(PT_PHYSICAL));
4664 				saw_error = B_TRUE;
4665 			} else {
4666 				snprintf(in_progress_mcaptab.zone_physmem_cap,
4667 				    physmem_size, "%llu", mem_cap);
4668 			}
4669 			break;
4670 		case PT_SWAP:
4671 			/*
4672 			 * We have to check if an rctl is allowed here since
4673 			 * there might already be a rctl defined that blocks
4674 			 * the alias.
4675 			 */
4676 			if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4677 				zone_perror(pt_to_str(PT_MAXSWAP),
4678 				    Z_ALIAS_DISALLOW, B_FALSE);
4679 				saw_error = B_TRUE;
4680 				return;
4681 			}
4682 
4683 			if (global_zone)
4684 				mem_limit = ONE_MB * 100;
4685 			else
4686 				mem_limit = ONE_MB * 50;
4687 
4688 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4689 				zerr(gettext("A positive number with a "
4690 				    "required scale suffix (K, M, G or T) was "
4691 				    "expected here."));
4692 				saw_error = B_TRUE;
4693 			} else if (mem_cap < mem_limit) {
4694 				char buf[128];
4695 
4696 				(void) snprintf(buf, sizeof (buf), "%llu",
4697 				    mem_limit);
4698 				bytes_to_units(buf, buf, sizeof (buf));
4699 				zerr(gettext("%s value is too small.  It must "
4700 				    "be at least %s."), pt_to_str(PT_SWAP),
4701 				    buf);
4702 				saw_error = B_TRUE;
4703 			} else {
4704 				if ((err = zonecfg_set_aliased_rctl(handle,
4705 				    ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4706 					zone_perror(zone, err, B_TRUE);
4707 				else
4708 					need_to_commit = B_TRUE;
4709 			}
4710 			break;
4711 		case PT_LOCKED:
4712 			/*
4713 			 * We have to check if an rctl is allowed here since
4714 			 * there might already be a rctl defined that blocks
4715 			 * the alias.
4716 			 */
4717 			if (!zonecfg_aliased_rctl_ok(handle,
4718 			    ALIAS_MAXLOCKEDMEM)) {
4719 				zone_perror(pt_to_str(PT_LOCKED),
4720 				    Z_ALIAS_DISALLOW, B_FALSE);
4721 				saw_error = B_TRUE;
4722 				return;
4723 			}
4724 
4725 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4726 				zerr(gettext("A non-negative number with a "
4727 				    "required scale suffix (K, M, G or T) was "
4728 				    "expected\nhere."));
4729 				saw_error = B_TRUE;
4730 			} else {
4731 				if ((err = zonecfg_set_aliased_rctl(handle,
4732 				    ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4733 					zone_perror(zone, err, B_TRUE);
4734 				else
4735 					need_to_commit = B_TRUE;
4736 			}
4737 			break;
4738 		default:
4739 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4740 			    B_TRUE);
4741 			long_usage(CMD_SET, B_TRUE);
4742 			usage(B_FALSE, HELP_PROPS);
4743 			return;
4744 		}
4745 		return;
4746 	case RT_ADMIN:
4747 		switch (prop_type) {
4748 		case PT_USER:
4749 			(void) strlcpy(in_progress_admintab.zone_admin_user,
4750 			    prop_id,
4751 			    sizeof (in_progress_admintab.zone_admin_user));
4752 			return;
4753 		case PT_AUTHS:
4754 			(void) strlcpy(in_progress_admintab.zone_admin_auths,
4755 			    prop_id,
4756 			    sizeof (in_progress_admintab.zone_admin_auths));
4757 			return;
4758 		default:
4759 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4760 			    B_TRUE);
4761 			long_usage(CMD_SET, B_TRUE);
4762 			usage(B_FALSE, HELP_PROPS);
4763 			return;
4764 		}
4765 	default:
4766 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4767 		long_usage(CMD_SET, B_TRUE);
4768 		usage(B_FALSE, HELP_RESOURCES);
4769 		return;
4770 	}
4771 }
4772 
4773 static void
4774 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4775 {
4776 	char *qstr;
4777 
4778 	if (*pval != '\0') {
4779 		qstr = quoteit(pval);
4780 		if (pnum == PT_SWAP || pnum == PT_LOCKED)
4781 			(void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4782 			    qstr);
4783 		else
4784 			(void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4785 		free(qstr);
4786 	} else if (print_notspec)
4787 		(void) fprintf(fp, gettext("\t%s not specified\n"),
4788 		    pt_to_str(pnum));
4789 }
4790 
4791 static void
4792 info_zonename(zone_dochandle_t handle, FILE *fp)
4793 {
4794 	char zonename[ZONENAME_MAX];
4795 
4796 	if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4797 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4798 		    zonename);
4799 	else
4800 		(void) fprintf(fp, gettext("%s not specified\n"),
4801 		    pt_to_str(PT_ZONENAME));
4802 }
4803 
4804 static void
4805 info_zonepath(zone_dochandle_t handle, FILE *fp)
4806 {
4807 	char zonepath[MAXPATHLEN];
4808 
4809 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
4810 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
4811 		    zonepath);
4812 	else {
4813 		(void) fprintf(fp, gettext("%s not specified\n"),
4814 		    pt_to_str(PT_ZONEPATH));
4815 	}
4816 }
4817 
4818 static void
4819 info_brand(zone_dochandle_t handle, FILE *fp)
4820 {
4821 	char brand[MAXNAMELEN];
4822 
4823 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
4824 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
4825 		    brand);
4826 	else
4827 		(void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
4828 		    gettext("not specified"));
4829 }
4830 
4831 static void
4832 info_autoboot(zone_dochandle_t handle, FILE *fp)
4833 {
4834 	boolean_t autoboot;
4835 	int err;
4836 
4837 	if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
4838 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
4839 		    autoboot ? "true" : "false");
4840 	else
4841 		zone_perror(zone, err, B_TRUE);
4842 }
4843 
4844 static void
4845 info_pool(zone_dochandle_t handle, FILE *fp)
4846 {
4847 	char pool[MAXNAMELEN];
4848 	int err;
4849 
4850 	if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
4851 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
4852 	else
4853 		zone_perror(zone, err, B_TRUE);
4854 }
4855 
4856 static void
4857 info_limitpriv(zone_dochandle_t handle, FILE *fp)
4858 {
4859 	char *limitpriv;
4860 	int err;
4861 
4862 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
4863 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
4864 		    limitpriv);
4865 		free(limitpriv);
4866 	} else {
4867 		zone_perror(zone, err, B_TRUE);
4868 	}
4869 }
4870 
4871 static void
4872 info_bootargs(zone_dochandle_t handle, FILE *fp)
4873 {
4874 	char bootargs[BOOTARGS_MAX];
4875 	int err;
4876 
4877 	if ((err = zonecfg_get_bootargs(handle, bootargs,
4878 	    sizeof (bootargs))) == Z_OK) {
4879 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
4880 		    bootargs);
4881 	} else {
4882 		zone_perror(zone, err, B_TRUE);
4883 	}
4884 }
4885 
4886 static void
4887 info_sched(zone_dochandle_t handle, FILE *fp)
4888 {
4889 	char sched[MAXNAMELEN];
4890 	int err;
4891 
4892 	if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
4893 	    == Z_OK) {
4894 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
4895 	} else {
4896 		zone_perror(zone, err, B_TRUE);
4897 	}
4898 }
4899 
4900 static void
4901 info_iptype(zone_dochandle_t handle, FILE *fp)
4902 {
4903 	zone_iptype_t iptype;
4904 	int err;
4905 
4906 	if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
4907 		switch (iptype) {
4908 		case ZS_SHARED:
4909 			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
4910 			    "shared");
4911 			break;
4912 		case ZS_EXCLUSIVE:
4913 			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
4914 			    "exclusive");
4915 			break;
4916 		}
4917 	} else {
4918 		zone_perror(zone, err, B_TRUE);
4919 	}
4920 }
4921 
4922 static void
4923 info_hostid(zone_dochandle_t handle, FILE *fp)
4924 {
4925 	char hostidp[HW_HOSTID_LEN];
4926 	int err;
4927 
4928 	if ((err = zonecfg_get_hostid(handle, hostidp,
4929 	    sizeof (hostidp))) == Z_OK) {
4930 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
4931 	} else if (err == Z_BAD_PROPERTY) {
4932 		(void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
4933 	} else {
4934 		zone_perror(zone, err, B_TRUE);
4935 	}
4936 }
4937 
4938 static void
4939 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
4940 {
4941 	char fsallowedp[ZONE_FS_ALLOWED_MAX];
4942 	int err;
4943 
4944 	if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
4945 	    sizeof (fsallowedp))) == Z_OK) {
4946 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
4947 		    fsallowedp);
4948 	} else if (err == Z_BAD_PROPERTY) {
4949 		(void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
4950 	} else {
4951 		zone_perror(zone, err, B_TRUE);
4952 	}
4953 }
4954 
4955 static void
4956 output_fs(FILE *fp, struct zone_fstab *fstab)
4957 {
4958 	zone_fsopt_t *this;
4959 
4960 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
4961 	output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
4962 	output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
4963 	output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
4964 	output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
4965 	(void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
4966 	for (this = fstab->zone_fs_options; this != NULL;
4967 	    this = this->zone_fsopt_next) {
4968 		if (strchr(this->zone_fsopt_opt, '='))
4969 			(void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
4970 		else
4971 			(void) fprintf(fp, "%s", this->zone_fsopt_opt);
4972 		if (this->zone_fsopt_next != NULL)
4973 			(void) fprintf(fp, ",");
4974 	}
4975 	(void) fprintf(fp, "]\n");
4976 }
4977 
4978 static void
4979 output_ipd(FILE *fp, struct zone_fstab *ipdtab)
4980 {
4981 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD));
4982 	output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE);
4983 }
4984 
4985 static void
4986 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4987 {
4988 	struct zone_fstab lookup, user;
4989 	boolean_t output = B_FALSE;
4990 
4991 	if (zonecfg_setfsent(handle) != Z_OK)
4992 		return;
4993 	while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
4994 		if (cmd->cmd_prop_nv_pairs == 0) {
4995 			output_fs(fp, &lookup);
4996 			goto loopend;
4997 		}
4998 		if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
4999 			goto loopend;
5000 		if (strlen(user.zone_fs_dir) > 0 &&
5001 		    strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5002 			goto loopend;	/* no match */
5003 		if (strlen(user.zone_fs_special) > 0 &&
5004 		    strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5005 			goto loopend;	/* no match */
5006 		if (strlen(user.zone_fs_type) > 0 &&
5007 		    strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5008 			goto loopend;	/* no match */
5009 		output_fs(fp, &lookup);
5010 		output = B_TRUE;
5011 loopend:
5012 		zonecfg_free_fs_option_list(lookup.zone_fs_options);
5013 	}
5014 	(void) zonecfg_endfsent(handle);
5015 	/*
5016 	 * If a property n/v pair was specified, warn the user if there was
5017 	 * nothing to output.
5018 	 */
5019 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5020 		(void) printf(gettext("No such %s resource.\n"),
5021 		    rt_to_str(RT_FS));
5022 }
5023 
5024 static void
5025 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5026 {
5027 	struct zone_fstab lookup, user;
5028 	boolean_t output = B_FALSE;
5029 
5030 	if (zonecfg_setipdent(handle) != Z_OK)
5031 		return;
5032 	while (zonecfg_getipdent(handle, &lookup) == Z_OK) {
5033 		if (cmd->cmd_prop_nv_pairs == 0) {
5034 			output_ipd(fp, &lookup);
5035 			continue;
5036 		}
5037 		if (fill_in_ipdtab(cmd, &user, B_TRUE) != Z_OK)
5038 			continue;
5039 		if (strlen(user.zone_fs_dir) > 0 &&
5040 		    strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5041 			continue;	/* no match */
5042 		output_ipd(fp, &lookup);
5043 		output = B_TRUE;
5044 	}
5045 	(void) zonecfg_endipdent(handle);
5046 	/*
5047 	 * If a property n/v pair was specified, warn the user if there was
5048 	 * nothing to output.
5049 	 */
5050 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5051 		(void) printf(gettext("No such %s resource.\n"),
5052 		    rt_to_str(RT_IPD));
5053 }
5054 
5055 static void
5056 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5057 {
5058 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5059 	output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5060 	output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5061 	output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5062 }
5063 
5064 static void
5065 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5066 {
5067 	struct zone_nwiftab lookup, user;
5068 	boolean_t output = B_FALSE;
5069 
5070 	if (zonecfg_setnwifent(handle) != Z_OK)
5071 		return;
5072 	while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5073 		if (cmd->cmd_prop_nv_pairs == 0) {
5074 			output_net(fp, &lookup);
5075 			continue;
5076 		}
5077 		if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5078 			continue;
5079 		if (strlen(user.zone_nwif_physical) > 0 &&
5080 		    strcmp(user.zone_nwif_physical,
5081 		    lookup.zone_nwif_physical) != 0)
5082 			continue;	/* no match */
5083 		/* If present make sure it matches */
5084 		if (strlen(user.zone_nwif_address) > 0 &&
5085 		    !zonecfg_same_net_address(user.zone_nwif_address,
5086 		    lookup.zone_nwif_address))
5087 			continue;	/* no match */
5088 		output_net(fp, &lookup);
5089 		output = B_TRUE;
5090 	}
5091 	(void) zonecfg_endnwifent(handle);
5092 	/*
5093 	 * If a property n/v pair was specified, warn the user if there was
5094 	 * nothing to output.
5095 	 */
5096 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5097 		(void) printf(gettext("No such %s resource.\n"),
5098 		    rt_to_str(RT_NET));
5099 }
5100 
5101 static void
5102 output_dev(FILE *fp, struct zone_devtab *devtab)
5103 {
5104 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5105 	output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5106 }
5107 
5108 static void
5109 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5110 {
5111 	struct zone_devtab lookup, user;
5112 	boolean_t output = B_FALSE;
5113 
5114 	if (zonecfg_setdevent(handle) != Z_OK)
5115 		return;
5116 	while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5117 		if (cmd->cmd_prop_nv_pairs == 0) {
5118 			output_dev(fp, &lookup);
5119 			continue;
5120 		}
5121 		if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5122 			continue;
5123 		if (strlen(user.zone_dev_match) > 0 &&
5124 		    strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5125 			continue;	/* no match */
5126 		output_dev(fp, &lookup);
5127 		output = B_TRUE;
5128 	}
5129 	(void) zonecfg_enddevent(handle);
5130 	/*
5131 	 * If a property n/v pair was specified, warn the user if there was
5132 	 * nothing to output.
5133 	 */
5134 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5135 		(void) printf(gettext("No such %s resource.\n"),
5136 		    rt_to_str(RT_DEVICE));
5137 }
5138 
5139 static void
5140 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5141 {
5142 	struct zone_rctlvaltab *valptr;
5143 
5144 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5145 	output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5146 	for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5147 	    valptr = valptr->zone_rctlval_next) {
5148 		fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5149 		    pt_to_str(PT_VALUE),
5150 		    pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5151 		    pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5152 		    pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5153 	}
5154 }
5155 
5156 static void
5157 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5158 {
5159 	struct zone_rctltab lookup, user;
5160 	boolean_t output = B_FALSE;
5161 
5162 	if (zonecfg_setrctlent(handle) != Z_OK)
5163 		return;
5164 	while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5165 		if (cmd->cmd_prop_nv_pairs == 0) {
5166 			output_rctl(fp, &lookup);
5167 		} else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5168 		    (strlen(user.zone_rctl_name) == 0 ||
5169 		    strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5170 			output_rctl(fp, &lookup);
5171 			output = B_TRUE;
5172 		}
5173 		zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5174 	}
5175 	(void) zonecfg_endrctlent(handle);
5176 	/*
5177 	 * If a property n/v pair was specified, warn the user if there was
5178 	 * nothing to output.
5179 	 */
5180 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5181 		(void) printf(gettext("No such %s resource.\n"),
5182 		    rt_to_str(RT_RCTL));
5183 }
5184 
5185 static void
5186 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5187 {
5188 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5189 	output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5190 	output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5191 	output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5192 }
5193 
5194 static void
5195 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5196 {
5197 	struct zone_attrtab lookup, user;
5198 	boolean_t output = B_FALSE;
5199 
5200 	if (zonecfg_setattrent(handle) != Z_OK)
5201 		return;
5202 	while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5203 		if (cmd->cmd_prop_nv_pairs == 0) {
5204 			output_attr(fp, &lookup);
5205 			continue;
5206 		}
5207 		if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5208 			continue;
5209 		if (strlen(user.zone_attr_name) > 0 &&
5210 		    strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5211 			continue;	/* no match */
5212 		if (strlen(user.zone_attr_type) > 0 &&
5213 		    strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5214 			continue;	/* no match */
5215 		if (strlen(user.zone_attr_value) > 0 &&
5216 		    strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5217 			continue;	/* no match */
5218 		output_attr(fp, &lookup);
5219 		output = B_TRUE;
5220 	}
5221 	(void) zonecfg_endattrent(handle);
5222 	/*
5223 	 * If a property n/v pair was specified, warn the user if there was
5224 	 * nothing to output.
5225 	 */
5226 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5227 		(void) printf(gettext("No such %s resource.\n"),
5228 		    rt_to_str(RT_ATTR));
5229 }
5230 
5231 static void
5232 output_ds(FILE *fp, struct zone_dstab *dstab)
5233 {
5234 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5235 	output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5236 }
5237 
5238 static void
5239 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5240 {
5241 	struct zone_dstab lookup, user;
5242 	boolean_t output = B_FALSE;
5243 
5244 	if (zonecfg_setdsent(handle) != Z_OK)
5245 		return;
5246 	while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5247 		if (cmd->cmd_prop_nv_pairs == 0) {
5248 			output_ds(fp, &lookup);
5249 			continue;
5250 		}
5251 		if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5252 			continue;
5253 		if (strlen(user.zone_dataset_name) > 0 &&
5254 		    strcmp(user.zone_dataset_name,
5255 		    lookup.zone_dataset_name) != 0)
5256 			continue;	/* no match */
5257 		output_ds(fp, &lookup);
5258 		output = B_TRUE;
5259 	}
5260 	(void) zonecfg_enddsent(handle);
5261 	/*
5262 	 * If a property n/v pair was specified, warn the user if there was
5263 	 * nothing to output.
5264 	 */
5265 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5266 		(void) printf(gettext("No such %s resource.\n"),
5267 		    rt_to_str(RT_DATASET));
5268 }
5269 
5270 static void
5271 output_pset(FILE *fp, struct zone_psettab *psettab)
5272 {
5273 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5274 	if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5275 		(void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5276 		    psettab->zone_ncpu_max);
5277 	else
5278 		(void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5279 		    psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5280 	if (psettab->zone_importance[0] != '\0')
5281 		(void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5282 		    psettab->zone_importance);
5283 }
5284 
5285 static void
5286 info_pset(zone_dochandle_t handle, FILE *fp)
5287 {
5288 	struct zone_psettab lookup;
5289 
5290 	if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5291 		output_pset(fp, &lookup);
5292 }
5293 
5294 static void
5295 output_pcap(FILE *fp)
5296 {
5297 	uint64_t cap;
5298 
5299 	if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5300 		float scaled = (float)cap / 100;
5301 		(void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5302 		(void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5303 		    scaled);
5304 	}
5305 }
5306 
5307 static void
5308 info_pcap(FILE *fp)
5309 {
5310 	output_pcap(fp);
5311 }
5312 
5313 
5314 static void
5315 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5316 {
5317 	uint64_t limit;
5318 
5319 	if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5320 		/* convert memory based properties */
5321 		if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5322 			char buf[128];
5323 
5324 			(void) snprintf(buf, sizeof (buf), "%llu", limit);
5325 			bytes_to_units(buf, buf, sizeof (buf));
5326 			(void) fprintf(fp, "[%s: %s]\n", alias, buf);
5327 			return;
5328 		}
5329 
5330 		(void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5331 	}
5332 }
5333 
5334 static void
5335 bytes_to_units(char *str, char *buf, int bufsize)
5336 {
5337 	unsigned long long num;
5338 	unsigned long long save = 0;
5339 	char *units = "BKMGT";
5340 	char *up = units;
5341 
5342 	num = strtoll(str, NULL, 10);
5343 
5344 	if (num < 1024) {
5345 		(void) snprintf(buf, bufsize, "%llu", num);
5346 		return;
5347 	}
5348 
5349 	while ((num >= 1024) && (*up != 'T')) {
5350 		up++; /* next unit of measurement */
5351 		save = num;
5352 		num = (num + 512) >> 10;
5353 	}
5354 
5355 	/* check if we should output a fraction.  snprintf will round for us */
5356 	if (save % 1024 != 0 && ((save >> 10) < 10))
5357 		(void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5358 		    *up);
5359 	else
5360 		(void) snprintf(buf, bufsize, "%llu%c", num, *up);
5361 }
5362 
5363 static void
5364 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5365     uint64_t maxswap, int showlocked, uint64_t maxlocked)
5366 {
5367 	char buf[128];
5368 
5369 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5370 	if (mcaptab->zone_physmem_cap[0] != '\0') {
5371 		bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5372 		output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5373 	}
5374 
5375 	if (showswap == Z_OK) {
5376 		(void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5377 		bytes_to_units(buf, buf, sizeof (buf));
5378 		output_prop(fp, PT_SWAP, buf, B_TRUE);
5379 	}
5380 
5381 	if (showlocked == Z_OK) {
5382 		(void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5383 		bytes_to_units(buf, buf, sizeof (buf));
5384 		output_prop(fp, PT_LOCKED, buf, B_TRUE);
5385 	}
5386 }
5387 
5388 static void
5389 info_mcap(zone_dochandle_t handle, FILE *fp)
5390 {
5391 	int res1, res2, res3;
5392 	uint64_t swap_limit;
5393 	uint64_t locked_limit;
5394 	struct zone_mcaptab lookup;
5395 
5396 	bzero(&lookup, sizeof (lookup));
5397 	res1 = zonecfg_getmcapent(handle, &lookup);
5398 	res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5399 	res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5400 	    &locked_limit);
5401 
5402 	if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5403 		output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5404 }
5405 
5406 static void
5407 output_auth(FILE *fp, struct zone_admintab *admintab)
5408 {
5409 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5410 	output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5411 	output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5412 }
5413 
5414 static void
5415 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5416 {
5417 	struct zone_admintab lookup, user;
5418 	boolean_t output = B_FALSE;
5419 	int err;
5420 
5421 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5422 		zone_perror(zone, err, B_TRUE);
5423 		return;
5424 	}
5425 	while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5426 		if (cmd->cmd_prop_nv_pairs == 0) {
5427 			output_auth(fp, &lookup);
5428 			continue;
5429 		}
5430 		if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5431 			continue;
5432 		if (strlen(user.zone_admin_user) > 0 &&
5433 		    strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5434 			continue;	/* no match */
5435 		output_auth(fp, &lookup);
5436 		output = B_TRUE;
5437 	}
5438 	(void) zonecfg_endadminent(handle);
5439 	/*
5440 	 * If a property n/v pair was specified, warn the user if there was
5441 	 * nothing to output.
5442 	 */
5443 	if (!output && cmd->cmd_prop_nv_pairs > 0)
5444 		(void) printf(gettext("No such %s resource.\n"),
5445 		    rt_to_str(RT_ADMIN));
5446 }
5447 
5448 void
5449 info_func(cmd_t *cmd)
5450 {
5451 	FILE *fp = stdout;
5452 	boolean_t need_to_close = B_FALSE;
5453 	char *pager;
5454 	int type;
5455 	int res1, res2;
5456 	uint64_t swap_limit;
5457 	uint64_t locked_limit;
5458 	struct stat statbuf;
5459 
5460 	assert(cmd != NULL);
5461 
5462 	if (initialize(B_TRUE) != Z_OK)
5463 		return;
5464 
5465 	/* don't page error output */
5466 	if (interactive_mode) {
5467 		if ((pager = getenv("PAGER")) == NULL)
5468 			pager = PAGER;
5469 
5470 		if (stat(pager, &statbuf) == 0) {
5471 			if ((fp = popen(pager, "w")) != NULL)
5472 				need_to_close = B_TRUE;
5473 			else
5474 				fp = stdout;
5475 		} else {
5476 			zerr(gettext("PAGER %s does not exist (%s)."),
5477 			    pager, strerror(errno));
5478 		}
5479 
5480 		setbuf(fp, NULL);
5481 	}
5482 
5483 	if (!global_scope) {
5484 		switch (resource_scope) {
5485 		case RT_FS:
5486 			output_fs(fp, &in_progress_fstab);
5487 			break;
5488 		case RT_IPD:
5489 			output_ipd(fp, &in_progress_ipdtab);
5490 			break;
5491 		case RT_NET:
5492 			output_net(fp, &in_progress_nwiftab);
5493 			break;
5494 		case RT_DEVICE:
5495 			output_dev(fp, &in_progress_devtab);
5496 			break;
5497 		case RT_RCTL:
5498 			output_rctl(fp, &in_progress_rctltab);
5499 			break;
5500 		case RT_ATTR:
5501 			output_attr(fp, &in_progress_attrtab);
5502 			break;
5503 		case RT_DATASET:
5504 			output_ds(fp, &in_progress_dstab);
5505 			break;
5506 		case RT_DCPU:
5507 			output_pset(fp, &in_progress_psettab);
5508 			break;
5509 		case RT_PCAP:
5510 			output_pcap(fp);
5511 			break;
5512 		case RT_MCAP:
5513 			res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5514 			    &swap_limit);
5515 			res2 = zonecfg_get_aliased_rctl(handle,
5516 			    ALIAS_MAXLOCKEDMEM, &locked_limit);
5517 			output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5518 			    res2, locked_limit);
5519 			break;
5520 		case RT_ADMIN:
5521 			output_auth(fp, &in_progress_admintab);
5522 			break;
5523 		}
5524 		goto cleanup;
5525 	}
5526 
5527 	type = cmd->cmd_res_type;
5528 
5529 	if (gz_invalid_rt_property(type)) {
5530 		zerr(gettext("%s is not a valid property for the global zone."),
5531 		    rt_to_str(type));
5532 		goto cleanup;
5533 	}
5534 
5535 	if (gz_invalid_resource(type)) {
5536 		zerr(gettext("%s is not a valid resource for the global zone."),
5537 		    rt_to_str(type));
5538 		goto cleanup;
5539 	}
5540 
5541 	switch (cmd->cmd_res_type) {
5542 	case RT_UNKNOWN:
5543 		info_zonename(handle, fp);
5544 		if (!global_zone) {
5545 			info_zonepath(handle, fp);
5546 			info_brand(handle, fp);
5547 			info_autoboot(handle, fp);
5548 			info_bootargs(handle, fp);
5549 		}
5550 		info_pool(handle, fp);
5551 		if (!global_zone) {
5552 			info_limitpriv(handle, fp);
5553 			info_sched(handle, fp);
5554 			info_iptype(handle, fp);
5555 			info_hostid(handle, fp);
5556 			info_fs_allowed(handle, fp);
5557 		}
5558 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5559 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5560 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5561 		info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5562 		info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5563 		info_aliased_rctl(handle, fp, ALIAS_SHARES);
5564 		if (!global_zone) {
5565 			info_ipd(handle, fp, cmd);
5566 			info_fs(handle, fp, cmd);
5567 			info_net(handle, fp, cmd);
5568 			info_dev(handle, fp, cmd);
5569 		}
5570 		info_pset(handle, fp);
5571 		info_pcap(fp);
5572 		info_mcap(handle, fp);
5573 		if (!global_zone) {
5574 			info_attr(handle, fp, cmd);
5575 			info_ds(handle, fp, cmd);
5576 			info_auth(handle, fp, cmd);
5577 		}
5578 		info_rctl(handle, fp, cmd);
5579 		break;
5580 	case RT_ZONENAME:
5581 		info_zonename(handle, fp);
5582 		break;
5583 	case RT_ZONEPATH:
5584 		info_zonepath(handle, fp);
5585 		break;
5586 	case RT_BRAND:
5587 		info_brand(handle, fp);
5588 		break;
5589 	case RT_AUTOBOOT:
5590 		info_autoboot(handle, fp);
5591 		break;
5592 	case RT_POOL:
5593 		info_pool(handle, fp);
5594 		break;
5595 	case RT_LIMITPRIV:
5596 		info_limitpriv(handle, fp);
5597 		break;
5598 	case RT_BOOTARGS:
5599 		info_bootargs(handle, fp);
5600 		break;
5601 	case RT_SCHED:
5602 		info_sched(handle, fp);
5603 		break;
5604 	case RT_IPTYPE:
5605 		info_iptype(handle, fp);
5606 		break;
5607 	case RT_MAXLWPS:
5608 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5609 		break;
5610 	case RT_MAXSHMMEM:
5611 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5612 		break;
5613 	case RT_MAXSHMIDS:
5614 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5615 		break;
5616 	case RT_MAXMSGIDS:
5617 		info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5618 		break;
5619 	case RT_MAXSEMIDS:
5620 		info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5621 		break;
5622 	case RT_SHARES:
5623 		info_aliased_rctl(handle, fp, ALIAS_SHARES);
5624 		break;
5625 	case RT_FS:
5626 		info_fs(handle, fp, cmd);
5627 		break;
5628 	case RT_IPD:
5629 		info_ipd(handle, fp, cmd);
5630 		break;
5631 	case RT_NET:
5632 		info_net(handle, fp, cmd);
5633 		break;
5634 	case RT_DEVICE:
5635 		info_dev(handle, fp, cmd);
5636 		break;
5637 	case RT_RCTL:
5638 		info_rctl(handle, fp, cmd);
5639 		break;
5640 	case RT_ATTR:
5641 		info_attr(handle, fp, cmd);
5642 		break;
5643 	case RT_DATASET:
5644 		info_ds(handle, fp, cmd);
5645 		break;
5646 	case RT_DCPU:
5647 		info_pset(handle, fp);
5648 		break;
5649 	case RT_PCAP:
5650 		info_pcap(fp);
5651 		break;
5652 	case RT_MCAP:
5653 		info_mcap(handle, fp);
5654 		break;
5655 	case RT_HOSTID:
5656 		info_hostid(handle, fp);
5657 		break;
5658 	case RT_ADMIN:
5659 		info_auth(handle, fp, cmd);
5660 		break;
5661 	case RT_FS_ALLOWED:
5662 		info_fs_allowed(handle, fp);
5663 		break;
5664 	default:
5665 		zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5666 		    B_TRUE);
5667 	}
5668 
5669 cleanup:
5670 	if (need_to_close)
5671 		(void) pclose(fp);
5672 }
5673 
5674 /*
5675  * Helper function for verify-- checks that a required string property
5676  * exists.
5677  */
5678 static void
5679 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5680 {
5681 	if (strlen(attr) == 0) {
5682 		zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5683 		    pt_to_str(pt));
5684 		saw_error = B_TRUE;
5685 		if (*ret_val == Z_OK)
5686 			*ret_val = Z_REQD_PROPERTY_MISSING;
5687 	}
5688 }
5689 
5690 static int
5691 do_subproc(char *cmdbuf)
5692 {
5693 	char inbuf[MAX_CMD_LEN];
5694 	FILE *file;
5695 	int status;
5696 
5697 	file = popen(cmdbuf, "r");
5698 	if (file == NULL) {
5699 		zerr(gettext("Could not launch: %s"), cmdbuf);
5700 		return (-1);
5701 	}
5702 
5703 	while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5704 		fprintf(stderr, "%s", inbuf);
5705 	status = pclose(file);
5706 
5707 	if (WIFSIGNALED(status)) {
5708 		zerr(gettext("%s unexpectedly terminated due to signal %d"),
5709 		    cmdbuf, WTERMSIG(status));
5710 		return (-1);
5711 	}
5712 	assert(WIFEXITED(status));
5713 	return (WEXITSTATUS(status));
5714 }
5715 
5716 static int
5717 brand_verify(zone_dochandle_t handle)
5718 {
5719 	char xml_file[32];
5720 	char cmdbuf[MAX_CMD_LEN];
5721 	brand_handle_t bh;
5722 	char brand[MAXNAMELEN];
5723 	int err;
5724 
5725 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5726 		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5727 		return (Z_INVALID_DOCUMENT);
5728 	}
5729 	if ((bh = brand_open(brand)) == NULL) {
5730 		zerr("%s: %s\n", zone, gettext("unknown brand."));
5731 		return (Z_INVALID_DOCUMENT);
5732 	}
5733 
5734 	/*
5735 	 * Fetch the verify command, if any, from the brand configuration
5736 	 * and build the command line to execute it.
5737 	 */
5738 	strcpy(cmdbuf, EXEC_PREFIX);
5739 	err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5740 	    sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5741 	brand_close(bh);
5742 	if (err != Z_OK) {
5743 		zerr("%s: %s\n", zone,
5744 		    gettext("could not get brand verification command"));
5745 		return (Z_INVALID_DOCUMENT);
5746 	}
5747 
5748 	/*
5749 	 * If the brand doesn't provide a verification routine, we just
5750 	 * return success.
5751 	 */
5752 	if (strlen(cmdbuf) == EXEC_LEN)
5753 		return (Z_OK);
5754 
5755 	/*
5756 	 * Dump the current config information for this zone to a file.
5757 	 */
5758 	strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5759 	if (mkstemp(xml_file) == NULL)
5760 		return (Z_TEMP_FILE);
5761 	if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5762 		(void) unlink(xml_file);
5763 		return (err);
5764 	}
5765 
5766 	/*
5767 	 * Execute the verification command.
5768 	 */
5769 	if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5770 	    (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5771 		err = Z_BRAND_ERROR;
5772 	} else {
5773 		err = do_subproc(cmdbuf);
5774 	}
5775 
5776 	(void) unlink(xml_file);
5777 	return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5778 }
5779 
5780 /*
5781  * See the DTD for which attributes are required for which resources.
5782  *
5783  * This function can be called by commit_func(), which needs to save things,
5784  * in addition to the general call from parse_and_run(), which doesn't need
5785  * things saved.  Since the parameters are standardized, we distinguish by
5786  * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
5787  * that a save is needed.
5788  */
5789 void
5790 verify_func(cmd_t *cmd)
5791 {
5792 	struct zone_nwiftab nwiftab;
5793 	struct zone_fstab fstab;
5794 	struct zone_attrtab attrtab;
5795 	struct zone_rctltab rctltab;
5796 	struct zone_dstab dstab;
5797 	struct zone_psettab psettab;
5798 	struct zone_admintab admintab;
5799 	char zonepath[MAXPATHLEN];
5800 	char sched[MAXNAMELEN];
5801 	char brand[MAXNAMELEN];
5802 	char hostidp[HW_HOSTID_LEN];
5803 	char fsallowedp[ZONE_FS_ALLOWED_MAX];
5804 	int err, ret_val = Z_OK, arg;
5805 	int pset_res;
5806 	boolean_t save = B_FALSE;
5807 	boolean_t arg_err = B_FALSE;
5808 	zone_iptype_t iptype;
5809 	boolean_t has_cpu_shares = B_FALSE;
5810 	boolean_t has_cpu_cap = B_FALSE;
5811 
5812 	optind = 0;
5813 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
5814 		switch (arg) {
5815 		case '?':
5816 			longer_usage(CMD_VERIFY);
5817 			arg_err = B_TRUE;
5818 			break;
5819 		default:
5820 			short_usage(CMD_VERIFY);
5821 			arg_err = B_TRUE;
5822 			break;
5823 		}
5824 	}
5825 	if (arg_err)
5826 		return;
5827 
5828 	if (optind > cmd->cmd_argc) {
5829 		short_usage(CMD_VERIFY);
5830 		return;
5831 	}
5832 
5833 	if (zone_is_read_only(CMD_VERIFY))
5834 		return;
5835 
5836 	assert(cmd != NULL);
5837 
5838 	if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
5839 		save = B_TRUE;
5840 	if (initialize(B_TRUE) != Z_OK)
5841 		return;
5842 
5843 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
5844 	    !global_zone) {
5845 		zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
5846 		ret_val = Z_REQD_RESOURCE_MISSING;
5847 		saw_error = B_TRUE;
5848 	}
5849 	if (strlen(zonepath) == 0 && !global_zone) {
5850 		zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
5851 		ret_val = Z_REQD_RESOURCE_MISSING;
5852 		saw_error = B_TRUE;
5853 	}
5854 
5855 	if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
5856 		zone_perror(zone, err, B_TRUE);
5857 		return;
5858 	}
5859 	if ((err = brand_verify(handle)) != Z_OK) {
5860 		zone_perror(zone, err, B_TRUE);
5861 		return;
5862 	}
5863 
5864 	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
5865 		zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
5866 		ret_val = Z_REQD_RESOURCE_MISSING;
5867 		saw_error = B_TRUE;
5868 	}
5869 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
5870 		zone_perror(zone, err, B_TRUE);
5871 		return;
5872 	}
5873 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
5874 		check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val);
5875 	}
5876 	(void) zonecfg_endipdent(handle);
5877 
5878 	if (zonecfg_get_hostid(handle, hostidp,
5879 	    sizeof (hostidp)) == Z_INVALID_PROPERTY) {
5880 		zerr(gettext("%s: invalid hostid: %s"),
5881 		    zone, hostidp);
5882 		return;
5883 	}
5884 
5885 	if (zonecfg_get_fs_allowed(handle, fsallowedp,
5886 	    sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
5887 		zerr(gettext("%s: invalid fs-allowed: %s"),
5888 		    zone, fsallowedp);
5889 		return;
5890 	}
5891 
5892 	if ((err = zonecfg_setfsent(handle)) != Z_OK) {
5893 		zone_perror(zone, err, B_TRUE);
5894 		return;
5895 	}
5896 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
5897 		check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
5898 		check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
5899 		    &ret_val);
5900 		check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
5901 
5902 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
5903 	}
5904 	(void) zonecfg_endfsent(handle);
5905 
5906 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
5907 		zone_perror(zone, err, B_TRUE);
5908 		return;
5909 	}
5910 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
5911 		/*
5912 		 * physical is required in all cases.
5913 		 * A shared IP requires an address,
5914 		 * and may include a default router, while
5915 		 * an exclusive IP must have neither an address
5916 		 * nor a default router.
5917 		 * The physical interface name must be valid in all cases.
5918 		 */
5919 		check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
5920 		    PT_PHYSICAL, &ret_val);
5921 		if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
5922 		    Z_OK) {
5923 			saw_error = B_TRUE;
5924 			if (ret_val == Z_OK)
5925 				ret_val = Z_INVAL;
5926 		}
5927 
5928 		switch (iptype) {
5929 		case ZS_SHARED:
5930 			check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
5931 			    PT_ADDRESS, &ret_val);
5932 			break;
5933 		case ZS_EXCLUSIVE:
5934 			if (strlen(nwiftab.zone_nwif_address) > 0) {
5935 				zerr(gettext("%s: %s cannot be specified "
5936 				    "for an exclusive IP type"),
5937 				    rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
5938 				saw_error = B_TRUE;
5939 				if (ret_val == Z_OK)
5940 					ret_val = Z_INVAL;
5941 			}
5942 			if (strlen(nwiftab.zone_nwif_defrouter) > 0) {
5943 				zerr(gettext("%s: %s cannot be specified "
5944 				    "for an exclusive IP type"),
5945 				    rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER));
5946 				saw_error = B_TRUE;
5947 				if (ret_val == Z_OK)
5948 					ret_val = Z_INVAL;
5949 			}
5950 			break;
5951 		}
5952 	}
5953 	(void) zonecfg_endnwifent(handle);
5954 
5955 	if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
5956 		zone_perror(zone, err, B_TRUE);
5957 		return;
5958 	}
5959 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
5960 		check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
5961 		    &ret_val);
5962 
5963 		if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
5964 			has_cpu_shares = B_TRUE;
5965 
5966 		if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
5967 			has_cpu_cap = B_TRUE;
5968 
5969 		if (rctltab.zone_rctl_valptr == NULL) {
5970 			zerr(gettext("%s: no %s specified"),
5971 			    rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
5972 			saw_error = B_TRUE;
5973 			if (ret_val == Z_OK)
5974 				ret_val = Z_REQD_PROPERTY_MISSING;
5975 		} else {
5976 			zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
5977 		}
5978 	}
5979 	(void) zonecfg_endrctlent(handle);
5980 
5981 	if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
5982 	    has_cpu_shares) {
5983 		zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
5984 		    rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
5985 		saw_error = B_TRUE;
5986 		if (ret_val == Z_OK)
5987 			ret_val = Z_INCOMPATIBLE;
5988 	}
5989 
5990 	if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
5991 	    sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
5992 	    strcmp(sched, "FSS") != 0) {
5993 		zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
5994 		    "incompatible"),
5995 		    rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
5996 		saw_error = B_TRUE;
5997 		if (ret_val == Z_OK)
5998 			ret_val = Z_INCOMPATIBLE;
5999 	}
6000 
6001 	if (pset_res == Z_OK && has_cpu_cap) {
6002 		zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6003 		    rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6004 		saw_error = B_TRUE;
6005 		if (ret_val == Z_OK)
6006 			ret_val = Z_INCOMPATIBLE;
6007 	}
6008 
6009 	if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6010 		zone_perror(zone, err, B_TRUE);
6011 		return;
6012 	}
6013 	while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6014 		check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6015 		    &ret_val);
6016 		check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6017 		    &ret_val);
6018 		check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6019 		    &ret_val);
6020 	}
6021 	(void) zonecfg_endattrent(handle);
6022 
6023 	if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6024 		zone_perror(zone, err, B_TRUE);
6025 		return;
6026 	}
6027 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6028 		if (strlen(dstab.zone_dataset_name) == 0) {
6029 			zerr("%s: %s %s", rt_to_str(RT_DATASET),
6030 			    pt_to_str(PT_NAME), gettext("not specified"));
6031 			saw_error = B_TRUE;
6032 			if (ret_val == Z_OK)
6033 				ret_val = Z_REQD_PROPERTY_MISSING;
6034 		} else if (!zfs_name_valid(dstab.zone_dataset_name,
6035 		    ZFS_TYPE_FILESYSTEM)) {
6036 			zerr("%s: %s %s", rt_to_str(RT_DATASET),
6037 			    pt_to_str(PT_NAME), gettext("invalid"));
6038 			saw_error = B_TRUE;
6039 			if (ret_val == Z_OK)
6040 				ret_val = Z_BAD_PROPERTY;
6041 		}
6042 
6043 	}
6044 	(void) zonecfg_enddsent(handle);
6045 
6046 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6047 		zone_perror(zone, err, B_TRUE);
6048 		return;
6049 	}
6050 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6051 		check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6052 		    PT_USER, &ret_val);
6053 		check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6054 		    PT_AUTHS, &ret_val);
6055 		if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6056 		    == NULL)) {
6057 			zerr(gettext("%s %s is not a valid username"),
6058 			    pt_to_str(PT_USER),
6059 			    admintab.zone_admin_user);
6060 			ret_val = Z_BAD_PROPERTY;
6061 		}
6062 		if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6063 		    admintab.zone_admin_auths, zone))) {
6064 			ret_val = Z_BAD_PROPERTY;
6065 		}
6066 	}
6067 	(void) zonecfg_endadminent(handle);
6068 
6069 	if (!global_scope) {
6070 		zerr(gettext("resource specification incomplete"));
6071 		saw_error = B_TRUE;
6072 		if (ret_val == Z_OK)
6073 			ret_val = Z_INSUFFICIENT_SPEC;
6074 	}
6075 
6076 	if (save) {
6077 		if (ret_val == Z_OK) {
6078 			if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6079 				need_to_commit = B_FALSE;
6080 				(void) strlcpy(revert_zone, zone,
6081 				    sizeof (revert_zone));
6082 			}
6083 		} else {
6084 			zerr(gettext("Zone %s failed to verify"), zone);
6085 		}
6086 	}
6087 	if (ret_val != Z_OK)
6088 		zone_perror(zone, ret_val, B_TRUE);
6089 }
6090 
6091 void
6092 cancel_func(cmd_t *cmd)
6093 {
6094 	int arg;
6095 	boolean_t arg_err = B_FALSE;
6096 
6097 	assert(cmd != NULL);
6098 
6099 	optind = 0;
6100 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6101 		switch (arg) {
6102 		case '?':
6103 			longer_usage(CMD_CANCEL);
6104 			arg_err = B_TRUE;
6105 			break;
6106 		default:
6107 			short_usage(CMD_CANCEL);
6108 			arg_err = B_TRUE;
6109 			break;
6110 		}
6111 	}
6112 	if (arg_err)
6113 		return;
6114 
6115 	if (optind != cmd->cmd_argc) {
6116 		short_usage(CMD_CANCEL);
6117 		return;
6118 	}
6119 
6120 	if (global_scope)
6121 		scope_usage(CMD_CANCEL);
6122 	global_scope = B_TRUE;
6123 	zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6124 	bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6125 	bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6126 	bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab));
6127 	bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6128 	zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6129 	bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6130 	bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6131 	bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6132 }
6133 
6134 static int
6135 validate_attr_name(char *name)
6136 {
6137 	int i;
6138 
6139 	if (!isalnum(name[0])) {
6140 		zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6141 		    "numeric character."), rt_to_str(RT_ATTR),
6142 		    pt_to_str(PT_NAME), name);
6143 		return (Z_INVAL);
6144 	}
6145 	for (i = 1; name[i]; i++)
6146 		if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6147 			zerr(gettext("Invalid %s %s %s: can only contain "
6148 			    "alpha-numeric characters, plus '-' and '.'."),
6149 			    rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6150 			return (Z_INVAL);
6151 		}
6152 	return (Z_OK);
6153 }
6154 
6155 static int
6156 validate_attr_type_val(struct zone_attrtab *attrtab)
6157 {
6158 	boolean_t boolval;
6159 	int64_t intval;
6160 	char strval[MAXNAMELEN];
6161 	uint64_t uintval;
6162 
6163 	if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6164 		if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6165 			return (Z_OK);
6166 		zerr(gettext("invalid %s value for %s=%s"),
6167 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6168 		return (Z_ERR);
6169 	}
6170 
6171 	if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6172 		if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6173 			return (Z_OK);
6174 		zerr(gettext("invalid %s value for %s=%s"),
6175 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6176 		return (Z_ERR);
6177 	}
6178 
6179 	if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6180 		if (zonecfg_get_attr_string(attrtab, strval,
6181 		    sizeof (strval)) == Z_OK)
6182 			return (Z_OK);
6183 		zerr(gettext("invalid %s value for %s=%s"),
6184 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6185 		return (Z_ERR);
6186 	}
6187 
6188 	if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6189 		if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6190 			return (Z_OK);
6191 		zerr(gettext("invalid %s value for %s=%s"),
6192 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6193 		return (Z_ERR);
6194 	}
6195 
6196 	zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6197 	    pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6198 	return (Z_ERR);
6199 }
6200 
6201 /*
6202  * Helper function for end_func-- checks the existence of a given property
6203  * and emits a message if not specified.
6204  */
6205 static int
6206 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6207 {
6208 	if (strlen(attr) == 0) {
6209 		*validation_failed = B_TRUE;
6210 		zerr(gettext("%s not specified"), pt_to_str(pt));
6211 		return (Z_ERR);
6212 	}
6213 	return (Z_OK);
6214 }
6215 
6216 void
6217 end_func(cmd_t *cmd)
6218 {
6219 	boolean_t validation_failed = B_FALSE;
6220 	boolean_t arg_err = B_FALSE;
6221 	struct zone_fstab tmp_fstab;
6222 	struct zone_nwiftab tmp_nwiftab;
6223 	struct zone_devtab tmp_devtab;
6224 	struct zone_rctltab tmp_rctltab;
6225 	struct zone_attrtab tmp_attrtab;
6226 	struct zone_dstab tmp_dstab;
6227 	struct zone_admintab tmp_admintab;
6228 	int err, arg, res1, res2, res3;
6229 	uint64_t swap_limit;
6230 	uint64_t locked_limit;
6231 	uint64_t proc_cap;
6232 
6233 	assert(cmd != NULL);
6234 
6235 	optind = 0;
6236 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6237 		switch (arg) {
6238 		case '?':
6239 			longer_usage(CMD_END);
6240 			arg_err = B_TRUE;
6241 			break;
6242 		default:
6243 			short_usage(CMD_END);
6244 			arg_err = B_TRUE;
6245 			break;
6246 		}
6247 	}
6248 	if (arg_err)
6249 		return;
6250 
6251 	if (optind != cmd->cmd_argc) {
6252 		short_usage(CMD_END);
6253 		return;
6254 	}
6255 
6256 	if (global_scope) {
6257 		scope_usage(CMD_END);
6258 		return;
6259 	}
6260 
6261 	assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6262 
6263 	switch (resource_scope) {
6264 	case RT_FS:
6265 		/* First make sure everything was filled in. */
6266 		if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6267 		    PT_DIR, &validation_failed) == Z_OK) {
6268 			if (in_progress_fstab.zone_fs_dir[0] != '/') {
6269 				zerr(gettext("%s %s is not an absolute path."),
6270 				    pt_to_str(PT_DIR),
6271 				    in_progress_fstab.zone_fs_dir);
6272 				validation_failed = B_TRUE;
6273 			}
6274 		}
6275 
6276 		(void) end_check_reqd(in_progress_fstab.zone_fs_special,
6277 		    PT_SPECIAL, &validation_failed);
6278 
6279 		if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6280 		    in_progress_fstab.zone_fs_raw[0] != '/') {
6281 			zerr(gettext("%s %s is not an absolute path."),
6282 			    pt_to_str(PT_RAW),
6283 			    in_progress_fstab.zone_fs_raw);
6284 			validation_failed = B_TRUE;
6285 		}
6286 
6287 		(void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6288 		    &validation_failed);
6289 
6290 		if (validation_failed) {
6291 			saw_error = B_TRUE;
6292 			return;
6293 		}
6294 
6295 		if (end_op == CMD_ADD) {
6296 			/* Make sure there isn't already one like this. */
6297 			bzero(&tmp_fstab, sizeof (tmp_fstab));
6298 			(void) strlcpy(tmp_fstab.zone_fs_dir,
6299 			    in_progress_fstab.zone_fs_dir,
6300 			    sizeof (tmp_fstab.zone_fs_dir));
6301 			err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6302 			zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6303 			if (err == Z_OK) {
6304 				zerr(gettext("A %s resource "
6305 				    "with the %s '%s' already exists."),
6306 				    rt_to_str(RT_FS), pt_to_str(PT_DIR),
6307 				    in_progress_fstab.zone_fs_dir);
6308 				saw_error = B_TRUE;
6309 				return;
6310 			}
6311 			err = zonecfg_add_filesystem(handle,
6312 			    &in_progress_fstab);
6313 		} else {
6314 			err = zonecfg_modify_filesystem(handle, &old_fstab,
6315 			    &in_progress_fstab);
6316 		}
6317 		zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6318 		in_progress_fstab.zone_fs_options = NULL;
6319 		break;
6320 
6321 	case RT_IPD:
6322 		/* First make sure everything was filled in. */
6323 		if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR,
6324 		    &validation_failed) == Z_OK) {
6325 			if (in_progress_ipdtab.zone_fs_dir[0] != '/') {
6326 				zerr(gettext("%s %s is not an absolute path."),
6327 				    pt_to_str(PT_DIR),
6328 				    in_progress_ipdtab.zone_fs_dir);
6329 				validation_failed = B_TRUE;
6330 			}
6331 		}
6332 		if (validation_failed) {
6333 			saw_error = B_TRUE;
6334 			return;
6335 		}
6336 
6337 		if (end_op == CMD_ADD) {
6338 			/* Make sure there isn't already one like this. */
6339 			bzero(&tmp_fstab, sizeof (tmp_fstab));
6340 			(void) strlcpy(tmp_fstab.zone_fs_dir,
6341 			    in_progress_ipdtab.zone_fs_dir,
6342 			    sizeof (tmp_fstab.zone_fs_dir));
6343 			err = zonecfg_lookup_ipd(handle, &tmp_fstab);
6344 			if (err == Z_OK) {
6345 				zerr(gettext("An %s resource "
6346 				    "with the %s '%s' already exists."),
6347 				    rt_to_str(RT_IPD), pt_to_str(PT_DIR),
6348 				    in_progress_ipdtab.zone_fs_dir);
6349 				saw_error = B_TRUE;
6350 				return;
6351 			}
6352 			err = zonecfg_add_ipd(handle, &in_progress_ipdtab);
6353 		} else {
6354 			err = zonecfg_modify_ipd(handle, &old_ipdtab,
6355 			    &in_progress_ipdtab);
6356 		}
6357 		break;
6358 	case RT_NET:
6359 		/*
6360 		 * First make sure everything was filled in.
6361 		 * Since we don't know whether IP will be shared
6362 		 * or exclusive here, some checks are deferred until
6363 		 * the verify command.
6364 		 */
6365 		(void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6366 		    PT_PHYSICAL, &validation_failed);
6367 
6368 		if (validation_failed) {
6369 			saw_error = B_TRUE;
6370 			return;
6371 		}
6372 		if (end_op == CMD_ADD) {
6373 			/* Make sure there isn't already one like this. */
6374 			bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6375 			(void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6376 			    in_progress_nwiftab.zone_nwif_physical,
6377 			    sizeof (tmp_nwiftab.zone_nwif_physical));
6378 			(void) strlcpy(tmp_nwiftab.zone_nwif_address,
6379 			    in_progress_nwiftab.zone_nwif_address,
6380 			    sizeof (tmp_nwiftab.zone_nwif_address));
6381 			if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6382 				zerr(gettext("A %s resource with the %s '%s', "
6383 				    "and %s '%s' already exists."),
6384 				    rt_to_str(RT_NET),
6385 				    pt_to_str(PT_PHYSICAL),
6386 				    in_progress_nwiftab.zone_nwif_physical,
6387 				    pt_to_str(PT_ADDRESS),
6388 				    in_progress_nwiftab.zone_nwif_address);
6389 				saw_error = B_TRUE;
6390 				return;
6391 			}
6392 			err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6393 		} else {
6394 			err = zonecfg_modify_nwif(handle, &old_nwiftab,
6395 			    &in_progress_nwiftab);
6396 		}
6397 		break;
6398 
6399 	case RT_DEVICE:
6400 		/* First make sure everything was filled in. */
6401 		(void) end_check_reqd(in_progress_devtab.zone_dev_match,
6402 		    PT_MATCH, &validation_failed);
6403 
6404 		if (validation_failed) {
6405 			saw_error = B_TRUE;
6406 			return;
6407 		}
6408 
6409 		if (end_op == CMD_ADD) {
6410 			/* Make sure there isn't already one like this. */
6411 			(void) strlcpy(tmp_devtab.zone_dev_match,
6412 			    in_progress_devtab.zone_dev_match,
6413 			    sizeof (tmp_devtab.zone_dev_match));
6414 			if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6415 				zerr(gettext("A %s resource with the %s '%s' "
6416 				    "already exists."), rt_to_str(RT_DEVICE),
6417 				    pt_to_str(PT_MATCH),
6418 				    in_progress_devtab.zone_dev_match);
6419 				saw_error = B_TRUE;
6420 				return;
6421 			}
6422 			err = zonecfg_add_dev(handle, &in_progress_devtab);
6423 		} else {
6424 			err = zonecfg_modify_dev(handle, &old_devtab,
6425 			    &in_progress_devtab);
6426 		}
6427 		break;
6428 
6429 	case RT_RCTL:
6430 		/* First make sure everything was filled in. */
6431 		(void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6432 		    PT_NAME, &validation_failed);
6433 
6434 		if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6435 			zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6436 			validation_failed = B_TRUE;
6437 		}
6438 
6439 		if (validation_failed) {
6440 			saw_error = B_TRUE;
6441 			return;
6442 		}
6443 
6444 		if (end_op == CMD_ADD) {
6445 			/* Make sure there isn't already one like this. */
6446 			(void) strlcpy(tmp_rctltab.zone_rctl_name,
6447 			    in_progress_rctltab.zone_rctl_name,
6448 			    sizeof (tmp_rctltab.zone_rctl_name));
6449 			tmp_rctltab.zone_rctl_valptr = NULL;
6450 			err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6451 			zonecfg_free_rctl_value_list(
6452 			    tmp_rctltab.zone_rctl_valptr);
6453 			if (err == Z_OK) {
6454 				zerr(gettext("A %s resource "
6455 				    "with the %s '%s' already exists."),
6456 				    rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6457 				    in_progress_rctltab.zone_rctl_name);
6458 				saw_error = B_TRUE;
6459 				return;
6460 			}
6461 			err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6462 		} else {
6463 			err = zonecfg_modify_rctl(handle, &old_rctltab,
6464 			    &in_progress_rctltab);
6465 		}
6466 		if (err == Z_OK) {
6467 			zonecfg_free_rctl_value_list(
6468 			    in_progress_rctltab.zone_rctl_valptr);
6469 			in_progress_rctltab.zone_rctl_valptr = NULL;
6470 		}
6471 		break;
6472 
6473 	case RT_ATTR:
6474 		/* First make sure everything was filled in. */
6475 		(void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6476 		    PT_NAME, &validation_failed);
6477 		(void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6478 		    PT_TYPE, &validation_failed);
6479 		(void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6480 		    PT_VALUE, &validation_failed);
6481 
6482 		if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6483 		    Z_OK)
6484 			validation_failed = B_TRUE;
6485 
6486 		if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6487 			validation_failed = B_TRUE;
6488 
6489 		if (validation_failed) {
6490 			saw_error = B_TRUE;
6491 			return;
6492 		}
6493 		if (end_op == CMD_ADD) {
6494 			/* Make sure there isn't already one like this. */
6495 			bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6496 			(void) strlcpy(tmp_attrtab.zone_attr_name,
6497 			    in_progress_attrtab.zone_attr_name,
6498 			    sizeof (tmp_attrtab.zone_attr_name));
6499 			if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6500 				zerr(gettext("An %s resource "
6501 				    "with the %s '%s' already exists."),
6502 				    rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6503 				    in_progress_attrtab.zone_attr_name);
6504 				saw_error = B_TRUE;
6505 				return;
6506 			}
6507 			err = zonecfg_add_attr(handle, &in_progress_attrtab);
6508 		} else {
6509 			err = zonecfg_modify_attr(handle, &old_attrtab,
6510 			    &in_progress_attrtab);
6511 		}
6512 		break;
6513 	case RT_DATASET:
6514 		/* First make sure everything was filled in. */
6515 		if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6516 			zerr("%s %s", pt_to_str(PT_NAME),
6517 			    gettext("not specified"));
6518 			saw_error = B_TRUE;
6519 			validation_failed = B_TRUE;
6520 		}
6521 		if (validation_failed)
6522 			return;
6523 		if (end_op == CMD_ADD) {
6524 			/* Make sure there isn't already one like this. */
6525 			bzero(&tmp_dstab, sizeof (tmp_dstab));
6526 			(void) strlcpy(tmp_dstab.zone_dataset_name,
6527 			    in_progress_dstab.zone_dataset_name,
6528 			    sizeof (tmp_dstab.zone_dataset_name));
6529 			err = zonecfg_lookup_ds(handle, &tmp_dstab);
6530 			if (err == Z_OK) {
6531 				zerr(gettext("A %s resource "
6532 				    "with the %s '%s' already exists."),
6533 				    rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6534 				    in_progress_dstab.zone_dataset_name);
6535 				saw_error = B_TRUE;
6536 				return;
6537 			}
6538 			err = zonecfg_add_ds(handle, &in_progress_dstab);
6539 		} else {
6540 			err = zonecfg_modify_ds(handle, &old_dstab,
6541 			    &in_progress_dstab);
6542 		}
6543 		break;
6544 	case RT_DCPU:
6545 		/* Make sure everything was filled in. */
6546 		if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6547 		    PT_NCPUS, &validation_failed) != Z_OK) {
6548 			saw_error = B_TRUE;
6549 			return;
6550 		}
6551 
6552 		if (end_op == CMD_ADD) {
6553 			err = zonecfg_add_pset(handle, &in_progress_psettab);
6554 		} else {
6555 			err = zonecfg_modify_pset(handle, &in_progress_psettab);
6556 		}
6557 		break;
6558 	case RT_PCAP:
6559 		/* Make sure everything was filled in. */
6560 		if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6561 		    != Z_OK) {
6562 			zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6563 			saw_error = B_TRUE;
6564 			validation_failed = B_TRUE;
6565 			return;
6566 		}
6567 		err = Z_OK;
6568 		break;
6569 	case RT_MCAP:
6570 		/* Make sure everything was filled in. */
6571 		res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6572 		    Z_ERR : Z_OK;
6573 		res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6574 		    &swap_limit);
6575 		res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6576 		    &locked_limit);
6577 
6578 		if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6579 			zerr(gettext("No property was specified.  One of %s, "
6580 			    "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6581 			    pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6582 			saw_error = B_TRUE;
6583 			return;
6584 		}
6585 
6586 		/* if phys & locked are both set, verify locked <= phys */
6587 		if (res1 == Z_OK && res3 == Z_OK) {
6588 			uint64_t phys_limit;
6589 			char *endp;
6590 
6591 			phys_limit = strtoull(
6592 			    in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6593 			if (phys_limit < locked_limit) {
6594 				zerr(gettext("The %s cap must be less than or "
6595 				    "equal to the %s cap."),
6596 				    pt_to_str(PT_LOCKED),
6597 				    pt_to_str(PT_PHYSICAL));
6598 				saw_error = B_TRUE;
6599 				return;
6600 			}
6601 		}
6602 
6603 		err = Z_OK;
6604 		if (res1 == Z_OK) {
6605 			/*
6606 			 * We could be ending from either an add operation
6607 			 * or a select operation.  Since all of the properties
6608 			 * within this resource are optional, we always use
6609 			 * modify on the mcap entry.  zonecfg_modify_mcap()
6610 			 * will handle both adding and modifying a memory cap.
6611 			 */
6612 			err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6613 		} else if (end_op == CMD_SELECT) {
6614 			/*
6615 			 * If we're ending from a select and the physical
6616 			 * memory cap is empty then the user could have cleared
6617 			 * the physical cap value, so try to delete the entry.
6618 			 */
6619 			(void) zonecfg_delete_mcap(handle);
6620 		}
6621 		break;
6622 	case RT_ADMIN:
6623 		/* First make sure everything was filled in. */
6624 		if (end_check_reqd(in_progress_admintab.zone_admin_user,
6625 		    PT_USER, &validation_failed) == Z_OK) {
6626 			if (getpwnam(in_progress_admintab.zone_admin_user)
6627 			    == NULL) {
6628 				zerr(gettext("%s %s is not a valid username"),
6629 				    pt_to_str(PT_USER),
6630 				    in_progress_admintab.zone_admin_user);
6631 				validation_failed = B_TRUE;
6632 			}
6633 		}
6634 
6635 		if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6636 		    PT_AUTHS, &validation_failed) == Z_OK) {
6637 			if (!zonecfg_valid_auths(
6638 			    in_progress_admintab.zone_admin_auths,
6639 			    zone)) {
6640 				validation_failed = B_TRUE;
6641 			}
6642 		}
6643 
6644 		if (validation_failed) {
6645 			saw_error = B_TRUE;
6646 			return;
6647 		}
6648 
6649 		if (end_op == CMD_ADD) {
6650 			/* Make sure there isn't already one like this. */
6651 			bzero(&tmp_admintab, sizeof (tmp_admintab));
6652 			(void) strlcpy(tmp_admintab.zone_admin_user,
6653 			    in_progress_admintab.zone_admin_user,
6654 			    sizeof (tmp_admintab.zone_admin_user));
6655 			err = zonecfg_lookup_admin(
6656 			    handle, &tmp_admintab);
6657 			if (err == Z_OK) {
6658 				zerr(gettext("A %s resource "
6659 				    "with the %s '%s' already exists."),
6660 				    rt_to_str(RT_ADMIN),
6661 				    pt_to_str(PT_USER),
6662 				    in_progress_admintab.zone_admin_user);
6663 				saw_error = B_TRUE;
6664 				return;
6665 			}
6666 			err = zonecfg_add_admin(handle,
6667 			    &in_progress_admintab, zone);
6668 		} else {
6669 			err = zonecfg_modify_admin(handle,
6670 			    &old_admintab, &in_progress_admintab,
6671 			    zone);
6672 		}
6673 		break;
6674 	default:
6675 		zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
6676 		    B_TRUE);
6677 		saw_error = B_TRUE;
6678 		return;
6679 	}
6680 
6681 	if (err != Z_OK) {
6682 		zone_perror(zone, err, B_TRUE);
6683 	} else {
6684 		need_to_commit = B_TRUE;
6685 		global_scope = B_TRUE;
6686 		end_op = -1;
6687 	}
6688 }
6689 
6690 void
6691 commit_func(cmd_t *cmd)
6692 {
6693 	int arg;
6694 	boolean_t arg_err = B_FALSE;
6695 
6696 	optind = 0;
6697 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6698 		switch (arg) {
6699 		case '?':
6700 			longer_usage(CMD_COMMIT);
6701 			arg_err = B_TRUE;
6702 			break;
6703 		default:
6704 			short_usage(CMD_COMMIT);
6705 			arg_err = B_TRUE;
6706 			break;
6707 		}
6708 	}
6709 	if (arg_err)
6710 		return;
6711 
6712 	if (optind != cmd->cmd_argc) {
6713 		short_usage(CMD_COMMIT);
6714 		return;
6715 	}
6716 
6717 	if (zone_is_read_only(CMD_COMMIT))
6718 		return;
6719 
6720 	assert(cmd != NULL);
6721 
6722 	cmd->cmd_argc = 1;
6723 	/*
6724 	 * cmd_arg normally comes from a strdup() in the lexer, and the
6725 	 * whole cmd structure and its (char *) attributes are freed at
6726 	 * the completion of each command, so the strdup() below is needed
6727 	 * to match this and prevent a core dump from trying to free()
6728 	 * something that can't be.
6729 	 */
6730 	if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
6731 		zone_perror(zone, Z_NOMEM, B_TRUE);
6732 		exit(Z_ERR);
6733 	}
6734 	cmd->cmd_argv[1] = NULL;
6735 	verify_func(cmd);
6736 }
6737 
6738 void
6739 revert_func(cmd_t *cmd)
6740 {
6741 	char line[128];	/* enough to ask a question */
6742 	boolean_t force = B_FALSE;
6743 	boolean_t arg_err = B_FALSE;
6744 	int err, arg, answer;
6745 
6746 	optind = 0;
6747 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
6748 		switch (arg) {
6749 		case '?':
6750 			longer_usage(CMD_REVERT);
6751 			arg_err = B_TRUE;
6752 			break;
6753 		case 'F':
6754 			force = B_TRUE;
6755 			break;
6756 		default:
6757 			short_usage(CMD_REVERT);
6758 			arg_err = B_TRUE;
6759 			break;
6760 		}
6761 	}
6762 	if (arg_err)
6763 		return;
6764 
6765 	if (optind != cmd->cmd_argc) {
6766 		short_usage(CMD_REVERT);
6767 		return;
6768 	}
6769 
6770 	if (zone_is_read_only(CMD_REVERT))
6771 		return;
6772 
6773 	if (!global_scope) {
6774 		zerr(gettext("You can only use %s in the global scope.\nUse"
6775 		    " '%s' to cancel changes to a resource specification."),
6776 		    cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
6777 		saw_error = B_TRUE;
6778 		return;
6779 	}
6780 
6781 	if (zonecfg_check_handle(handle) != Z_OK) {
6782 		zerr(gettext("No changes to revert."));
6783 		saw_error = B_TRUE;
6784 		return;
6785 	}
6786 
6787 	if (!force) {
6788 		(void) snprintf(line, sizeof (line),
6789 		    gettext("Are you sure you want to revert"));
6790 		if ((answer = ask_yesno(B_FALSE, line)) == -1) {
6791 			zerr(gettext("Input not from terminal and -F not "
6792 			    "specified:\n%s command ignored, exiting."),
6793 			    cmd_to_str(CMD_REVERT));
6794 			exit(Z_ERR);
6795 		}
6796 		if (answer != 1)
6797 			return;
6798 	}
6799 
6800 	/*
6801 	 * Reset any pending admins that were
6802 	 * removed from the previous zone
6803 	 */
6804 	zonecfg_remove_userauths(handle, "", zone, B_FALSE);
6805 
6806 	/*
6807 	 * Time for a new handle: finish the old one off first
6808 	 * then get a new one properly to avoid leaks.
6809 	 */
6810 	zonecfg_fini_handle(handle);
6811 	if ((handle = zonecfg_init_handle()) == NULL) {
6812 		zone_perror(execname, Z_NOMEM, B_TRUE);
6813 		exit(Z_ERR);
6814 	}
6815 
6816 	if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
6817 		saw_error = B_TRUE;
6818 		got_handle = B_FALSE;
6819 		if (err == Z_NO_ZONE)
6820 			zerr(gettext("%s: no such saved zone to revert to."),
6821 			    revert_zone);
6822 		else
6823 			zone_perror(zone, err, B_TRUE);
6824 	}
6825 	(void) strlcpy(zone, revert_zone, sizeof (zone));
6826 }
6827 
6828 void
6829 help_func(cmd_t *cmd)
6830 {
6831 	int i;
6832 
6833 	assert(cmd != NULL);
6834 
6835 	if (cmd->cmd_argc == 0) {
6836 		usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
6837 		return;
6838 	}
6839 	if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
6840 		usage(B_TRUE, HELP_USAGE);
6841 		return;
6842 	}
6843 	if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
6844 		usage(B_TRUE, HELP_SUBCMDS);
6845 		return;
6846 	}
6847 	if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
6848 		usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
6849 		return;
6850 	}
6851 	if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
6852 		longer_usage(CMD_HELP);
6853 		return;
6854 	}
6855 
6856 	for (i = 0; i <= CMD_MAX; i++) {
6857 		if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
6858 			longer_usage(i);
6859 			return;
6860 		}
6861 	}
6862 	/* We do not use zerr() here because we do not want its extra \n. */
6863 	(void) fprintf(stderr, gettext("Unknown help subject %s.  "),
6864 	    cmd->cmd_argv[0]);
6865 	usage(B_FALSE, HELP_META);
6866 }
6867 
6868 static int
6869 string_to_yyin(char *string)
6870 {
6871 	if ((yyin = tmpfile()) == NULL) {
6872 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6873 		return (Z_ERR);
6874 	}
6875 	if (fwrite(string, strlen(string), 1, yyin) != 1) {
6876 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6877 		return (Z_ERR);
6878 	}
6879 	if (fseek(yyin, 0, SEEK_SET) != 0) {
6880 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6881 		return (Z_ERR);
6882 	}
6883 	return (Z_OK);
6884 }
6885 
6886 /* This is the back-end helper function for read_input() below. */
6887 
6888 static int
6889 cleanup()
6890 {
6891 	int answer;
6892 	cmd_t *cmd;
6893 
6894 	if (!interactive_mode && !cmd_file_mode) {
6895 		/*
6896 		 * If we're not in interactive mode, and we're not in command
6897 		 * file mode, then we must be in commands-from-the-command-line
6898 		 * mode.  As such, we can't loop back and ask for more input.
6899 		 * It was OK to prompt for such things as whether or not to
6900 		 * really delete a zone in the command handler called from
6901 		 * yyparse() above, but "really quit?" makes no sense in this
6902 		 * context.  So disable prompting.
6903 		 */
6904 		ok_to_prompt = B_FALSE;
6905 	}
6906 	if (!global_scope) {
6907 		if (!time_to_exit) {
6908 			/*
6909 			 * Just print a simple error message in the -1 case,
6910 			 * since exit_func() already handles that case, and
6911 			 * EOF means we are finished anyway.
6912 			 */
6913 			answer = ask_yesno(B_FALSE,
6914 			    gettext("Resource incomplete; really quit"));
6915 			if (answer == -1) {
6916 				zerr(gettext("Resource incomplete."));
6917 				return (Z_ERR);
6918 			}
6919 			if (answer != 1) {
6920 				yyin = stdin;
6921 				return (Z_REPEAT);
6922 			}
6923 		} else {
6924 			saw_error = B_TRUE;
6925 		}
6926 	}
6927 	/*
6928 	 * Make sure we tried something and that the handle checks
6929 	 * out, or we would get a false error trying to commit.
6930 	 */
6931 	if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
6932 		if ((cmd = alloc_cmd()) == NULL) {
6933 			zone_perror(zone, Z_NOMEM, B_TRUE);
6934 			return (Z_ERR);
6935 		}
6936 		cmd->cmd_argc = 0;
6937 		cmd->cmd_argv[0] = NULL;
6938 		commit_func(cmd);
6939 		free_cmd(cmd);
6940 		/*
6941 		 * need_to_commit will get set back to FALSE if the
6942 		 * configuration is saved successfully.
6943 		 */
6944 		if (need_to_commit) {
6945 			if (force_exit) {
6946 				zerr(gettext("Configuration not saved."));
6947 				return (Z_ERR);
6948 			}
6949 			answer = ask_yesno(B_FALSE,
6950 			    gettext("Configuration not saved; really quit"));
6951 			if (answer == -1) {
6952 				zerr(gettext("Configuration not saved."));
6953 				return (Z_ERR);
6954 			}
6955 			if (answer != 1) {
6956 				time_to_exit = B_FALSE;
6957 				yyin = stdin;
6958 				return (Z_REPEAT);
6959 			}
6960 		}
6961 	}
6962 	return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
6963 }
6964 
6965 /*
6966  * read_input() is the driver of this program.  It is a wrapper around
6967  * yyparse(), printing appropriate prompts when needed, checking for
6968  * exit conditions and reacting appropriately [the latter in its cleanup()
6969  * helper function].
6970  *
6971  * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
6972  * so do_interactive() knows that we are not really done (i.e, we asked
6973  * the user if we should really quit and the user said no).
6974  */
6975 static int
6976 read_input()
6977 {
6978 	boolean_t yyin_is_a_tty = isatty(fileno(yyin));
6979 	/*
6980 	 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
6981 	 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
6982 	 */
6983 	char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
6984 
6985 	/* yyin should have been set to the appropriate (FILE *) if not stdin */
6986 	newline_terminated = B_TRUE;
6987 	for (;;) {
6988 		if (yyin_is_a_tty) {
6989 			if (newline_terminated) {
6990 				if (global_scope)
6991 					(void) snprintf(prompt, sizeof (prompt),
6992 					    "%s:%s> ", execname, zone);
6993 				else
6994 					(void) snprintf(prompt, sizeof (prompt),
6995 					    "%s:%s:%s> ", execname, zone,
6996 					    rt_to_str(resource_scope));
6997 			}
6998 			/*
6999 			 * If the user hits ^C then we want to catch it and
7000 			 * start over.  If the user hits EOF then we want to
7001 			 * bail out.
7002 			 */
7003 			line = gl_get_line(gl, prompt, NULL, -1);
7004 			if (gl_return_status(gl) == GLR_SIGNAL) {
7005 				gl_abandon_line(gl);
7006 				continue;
7007 			}
7008 			if (line == NULL)
7009 				break;
7010 			(void) string_to_yyin(line);
7011 			while (!feof(yyin))
7012 				yyparse();
7013 		} else {
7014 			yyparse();
7015 		}
7016 		/* Bail out on an error in command file mode. */
7017 		if (saw_error && cmd_file_mode && !interactive_mode)
7018 			time_to_exit = B_TRUE;
7019 		if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7020 			break;
7021 	}
7022 	return (cleanup());
7023 }
7024 
7025 /*
7026  * This function is used in the zonecfg-interactive-mode scenario: it just
7027  * calls read_input() until we are done.
7028  */
7029 
7030 static int
7031 do_interactive(void)
7032 {
7033 	int err;
7034 
7035 	interactive_mode = B_TRUE;
7036 	if (!read_only_mode) {
7037 		/*
7038 		 * Try to set things up proactively in interactive mode, so
7039 		 * that if the zone in question does not exist yet, we can
7040 		 * provide the user with a clue.
7041 		 */
7042 		(void) initialize(B_FALSE);
7043 	}
7044 	do {
7045 		err = read_input();
7046 	} while (err == Z_REPEAT);
7047 	return (err);
7048 }
7049 
7050 /*
7051  * cmd_file is slightly more complicated, as it has to open the command file
7052  * and set yyin appropriately.  Once that is done, though, it just calls
7053  * read_input(), and only once, since prompting is not possible.
7054  */
7055 
7056 static int
7057 cmd_file(char *file)
7058 {
7059 	FILE *infile;
7060 	int err;
7061 	struct stat statbuf;
7062 	boolean_t using_real_file = (strcmp(file, "-") != 0);
7063 
7064 	if (using_real_file) {
7065 		/*
7066 		 * zerr() prints a line number in cmd_file_mode, which we do
7067 		 * not want here, so temporarily unset it.
7068 		 */
7069 		cmd_file_mode = B_FALSE;
7070 		if ((infile = fopen(file, "r")) == NULL) {
7071 			zerr(gettext("could not open file %s: %s"),
7072 			    file, strerror(errno));
7073 			return (Z_ERR);
7074 		}
7075 		if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7076 			zerr(gettext("could not stat file %s: %s"),
7077 			    file, strerror(errno));
7078 			err = Z_ERR;
7079 			goto done;
7080 		}
7081 		if (!S_ISREG(statbuf.st_mode)) {
7082 			zerr(gettext("%s is not a regular file."), file);
7083 			err = Z_ERR;
7084 			goto done;
7085 		}
7086 		yyin = infile;
7087 		cmd_file_mode = B_TRUE;
7088 		ok_to_prompt = B_FALSE;
7089 	} else {
7090 		/*
7091 		 * "-f -" is essentially the same as interactive mode,
7092 		 * so treat it that way.
7093 		 */
7094 		interactive_mode = B_TRUE;
7095 	}
7096 	/* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7097 	if ((err = read_input()) == Z_REPEAT)
7098 		err = Z_ERR;
7099 done:
7100 	if (using_real_file)
7101 		(void) fclose(infile);
7102 	return (err);
7103 }
7104 
7105 /*
7106  * Since yacc is based on reading from a (FILE *) whereas what we get from
7107  * the command line is in argv format, we need to convert when the user
7108  * gives us commands directly from the command line.  That is done here by
7109  * concatenating the argv list into a space-separated string, writing it
7110  * to a temp file, and rewinding the file so yyin can be set to it.  Then
7111  * we call read_input(), and only once, since prompting about whether to
7112  * continue or quit would make no sense in this context.
7113  */
7114 
7115 static int
7116 one_command_at_a_time(int argc, char *argv[])
7117 {
7118 	char *command;
7119 	size_t len = 2; /* terminal \n\0 */
7120 	int i, err;
7121 
7122 	for (i = 0; i < argc; i++)
7123 		len += strlen(argv[i]) + 1;
7124 	if ((command = malloc(len)) == NULL) {
7125 		zone_perror(execname, Z_NOMEM, B_TRUE);
7126 		return (Z_ERR);
7127 	}
7128 	(void) strlcpy(command, argv[0], len);
7129 	for (i = 1; i < argc; i++) {
7130 		(void) strlcat(command, " ", len);
7131 		(void) strlcat(command, argv[i], len);
7132 	}
7133 	(void) strlcat(command, "\n", len);
7134 	err = string_to_yyin(command);
7135 	free(command);
7136 	if (err != Z_OK)
7137 		return (err);
7138 	while (!feof(yyin))
7139 		yyparse();
7140 	return (cleanup());
7141 }
7142 
7143 static char *
7144 get_execbasename(char *execfullname)
7145 {
7146 	char *last_slash, *execbasename;
7147 
7148 	/* guard against '/' at end of command invocation */
7149 	for (;;) {
7150 		last_slash = strrchr(execfullname, '/');
7151 		if (last_slash == NULL) {
7152 			execbasename = execfullname;
7153 			break;
7154 		} else {
7155 			execbasename = last_slash + 1;
7156 			if (*execbasename == '\0') {
7157 				*last_slash = '\0';
7158 				continue;
7159 			}
7160 			break;
7161 		}
7162 	}
7163 	return (execbasename);
7164 }
7165 
7166 int
7167 main(int argc, char *argv[])
7168 {
7169 	int err, arg;
7170 	struct stat st;
7171 
7172 	/* This must be before anything goes to stdout. */
7173 	setbuf(stdout, NULL);
7174 
7175 	saw_error = B_FALSE;
7176 	cmd_file_mode = B_FALSE;
7177 	execname = get_execbasename(argv[0]);
7178 
7179 	(void) setlocale(LC_ALL, "");
7180 	(void) textdomain(TEXT_DOMAIN);
7181 
7182 	if (getzoneid() != GLOBAL_ZONEID) {
7183 		zerr(gettext("%s can only be run from the global zone."),
7184 		    execname);
7185 		exit(Z_ERR);
7186 	}
7187 
7188 	if (argc < 2) {
7189 		usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7190 		exit(Z_USAGE);
7191 	}
7192 	if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7193 		(void) one_command_at_a_time(argc - 1, &(argv[1]));
7194 		exit(Z_OK);
7195 	}
7196 
7197 	while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7198 		switch (arg) {
7199 		case '?':
7200 			if (optopt == '?')
7201 				usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7202 			else
7203 				usage(B_FALSE, HELP_USAGE);
7204 			exit(Z_USAGE);
7205 			/* NOTREACHED */
7206 		case 'f':
7207 			cmd_file_name = optarg;
7208 			cmd_file_mode = B_TRUE;
7209 			break;
7210 		case 'R':
7211 			if (*optarg != '/') {
7212 				zerr(gettext("root path must be absolute: %s"),
7213 				    optarg);
7214 				exit(Z_USAGE);
7215 			}
7216 			if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7217 				zerr(gettext(
7218 				    "root path must be a directory: %s"),
7219 				    optarg);
7220 				exit(Z_USAGE);
7221 			}
7222 			zonecfg_set_root(optarg);
7223 			break;
7224 		case 'z':
7225 			if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7226 				global_zone = B_TRUE;
7227 			} else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7228 				zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7229 				usage(B_FALSE, HELP_SYNTAX);
7230 				exit(Z_USAGE);
7231 			}
7232 			(void) strlcpy(zone, optarg, sizeof (zone));
7233 			(void) strlcpy(revert_zone, optarg, sizeof (zone));
7234 			break;
7235 		default:
7236 			usage(B_FALSE, HELP_USAGE);
7237 			exit(Z_USAGE);
7238 		}
7239 	}
7240 
7241 	if (optind > argc || strcmp(zone, "") == 0) {
7242 		usage(B_FALSE, HELP_USAGE);
7243 		exit(Z_USAGE);
7244 	}
7245 
7246 	if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7247 		read_only_mode = B_FALSE;
7248 	} else if (err == Z_ACCES) {
7249 		read_only_mode = B_TRUE;
7250 		/* skip this message in one-off from command line mode */
7251 		if (optind == argc)
7252 			(void) fprintf(stderr, gettext("WARNING: you do not "
7253 			    "have write access to this zone's configuration "
7254 			    "file;\ngoing into read-only mode.\n"));
7255 	} else {
7256 		fprintf(stderr, "%s: Could not access zone configuration "
7257 		    "store: %s\n", execname, zonecfg_strerror(err));
7258 		exit(Z_ERR);
7259 	}
7260 
7261 	if ((handle = zonecfg_init_handle()) == NULL) {
7262 		zone_perror(execname, Z_NOMEM, B_TRUE);
7263 		exit(Z_ERR);
7264 	}
7265 
7266 	/*
7267 	 * This may get set back to FALSE again in cmd_file() if cmd_file_name
7268 	 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7269 	 */
7270 	if (isatty(STDIN_FILENO))
7271 		ok_to_prompt = B_TRUE;
7272 	if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7273 		exit(Z_ERR);
7274 	if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7275 		exit(Z_ERR);
7276 	(void) sigset(SIGINT, SIG_IGN);
7277 	if (optind == argc) {
7278 		if (!cmd_file_mode)
7279 			err = do_interactive();
7280 		else
7281 			err = cmd_file(cmd_file_name);
7282 	} else {
7283 		err = one_command_at_a_time(argc - optind, &(argv[optind]));
7284 	}
7285 	zonecfg_fini_handle(handle);
7286 	if (brand != NULL)
7287 		brand_close(brand);
7288 	(void) del_GetLine(gl);
7289 	return (err);
7290 }
7291