xref: /titanic_41/usr/src/cmd/zonecfg/zonecfg.c (revision 3afe87ebb25691cb6d158edaa34a6fb9b703a691)
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 
3740 	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
3741 		zerr(gettext("zone configuration has an invalid or nonexistent "
3742 		    "ip-type property"));
3743 		return (Z_ERR);
3744 	}
3745 	switch (iptype) {
3746 	case ZS_SHARED:
3747 		if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
3748 			zerr(gettext("%s: invalid physical interface name"),
3749 			    ifname);
3750 			return (Z_ERR);
3751 		}
3752 		if (ifnameprop.ifsp_lunvalid) {
3753 			zerr(gettext("%s: LUNs not allowed in physical "
3754 			    "interface names"), ifname);
3755 			return (Z_ERR);
3756 		}
3757 		break;
3758 	case ZS_EXCLUSIVE:
3759 		if (dladm_valid_linkname(ifname) == B_FALSE) {
3760 			if (strchr(ifname, ':') != NULL)
3761 				zerr(gettext("%s: physical interface name "
3762 				    "required; logical interface name not "
3763 				    "allowed"), ifname);
3764 			else
3765 				zerr(gettext("%s: invalid physical interface "
3766 				    "name"), ifname);
3767 			return (Z_ERR);
3768 		}
3769 		break;
3770 	}
3771 	return (Z_OK);
3772 }
3773 
3774 static boolean_t
3775 valid_fs_type(const char *type)
3776 {
3777 	/*
3778 	 * Is this a valid path component?
3779 	 */
3780 	if (strlen(type) + 1 > MAXNAMELEN)
3781 		return (B_FALSE);
3782 	/*
3783 	 * Make sure a bad value for "type" doesn't make
3784 	 * /usr/lib/fs/<type>/mount turn into something else.
3785 	 */
3786 	if (strchr(type, '/') != NULL || type[0] == '\0' ||
3787 	    strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
3788 		return (B_FALSE);
3789 	/*
3790 	 * More detailed verification happens later by zoneadm(1m).
3791 	 */
3792 	return (B_TRUE);
3793 }
3794 
3795 static boolean_t
3796 allow_exclusive()
3797 {
3798 	brand_handle_t	bh;
3799 	char		brand[MAXNAMELEN];
3800 	boolean_t	ret;
3801 
3802 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
3803 		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
3804 		return (B_FALSE);
3805 	}
3806 	if ((bh = brand_open(brand)) == NULL) {
3807 		zerr("%s: %s\n", zone, gettext("unknown brand."));
3808 		return (B_FALSE);
3809 	}
3810 	ret = brand_allow_exclusive_ip(bh);
3811 	brand_close(bh);
3812 	if (!ret)
3813 		zerr(gettext("%s cannot be '%s' when %s is '%s'."),
3814 		    pt_to_str(PT_IPTYPE), "exclusive",
3815 		    pt_to_str(PT_BRAND), brand);
3816 	return (ret);
3817 }
3818 
3819 static void
3820 set_aliased_rctl(char *alias, int prop_type, char *s)
3821 {
3822 	uint64_t limit;
3823 	int err;
3824 	char tmp[128];
3825 
3826 	if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
3827 		zerr(gettext("WARNING: Setting a global zone resource "
3828 		    "control too low could deny\nservice "
3829 		    "to even the root user; "
3830 		    "this could render the system impossible\n"
3831 		    "to administer.  Please use caution."));
3832 
3833 	/* convert memory based properties */
3834 	if (prop_type == PT_MAXSHMMEM) {
3835 		if (!zonecfg_valid_memlimit(s, &limit)) {
3836 			zerr(gettext("A non-negative number with a required "
3837 			    "scale suffix (K, M, G or T) was expected\nhere."));
3838 			saw_error = B_TRUE;
3839 			return;
3840 		}
3841 
3842 		(void) snprintf(tmp, sizeof (tmp), "%llu", limit);
3843 		s = tmp;
3844 	}
3845 
3846 	if (!zonecfg_aliased_rctl_ok(handle, alias)) {
3847 		zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
3848 		saw_error = B_TRUE;
3849 	} else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
3850 		zerr(gettext("%s property is out of range."),
3851 		    pt_to_str(prop_type));
3852 		saw_error = B_TRUE;
3853 	} else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
3854 	    != Z_OK) {
3855 		zone_perror(zone, err, B_TRUE);
3856 		saw_error = B_TRUE;
3857 	} else {
3858 		need_to_commit = B_TRUE;
3859 	}
3860 }
3861 
3862 void
3863 set_func(cmd_t *cmd)
3864 {
3865 	char *prop_id;
3866 	int arg, err, res_type, prop_type;
3867 	property_value_ptr_t pp;
3868 	boolean_t autoboot;
3869 	zone_iptype_t iptype;
3870 	boolean_t force_set = B_FALSE;
3871 	size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
3872 	uint64_t mem_cap, mem_limit;
3873 	float cap;
3874 	char *unitp;
3875 	struct zone_psettab tmp_psettab;
3876 	boolean_t arg_err = B_FALSE;
3877 
3878 	if (zone_is_read_only(CMD_SET))
3879 		return;
3880 
3881 	assert(cmd != NULL);
3882 
3883 	optind = opterr = 0;
3884 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3885 		switch (arg) {
3886 		case 'F':
3887 			force_set = B_TRUE;
3888 			break;
3889 		default:
3890 			if (optopt == '?')
3891 				longer_usage(CMD_SET);
3892 			else
3893 				short_usage(CMD_SET);
3894 			arg_err = B_TRUE;
3895 			break;
3896 		}
3897 	}
3898 	if (arg_err)
3899 		return;
3900 
3901 	prop_type = cmd->cmd_prop_name[0];
3902 	if (global_scope) {
3903 		if (gz_invalid_property(prop_type)) {
3904 			zerr(gettext("%s is not a valid property for the "
3905 			    "global zone."), pt_to_str(prop_type));
3906 			saw_error = B_TRUE;
3907 			return;
3908 		}
3909 
3910 		if (prop_type == PT_ZONENAME) {
3911 			res_type = RT_ZONENAME;
3912 		} else if (prop_type == PT_ZONEPATH) {
3913 			res_type = RT_ZONEPATH;
3914 		} else if (prop_type == PT_AUTOBOOT) {
3915 			res_type = RT_AUTOBOOT;
3916 		} else if (prop_type == PT_BRAND) {
3917 			res_type = RT_BRAND;
3918 		} else if (prop_type == PT_POOL) {
3919 			res_type = RT_POOL;
3920 		} else if (prop_type == PT_LIMITPRIV) {
3921 			res_type = RT_LIMITPRIV;
3922 		} else if (prop_type == PT_BOOTARGS) {
3923 			res_type = RT_BOOTARGS;
3924 		} else if (prop_type == PT_SCHED) {
3925 			res_type = RT_SCHED;
3926 		} else if (prop_type == PT_IPTYPE) {
3927 			res_type = RT_IPTYPE;
3928 		} else if (prop_type == PT_MAXLWPS) {
3929 			res_type = RT_MAXLWPS;
3930 		} else if (prop_type == PT_MAXSHMMEM) {
3931 			res_type = RT_MAXSHMMEM;
3932 		} else if (prop_type == PT_MAXSHMIDS) {
3933 			res_type = RT_MAXSHMIDS;
3934 		} else if (prop_type == PT_MAXMSGIDS) {
3935 			res_type = RT_MAXMSGIDS;
3936 		} else if (prop_type == PT_MAXSEMIDS) {
3937 			res_type = RT_MAXSEMIDS;
3938 		} else if (prop_type == PT_SHARES) {
3939 			res_type = RT_SHARES;
3940 		} else {
3941 			zerr(gettext("Cannot set a resource-specific property "
3942 			    "from the global scope."));
3943 			saw_error = B_TRUE;
3944 			return;
3945 		}
3946 	} else {
3947 		res_type = resource_scope;
3948 	}
3949 
3950 	if (force_set) {
3951 		if (res_type != RT_ZONEPATH) {
3952 			zerr(gettext("Only zonepath setting can be forced."));
3953 			saw_error = B_TRUE;
3954 			return;
3955 		}
3956 		if (!zonecfg_in_alt_root()) {
3957 			zerr(gettext("Zonepath is changeable only in an "
3958 			    "alternate root."));
3959 			saw_error = B_TRUE;
3960 			return;
3961 		}
3962 	}
3963 
3964 	pp = cmd->cmd_property_ptr[0];
3965 	/*
3966 	 * A nasty expression but not that complicated:
3967 	 * 1. fs options are simple or list (tested below)
3968 	 * 2. rctl value's are complex or list (tested below)
3969 	 * Anything else should be simple.
3970 	 */
3971 	if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
3972 	    !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
3973 	    (pp->pv_type != PROP_VAL_SIMPLE ||
3974 	    (prop_id = pp->pv_simple) == NULL)) {
3975 		zerr(gettext("A %s value was expected here."),
3976 		    pvt_to_str(PROP_VAL_SIMPLE));
3977 		saw_error = B_TRUE;
3978 		return;
3979 	}
3980 	if (prop_type == PT_UNKNOWN) {
3981 		long_usage(CMD_SET, B_TRUE);
3982 		return;
3983 	}
3984 
3985 	/*
3986 	 * Special case: the user can change the zone name prior to 'create';
3987 	 * if the zone already exists, we fall through letting initialize()
3988 	 * and the rest of the logic run.
3989 	 */
3990 	if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
3991 	    !state_atleast(ZONE_STATE_CONFIGURED)) {
3992 		if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
3993 			zone_perror(prop_id, err, B_TRUE);
3994 			usage(B_FALSE, HELP_SYNTAX);
3995 			return;
3996 		}
3997 		(void) strlcpy(zone, prop_id, sizeof (zone));
3998 		return;
3999 	}
4000 
4001 	if (initialize(B_TRUE) != Z_OK)
4002 		return;
4003 
4004 	switch (res_type) {
4005 	case RT_ZONENAME:
4006 		if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4007 			/*
4008 			 * Use prop_id instead of 'zone' here, since we're
4009 			 * reporting a problem about the *new* zonename.
4010 			 */
4011 			zone_perror(prop_id, err, B_TRUE);
4012 			usage(B_FALSE, HELP_SYNTAX);
4013 		} else {
4014 			need_to_commit = B_TRUE;
4015 			(void) strlcpy(zone, prop_id, sizeof (zone));
4016 		}
4017 		return;
4018 	case RT_ZONEPATH:
4019 		if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4020 			zerr(gettext("Zone %s already installed; %s %s not "
4021 			    "allowed."), zone, cmd_to_str(CMD_SET),
4022 			    rt_to_str(RT_ZONEPATH));
4023 			return;
4024 		}
4025 		if (validate_zonepath_syntax(prop_id) != Z_OK) {
4026 			saw_error = B_TRUE;
4027 			return;
4028 		}
4029 		if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4030 			zone_perror(zone, err, B_TRUE);
4031 		else
4032 			need_to_commit = B_TRUE;
4033 		return;
4034 	case RT_BRAND:
4035 		if (state_atleast(ZONE_STATE_INSTALLED)) {
4036 			zerr(gettext("Zone %s already installed; %s %s not "
4037 			    "allowed."), zone, cmd_to_str(CMD_SET),
4038 			    rt_to_str(RT_BRAND));
4039 			return;
4040 		}
4041 		if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4042 			zone_perror(zone, err, B_TRUE);
4043 		else
4044 			need_to_commit = B_TRUE;
4045 		return;
4046 	case RT_AUTOBOOT:
4047 		if (strcmp(prop_id, "true") == 0) {
4048 			autoboot = B_TRUE;
4049 		} else if (strcmp(prop_id, "false") == 0) {
4050 			autoboot = B_FALSE;
4051 		} else {
4052 			zerr(gettext("%s value must be '%s' or '%s'."),
4053 			    pt_to_str(PT_AUTOBOOT), "true", "false");
4054 			saw_error = B_TRUE;
4055 			return;
4056 		}
4057 		if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4058 			zone_perror(zone, err, B_TRUE);
4059 		else
4060 			need_to_commit = B_TRUE;
4061 		return;
4062 	case RT_POOL:
4063 		/* don't allow use of the reserved temporary pool names */
4064 		if (strncmp("SUNW", prop_id, 4) == 0) {
4065 			zerr(gettext("pool names starting with SUNW are "
4066 			    "reserved."));
4067 			saw_error = B_TRUE;
4068 			return;
4069 		}
4070 
4071 		/* can't set pool if dedicated-cpu exists */
4072 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4073 			zerr(gettext("The %s resource already exists.  "
4074 			    "A persistent pool is incompatible\nwith the %s "
4075 			    "resource."), rt_to_str(RT_DCPU),
4076 			    rt_to_str(RT_DCPU));
4077 			saw_error = B_TRUE;
4078 			return;
4079 		}
4080 
4081 		if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4082 			zone_perror(zone, err, B_TRUE);
4083 		else
4084 			need_to_commit = B_TRUE;
4085 		return;
4086 	case RT_LIMITPRIV:
4087 		if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4088 			zone_perror(zone, err, B_TRUE);
4089 		else
4090 			need_to_commit = B_TRUE;
4091 		return;
4092 	case RT_BOOTARGS:
4093 		if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4094 			zone_perror(zone, err, B_TRUE);
4095 		else
4096 			need_to_commit = B_TRUE;
4097 		return;
4098 	case RT_SCHED:
4099 		if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4100 			zone_perror(zone, err, B_TRUE);
4101 		else
4102 			need_to_commit = B_TRUE;
4103 		return;
4104 	case RT_IPTYPE:
4105 		if (strcmp(prop_id, "shared") == 0) {
4106 			iptype = ZS_SHARED;
4107 		} else if (strcmp(prop_id, "exclusive") == 0) {
4108 			iptype = ZS_EXCLUSIVE;
4109 		} else {
4110 			zerr(gettext("%s value must be '%s' or '%s'."),
4111 			    pt_to_str(PT_IPTYPE), "shared", "exclusive");
4112 			saw_error = B_TRUE;
4113 			return;
4114 		}
4115 		if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4116 			saw_error = B_TRUE;
4117 			return;
4118 		}
4119 		if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4120 			zone_perror(zone, err, B_TRUE);
4121 		else
4122 			need_to_commit = B_TRUE;
4123 		return;
4124 	case RT_MAXLWPS:
4125 		set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4126 		return;
4127 	case RT_MAXSHMMEM:
4128 		set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4129 		return;
4130 	case RT_MAXSHMIDS:
4131 		set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4132 		return;
4133 	case RT_MAXMSGIDS:
4134 		set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4135 		return;
4136 	case RT_MAXSEMIDS:
4137 		set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4138 		return;
4139 	case RT_SHARES:
4140 		set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4141 		return;
4142 	case RT_FS:
4143 		switch (prop_type) {
4144 		case PT_DIR:
4145 			(void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4146 			    sizeof (in_progress_fstab.zone_fs_dir));
4147 			return;
4148 		case PT_SPECIAL:
4149 			(void) strlcpy(in_progress_fstab.zone_fs_special,
4150 			    prop_id,
4151 			    sizeof (in_progress_fstab.zone_fs_special));
4152 			return;
4153 		case PT_RAW:
4154 			(void) strlcpy(in_progress_fstab.zone_fs_raw,
4155 			    prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4156 			return;
4157 		case PT_TYPE:
4158 			if (!valid_fs_type(prop_id)) {
4159 				zerr(gettext("\"%s\" is not a valid %s."),
4160 				    prop_id, pt_to_str(PT_TYPE));
4161 				saw_error = B_TRUE;
4162 				return;
4163 			}
4164 			(void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4165 			    sizeof (in_progress_fstab.zone_fs_type));
4166 			return;
4167 		case PT_OPTIONS:
4168 			if (pp->pv_type != PROP_VAL_SIMPLE &&
4169 			    pp->pv_type != PROP_VAL_LIST) {
4170 				zerr(gettext("A %s or %s value was expected "
4171 				    "here."), pvt_to_str(PROP_VAL_SIMPLE),
4172 				    pvt_to_str(PROP_VAL_LIST));
4173 				saw_error = B_TRUE;
4174 				return;
4175 			}
4176 			zonecfg_free_fs_option_list(
4177 			    in_progress_fstab.zone_fs_options);
4178 			in_progress_fstab.zone_fs_options = NULL;
4179 			if (!(pp->pv_type == PROP_VAL_LIST &&
4180 			    pp->pv_list == NULL))
4181 				add_property(cmd);
4182 			return;
4183 		default:
4184 			break;
4185 		}
4186 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4187 		long_usage(CMD_SET, B_TRUE);
4188 		usage(B_FALSE, HELP_PROPS);
4189 		return;
4190 	case RT_IPD:
4191 		switch (prop_type) {
4192 		case PT_DIR:
4193 			(void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id,
4194 			    sizeof (in_progress_ipdtab.zone_fs_dir));
4195 			return;
4196 		default:
4197 			break;
4198 		}
4199 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4200 		long_usage(CMD_SET, B_TRUE);
4201 		usage(B_FALSE, HELP_PROPS);
4202 		return;
4203 	case RT_NET:
4204 		switch (prop_type) {
4205 		case PT_ADDRESS:
4206 			if (validate_net_address_syntax(prop_id) != Z_OK) {
4207 				saw_error = B_TRUE;
4208 				return;
4209 			}
4210 			(void) strlcpy(in_progress_nwiftab.zone_nwif_address,
4211 			    prop_id,
4212 			    sizeof (in_progress_nwiftab.zone_nwif_address));
4213 			break;
4214 		case PT_PHYSICAL:
4215 			if (validate_net_physical_syntax(prop_id) != Z_OK) {
4216 				saw_error = B_TRUE;
4217 				return;
4218 			}
4219 			(void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4220 			    prop_id,
4221 			    sizeof (in_progress_nwiftab.zone_nwif_physical));
4222 			break;
4223 		case PT_DEFROUTER:
4224 			if (validate_net_address_syntax(prop_id) != Z_OK) {
4225 				saw_error = B_TRUE;
4226 				return;
4227 			}
4228 			(void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4229 			    prop_id,
4230 			    sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4231 			break;
4232 		default:
4233 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4234 			    B_TRUE);
4235 			long_usage(CMD_SET, B_TRUE);
4236 			usage(B_FALSE, HELP_PROPS);
4237 			return;
4238 		}
4239 		return;
4240 	case RT_DEVICE:
4241 		switch (prop_type) {
4242 		case PT_MATCH:
4243 			(void) strlcpy(in_progress_devtab.zone_dev_match,
4244 			    prop_id,
4245 			    sizeof (in_progress_devtab.zone_dev_match));
4246 			break;
4247 		default:
4248 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4249 			    B_TRUE);
4250 			long_usage(CMD_SET, B_TRUE);
4251 			usage(B_FALSE, HELP_PROPS);
4252 			return;
4253 		}
4254 		return;
4255 	case RT_RCTL:
4256 		switch (prop_type) {
4257 		case PT_NAME:
4258 			if (!zonecfg_valid_rctlname(prop_id)) {
4259 				zerr(gettext("'%s' is not a valid zone %s "
4260 				    "name."), prop_id, rt_to_str(RT_RCTL));
4261 				return;
4262 			}
4263 			(void) strlcpy(in_progress_rctltab.zone_rctl_name,
4264 			    prop_id,
4265 			    sizeof (in_progress_rctltab.zone_rctl_name));
4266 			break;
4267 		case PT_VALUE:
4268 			if (pp->pv_type != PROP_VAL_COMPLEX &&
4269 			    pp->pv_type != PROP_VAL_LIST) {
4270 				zerr(gettext("A %s or %s value was expected "
4271 				    "here."), pvt_to_str(PROP_VAL_COMPLEX),
4272 				    pvt_to_str(PROP_VAL_LIST));
4273 				saw_error = B_TRUE;
4274 				return;
4275 			}
4276 			zonecfg_free_rctl_value_list(
4277 			    in_progress_rctltab.zone_rctl_valptr);
4278 			in_progress_rctltab.zone_rctl_valptr = NULL;
4279 			if (!(pp->pv_type == PROP_VAL_LIST &&
4280 			    pp->pv_list == NULL))
4281 				add_property(cmd);
4282 			break;
4283 		default:
4284 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4285 			    B_TRUE);
4286 			long_usage(CMD_SET, B_TRUE);
4287 			usage(B_FALSE, HELP_PROPS);
4288 			return;
4289 		}
4290 		return;
4291 	case RT_ATTR:
4292 		switch (prop_type) {
4293 		case PT_NAME:
4294 			(void) strlcpy(in_progress_attrtab.zone_attr_name,
4295 			    prop_id,
4296 			    sizeof (in_progress_attrtab.zone_attr_name));
4297 			break;
4298 		case PT_TYPE:
4299 			(void) strlcpy(in_progress_attrtab.zone_attr_type,
4300 			    prop_id,
4301 			    sizeof (in_progress_attrtab.zone_attr_type));
4302 			break;
4303 		case PT_VALUE:
4304 			(void) strlcpy(in_progress_attrtab.zone_attr_value,
4305 			    prop_id,
4306 			    sizeof (in_progress_attrtab.zone_attr_value));
4307 			break;
4308 		default:
4309 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4310 			    B_TRUE);
4311 			long_usage(CMD_SET, B_TRUE);
4312 			usage(B_FALSE, HELP_PROPS);
4313 			return;
4314 		}
4315 		return;
4316 	case RT_DATASET:
4317 		switch (prop_type) {
4318 		case PT_NAME:
4319 			(void) strlcpy(in_progress_dstab.zone_dataset_name,
4320 			    prop_id,
4321 			    sizeof (in_progress_dstab.zone_dataset_name));
4322 			return;
4323 		default:
4324 			break;
4325 		}
4326 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4327 		long_usage(CMD_SET, B_TRUE);
4328 		usage(B_FALSE, HELP_PROPS);
4329 		return;
4330 	case RT_DCPU:
4331 		switch (prop_type) {
4332 		char *lowp, *highp;
4333 
4334 		case PT_NCPUS:
4335 			lowp = prop_id;
4336 			if ((highp = strchr(prop_id, '-')) != NULL)
4337 				*highp++ = '\0';
4338 			else
4339 				highp = lowp;
4340 
4341 			/* Make sure the input makes sense. */
4342 			if (!zonecfg_valid_ncpus(lowp, highp)) {
4343 				zerr(gettext("%s property is out of range."),
4344 				    pt_to_str(PT_NCPUS));
4345 				saw_error = B_TRUE;
4346 				return;
4347 			}
4348 
4349 			(void) strlcpy(
4350 			    in_progress_psettab.zone_ncpu_min, lowp,
4351 			    sizeof (in_progress_psettab.zone_ncpu_min));
4352 			(void) strlcpy(
4353 			    in_progress_psettab.zone_ncpu_max, highp,
4354 			    sizeof (in_progress_psettab.zone_ncpu_max));
4355 			return;
4356 		case PT_IMPORTANCE:
4357 			/* Make sure the value makes sense. */
4358 			if (!zonecfg_valid_importance(prop_id)) {
4359 				zerr(gettext("%s property is out of range."),
4360 				    pt_to_str(PT_IMPORTANCE));
4361 				saw_error = B_TRUE;
4362 				return;
4363 			}
4364 
4365 			(void) strlcpy(in_progress_psettab.zone_importance,
4366 			    prop_id,
4367 			    sizeof (in_progress_psettab.zone_importance));
4368 			return;
4369 		default:
4370 			break;
4371 		}
4372 		zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4373 		long_usage(CMD_SET, B_TRUE);
4374 		usage(B_FALSE, HELP_PROPS);
4375 		return;
4376 	case RT_PCAP:
4377 		if (prop_type != PT_NCPUS) {
4378 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4379 			    B_TRUE);
4380 			long_usage(CMD_SET, B_TRUE);
4381 			usage(B_FALSE, HELP_PROPS);
4382 			return;
4383 		}
4384 
4385 		/*
4386 		 * We already checked that an rctl alias is allowed in
4387 		 * the add_resource() function.
4388 		 */
4389 
4390 		if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4391 		    (int)(cap * 100) < 1) {
4392 			zerr(gettext("%s property is out of range."),
4393 			    pt_to_str(PT_NCPUS));
4394 			saw_error = B_TRUE;
4395 			return;
4396 		}
4397 
4398 		if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4399 		    (int)(cap * 100))) != Z_OK)
4400 			zone_perror(zone, err, B_TRUE);
4401 		else
4402 			need_to_commit = B_TRUE;
4403 		return;
4404 	case RT_MCAP:
4405 		switch (prop_type) {
4406 		case PT_PHYSICAL:
4407 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4408 				zerr(gettext("A positive number with a "
4409 				    "required scale suffix (K, M, G or T) was "
4410 				    "expected here."));
4411 				saw_error = B_TRUE;
4412 			} else if (mem_cap < ONE_MB) {
4413 				zerr(gettext("%s value is too small.  It must "
4414 				    "be at least 1M."), pt_to_str(PT_PHYSICAL));
4415 				saw_error = B_TRUE;
4416 			} else {
4417 				snprintf(in_progress_mcaptab.zone_physmem_cap,
4418 				    physmem_size, "%llu", mem_cap);
4419 			}
4420 			break;
4421 		case PT_SWAP:
4422 			/*
4423 			 * We have to check if an rctl is allowed here since
4424 			 * there might already be a rctl defined that blocks
4425 			 * the alias.
4426 			 */
4427 			if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4428 				zone_perror(pt_to_str(PT_MAXSWAP),
4429 				    Z_ALIAS_DISALLOW, B_FALSE);
4430 				saw_error = B_TRUE;
4431 				return;
4432 			}
4433 
4434 			if (global_zone)
4435 				mem_limit = ONE_MB * 100;
4436 			else
4437 				mem_limit = ONE_MB * 50;
4438 
4439 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4440 				zerr(gettext("A positive number with a "
4441 				    "required scale suffix (K, M, G or T) was "
4442 				    "expected here."));
4443 				saw_error = B_TRUE;
4444 			} else if (mem_cap < mem_limit) {
4445 				char buf[128];
4446 
4447 				(void) snprintf(buf, sizeof (buf), "%llu",
4448 				    mem_limit);
4449 				bytes_to_units(buf, buf, sizeof (buf));
4450 				zerr(gettext("%s value is too small.  It must "
4451 				    "be at least %s."), pt_to_str(PT_SWAP),
4452 				    buf);
4453 				saw_error = B_TRUE;
4454 			} else {
4455 				if ((err = zonecfg_set_aliased_rctl(handle,
4456 				    ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4457 					zone_perror(zone, err, B_TRUE);
4458 				else
4459 					need_to_commit = B_TRUE;
4460 			}
4461 			break;
4462 		case PT_LOCKED:
4463 			/*
4464 			 * We have to check if an rctl is allowed here since
4465 			 * there might already be a rctl defined that blocks
4466 			 * the alias.
4467 			 */
4468 			if (!zonecfg_aliased_rctl_ok(handle,
4469 			    ALIAS_MAXLOCKEDMEM)) {
4470 				zone_perror(pt_to_str(PT_LOCKED),
4471 				    Z_ALIAS_DISALLOW, B_FALSE);
4472 				saw_error = B_TRUE;
4473 				return;
4474 			}
4475 
4476 			if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4477 				zerr(gettext("A non-negative number with a "
4478 				    "required scale suffix (K, M, G or T) was "
4479 				    "expected\nhere."));
4480 				saw_error = B_TRUE;
4481 			} else {
4482 				if ((err = zonecfg_set_aliased_rctl(handle,
4483 				    ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4484 					zone_perror(zone, err, B_TRUE);
4485 				else
4486 					need_to_commit = B_TRUE;
4487 			}
4488 			break;
4489 		default:
4490 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4491 			    B_TRUE);
4492 			long_usage(CMD_SET, B_TRUE);
4493 			usage(B_FALSE, HELP_PROPS);
4494 			return;
4495 		}
4496 
4497 		return;
4498 	default:
4499 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4500 		long_usage(CMD_SET, B_TRUE);
4501 		usage(B_FALSE, HELP_RESOURCES);
4502 		return;
4503 	}
4504 }
4505 
4506 static void
4507 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4508 {
4509 	char *qstr;
4510 
4511 	if (*pval != '\0') {
4512 		qstr = quoteit(pval);
4513 		if (pnum == PT_SWAP || pnum == PT_LOCKED)
4514 			(void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4515 			    qstr);
4516 		else
4517 			(void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4518 		free(qstr);
4519 	} else if (print_notspec)
4520 		(void) fprintf(fp, gettext("\t%s not specified\n"),
4521 		    pt_to_str(pnum));
4522 }
4523 
4524 static void
4525 info_zonename(zone_dochandle_t handle, FILE *fp)
4526 {
4527 	char zonename[ZONENAME_MAX];
4528 
4529 	if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4530 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4531 		    zonename);
4532 	else
4533 		(void) fprintf(fp, gettext("%s not specified\n"),
4534 		    pt_to_str(PT_ZONENAME));
4535 }
4536 
4537 static void
4538 info_zonepath(zone_dochandle_t handle, FILE *fp)
4539 {
4540 	char zonepath[MAXPATHLEN];
4541 
4542 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
4543 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
4544 		    zonepath);
4545 	else {
4546 		(void) fprintf(fp, gettext("%s not specified\n"),
4547 		    pt_to_str(PT_ZONEPATH));
4548 	}
4549 }
4550 
4551 static void
4552 info_brand(zone_dochandle_t handle, FILE *fp)
4553 {
4554 	char brand[MAXNAMELEN];
4555 
4556 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
4557 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
4558 		    brand);
4559 	else
4560 		(void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
4561 		    gettext("not specified"));
4562 }
4563 
4564 static void
4565 info_autoboot(zone_dochandle_t handle, FILE *fp)
4566 {
4567 	boolean_t autoboot;
4568 	int err;
4569 
4570 	if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
4571 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
4572 		    autoboot ? "true" : "false");
4573 	else
4574 		zone_perror(zone, err, B_TRUE);
4575 }
4576 
4577 static void
4578 info_pool(zone_dochandle_t handle, FILE *fp)
4579 {
4580 	char pool[MAXNAMELEN];
4581 	int err;
4582 
4583 	if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
4584 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
4585 	else
4586 		zone_perror(zone, err, B_TRUE);
4587 }
4588 
4589 static void
4590 info_limitpriv(zone_dochandle_t handle, FILE *fp)
4591 {
4592 	char *limitpriv;
4593 	int err;
4594 
4595 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
4596 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
4597 		    limitpriv);
4598 		free(limitpriv);
4599 	} else {
4600 		zone_perror(zone, err, B_TRUE);
4601 	}
4602 }
4603 
4604 static void
4605 info_bootargs(zone_dochandle_t handle, FILE *fp)
4606 {
4607 	char bootargs[BOOTARGS_MAX];
4608 	int err;
4609 
4610 	if ((err = zonecfg_get_bootargs(handle, bootargs,
4611 	    sizeof (bootargs))) == Z_OK) {
4612 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
4613 		    bootargs);
4614 	} else {
4615 		zone_perror(zone, err, B_TRUE);
4616 	}
4617 }
4618 
4619 static void
4620 info_sched(zone_dochandle_t handle, FILE *fp)
4621 {
4622 	char sched[MAXNAMELEN];
4623 	int err;
4624 
4625 	if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
4626 	    == Z_OK) {
4627 		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
4628 	} else {
4629 		zone_perror(zone, err, B_TRUE);
4630 	}
4631 }
4632 
4633 static void
4634 info_iptype(zone_dochandle_t handle, FILE *fp)
4635 {
4636 	zone_iptype_t iptype;
4637 	int err;
4638 
4639 	if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
4640 		switch (iptype) {
4641 		case ZS_SHARED:
4642 			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
4643 			    "shared");
4644 			break;
4645 		case ZS_EXCLUSIVE:
4646 			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
4647 			    "exclusive");
4648 			break;
4649 		}
4650 	} else {
4651 		zone_perror(zone, err, B_TRUE);
4652 	}
4653 }
4654 
4655 static void
4656 output_fs(FILE *fp, struct zone_fstab *fstab)
4657 {
4658 	zone_fsopt_t *this;
4659 
4660 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
4661 	output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
4662 	output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
4663 	output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
4664 	output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
4665 	(void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
4666 	for (this = fstab->zone_fs_options; this != NULL;
4667 	    this = this->zone_fsopt_next) {
4668 		if (strchr(this->zone_fsopt_opt, '='))
4669 			(void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
4670 		else
4671 			(void) fprintf(fp, "%s", this->zone_fsopt_opt);
4672 		if (this->zone_fsopt_next != NULL)
4673 			(void) fprintf(fp, ",");
4674 	}
4675 	(void) fprintf(fp, "]\n");
4676 }
4677 
4678 static void
4679 output_ipd(FILE *fp, struct zone_fstab *ipdtab)
4680 {
4681 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD));
4682 	output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE);
4683 }
4684 
4685 static void
4686 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4687 {
4688 	struct zone_fstab lookup, user;
4689 	boolean_t output = B_FALSE;
4690 
4691 	if (zonecfg_setfsent(handle) != Z_OK)
4692 		return;
4693 	while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
4694 		if (cmd->cmd_prop_nv_pairs == 0) {
4695 			output_fs(fp, &lookup);
4696 			goto loopend;
4697 		}
4698 		if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
4699 			goto loopend;
4700 		if (strlen(user.zone_fs_dir) > 0 &&
4701 		    strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
4702 			goto loopend;	/* no match */
4703 		if (strlen(user.zone_fs_special) > 0 &&
4704 		    strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
4705 			goto loopend;	/* no match */
4706 		if (strlen(user.zone_fs_type) > 0 &&
4707 		    strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
4708 			goto loopend;	/* no match */
4709 		output_fs(fp, &lookup);
4710 		output = B_TRUE;
4711 loopend:
4712 		zonecfg_free_fs_option_list(lookup.zone_fs_options);
4713 	}
4714 	(void) zonecfg_endfsent(handle);
4715 	/*
4716 	 * If a property n/v pair was specified, warn the user if there was
4717 	 * nothing to output.
4718 	 */
4719 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4720 		(void) printf(gettext("No such %s resource.\n"),
4721 		    rt_to_str(RT_FS));
4722 }
4723 
4724 static void
4725 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4726 {
4727 	struct zone_fstab lookup, user;
4728 	boolean_t output = B_FALSE;
4729 
4730 	if (zonecfg_setipdent(handle) != Z_OK)
4731 		return;
4732 	while (zonecfg_getipdent(handle, &lookup) == Z_OK) {
4733 		if (cmd->cmd_prop_nv_pairs == 0) {
4734 			output_ipd(fp, &lookup);
4735 			continue;
4736 		}
4737 		if (fill_in_ipdtab(cmd, &user, B_TRUE) != Z_OK)
4738 			continue;
4739 		if (strlen(user.zone_fs_dir) > 0 &&
4740 		    strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
4741 			continue;	/* no match */
4742 		output_ipd(fp, &lookup);
4743 		output = B_TRUE;
4744 	}
4745 	(void) zonecfg_endipdent(handle);
4746 	/*
4747 	 * If a property n/v pair was specified, warn the user if there was
4748 	 * nothing to output.
4749 	 */
4750 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4751 		(void) printf(gettext("No such %s resource.\n"),
4752 		    rt_to_str(RT_IPD));
4753 }
4754 
4755 static void
4756 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
4757 {
4758 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
4759 	output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
4760 	output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
4761 	output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
4762 }
4763 
4764 static void
4765 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4766 {
4767 	struct zone_nwiftab lookup, user;
4768 	boolean_t output = B_FALSE;
4769 
4770 	if (zonecfg_setnwifent(handle) != Z_OK)
4771 		return;
4772 	while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
4773 		if (cmd->cmd_prop_nv_pairs == 0) {
4774 			output_net(fp, &lookup);
4775 			continue;
4776 		}
4777 		if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
4778 			continue;
4779 		if (strlen(user.zone_nwif_physical) > 0 &&
4780 		    strcmp(user.zone_nwif_physical,
4781 		    lookup.zone_nwif_physical) != 0)
4782 			continue;	/* no match */
4783 		/* If present make sure it matches */
4784 		if (strlen(user.zone_nwif_address) > 0 &&
4785 		    !zonecfg_same_net_address(user.zone_nwif_address,
4786 		    lookup.zone_nwif_address))
4787 			continue;	/* no match */
4788 		output_net(fp, &lookup);
4789 		output = B_TRUE;
4790 	}
4791 	(void) zonecfg_endnwifent(handle);
4792 	/*
4793 	 * If a property n/v pair was specified, warn the user if there was
4794 	 * nothing to output.
4795 	 */
4796 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4797 		(void) printf(gettext("No such %s resource.\n"),
4798 		    rt_to_str(RT_NET));
4799 }
4800 
4801 static void
4802 output_dev(FILE *fp, struct zone_devtab *devtab)
4803 {
4804 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
4805 	output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
4806 }
4807 
4808 static void
4809 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4810 {
4811 	struct zone_devtab lookup, user;
4812 	boolean_t output = B_FALSE;
4813 
4814 	if (zonecfg_setdevent(handle) != Z_OK)
4815 		return;
4816 	while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
4817 		if (cmd->cmd_prop_nv_pairs == 0) {
4818 			output_dev(fp, &lookup);
4819 			continue;
4820 		}
4821 		if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
4822 			continue;
4823 		if (strlen(user.zone_dev_match) > 0 &&
4824 		    strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
4825 			continue;	/* no match */
4826 		output_dev(fp, &lookup);
4827 		output = B_TRUE;
4828 	}
4829 	(void) zonecfg_enddevent(handle);
4830 	/*
4831 	 * If a property n/v pair was specified, warn the user if there was
4832 	 * nothing to output.
4833 	 */
4834 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4835 		(void) printf(gettext("No such %s resource.\n"),
4836 		    rt_to_str(RT_DEVICE));
4837 }
4838 
4839 static void
4840 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
4841 {
4842 	struct zone_rctlvaltab *valptr;
4843 
4844 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
4845 	output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
4846 	for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
4847 	    valptr = valptr->zone_rctlval_next) {
4848 		fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
4849 		    pt_to_str(PT_VALUE),
4850 		    pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
4851 		    pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
4852 		    pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
4853 	}
4854 }
4855 
4856 static void
4857 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4858 {
4859 	struct zone_rctltab lookup, user;
4860 	boolean_t output = B_FALSE;
4861 
4862 	if (zonecfg_setrctlent(handle) != Z_OK)
4863 		return;
4864 	while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
4865 		if (cmd->cmd_prop_nv_pairs == 0) {
4866 			output_rctl(fp, &lookup);
4867 		} else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
4868 		    (strlen(user.zone_rctl_name) == 0 ||
4869 		    strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
4870 			output_rctl(fp, &lookup);
4871 			output = B_TRUE;
4872 		}
4873 		zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
4874 	}
4875 	(void) zonecfg_endrctlent(handle);
4876 	/*
4877 	 * If a property n/v pair was specified, warn the user if there was
4878 	 * nothing to output.
4879 	 */
4880 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4881 		(void) printf(gettext("No such %s resource.\n"),
4882 		    rt_to_str(RT_RCTL));
4883 }
4884 
4885 static void
4886 output_attr(FILE *fp, struct zone_attrtab *attrtab)
4887 {
4888 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
4889 	output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
4890 	output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
4891 	output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
4892 }
4893 
4894 static void
4895 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4896 {
4897 	struct zone_attrtab lookup, user;
4898 	boolean_t output = B_FALSE;
4899 
4900 	if (zonecfg_setattrent(handle) != Z_OK)
4901 		return;
4902 	while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
4903 		if (cmd->cmd_prop_nv_pairs == 0) {
4904 			output_attr(fp, &lookup);
4905 			continue;
4906 		}
4907 		if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
4908 			continue;
4909 		if (strlen(user.zone_attr_name) > 0 &&
4910 		    strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
4911 			continue;	/* no match */
4912 		if (strlen(user.zone_attr_type) > 0 &&
4913 		    strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
4914 			continue;	/* no match */
4915 		if (strlen(user.zone_attr_value) > 0 &&
4916 		    strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
4917 			continue;	/* no match */
4918 		output_attr(fp, &lookup);
4919 		output = B_TRUE;
4920 	}
4921 	(void) zonecfg_endattrent(handle);
4922 	/*
4923 	 * If a property n/v pair was specified, warn the user if there was
4924 	 * nothing to output.
4925 	 */
4926 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4927 		(void) printf(gettext("No such %s resource.\n"),
4928 		    rt_to_str(RT_ATTR));
4929 }
4930 
4931 static void
4932 output_ds(FILE *fp, struct zone_dstab *dstab)
4933 {
4934 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
4935 	output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
4936 }
4937 
4938 static void
4939 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
4940 {
4941 	struct zone_dstab lookup, user;
4942 	boolean_t output = B_FALSE;
4943 
4944 	if (zonecfg_setdsent(handle) != Z_OK)
4945 		return;
4946 	while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
4947 		if (cmd->cmd_prop_nv_pairs == 0) {
4948 			output_ds(fp, &lookup);
4949 			continue;
4950 		}
4951 		if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
4952 			continue;
4953 		if (strlen(user.zone_dataset_name) > 0 &&
4954 		    strcmp(user.zone_dataset_name,
4955 		    lookup.zone_dataset_name) != 0)
4956 			continue;	/* no match */
4957 		output_ds(fp, &lookup);
4958 		output = B_TRUE;
4959 	}
4960 	(void) zonecfg_enddsent(handle);
4961 	/*
4962 	 * If a property n/v pair was specified, warn the user if there was
4963 	 * nothing to output.
4964 	 */
4965 	if (!output && cmd->cmd_prop_nv_pairs > 0)
4966 		(void) printf(gettext("No such %s resource.\n"),
4967 		    rt_to_str(RT_DATASET));
4968 }
4969 
4970 static void
4971 output_pset(FILE *fp, struct zone_psettab *psettab)
4972 {
4973 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
4974 	if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
4975 		(void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
4976 		    psettab->zone_ncpu_max);
4977 	else
4978 		(void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
4979 		    psettab->zone_ncpu_min, psettab->zone_ncpu_max);
4980 	if (psettab->zone_importance[0] != '\0')
4981 		(void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
4982 		    psettab->zone_importance);
4983 }
4984 
4985 static void
4986 info_pset(zone_dochandle_t handle, FILE *fp)
4987 {
4988 	struct zone_psettab lookup;
4989 
4990 	if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
4991 		output_pset(fp, &lookup);
4992 }
4993 
4994 static void
4995 output_pcap(FILE *fp)
4996 {
4997 	uint64_t cap;
4998 
4999 	if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5000 		float scaled = (float)cap / 100;
5001 		(void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5002 		(void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5003 		    scaled);
5004 	}
5005 }
5006 
5007 static void
5008 info_pcap(FILE *fp)
5009 {
5010 	output_pcap(fp);
5011 }
5012 
5013 
5014 static void
5015 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5016 {
5017 	uint64_t limit;
5018 
5019 	if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5020 		/* convert memory based properties */
5021 		if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5022 			char buf[128];
5023 
5024 			(void) snprintf(buf, sizeof (buf), "%llu", limit);
5025 			bytes_to_units(buf, buf, sizeof (buf));
5026 			(void) fprintf(fp, "[%s: %s]\n", alias, buf);
5027 			return;
5028 		}
5029 
5030 		(void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5031 	}
5032 }
5033 
5034 static void
5035 bytes_to_units(char *str, char *buf, int bufsize)
5036 {
5037 	unsigned long long num;
5038 	unsigned long long save = 0;
5039 	char *units = "BKMGT";
5040 	char *up = units;
5041 
5042 	num = strtoll(str, NULL, 10);
5043 
5044 	if (num < 1024) {
5045 		(void) snprintf(buf, bufsize, "%llu", num);
5046 		return;
5047 	}
5048 
5049 	while ((num >= 1024) && (*up != 'T')) {
5050 		up++; /* next unit of measurement */
5051 		save = num;
5052 		num = (num + 512) >> 10;
5053 	}
5054 
5055 	/* check if we should output a fraction.  snprintf will round for us */
5056 	if (save % 1024 != 0 && ((save >> 10) < 10))
5057 		(void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5058 		    *up);
5059 	else
5060 		(void) snprintf(buf, bufsize, "%llu%c", num, *up);
5061 }
5062 
5063 static void
5064 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5065     uint64_t maxswap, int showlocked, uint64_t maxlocked)
5066 {
5067 	char buf[128];
5068 
5069 	(void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5070 	if (mcaptab->zone_physmem_cap[0] != '\0') {
5071 		bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5072 		output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5073 	}
5074 
5075 	if (showswap == Z_OK) {
5076 		(void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5077 		bytes_to_units(buf, buf, sizeof (buf));
5078 		output_prop(fp, PT_SWAP, buf, B_TRUE);
5079 	}
5080 
5081 	if (showlocked == Z_OK) {
5082 		(void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5083 		bytes_to_units(buf, buf, sizeof (buf));
5084 		output_prop(fp, PT_LOCKED, buf, B_TRUE);
5085 	}
5086 }
5087 
5088 static void
5089 info_mcap(zone_dochandle_t handle, FILE *fp)
5090 {
5091 	int res1, res2, res3;
5092 	uint64_t swap_limit;
5093 	uint64_t locked_limit;
5094 	struct zone_mcaptab lookup;
5095 
5096 	bzero(&lookup, sizeof (lookup));
5097 	res1 = zonecfg_getmcapent(handle, &lookup);
5098 	res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5099 	res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5100 	    &locked_limit);
5101 
5102 	if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5103 		output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5104 }
5105 
5106 void
5107 info_func(cmd_t *cmd)
5108 {
5109 	FILE *fp = stdout;
5110 	boolean_t need_to_close = B_FALSE;
5111 	char *pager;
5112 	int type;
5113 	int res1, res2;
5114 	uint64_t swap_limit;
5115 	uint64_t locked_limit;
5116 
5117 	assert(cmd != NULL);
5118 
5119 	if (initialize(B_TRUE) != Z_OK)
5120 		return;
5121 
5122 	/* don't page error output */
5123 	if (interactive_mode) {
5124 		if ((pager = getenv("PAGER")) == NULL)
5125 			pager = PAGER;
5126 		if ((fp = popen(pager, "w")) != NULL)
5127 			need_to_close = B_TRUE;
5128 		setbuf(fp, NULL);
5129 	}
5130 
5131 	if (!global_scope) {
5132 		switch (resource_scope) {
5133 		case RT_FS:
5134 			output_fs(fp, &in_progress_fstab);
5135 			break;
5136 		case RT_IPD:
5137 			output_ipd(fp, &in_progress_ipdtab);
5138 			break;
5139 		case RT_NET:
5140 			output_net(fp, &in_progress_nwiftab);
5141 			break;
5142 		case RT_DEVICE:
5143 			output_dev(fp, &in_progress_devtab);
5144 			break;
5145 		case RT_RCTL:
5146 			output_rctl(fp, &in_progress_rctltab);
5147 			break;
5148 		case RT_ATTR:
5149 			output_attr(fp, &in_progress_attrtab);
5150 			break;
5151 		case RT_DATASET:
5152 			output_ds(fp, &in_progress_dstab);
5153 			break;
5154 		case RT_DCPU:
5155 			output_pset(fp, &in_progress_psettab);
5156 			break;
5157 		case RT_PCAP:
5158 			output_pcap(fp);
5159 			break;
5160 		case RT_MCAP:
5161 			res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5162 			    &swap_limit);
5163 			res2 = zonecfg_get_aliased_rctl(handle,
5164 			    ALIAS_MAXLOCKEDMEM, &locked_limit);
5165 			output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5166 			    res2, locked_limit);
5167 			break;
5168 		}
5169 		goto cleanup;
5170 	}
5171 
5172 	type = cmd->cmd_res_type;
5173 
5174 	if (gz_invalid_rt_property(type)) {
5175 		zerr(gettext("%s is not a valid property for the global zone."),
5176 		    rt_to_str(type));
5177 		goto cleanup;
5178 	}
5179 
5180 	if (gz_invalid_resource(type)) {
5181 		zerr(gettext("%s is not a valid resource for the global zone."),
5182 		    rt_to_str(type));
5183 		goto cleanup;
5184 	}
5185 
5186 	switch (cmd->cmd_res_type) {
5187 	case RT_UNKNOWN:
5188 		info_zonename(handle, fp);
5189 		if (!global_zone) {
5190 			info_zonepath(handle, fp);
5191 			info_brand(handle, fp);
5192 			info_autoboot(handle, fp);
5193 			info_bootargs(handle, fp);
5194 		}
5195 		info_pool(handle, fp);
5196 		if (!global_zone) {
5197 			info_limitpriv(handle, fp);
5198 			info_sched(handle, fp);
5199 			info_iptype(handle, fp);
5200 		}
5201 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5202 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5203 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5204 		info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5205 		info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5206 		info_aliased_rctl(handle, fp, ALIAS_SHARES);
5207 		if (!global_zone) {
5208 			info_ipd(handle, fp, cmd);
5209 			info_fs(handle, fp, cmd);
5210 			info_net(handle, fp, cmd);
5211 			info_dev(handle, fp, cmd);
5212 		}
5213 		info_pset(handle, fp);
5214 		info_pcap(fp);
5215 		info_mcap(handle, fp);
5216 		if (!global_zone) {
5217 			info_attr(handle, fp, cmd);
5218 			info_ds(handle, fp, cmd);
5219 		}
5220 		info_rctl(handle, fp, cmd);
5221 		break;
5222 	case RT_ZONENAME:
5223 		info_zonename(handle, fp);
5224 		break;
5225 	case RT_ZONEPATH:
5226 		info_zonepath(handle, fp);
5227 		break;
5228 	case RT_BRAND:
5229 		info_brand(handle, fp);
5230 		break;
5231 	case RT_AUTOBOOT:
5232 		info_autoboot(handle, fp);
5233 		break;
5234 	case RT_POOL:
5235 		info_pool(handle, fp);
5236 		break;
5237 	case RT_LIMITPRIV:
5238 		info_limitpriv(handle, fp);
5239 		break;
5240 	case RT_BOOTARGS:
5241 		info_bootargs(handle, fp);
5242 		break;
5243 	case RT_SCHED:
5244 		info_sched(handle, fp);
5245 		break;
5246 	case RT_IPTYPE:
5247 		info_iptype(handle, fp);
5248 		break;
5249 	case RT_MAXLWPS:
5250 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5251 		break;
5252 	case RT_MAXSHMMEM:
5253 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5254 		break;
5255 	case RT_MAXSHMIDS:
5256 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5257 		break;
5258 	case RT_MAXMSGIDS:
5259 		info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5260 		break;
5261 	case RT_MAXSEMIDS:
5262 		info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5263 		break;
5264 	case RT_SHARES:
5265 		info_aliased_rctl(handle, fp, ALIAS_SHARES);
5266 		break;
5267 	case RT_FS:
5268 		info_fs(handle, fp, cmd);
5269 		break;
5270 	case RT_IPD:
5271 		info_ipd(handle, fp, cmd);
5272 		break;
5273 	case RT_NET:
5274 		info_net(handle, fp, cmd);
5275 		break;
5276 	case RT_DEVICE:
5277 		info_dev(handle, fp, cmd);
5278 		break;
5279 	case RT_RCTL:
5280 		info_rctl(handle, fp, cmd);
5281 		break;
5282 	case RT_ATTR:
5283 		info_attr(handle, fp, cmd);
5284 		break;
5285 	case RT_DATASET:
5286 		info_ds(handle, fp, cmd);
5287 		break;
5288 	case RT_DCPU:
5289 		info_pset(handle, fp);
5290 		break;
5291 	case RT_PCAP:
5292 		info_pcap(fp);
5293 		break;
5294 	case RT_MCAP:
5295 		info_mcap(handle, fp);
5296 		break;
5297 	default:
5298 		zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5299 		    B_TRUE);
5300 	}
5301 
5302 cleanup:
5303 	if (need_to_close)
5304 		(void) pclose(fp);
5305 }
5306 
5307 /*
5308  * Helper function for verify-- checks that a required string property
5309  * exists.
5310  */
5311 static void
5312 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5313 {
5314 	if (strlen(attr) == 0) {
5315 		zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5316 		    pt_to_str(pt));
5317 		saw_error = B_TRUE;
5318 		if (*ret_val == Z_OK)
5319 			*ret_val = Z_REQD_PROPERTY_MISSING;
5320 	}
5321 }
5322 
5323 static int
5324 do_subproc(char *cmdbuf)
5325 {
5326 	char inbuf[MAX_CMD_LEN];
5327 	FILE *file;
5328 	int status;
5329 
5330 	file = popen(cmdbuf, "r");
5331 	if (file == NULL) {
5332 		zerr(gettext("Could not launch: %s"), cmdbuf);
5333 		return (-1);
5334 	}
5335 
5336 	while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5337 		fprintf(stderr, "%s", inbuf);
5338 	status = pclose(file);
5339 
5340 	if (WIFSIGNALED(status)) {
5341 		zerr(gettext("%s unexpectedly terminated due to signal %d"),
5342 		    cmdbuf, WTERMSIG(status));
5343 		return (-1);
5344 	}
5345 	assert(WIFEXITED(status));
5346 	return (WEXITSTATUS(status));
5347 }
5348 
5349 static int
5350 brand_verify(zone_dochandle_t handle)
5351 {
5352 	char xml_file[32];
5353 	char cmdbuf[MAX_CMD_LEN];
5354 	brand_handle_t bh;
5355 	char brand[MAXNAMELEN];
5356 	int err;
5357 
5358 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5359 		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5360 		return (Z_INVALID_DOCUMENT);
5361 	}
5362 	if ((bh = brand_open(brand)) == NULL) {
5363 		zerr("%s: %s\n", zone, gettext("unknown brand."));
5364 		return (Z_INVALID_DOCUMENT);
5365 	}
5366 
5367 	/*
5368 	 * Fetch the verify command, if any, from the brand configuration
5369 	 * and build the command line to execute it.
5370 	 */
5371 	strcpy(cmdbuf, EXEC_PREFIX);
5372 	err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5373 	    sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5374 	brand_close(bh);
5375 	if (err != Z_OK) {
5376 		zerr("%s: %s\n", zone,
5377 		    gettext("could not get brand verification command"));
5378 		return (Z_INVALID_DOCUMENT);
5379 	}
5380 
5381 	/*
5382 	 * If the brand doesn't provide a verification routine, we just
5383 	 * return success.
5384 	 */
5385 	if (strlen(cmdbuf) == EXEC_LEN)
5386 		return (Z_OK);
5387 
5388 	/*
5389 	 * Dump the current config information for this zone to a file.
5390 	 */
5391 	strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5392 	if (mkstemp(xml_file) == NULL)
5393 		return (Z_TEMP_FILE);
5394 	if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5395 		(void) unlink(xml_file);
5396 		return (err);
5397 	}
5398 
5399 	/*
5400 	 * Execute the verification command.
5401 	 */
5402 	if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5403 	    (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5404 		err = Z_BRAND_ERROR;
5405 	} else {
5406 		err = do_subproc(cmdbuf);
5407 	}
5408 
5409 	(void) unlink(xml_file);
5410 	return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5411 }
5412 
5413 /*
5414  * See the DTD for which attributes are required for which resources.
5415  *
5416  * This function can be called by commit_func(), which needs to save things,
5417  * in addition to the general call from parse_and_run(), which doesn't need
5418  * things saved.  Since the parameters are standardized, we distinguish by
5419  * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
5420  * that a save is needed.
5421  */
5422 void
5423 verify_func(cmd_t *cmd)
5424 {
5425 	struct zone_nwiftab nwiftab;
5426 	struct zone_fstab fstab;
5427 	struct zone_attrtab attrtab;
5428 	struct zone_rctltab rctltab;
5429 	struct zone_dstab dstab;
5430 	struct zone_psettab psettab;
5431 	char zonepath[MAXPATHLEN];
5432 	char sched[MAXNAMELEN];
5433 	char brand[MAXNAMELEN];
5434 	int err, ret_val = Z_OK, arg;
5435 	int pset_res;
5436 	boolean_t save = B_FALSE;
5437 	boolean_t arg_err = B_FALSE;
5438 	zone_iptype_t iptype;
5439 	boolean_t has_cpu_shares = B_FALSE;
5440 	boolean_t has_cpu_cap = B_FALSE;
5441 
5442 	optind = 0;
5443 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
5444 		switch (arg) {
5445 		case '?':
5446 			longer_usage(CMD_VERIFY);
5447 			arg_err = B_TRUE;
5448 			break;
5449 		default:
5450 			short_usage(CMD_VERIFY);
5451 			arg_err = B_TRUE;
5452 			break;
5453 		}
5454 	}
5455 	if (arg_err)
5456 		return;
5457 
5458 	if (optind > cmd->cmd_argc) {
5459 		short_usage(CMD_VERIFY);
5460 		return;
5461 	}
5462 
5463 	if (zone_is_read_only(CMD_VERIFY))
5464 		return;
5465 
5466 	assert(cmd != NULL);
5467 
5468 	if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
5469 		save = B_TRUE;
5470 	if (initialize(B_TRUE) != Z_OK)
5471 		return;
5472 
5473 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
5474 	    !global_zone) {
5475 		zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
5476 		ret_val = Z_REQD_RESOURCE_MISSING;
5477 		saw_error = B_TRUE;
5478 	}
5479 	if (strlen(zonepath) == 0 && !global_zone) {
5480 		zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
5481 		ret_val = Z_REQD_RESOURCE_MISSING;
5482 		saw_error = B_TRUE;
5483 	}
5484 
5485 	if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
5486 		zone_perror(zone, err, B_TRUE);
5487 		return;
5488 	}
5489 	if (strcmp(brand, NATIVE_BRAND_NAME) != 0) {
5490 		if ((err = brand_verify(handle)) != Z_OK) {
5491 			zone_perror(zone, err, B_TRUE);
5492 			return;
5493 		}
5494 	}
5495 
5496 	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
5497 		zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
5498 		ret_val = Z_REQD_RESOURCE_MISSING;
5499 		saw_error = B_TRUE;
5500 	}
5501 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
5502 		zone_perror(zone, err, B_TRUE);
5503 		return;
5504 	}
5505 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
5506 		check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val);
5507 	}
5508 	(void) zonecfg_endipdent(handle);
5509 
5510 	if ((err = zonecfg_setfsent(handle)) != Z_OK) {
5511 		zone_perror(zone, err, B_TRUE);
5512 		return;
5513 	}
5514 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
5515 		check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
5516 		check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
5517 		    &ret_val);
5518 		check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
5519 
5520 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
5521 	}
5522 	(void) zonecfg_endfsent(handle);
5523 
5524 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
5525 		zone_perror(zone, err, B_TRUE);
5526 		return;
5527 	}
5528 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
5529 		/*
5530 		 * physical is required in all cases.
5531 		 * A shared IP requires an address,
5532 		 * and may include a default router, while
5533 		 * an exclusive IP must have neither an address
5534 		 * nor a default router.
5535 		 * The physical interface name must be valid in all cases.
5536 		 */
5537 		check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
5538 		    PT_PHYSICAL, &ret_val);
5539 		if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
5540 		    Z_OK) {
5541 			saw_error = B_TRUE;
5542 			if (ret_val == Z_OK)
5543 				ret_val = Z_INVAL;
5544 		}
5545 
5546 		switch (iptype) {
5547 		case ZS_SHARED:
5548 			check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
5549 			    PT_ADDRESS, &ret_val);
5550 			break;
5551 		case ZS_EXCLUSIVE:
5552 			if (strlen(nwiftab.zone_nwif_address) > 0) {
5553 				zerr(gettext("%s: %s cannot be specified "
5554 				    "for an exclusive IP type"),
5555 				    rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
5556 				saw_error = B_TRUE;
5557 				if (ret_val == Z_OK)
5558 					ret_val = Z_INVAL;
5559 			}
5560 			if (strlen(nwiftab.zone_nwif_defrouter) > 0) {
5561 				zerr(gettext("%s: %s cannot be specified "
5562 				    "for an exclusive IP type"),
5563 				    rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER));
5564 				saw_error = B_TRUE;
5565 				if (ret_val == Z_OK)
5566 					ret_val = Z_INVAL;
5567 			}
5568 			break;
5569 		}
5570 	}
5571 	(void) zonecfg_endnwifent(handle);
5572 
5573 	if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
5574 		zone_perror(zone, err, B_TRUE);
5575 		return;
5576 	}
5577 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
5578 		check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
5579 		    &ret_val);
5580 
5581 		if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
5582 			has_cpu_shares = B_TRUE;
5583 
5584 		if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
5585 			has_cpu_cap = B_TRUE;
5586 
5587 		if (rctltab.zone_rctl_valptr == NULL) {
5588 			zerr(gettext("%s: no %s specified"),
5589 			    rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
5590 			saw_error = B_TRUE;
5591 			if (ret_val == Z_OK)
5592 				ret_val = Z_REQD_PROPERTY_MISSING;
5593 		} else {
5594 			zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
5595 		}
5596 	}
5597 	(void) zonecfg_endrctlent(handle);
5598 
5599 	if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
5600 	    has_cpu_shares) {
5601 		zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
5602 		    rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
5603 		saw_error = B_TRUE;
5604 		if (ret_val == Z_OK)
5605 			ret_val = Z_INCOMPATIBLE;
5606 	}
5607 
5608 	if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
5609 	    sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
5610 	    strcmp(sched, "FSS") != 0) {
5611 		zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
5612 		    "incompatible"),
5613 		    rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
5614 		saw_error = B_TRUE;
5615 		if (ret_val == Z_OK)
5616 			ret_val = Z_INCOMPATIBLE;
5617 	}
5618 
5619 	if (pset_res == Z_OK && has_cpu_cap) {
5620 		zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
5621 		    rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
5622 		saw_error = B_TRUE;
5623 		if (ret_val == Z_OK)
5624 			ret_val = Z_INCOMPATIBLE;
5625 	}
5626 
5627 	if ((err = zonecfg_setattrent(handle)) != Z_OK) {
5628 		zone_perror(zone, err, B_TRUE);
5629 		return;
5630 	}
5631 	while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
5632 		check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
5633 		    &ret_val);
5634 		check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
5635 		    &ret_val);
5636 		check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
5637 		    &ret_val);
5638 	}
5639 	(void) zonecfg_endattrent(handle);
5640 
5641 	if ((err = zonecfg_setdsent(handle)) != Z_OK) {
5642 		zone_perror(zone, err, B_TRUE);
5643 		return;
5644 	}
5645 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
5646 		if (strlen(dstab.zone_dataset_name) == 0) {
5647 			zerr("%s: %s %s", rt_to_str(RT_DATASET),
5648 			    pt_to_str(PT_NAME), gettext("not specified"));
5649 			saw_error = B_TRUE;
5650 			if (ret_val == Z_OK)
5651 				ret_val = Z_REQD_PROPERTY_MISSING;
5652 		} else if (!zfs_name_valid(dstab.zone_dataset_name,
5653 		    ZFS_TYPE_FILESYSTEM)) {
5654 			zerr("%s: %s %s", rt_to_str(RT_DATASET),
5655 			    pt_to_str(PT_NAME), gettext("invalid"));
5656 			saw_error = B_TRUE;
5657 			if (ret_val == Z_OK)
5658 				ret_val = Z_BAD_PROPERTY;
5659 		}
5660 
5661 	}
5662 	(void) zonecfg_enddsent(handle);
5663 
5664 	if (!global_scope) {
5665 		zerr(gettext("resource specification incomplete"));
5666 		saw_error = B_TRUE;
5667 		if (ret_val == Z_OK)
5668 			ret_val = Z_INSUFFICIENT_SPEC;
5669 	}
5670 
5671 	if (save) {
5672 		if (ret_val == Z_OK) {
5673 			if ((ret_val = zonecfg_save(handle)) == Z_OK) {
5674 				need_to_commit = B_FALSE;
5675 				(void) strlcpy(revert_zone, zone,
5676 				    sizeof (revert_zone));
5677 			}
5678 		} else {
5679 			zerr(gettext("Zone %s failed to verify"), zone);
5680 		}
5681 	}
5682 	if (ret_val != Z_OK)
5683 		zone_perror(zone, ret_val, B_TRUE);
5684 }
5685 
5686 void
5687 cancel_func(cmd_t *cmd)
5688 {
5689 	int arg;
5690 	boolean_t arg_err = B_FALSE;
5691 
5692 	assert(cmd != NULL);
5693 
5694 	optind = 0;
5695 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
5696 		switch (arg) {
5697 		case '?':
5698 			longer_usage(CMD_CANCEL);
5699 			arg_err = B_TRUE;
5700 			break;
5701 		default:
5702 			short_usage(CMD_CANCEL);
5703 			arg_err = B_TRUE;
5704 			break;
5705 		}
5706 	}
5707 	if (arg_err)
5708 		return;
5709 
5710 	if (optind != cmd->cmd_argc) {
5711 		short_usage(CMD_CANCEL);
5712 		return;
5713 	}
5714 
5715 	if (global_scope)
5716 		scope_usage(CMD_CANCEL);
5717 	global_scope = B_TRUE;
5718 	zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
5719 	bzero(&in_progress_fstab, sizeof (in_progress_fstab));
5720 	bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
5721 	bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab));
5722 	bzero(&in_progress_devtab, sizeof (in_progress_devtab));
5723 	zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
5724 	bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
5725 	bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
5726 	bzero(&in_progress_dstab, sizeof (in_progress_dstab));
5727 }
5728 
5729 static int
5730 validate_attr_name(char *name)
5731 {
5732 	int i;
5733 
5734 	if (!isalnum(name[0])) {
5735 		zerr(gettext("Invalid %s %s %s: must start with an alpha-"
5736 		    "numeric character."), rt_to_str(RT_ATTR),
5737 		    pt_to_str(PT_NAME), name);
5738 		return (Z_INVAL);
5739 	}
5740 	for (i = 1; name[i]; i++)
5741 		if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
5742 			zerr(gettext("Invalid %s %s %s: can only contain "
5743 			    "alpha-numeric characters, plus '-' and '.'."),
5744 			    rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
5745 			return (Z_INVAL);
5746 		}
5747 	return (Z_OK);
5748 }
5749 
5750 static int
5751 validate_attr_type_val(struct zone_attrtab *attrtab)
5752 {
5753 	boolean_t boolval;
5754 	int64_t intval;
5755 	char strval[MAXNAMELEN];
5756 	uint64_t uintval;
5757 
5758 	if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
5759 		if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
5760 			return (Z_OK);
5761 		zerr(gettext("invalid %s value for %s=%s"),
5762 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
5763 		return (Z_ERR);
5764 	}
5765 
5766 	if (strcmp(attrtab->zone_attr_type, "int") == 0) {
5767 		if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
5768 			return (Z_OK);
5769 		zerr(gettext("invalid %s value for %s=%s"),
5770 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
5771 		return (Z_ERR);
5772 	}
5773 
5774 	if (strcmp(attrtab->zone_attr_type, "string") == 0) {
5775 		if (zonecfg_get_attr_string(attrtab, strval,
5776 		    sizeof (strval)) == Z_OK)
5777 			return (Z_OK);
5778 		zerr(gettext("invalid %s value for %s=%s"),
5779 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
5780 		return (Z_ERR);
5781 	}
5782 
5783 	if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
5784 		if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
5785 			return (Z_OK);
5786 		zerr(gettext("invalid %s value for %s=%s"),
5787 		    rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
5788 		return (Z_ERR);
5789 	}
5790 
5791 	zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
5792 	    pt_to_str(PT_TYPE), attrtab->zone_attr_type);
5793 	return (Z_ERR);
5794 }
5795 
5796 /*
5797  * Helper function for end_func-- checks the existence of a given property
5798  * and emits a message if not specified.
5799  */
5800 static int
5801 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
5802 {
5803 	if (strlen(attr) == 0) {
5804 		*validation_failed = B_TRUE;
5805 		zerr(gettext("%s not specified"), pt_to_str(pt));
5806 		return (Z_ERR);
5807 	}
5808 	return (Z_OK);
5809 }
5810 
5811 void
5812 end_func(cmd_t *cmd)
5813 {
5814 	boolean_t validation_failed = B_FALSE;
5815 	boolean_t arg_err = B_FALSE;
5816 	struct zone_fstab tmp_fstab;
5817 	struct zone_nwiftab tmp_nwiftab;
5818 	struct zone_devtab tmp_devtab;
5819 	struct zone_rctltab tmp_rctltab;
5820 	struct zone_attrtab tmp_attrtab;
5821 	struct zone_dstab tmp_dstab;
5822 	int err, arg, res1, res2, res3;
5823 	uint64_t swap_limit;
5824 	uint64_t locked_limit;
5825 	uint64_t proc_cap;
5826 
5827 	assert(cmd != NULL);
5828 
5829 	optind = 0;
5830 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
5831 		switch (arg) {
5832 		case '?':
5833 			longer_usage(CMD_END);
5834 			arg_err = B_TRUE;
5835 			break;
5836 		default:
5837 			short_usage(CMD_END);
5838 			arg_err = B_TRUE;
5839 			break;
5840 		}
5841 	}
5842 	if (arg_err)
5843 		return;
5844 
5845 	if (optind != cmd->cmd_argc) {
5846 		short_usage(CMD_END);
5847 		return;
5848 	}
5849 
5850 	if (global_scope) {
5851 		scope_usage(CMD_END);
5852 		return;
5853 	}
5854 
5855 	assert(end_op == CMD_ADD || end_op == CMD_SELECT);
5856 
5857 	switch (resource_scope) {
5858 	case RT_FS:
5859 		/* First make sure everything was filled in. */
5860 		if (end_check_reqd(in_progress_fstab.zone_fs_dir,
5861 		    PT_DIR, &validation_failed) == Z_OK) {
5862 			if (in_progress_fstab.zone_fs_dir[0] != '/') {
5863 				zerr(gettext("%s %s is not an absolute path."),
5864 				    pt_to_str(PT_DIR),
5865 				    in_progress_fstab.zone_fs_dir);
5866 				validation_failed = B_TRUE;
5867 			}
5868 		}
5869 
5870 		(void) end_check_reqd(in_progress_fstab.zone_fs_special,
5871 		    PT_SPECIAL, &validation_failed);
5872 
5873 		if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
5874 		    in_progress_fstab.zone_fs_raw[0] != '/') {
5875 			zerr(gettext("%s %s is not an absolute path."),
5876 			    pt_to_str(PT_RAW),
5877 			    in_progress_fstab.zone_fs_raw);
5878 			validation_failed = B_TRUE;
5879 		}
5880 
5881 		(void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
5882 		    &validation_failed);
5883 
5884 		if (validation_failed) {
5885 			saw_error = B_TRUE;
5886 			return;
5887 		}
5888 
5889 		if (end_op == CMD_ADD) {
5890 			/* Make sure there isn't already one like this. */
5891 			bzero(&tmp_fstab, sizeof (tmp_fstab));
5892 			(void) strlcpy(tmp_fstab.zone_fs_dir,
5893 			    in_progress_fstab.zone_fs_dir,
5894 			    sizeof (tmp_fstab.zone_fs_dir));
5895 			err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
5896 			zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
5897 			if (err == Z_OK) {
5898 				zerr(gettext("A %s resource "
5899 				    "with the %s '%s' already exists."),
5900 				    rt_to_str(RT_FS), pt_to_str(PT_DIR),
5901 				    in_progress_fstab.zone_fs_dir);
5902 				saw_error = B_TRUE;
5903 				return;
5904 			}
5905 			err = zonecfg_add_filesystem(handle,
5906 			    &in_progress_fstab);
5907 		} else {
5908 			err = zonecfg_modify_filesystem(handle, &old_fstab,
5909 			    &in_progress_fstab);
5910 		}
5911 		zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
5912 		in_progress_fstab.zone_fs_options = NULL;
5913 		break;
5914 
5915 	case RT_IPD:
5916 		/* First make sure everything was filled in. */
5917 		if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR,
5918 		    &validation_failed) == Z_OK) {
5919 			if (in_progress_ipdtab.zone_fs_dir[0] != '/') {
5920 				zerr(gettext("%s %s is not an absolute path."),
5921 				    pt_to_str(PT_DIR),
5922 				    in_progress_ipdtab.zone_fs_dir);
5923 				validation_failed = B_TRUE;
5924 			}
5925 		}
5926 		if (validation_failed) {
5927 			saw_error = B_TRUE;
5928 			return;
5929 		}
5930 
5931 		if (end_op == CMD_ADD) {
5932 			/* Make sure there isn't already one like this. */
5933 			bzero(&tmp_fstab, sizeof (tmp_fstab));
5934 			(void) strlcpy(tmp_fstab.zone_fs_dir,
5935 			    in_progress_ipdtab.zone_fs_dir,
5936 			    sizeof (tmp_fstab.zone_fs_dir));
5937 			err = zonecfg_lookup_ipd(handle, &tmp_fstab);
5938 			if (err == Z_OK) {
5939 				zerr(gettext("An %s resource "
5940 				    "with the %s '%s' already exists."),
5941 				    rt_to_str(RT_IPD), pt_to_str(PT_DIR),
5942 				    in_progress_ipdtab.zone_fs_dir);
5943 				saw_error = B_TRUE;
5944 				return;
5945 			}
5946 			err = zonecfg_add_ipd(handle, &in_progress_ipdtab);
5947 		} else {
5948 			err = zonecfg_modify_ipd(handle, &old_ipdtab,
5949 			    &in_progress_ipdtab);
5950 		}
5951 		break;
5952 	case RT_NET:
5953 		/*
5954 		 * First make sure everything was filled in.
5955 		 * Since we don't know whether IP will be shared
5956 		 * or exclusive here, some checks are deferred until
5957 		 * the verify command.
5958 		 */
5959 		(void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
5960 		    PT_PHYSICAL, &validation_failed);
5961 
5962 		if (validation_failed) {
5963 			saw_error = B_TRUE;
5964 			return;
5965 		}
5966 		if (end_op == CMD_ADD) {
5967 			/* Make sure there isn't already one like this. */
5968 			bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
5969 			(void) strlcpy(tmp_nwiftab.zone_nwif_physical,
5970 			    in_progress_nwiftab.zone_nwif_physical,
5971 			    sizeof (tmp_nwiftab.zone_nwif_physical));
5972 			(void) strlcpy(tmp_nwiftab.zone_nwif_address,
5973 			    in_progress_nwiftab.zone_nwif_address,
5974 			    sizeof (tmp_nwiftab.zone_nwif_address));
5975 			if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
5976 				zerr(gettext("A %s resource with the %s '%s', "
5977 				    "and %s '%s' already exists."),
5978 				    rt_to_str(RT_NET),
5979 				    pt_to_str(PT_PHYSICAL),
5980 				    in_progress_nwiftab.zone_nwif_physical,
5981 				    pt_to_str(PT_ADDRESS),
5982 				    in_progress_nwiftab.zone_nwif_address);
5983 				saw_error = B_TRUE;
5984 				return;
5985 			}
5986 			err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
5987 		} else {
5988 			err = zonecfg_modify_nwif(handle, &old_nwiftab,
5989 			    &in_progress_nwiftab);
5990 		}
5991 		break;
5992 
5993 	case RT_DEVICE:
5994 		/* First make sure everything was filled in. */
5995 		(void) end_check_reqd(in_progress_devtab.zone_dev_match,
5996 		    PT_MATCH, &validation_failed);
5997 
5998 		if (validation_failed) {
5999 			saw_error = B_TRUE;
6000 			return;
6001 		}
6002 
6003 		if (end_op == CMD_ADD) {
6004 			/* Make sure there isn't already one like this. */
6005 			(void) strlcpy(tmp_devtab.zone_dev_match,
6006 			    in_progress_devtab.zone_dev_match,
6007 			    sizeof (tmp_devtab.zone_dev_match));
6008 			if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6009 				zerr(gettext("A %s resource with the %s '%s' "
6010 				    "already exists."), rt_to_str(RT_DEVICE),
6011 				    pt_to_str(PT_MATCH),
6012 				    in_progress_devtab.zone_dev_match);
6013 				saw_error = B_TRUE;
6014 				return;
6015 			}
6016 			err = zonecfg_add_dev(handle, &in_progress_devtab);
6017 		} else {
6018 			err = zonecfg_modify_dev(handle, &old_devtab,
6019 			    &in_progress_devtab);
6020 		}
6021 		break;
6022 
6023 	case RT_RCTL:
6024 		/* First make sure everything was filled in. */
6025 		(void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6026 		    PT_NAME, &validation_failed);
6027 
6028 		if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6029 			zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6030 			validation_failed = B_TRUE;
6031 		}
6032 
6033 		if (validation_failed) {
6034 			saw_error = B_TRUE;
6035 			return;
6036 		}
6037 
6038 		if (end_op == CMD_ADD) {
6039 			/* Make sure there isn't already one like this. */
6040 			(void) strlcpy(tmp_rctltab.zone_rctl_name,
6041 			    in_progress_rctltab.zone_rctl_name,
6042 			    sizeof (tmp_rctltab.zone_rctl_name));
6043 			tmp_rctltab.zone_rctl_valptr = NULL;
6044 			err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6045 			zonecfg_free_rctl_value_list(
6046 			    tmp_rctltab.zone_rctl_valptr);
6047 			if (err == Z_OK) {
6048 				zerr(gettext("A %s resource "
6049 				    "with the %s '%s' already exists."),
6050 				    rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6051 				    in_progress_rctltab.zone_rctl_name);
6052 				saw_error = B_TRUE;
6053 				return;
6054 			}
6055 			err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6056 		} else {
6057 			err = zonecfg_modify_rctl(handle, &old_rctltab,
6058 			    &in_progress_rctltab);
6059 		}
6060 		if (err == Z_OK) {
6061 			zonecfg_free_rctl_value_list(
6062 			    in_progress_rctltab.zone_rctl_valptr);
6063 			in_progress_rctltab.zone_rctl_valptr = NULL;
6064 		}
6065 		break;
6066 
6067 	case RT_ATTR:
6068 		/* First make sure everything was filled in. */
6069 		(void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6070 		    PT_NAME, &validation_failed);
6071 		(void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6072 		    PT_TYPE, &validation_failed);
6073 		(void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6074 		    PT_VALUE, &validation_failed);
6075 
6076 		if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6077 		    Z_OK)
6078 			validation_failed = B_TRUE;
6079 
6080 		if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6081 			validation_failed = B_TRUE;
6082 
6083 		if (validation_failed) {
6084 			saw_error = B_TRUE;
6085 			return;
6086 		}
6087 		if (end_op == CMD_ADD) {
6088 			/* Make sure there isn't already one like this. */
6089 			bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6090 			(void) strlcpy(tmp_attrtab.zone_attr_name,
6091 			    in_progress_attrtab.zone_attr_name,
6092 			    sizeof (tmp_attrtab.zone_attr_name));
6093 			if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6094 				zerr(gettext("An %s resource "
6095 				    "with the %s '%s' already exists."),
6096 				    rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6097 				    in_progress_attrtab.zone_attr_name);
6098 				saw_error = B_TRUE;
6099 				return;
6100 			}
6101 			err = zonecfg_add_attr(handle, &in_progress_attrtab);
6102 		} else {
6103 			err = zonecfg_modify_attr(handle, &old_attrtab,
6104 			    &in_progress_attrtab);
6105 		}
6106 		break;
6107 	case RT_DATASET:
6108 		/* First make sure everything was filled in. */
6109 		if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6110 			zerr("%s %s", pt_to_str(PT_NAME),
6111 			    gettext("not specified"));
6112 			saw_error = B_TRUE;
6113 			validation_failed = B_TRUE;
6114 		}
6115 		if (validation_failed)
6116 			return;
6117 		if (end_op == CMD_ADD) {
6118 			/* Make sure there isn't already one like this. */
6119 			bzero(&tmp_dstab, sizeof (tmp_dstab));
6120 			(void) strlcpy(tmp_dstab.zone_dataset_name,
6121 			    in_progress_dstab.zone_dataset_name,
6122 			    sizeof (tmp_dstab.zone_dataset_name));
6123 			err = zonecfg_lookup_ds(handle, &tmp_dstab);
6124 			if (err == Z_OK) {
6125 				zerr(gettext("A %s resource "
6126 				    "with the %s '%s' already exists."),
6127 				    rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6128 				    in_progress_dstab.zone_dataset_name);
6129 				saw_error = B_TRUE;
6130 				return;
6131 			}
6132 			err = zonecfg_add_ds(handle, &in_progress_dstab);
6133 		} else {
6134 			err = zonecfg_modify_ds(handle, &old_dstab,
6135 			    &in_progress_dstab);
6136 		}
6137 		break;
6138 	case RT_DCPU:
6139 		/* Make sure everything was filled in. */
6140 		if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6141 		    PT_NCPUS, &validation_failed) != Z_OK) {
6142 			saw_error = B_TRUE;
6143 			return;
6144 		}
6145 
6146 		if (end_op == CMD_ADD) {
6147 			err = zonecfg_add_pset(handle, &in_progress_psettab);
6148 		} else {
6149 			err = zonecfg_modify_pset(handle, &in_progress_psettab);
6150 		}
6151 		break;
6152 	case RT_PCAP:
6153 		/* Make sure everything was filled in. */
6154 		if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6155 		    != Z_OK) {
6156 			zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6157 			saw_error = B_TRUE;
6158 			validation_failed = B_TRUE;
6159 			return;
6160 		}
6161 		err = Z_OK;
6162 		break;
6163 	case RT_MCAP:
6164 		/* Make sure everything was filled in. */
6165 		res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6166 		    Z_ERR : Z_OK;
6167 		res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6168 		    &swap_limit);
6169 		res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6170 		    &locked_limit);
6171 
6172 		if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6173 			zerr(gettext("No property was specified.  One of %s, "
6174 			    "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6175 			    pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6176 			saw_error = B_TRUE;
6177 			return;
6178 		}
6179 
6180 		/* if phys & locked are both set, verify locked <= phys */
6181 		if (res1 == Z_OK && res3 == Z_OK) {
6182 			uint64_t phys_limit;
6183 			char *endp;
6184 
6185 			phys_limit = strtoull(
6186 			    in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6187 			if (phys_limit < locked_limit) {
6188 				zerr(gettext("The %s cap must be less than or "
6189 				    "equal to the %s cap."),
6190 				    pt_to_str(PT_LOCKED),
6191 				    pt_to_str(PT_PHYSICAL));
6192 				saw_error = B_TRUE;
6193 				return;
6194 			}
6195 		}
6196 
6197 		err = Z_OK;
6198 		if (res1 == Z_OK) {
6199 			/*
6200 			 * We could be ending from either an add operation
6201 			 * or a select operation.  Since all of the properties
6202 			 * within this resource are optional, we always use
6203 			 * modify on the mcap entry.  zonecfg_modify_mcap()
6204 			 * will handle both adding and modifying a memory cap.
6205 			 */
6206 			err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6207 		} else if (end_op == CMD_SELECT) {
6208 			/*
6209 			 * If we're ending from a select and the physical
6210 			 * memory cap is empty then the user could have cleared
6211 			 * the physical cap value, so try to delete the entry.
6212 			 */
6213 			(void) zonecfg_delete_mcap(handle);
6214 		}
6215 		break;
6216 	default:
6217 		zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
6218 		    B_TRUE);
6219 		saw_error = B_TRUE;
6220 		return;
6221 	}
6222 
6223 	if (err != Z_OK) {
6224 		zone_perror(zone, err, B_TRUE);
6225 	} else {
6226 		need_to_commit = B_TRUE;
6227 		global_scope = B_TRUE;
6228 		end_op = -1;
6229 	}
6230 }
6231 
6232 void
6233 commit_func(cmd_t *cmd)
6234 {
6235 	int arg;
6236 	boolean_t arg_err = B_FALSE;
6237 
6238 	optind = 0;
6239 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6240 		switch (arg) {
6241 		case '?':
6242 			longer_usage(CMD_COMMIT);
6243 			arg_err = B_TRUE;
6244 			break;
6245 		default:
6246 			short_usage(CMD_COMMIT);
6247 			arg_err = B_TRUE;
6248 			break;
6249 		}
6250 	}
6251 	if (arg_err)
6252 		return;
6253 
6254 	if (optind != cmd->cmd_argc) {
6255 		short_usage(CMD_COMMIT);
6256 		return;
6257 	}
6258 
6259 	if (zone_is_read_only(CMD_COMMIT))
6260 		return;
6261 
6262 	assert(cmd != NULL);
6263 
6264 	cmd->cmd_argc = 1;
6265 	/*
6266 	 * cmd_arg normally comes from a strdup() in the lexer, and the
6267 	 * whole cmd structure and its (char *) attributes are freed at
6268 	 * the completion of each command, so the strdup() below is needed
6269 	 * to match this and prevent a core dump from trying to free()
6270 	 * something that can't be.
6271 	 */
6272 	if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
6273 		zone_perror(zone, Z_NOMEM, B_TRUE);
6274 		exit(Z_ERR);
6275 	}
6276 	cmd->cmd_argv[1] = NULL;
6277 	verify_func(cmd);
6278 }
6279 
6280 void
6281 revert_func(cmd_t *cmd)
6282 {
6283 	char line[128];	/* enough to ask a question */
6284 	boolean_t force = B_FALSE;
6285 	boolean_t arg_err = B_FALSE;
6286 	int err, arg, answer;
6287 
6288 	optind = 0;
6289 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
6290 		switch (arg) {
6291 		case '?':
6292 			longer_usage(CMD_REVERT);
6293 			arg_err = B_TRUE;
6294 			break;
6295 		case 'F':
6296 			force = B_TRUE;
6297 			break;
6298 		default:
6299 			short_usage(CMD_REVERT);
6300 			arg_err = B_TRUE;
6301 			break;
6302 		}
6303 	}
6304 	if (arg_err)
6305 		return;
6306 
6307 	if (optind != cmd->cmd_argc) {
6308 		short_usage(CMD_REVERT);
6309 		return;
6310 	}
6311 
6312 	if (zone_is_read_only(CMD_REVERT))
6313 		return;
6314 
6315 	if (!global_scope) {
6316 		zerr(gettext("You can only use %s in the global scope.\nUse"
6317 		    " '%s' to cancel changes to a resource specification."),
6318 		    cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
6319 		saw_error = B_TRUE;
6320 		return;
6321 	}
6322 
6323 	if (zonecfg_check_handle(handle) != Z_OK) {
6324 		zerr(gettext("No changes to revert."));
6325 		saw_error = B_TRUE;
6326 		return;
6327 	}
6328 
6329 	if (!force) {
6330 		(void) snprintf(line, sizeof (line),
6331 		    gettext("Are you sure you want to revert"));
6332 		if ((answer = ask_yesno(B_FALSE, line)) == -1) {
6333 			zerr(gettext("Input not from terminal and -F not "
6334 			    "specified:\n%s command ignored, exiting."),
6335 			    cmd_to_str(CMD_REVERT));
6336 			exit(Z_ERR);
6337 		}
6338 		if (answer != 1)
6339 			return;
6340 	}
6341 
6342 	/*
6343 	 * Time for a new handle: finish the old one off first
6344 	 * then get a new one properly to avoid leaks.
6345 	 */
6346 	zonecfg_fini_handle(handle);
6347 	if ((handle = zonecfg_init_handle()) == NULL) {
6348 		zone_perror(execname, Z_NOMEM, B_TRUE);
6349 		exit(Z_ERR);
6350 	}
6351 	if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
6352 		saw_error = B_TRUE;
6353 		got_handle = B_FALSE;
6354 		if (err == Z_NO_ZONE)
6355 			zerr(gettext("%s: no such saved zone to revert to."),
6356 			    revert_zone);
6357 		else
6358 			zone_perror(zone, err, B_TRUE);
6359 	}
6360 	(void) strlcpy(zone, revert_zone, sizeof (zone));
6361 }
6362 
6363 void
6364 help_func(cmd_t *cmd)
6365 {
6366 	int i;
6367 
6368 	assert(cmd != NULL);
6369 
6370 	if (cmd->cmd_argc == 0) {
6371 		usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
6372 		return;
6373 	}
6374 	if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
6375 		usage(B_TRUE, HELP_USAGE);
6376 		return;
6377 	}
6378 	if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
6379 		usage(B_TRUE, HELP_SUBCMDS);
6380 		return;
6381 	}
6382 	if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
6383 		usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
6384 		return;
6385 	}
6386 	if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
6387 		longer_usage(CMD_HELP);
6388 		return;
6389 	}
6390 
6391 	for (i = 0; i <= CMD_MAX; i++) {
6392 		if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
6393 			longer_usage(i);
6394 			return;
6395 		}
6396 	}
6397 	/* We do not use zerr() here because we do not want its extra \n. */
6398 	(void) fprintf(stderr, gettext("Unknown help subject %s.  "),
6399 	    cmd->cmd_argv[0]);
6400 	usage(B_FALSE, HELP_META);
6401 }
6402 
6403 static int
6404 string_to_yyin(char *string)
6405 {
6406 	if ((yyin = tmpfile()) == NULL) {
6407 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6408 		return (Z_ERR);
6409 	}
6410 	if (fwrite(string, strlen(string), 1, yyin) != 1) {
6411 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6412 		return (Z_ERR);
6413 	}
6414 	if (fseek(yyin, 0, SEEK_SET) != 0) {
6415 		zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6416 		return (Z_ERR);
6417 	}
6418 	return (Z_OK);
6419 }
6420 
6421 /* This is the back-end helper function for read_input() below. */
6422 
6423 static int
6424 cleanup()
6425 {
6426 	int answer;
6427 	cmd_t *cmd;
6428 
6429 	if (!interactive_mode && !cmd_file_mode) {
6430 		/*
6431 		 * If we're not in interactive mode, and we're not in command
6432 		 * file mode, then we must be in commands-from-the-command-line
6433 		 * mode.  As such, we can't loop back and ask for more input.
6434 		 * It was OK to prompt for such things as whether or not to
6435 		 * really delete a zone in the command handler called from
6436 		 * yyparse() above, but "really quit?" makes no sense in this
6437 		 * context.  So disable prompting.
6438 		 */
6439 		ok_to_prompt = B_FALSE;
6440 	}
6441 	if (!global_scope) {
6442 		if (!time_to_exit) {
6443 			/*
6444 			 * Just print a simple error message in the -1 case,
6445 			 * since exit_func() already handles that case, and
6446 			 * EOF means we are finished anyway.
6447 			 */
6448 			answer = ask_yesno(B_FALSE,
6449 			    gettext("Resource incomplete; really quit"));
6450 			if (answer == -1) {
6451 				zerr(gettext("Resource incomplete."));
6452 				return (Z_ERR);
6453 			}
6454 			if (answer != 1) {
6455 				yyin = stdin;
6456 				return (Z_REPEAT);
6457 			}
6458 		} else {
6459 			saw_error = B_TRUE;
6460 		}
6461 	}
6462 	/*
6463 	 * Make sure we tried something and that the handle checks
6464 	 * out, or we would get a false error trying to commit.
6465 	 */
6466 	if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
6467 		if ((cmd = alloc_cmd()) == NULL) {
6468 			zone_perror(zone, Z_NOMEM, B_TRUE);
6469 			return (Z_ERR);
6470 		}
6471 		cmd->cmd_argc = 0;
6472 		cmd->cmd_argv[0] = NULL;
6473 		commit_func(cmd);
6474 		free_cmd(cmd);
6475 		/*
6476 		 * need_to_commit will get set back to FALSE if the
6477 		 * configuration is saved successfully.
6478 		 */
6479 		if (need_to_commit) {
6480 			if (force_exit) {
6481 				zerr(gettext("Configuration not saved."));
6482 				return (Z_ERR);
6483 			}
6484 			answer = ask_yesno(B_FALSE,
6485 			    gettext("Configuration not saved; really quit"));
6486 			if (answer == -1) {
6487 				zerr(gettext("Configuration not saved."));
6488 				return (Z_ERR);
6489 			}
6490 			if (answer != 1) {
6491 				time_to_exit = B_FALSE;
6492 				yyin = stdin;
6493 				return (Z_REPEAT);
6494 			}
6495 		}
6496 	}
6497 	return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
6498 }
6499 
6500 /*
6501  * read_input() is the driver of this program.  It is a wrapper around
6502  * yyparse(), printing appropriate prompts when needed, checking for
6503  * exit conditions and reacting appropriately [the latter in its cleanup()
6504  * helper function].
6505  *
6506  * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
6507  * so do_interactive() knows that we are not really done (i.e, we asked
6508  * the user if we should really quit and the user said no).
6509  */
6510 static int
6511 read_input()
6512 {
6513 	boolean_t yyin_is_a_tty = isatty(fileno(yyin));
6514 	/*
6515 	 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
6516 	 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
6517 	 */
6518 	char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
6519 
6520 	/* yyin should have been set to the appropriate (FILE *) if not stdin */
6521 	newline_terminated = B_TRUE;
6522 	for (;;) {
6523 		if (yyin_is_a_tty) {
6524 			if (newline_terminated) {
6525 				if (global_scope)
6526 					(void) snprintf(prompt, sizeof (prompt),
6527 					    "%s:%s> ", execname, zone);
6528 				else
6529 					(void) snprintf(prompt, sizeof (prompt),
6530 					    "%s:%s:%s> ", execname, zone,
6531 					    rt_to_str(resource_scope));
6532 			}
6533 			/*
6534 			 * If the user hits ^C then we want to catch it and
6535 			 * start over.  If the user hits EOF then we want to
6536 			 * bail out.
6537 			 */
6538 			line = gl_get_line(gl, prompt, NULL, -1);
6539 			if (gl_return_status(gl) == GLR_SIGNAL) {
6540 				gl_abandon_line(gl);
6541 				continue;
6542 			}
6543 			if (line == NULL)
6544 				break;
6545 			(void) string_to_yyin(line);
6546 			while (!feof(yyin))
6547 				yyparse();
6548 		} else {
6549 			yyparse();
6550 		}
6551 		/* Bail out on an error in command file mode. */
6552 		if (saw_error && cmd_file_mode && !interactive_mode)
6553 			time_to_exit = B_TRUE;
6554 		if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
6555 			break;
6556 	}
6557 	return (cleanup());
6558 }
6559 
6560 /*
6561  * This function is used in the zonecfg-interactive-mode scenario: it just
6562  * calls read_input() until we are done.
6563  */
6564 
6565 static int
6566 do_interactive(void)
6567 {
6568 	int err;
6569 
6570 	interactive_mode = B_TRUE;
6571 	if (!read_only_mode) {
6572 		/*
6573 		 * Try to set things up proactively in interactive mode, so
6574 		 * that if the zone in question does not exist yet, we can
6575 		 * provide the user with a clue.
6576 		 */
6577 		(void) initialize(B_FALSE);
6578 	}
6579 	do {
6580 		err = read_input();
6581 	} while (err == Z_REPEAT);
6582 	return (err);
6583 }
6584 
6585 /*
6586  * cmd_file is slightly more complicated, as it has to open the command file
6587  * and set yyin appropriately.  Once that is done, though, it just calls
6588  * read_input(), and only once, since prompting is not possible.
6589  */
6590 
6591 static int
6592 cmd_file(char *file)
6593 {
6594 	FILE *infile;
6595 	int err;
6596 	struct stat statbuf;
6597 	boolean_t using_real_file = (strcmp(file, "-") != 0);
6598 
6599 	if (using_real_file) {
6600 		/*
6601 		 * zerr() prints a line number in cmd_file_mode, which we do
6602 		 * not want here, so temporarily unset it.
6603 		 */
6604 		cmd_file_mode = B_FALSE;
6605 		if ((infile = fopen(file, "r")) == NULL) {
6606 			zerr(gettext("could not open file %s: %s"),
6607 			    file, strerror(errno));
6608 			return (Z_ERR);
6609 		}
6610 		if ((err = fstat(fileno(infile), &statbuf)) != 0) {
6611 			zerr(gettext("could not stat file %s: %s"),
6612 			    file, strerror(errno));
6613 			err = Z_ERR;
6614 			goto done;
6615 		}
6616 		if (!S_ISREG(statbuf.st_mode)) {
6617 			zerr(gettext("%s is not a regular file."), file);
6618 			err = Z_ERR;
6619 			goto done;
6620 		}
6621 		yyin = infile;
6622 		cmd_file_mode = B_TRUE;
6623 		ok_to_prompt = B_FALSE;
6624 	} else {
6625 		/*
6626 		 * "-f -" is essentially the same as interactive mode,
6627 		 * so treat it that way.
6628 		 */
6629 		interactive_mode = B_TRUE;
6630 	}
6631 	/* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
6632 	if ((err = read_input()) == Z_REPEAT)
6633 		err = Z_ERR;
6634 done:
6635 	if (using_real_file)
6636 		(void) fclose(infile);
6637 	return (err);
6638 }
6639 
6640 /*
6641  * Since yacc is based on reading from a (FILE *) whereas what we get from
6642  * the command line is in argv format, we need to convert when the user
6643  * gives us commands directly from the command line.  That is done here by
6644  * concatenating the argv list into a space-separated string, writing it
6645  * to a temp file, and rewinding the file so yyin can be set to it.  Then
6646  * we call read_input(), and only once, since prompting about whether to
6647  * continue or quit would make no sense in this context.
6648  */
6649 
6650 static int
6651 one_command_at_a_time(int argc, char *argv[])
6652 {
6653 	char *command;
6654 	size_t len = 2; /* terminal \n\0 */
6655 	int i, err;
6656 
6657 	for (i = 0; i < argc; i++)
6658 		len += strlen(argv[i]) + 1;
6659 	if ((command = malloc(len)) == NULL) {
6660 		zone_perror(execname, Z_NOMEM, B_TRUE);
6661 		return (Z_ERR);
6662 	}
6663 	(void) strlcpy(command, argv[0], len);
6664 	for (i = 1; i < argc; i++) {
6665 		(void) strlcat(command, " ", len);
6666 		(void) strlcat(command, argv[i], len);
6667 	}
6668 	(void) strlcat(command, "\n", len);
6669 	err = string_to_yyin(command);
6670 	free(command);
6671 	if (err != Z_OK)
6672 		return (err);
6673 	while (!feof(yyin))
6674 		yyparse();
6675 	return (cleanup());
6676 }
6677 
6678 static char *
6679 get_execbasename(char *execfullname)
6680 {
6681 	char *last_slash, *execbasename;
6682 
6683 	/* guard against '/' at end of command invocation */
6684 	for (;;) {
6685 		last_slash = strrchr(execfullname, '/');
6686 		if (last_slash == NULL) {
6687 			execbasename = execfullname;
6688 			break;
6689 		} else {
6690 			execbasename = last_slash + 1;
6691 			if (*execbasename == '\0') {
6692 				*last_slash = '\0';
6693 				continue;
6694 			}
6695 			break;
6696 		}
6697 	}
6698 	return (execbasename);
6699 }
6700 
6701 int
6702 main(int argc, char *argv[])
6703 {
6704 	int err, arg;
6705 	struct stat st;
6706 
6707 	/* This must be before anything goes to stdout. */
6708 	setbuf(stdout, NULL);
6709 
6710 	saw_error = B_FALSE;
6711 	cmd_file_mode = B_FALSE;
6712 	execname = get_execbasename(argv[0]);
6713 
6714 	(void) setlocale(LC_ALL, "");
6715 	(void) textdomain(TEXT_DOMAIN);
6716 
6717 	if (getzoneid() != GLOBAL_ZONEID) {
6718 		zerr(gettext("%s can only be run from the global zone."),
6719 		    execname);
6720 		exit(Z_ERR);
6721 	}
6722 
6723 	if (argc < 2) {
6724 		usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
6725 		exit(Z_USAGE);
6726 	}
6727 	if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
6728 		(void) one_command_at_a_time(argc - 1, &(argv[1]));
6729 		exit(Z_OK);
6730 	}
6731 
6732 	while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
6733 		switch (arg) {
6734 		case '?':
6735 			if (optopt == '?')
6736 				usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
6737 			else
6738 				usage(B_FALSE, HELP_USAGE);
6739 			exit(Z_USAGE);
6740 			/* NOTREACHED */
6741 		case 'f':
6742 			cmd_file_name = optarg;
6743 			cmd_file_mode = B_TRUE;
6744 			break;
6745 		case 'R':
6746 			if (*optarg != '/') {
6747 				zerr(gettext("root path must be absolute: %s"),
6748 				    optarg);
6749 				exit(Z_USAGE);
6750 			}
6751 			if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
6752 				zerr(gettext(
6753 				    "root path must be a directory: %s"),
6754 				    optarg);
6755 				exit(Z_USAGE);
6756 			}
6757 			zonecfg_set_root(optarg);
6758 			break;
6759 		case 'z':
6760 			if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
6761 				global_zone = B_TRUE;
6762 			} else if (zonecfg_validate_zonename(optarg) != Z_OK) {
6763 				zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
6764 				usage(B_FALSE, HELP_SYNTAX);
6765 				exit(Z_USAGE);
6766 			}
6767 			(void) strlcpy(zone, optarg, sizeof (zone));
6768 			(void) strlcpy(revert_zone, optarg, sizeof (zone));
6769 			break;
6770 		default:
6771 			usage(B_FALSE, HELP_USAGE);
6772 			exit(Z_USAGE);
6773 		}
6774 	}
6775 
6776 	if (optind > argc || strcmp(zone, "") == 0) {
6777 		usage(B_FALSE, HELP_USAGE);
6778 		exit(Z_USAGE);
6779 	}
6780 
6781 	if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
6782 		read_only_mode = B_FALSE;
6783 	} else if (err == Z_ACCES) {
6784 		read_only_mode = B_TRUE;
6785 		/* skip this message in one-off from command line mode */
6786 		if (optind == argc)
6787 			(void) fprintf(stderr, gettext("WARNING: you do not "
6788 			    "have write access to this zone's configuration "
6789 			    "file;\ngoing into read-only mode.\n"));
6790 	} else {
6791 		fprintf(stderr, "%s: Could not access zone configuration "
6792 		    "store: %s\n", execname, zonecfg_strerror(err));
6793 		exit(Z_ERR);
6794 	}
6795 
6796 	if ((handle = zonecfg_init_handle()) == NULL) {
6797 		zone_perror(execname, Z_NOMEM, B_TRUE);
6798 		exit(Z_ERR);
6799 	}
6800 
6801 	/*
6802 	 * This may get set back to FALSE again in cmd_file() if cmd_file_name
6803 	 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
6804 	 */
6805 	if (isatty(STDIN_FILENO))
6806 		ok_to_prompt = B_TRUE;
6807 	if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
6808 		exit(Z_ERR);
6809 	if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
6810 		exit(Z_ERR);
6811 	(void) sigset(SIGINT, SIG_IGN);
6812 	if (optind == argc) {
6813 		if (!cmd_file_mode)
6814 			err = do_interactive();
6815 		else
6816 			err = cmd_file(cmd_file_name);
6817 	} else {
6818 		err = one_command_at_a_time(argc - optind, &(argv[optind]));
6819 	}
6820 	zonecfg_fini_handle(handle);
6821 	if (brand != NULL)
6822 		brand_close(brand);
6823 	(void) del_GetLine(gl);
6824 	return (err);
6825 }
6826