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