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