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