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