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