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