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