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