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