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