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