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