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