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