Home | History | Annotate | Download | only in zonecfg
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * zonecfg is a lex/yacc based command interpreter used to manage zone
     29  * configurations.  The lexer (see zonecfg_lex.l) builds up tokens, which
     30  * the grammar (see zonecfg_grammar.y) builds up into commands, some of
     31  * which takes resources and/or properties as arguments.  See the block
     32  * comments near the end of zonecfg_grammar.y for how the data structures
     33  * which keep track of these resources and properties are built up.
     34  *
     35  * The resource/property data structures are inserted into a command
     36  * structure (see zonecfg.h), which also keeps track of command names,
     37  * miscellaneous arguments, and function handlers.  The grammar selects
     38  * the appropriate function handler, each of which takes a pointer to a
     39  * command structure as its sole argument, and invokes it.  The grammar
     40  * itself is "entered" (a la the Matrix) by yyparse(), which is called
     41  * from read_input(), our main driving function.  That in turn is called
     42  * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
     43  * of which is called from main() depending on how the program was invoked.
     44  *
     45  * The rest of this module consists of the various function handlers and
     46  * their helper functions.  Some of these functions, particularly the
     47  * X_to_str() functions, which maps command, resource and property numbers
     48  * to strings, are used quite liberally, as doing so results in a better
     49  * program w/rt I18N, reducing the need for translation notes.
     50  */
     51 
     52 #include <sys/mntent.h>
     53 #include <sys/varargs.h>
     54 #include <sys/sysmacros.h>
     55 
     56 #include <errno.h>
     57 #include <fcntl.h>
     58 #include <strings.h>
     59 #include <unistd.h>
     60 #include <ctype.h>
     61 #include <stdlib.h>
     62 #include <assert.h>
     63 #include <sys/stat.h>
     64 #include <zone.h>
     65 #include <arpa/inet.h>
     66 #include <netdb.h>
     67 #include <locale.h>
     68 #include <libintl.h>
     69 #include <alloca.h>
     70 #include <signal.h>
     71 #include <wait.h>
     72 #include <libtecla.h>
     73 #include <libzfs.h>
     74 #include <sys/brand.h>
     75 #include <libbrand.h>
     76 #include <sys/systeminfo.h>
     77 #include <libdladm.h>
     78 #include <libinetutil.h>
     79 
     80 #include <libzonecfg.h>
     81 #include "zonecfg.h"
     82 
     83 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
     84 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
     85 #endif
     86 
     87 #define	PAGER	"/usr/bin/more"
     88 #define	EXEC_PREFIX	"exec "
     89 #define	EXEC_LEN	(strlen(EXEC_PREFIX))
     90 
     91 struct help {
     92 	uint_t	cmd_num;
     93 	char	*cmd_name;
     94 	uint_t	flags;
     95 	char	*short_usage;
     96 };
     97 
     98 extern int yyparse(void);
     99 extern int lex_lineno;
    100 
    101 #define	MAX_LINE_LEN	1024
    102 #define	MAX_CMD_HIST	1024
    103 #define	MAX_CMD_LEN	1024
    104 
    105 #define	ONE_MB		1048576
    106 
    107 /*
    108  * Each SHELP_ should be a simple string.
    109  */
    110 
    111 #define	SHELP_ADD	"add <resource-type>\n\t(global scope)\n" \
    112 	"add <property-name> <property-value>\n\t(resource scope)"
    113 #define	SHELP_CANCEL	"cancel"
    114 #define	SHELP_CLEAR	"clear <property-name>"
    115 #define	SHELP_COMMIT	"commit"
    116 #define	SHELP_CREATE	"create [-F] [ -a <path> | -b | -t <template> ]"
    117 #define	SHELP_DELETE	"delete [-F]"
    118 #define	SHELP_END	"end"
    119 #define	SHELP_EXIT	"exit [-F]"
    120 #define	SHELP_EXPORT	"export [-f output-file]"
    121 #define	SHELP_HELP	"help [commands] [syntax] [usage] [<command-name>]"
    122 #define	SHELP_INFO	"info [<resource-type> [property-name=property-value]*]"
    123 #define	SHELP_REMOVE	"remove [-F] <resource-type> " \
    124 	"[ <property-name>=<property-value> ]*\n" \
    125 	"\t(global scope)\n" \
    126 	"remove <property-name> <property-value>\n" \
    127 	"\t(resource scope)"
    128 #define	SHELP_REVERT	"revert [-F]"
    129 #define	SHELP_SELECT	"select <resource-type> { <property-name>=" \
    130 	"<property-value> }"
    131 #define	SHELP_SET	"set <property-name>=<property-value>"
    132 #define	SHELP_VERIFY	"verify"
    133 
    134 static struct help helptab[] = {
    135 	{ CMD_ADD,	"add",		HELP_RES_PROPS,	SHELP_ADD, },
    136 	{ CMD_CANCEL,	"cancel",	0,		SHELP_CANCEL, },
    137 	{ CMD_CLEAR,	"clear",	HELP_PROPS,	SHELP_CLEAR, },
    138 	{ CMD_COMMIT,	"commit",	0,		SHELP_COMMIT, },
    139 	{ CMD_CREATE,	"create",	0,		SHELP_CREATE, },
    140 	{ CMD_DELETE,	"delete",	0,		SHELP_DELETE, },
    141 	{ CMD_END,	"end",		0,		SHELP_END, },
    142 	{ CMD_EXIT,	"exit",		0,		SHELP_EXIT, },
    143 	{ CMD_EXPORT,	"export",	0,		SHELP_EXPORT, },
    144 	{ CMD_HELP,	"help",		0,		SHELP_HELP },
    145 	{ CMD_INFO,	"info",		HELP_RES_PROPS,	SHELP_INFO, },
    146 	{ CMD_REMOVE,	"remove",	HELP_RES_PROPS,	SHELP_REMOVE, },
    147 	{ CMD_REVERT,	"revert",	0,		SHELP_REVERT, },
    148 	{ CMD_SELECT,	"select",	HELP_RES_PROPS,	SHELP_SELECT, },
    149 	{ CMD_SET,	"set",		HELP_PROPS,	SHELP_SET, },
    150 	{ CMD_VERIFY,	"verify",	0,		SHELP_VERIFY, },
    151 	{ 0 },
    152 };
    153 
    154 #define	MAX_RT_STRLEN	16
    155 
    156 /* These *must* match the order of the RT_ define's from zonecfg.h */
    157 static char *res_types[] = {
    158 	"unknown",
    159 	"zonename",
    160 	"zonepath",
    161 	"autoboot",
    162 	"pool",
    163 	"fs",
    164 	"inherit-pkg-dir",
    165 	"net",
    166 	"device",
    167 	"rctl",
    168 	"attr",
    169 	"dataset",
    170 	"limitpriv",
    171 	"bootargs",
    172 	"brand",
    173 	"dedicated-cpu",
    174 	"capped-memory",
    175 	ALIAS_MAXLWPS,
    176 	ALIAS_MAXSHMMEM,
    177 	ALIAS_MAXSHMIDS,
    178 	ALIAS_MAXMSGIDS,
    179 	ALIAS_MAXSEMIDS,
    180 	ALIAS_SHARES,
    181 	"scheduling-class",
    182 	"ip-type",
    183 	"capped-cpu",
    184 	"hostid",
    185 	NULL
    186 };
    187 
    188 /* These *must* match the order of the PT_ define's from zonecfg.h */
    189 static char *prop_types[] = {
    190 	"unknown",
    191 	"zonename",
    192 	"zonepath",
    193 	"autoboot",
    194 	"pool",
    195 	"dir",
    196 	"special",
    197 	"type",
    198 	"options",
    199 	"address",
    200 	"physical",
    201 	"name",
    202 	"value",
    203 	"match",
    204 	"priv",
    205 	"limit",
    206 	"action",
    207 	"raw",
    208 	"limitpriv",
    209 	"bootargs",
    210 	"brand",
    211 	"ncpus",
    212 	"importance",
    213 	"swap",
    214 	"locked",
    215 	ALIAS_SHARES,
    216 	ALIAS_MAXLWPS,
    217 	ALIAS_MAXSHMMEM,
    218 	ALIAS_MAXSHMIDS,
    219 	ALIAS_MAXMSGIDS,
    220 	ALIAS_MAXSEMIDS,
    221 	ALIAS_MAXLOCKEDMEM,
    222 	ALIAS_MAXSWAP,
    223 	"scheduling-class",
    224 	"ip-type",
    225 	"defrouter",
    226 	"hostid",
    227 	NULL
    228 };
    229 
    230 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
    231 static char *prop_val_types[] = {
    232 	"simple",
    233 	"complex",
    234 	"list",
    235 };
    236 
    237 /*
    238  * The various _cmds[] lists below are for command tab-completion.
    239  */
    240 
    241 /*
    242  * remove has a space afterwards because it has qualifiers; the other commands
    243  * that have qualifiers (add, select, etc.) don't need a space here because
    244  * they have their own _cmds[] lists below.
    245  */
    246 static const char *global_scope_cmds[] = {
    247 	"add",
    248 	"clear",
    249 	"commit",
    250 	"create",
    251 	"delete",
    252 	"exit",
    253 	"export",
    254 	"help",
    255 	"info",
    256 	"remove ",
    257 	"revert",
    258 	"select",
    259 	"set",
    260 	"verify",
    261 	NULL
    262 };
    263 
    264 static const char *add_cmds[] = {
    265 	"add fs",
    266 	"add inherit-pkg-dir",
    267 	"add net",
    268 	"add device",
    269 	"add rctl",
    270 	"add attr",
    271 	"add dataset",
    272 	"add dedicated-cpu",
    273 	"add capped-cpu",
    274 	"add capped-memory",
    275 	NULL
    276 };
    277 
    278 static const char *clear_cmds[] = {
    279 	"clear autoboot",
    280 	"clear pool",
    281 	"clear limitpriv",
    282 	"clear bootargs",
    283 	"clear scheduling-class",
    284 	"clear ip-type",
    285 	"clear " ALIAS_MAXLWPS,
    286 	"clear " ALIAS_MAXSHMMEM,
    287 	"clear " ALIAS_MAXSHMIDS,
    288 	"clear " ALIAS_MAXMSGIDS,
    289 	"clear " ALIAS_MAXSEMIDS,
    290 	"clear " ALIAS_SHARES,
    291 	NULL
    292 };
    293 
    294 static const char *remove_cmds[] = {
    295 	"remove fs ",
    296 	"remove inherit-pkg-dir ",
    297 	"remove net ",
    298 	"remove device ",
    299 	"remove rctl ",
    300 	"remove attr ",
    301 	"remove dataset ",
    302 	"remove dedicated-cpu ",
    303 	"remove capped-cpu ",
    304 	"remove capped-memory ",
    305 	NULL
    306 };
    307 
    308 static const char *select_cmds[] = {
    309 	"select fs ",
    310 	"select inherit-pkg-dir ",
    311 	"select net ",
    312 	"select device ",
    313 	"select rctl ",
    314 	"select attr ",
    315 	"select dataset ",
    316 	"select dedicated-cpu",
    317 	"select capped-cpu",
    318 	"select capped-memory",
    319 	NULL
    320 };
    321 
    322 static const char *set_cmds[] = {
    323 	"set zonename=",
    324 	"set zonepath=",
    325 	"set brand=",
    326 	"set autoboot=",
    327 	"set pool=",
    328 	"set limitpriv=",
    329 	"set bootargs=",
    330 	"set scheduling-class=",
    331 	"set ip-type=",
    332 	"set " ALIAS_MAXLWPS "=",
    333 	"set " ALIAS_MAXSHMMEM "=",
    334 	"set " ALIAS_MAXSHMIDS "=",
    335 	"set " ALIAS_MAXMSGIDS "=",
    336 	"set " ALIAS_MAXSEMIDS "=",
    337 	"set " ALIAS_SHARES "=",
    338 	"set hostid=",
    339 	NULL
    340 };
    341 
    342 static const char *info_cmds[] = {
    343 	"info fs ",
    344 	"info inherit-pkg-dir ",
    345 	"info net ",
    346 	"info device ",
    347 	"info rctl ",
    348 	"info attr ",
    349 	"info dataset ",
    350 	"info capped-memory",
    351 	"info dedicated-cpu",
    352 	"info capped-cpu",
    353 	"info zonename",
    354 	"info zonepath",
    355 	"info autoboot",
    356 	"info pool",
    357 	"info limitpriv",
    358 	"info bootargs",
    359 	"info brand",
    360 	"info scheduling-class",
    361 	"info ip-type",
    362 	"info max-lwps",
    363 	"info max-shm-memory",
    364 	"info max-shm-ids",
    365 	"info max-msg-ids",
    366 	"info max-sem-ids",
    367 	"info cpu-shares",
    368 	"info hostid",
    369 	NULL
    370 };
    371 
    372 static const char *fs_res_scope_cmds[] = {
    373 	"add options ",
    374 	"cancel",
    375 	"end",
    376 	"exit",
    377 	"help",
    378 	"info",
    379 	"remove options ",
    380 	"set dir=",
    381 	"set raw=",
    382 	"set special=",
    383 	"set type=",
    384 	"clear raw",
    385 	NULL
    386 };
    387 
    388 static const char *net_res_scope_cmds[] = {
    389 	"cancel",
    390 	"end",
    391 	"exit",
    392 	"help",
    393 	"info",
    394 	"set address=",
    395 	"set physical=",
    396 	NULL
    397 };
    398 
    399 static const char *ipd_res_scope_cmds[] = {
    400 	"cancel",
    401 	"end",
    402 	"exit",
    403 	"help",
    404 	"info",
    405 	"set dir=",
    406 	NULL
    407 };
    408 
    409 static const char *device_res_scope_cmds[] = {
    410 	"cancel",
    411 	"end",
    412 	"exit",
    413 	"help",
    414 	"info",
    415 	"set match=",
    416 	NULL
    417 };
    418 
    419 static const char *attr_res_scope_cmds[] = {
    420 	"cancel",
    421 	"end",
    422 	"exit",
    423 	"help",
    424 	"info",
    425 	"set name=",
    426 	"set type=",
    427 	"set value=",
    428 	NULL
    429 };
    430 
    431 static const char *rctl_res_scope_cmds[] = {
    432 	"add value ",
    433 	"cancel",
    434 	"end",
    435 	"exit",
    436 	"help",
    437 	"info",
    438 	"remove value ",
    439 	"set name=",
    440 	NULL
    441 };
    442 
    443 static const char *dataset_res_scope_cmds[] = {
    444 	"cancel",
    445 	"end",
    446 	"exit",
    447 	"help",
    448 	"info",
    449 	"set name=",
    450 	NULL
    451 };
    452 
    453 static const char *pset_res_scope_cmds[] = {
    454 	"cancel",
    455 	"end",
    456 	"exit",
    457 	"help",
    458 	"info",
    459 	"set ncpus=",
    460 	"set importance=",
    461 	"clear importance",
    462 	NULL
    463 };
    464 
    465 static const char *pcap_res_scope_cmds[] = {
    466 	"cancel",
    467 	"end",
    468 	"exit",
    469 	"help",
    470 	"info",
    471 	"set ncpus=",
    472 	NULL
    473 };
    474 
    475 static const char *mcap_res_scope_cmds[] = {
    476 	"cancel",
    477 	"end",
    478 	"exit",
    479 	"help",
    480 	"info",
    481 	"set physical=",
    482 	"set swap=",
    483 	"set locked=",
    484 	"clear physical",
    485 	"clear swap",
    486 	"clear locked",
    487 	NULL
    488 };
    489 
    490 /* Global variables */
    491 
    492 /* set early in main(), never modified thereafter, used all over the place */
    493 static char *execname;
    494 
    495 /* set in main(), used all over the place */
    496 static zone_dochandle_t handle;
    497 
    498 /* used all over the place */
    499 static char zone[ZONENAME_MAX];
    500 static char revert_zone[ZONENAME_MAX];
    501 
    502 /* global brand operations */
    503 static brand_handle_t brand;
    504 
    505 /* set in modifying functions, checked in read_input() */
    506 static boolean_t need_to_commit = B_FALSE;
    507 boolean_t saw_error;
    508 
    509 /* set in yacc parser, checked in read_input() */
    510 boolean_t newline_terminated;
    511 
    512 /* set in main(), checked in lex error handler */
    513 boolean_t cmd_file_mode;
    514 
    515 /* set in exit_func(), checked in read_input() */
    516 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
    517 
    518 /* used in short_usage() and zerr() */
    519 static char *cmd_file_name = NULL;
    520 
    521 /* checked in read_input() and other places */
    522 static boolean_t ok_to_prompt = B_FALSE;
    523 
    524 /* set and checked in initialize() */
    525 static boolean_t got_handle = B_FALSE;
    526 
    527 /* initialized in do_interactive(), checked in initialize() */
    528 static boolean_t interactive_mode;
    529 
    530 /* set if configuring the global zone */
    531 static boolean_t global_zone = B_FALSE;
    532 
    533 /* set in main(), checked in multiple places */
    534 static boolean_t read_only_mode;
    535 
    536 /* scope is outer/global or inner/resource */
    537 static boolean_t global_scope = B_TRUE;
    538 static int resource_scope;	/* should be in the RT_ list from zonecfg.h */
    539 static int end_op = -1;		/* operation on end is either add or modify */
    540 
    541 int num_prop_vals;		/* for grammar */
    542 
    543 /*
    544  * These are for keeping track of resources as they are specified as part of
    545  * the multi-step process.  They should be initialized by add_resource() or
    546  * select_func() and filled in by add_property() or set_func().
    547  */
    548 static struct zone_fstab	old_fstab, in_progress_fstab;
    549 static struct zone_fstab	old_ipdtab, in_progress_ipdtab;
    550 static struct zone_nwiftab	old_nwiftab, in_progress_nwiftab;
    551 static struct zone_devtab	old_devtab, in_progress_devtab;
    552 static struct zone_rctltab	old_rctltab, in_progress_rctltab;
    553 static struct zone_attrtab	old_attrtab, in_progress_attrtab;
    554 static struct zone_dstab	old_dstab, in_progress_dstab;
    555 static struct zone_psettab	old_psettab, in_progress_psettab;
    556 static struct zone_mcaptab	old_mcaptab, in_progress_mcaptab;
    557 
    558 static GetLine *gl;	/* The gl_get_line() resource object */
    559 
    560 static void bytes_to_units(char *str, char *buf, int bufsize);
    561 
    562 /* Functions begin here */
    563 
    564 static boolean_t
    565 initial_match(const char *line1, const char *line2, int word_end)
    566 {
    567 	if (word_end <= 0)
    568 		return (B_TRUE);
    569 	return (strncmp(line1, line2, word_end) == 0);
    570 }
    571 
    572 static int
    573 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
    574     int word_end)
    575 {
    576 	int i, err;
    577 
    578 	for (i = 0; list[i] != NULL; i++) {
    579 		if (initial_match(line1, list[i], word_end)) {
    580 			err = cpl_add_completion(cpl, line1, 0, word_end,
    581 			    list[i] + word_end, "", "");
    582 			if (err != 0)
    583 				return (err);
    584 		}
    585 	}
    586 	return (0);
    587 }
    588 
    589 static
    590 /* ARGSUSED */
    591 CPL_MATCH_FN(cmd_cpl_fn)
    592 {
    593 	if (global_scope) {
    594 		/*
    595 		 * The MAX/MIN tests below are to make sure we have at least
    596 		 * enough characters to distinguish from other prefixes (MAX)
    597 		 * but only check MIN(what we have, what we're checking).
    598 		 */
    599 		if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
    600 			return (add_stuff(cpl, line, add_cmds, word_end));
    601 		if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
    602 			return (add_stuff(cpl, line, clear_cmds, word_end));
    603 		if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
    604 			return (add_stuff(cpl, line, select_cmds, word_end));
    605 		if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
    606 			return (add_stuff(cpl, line, set_cmds, word_end));
    607 		if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
    608 			return (add_stuff(cpl, line, remove_cmds, word_end));
    609 		if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
    610 			return (add_stuff(cpl, line, info_cmds, word_end));
    611 		return (add_stuff(cpl, line, global_scope_cmds, word_end));
    612 	}
    613 	switch (resource_scope) {
    614 	case RT_FS:
    615 		return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
    616 	case RT_IPD:
    617 		return (add_stuff(cpl, line, ipd_res_scope_cmds, word_end));
    618 	case RT_NET:
    619 		return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
    620 	case RT_DEVICE:
    621 		return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
    622 	case RT_RCTL:
    623 		return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
    624 	case RT_ATTR:
    625 		return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
    626 	case RT_DATASET:
    627 		return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
    628 	case RT_DCPU:
    629 		return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
    630 	case RT_PCAP:
    631 		return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
    632 	case RT_MCAP:
    633 		return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
    634 	}
    635 	return (0);
    636 }
    637 
    638 /*
    639  * For the main CMD_func() functions below, several of them call getopt()
    640  * then check optind against argc to make sure an extra parameter was not
    641  * passed in.  The reason this is not caught in the grammar is that the
    642  * grammar just checks for a miscellaneous TOKEN, which is *expected* to
    643  * be "-F" (for example), but could be anything.  So (for example) this
    644  * check will prevent "create bogus".
    645  */
    646 
    647 cmd_t *
    648 alloc_cmd(void)
    649 {
    650 	return (calloc(1, sizeof (cmd_t)));
    651 }
    652 
    653 void
    654 free_cmd(cmd_t *cmd)
    655 {
    656 	int i;
    657 
    658 	for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
    659 		if (cmd->cmd_property_ptr[i] != NULL) {
    660 			property_value_ptr_t pp = cmd->cmd_property_ptr[i];
    661 
    662 			switch (pp->pv_type) {
    663 			case PROP_VAL_SIMPLE:
    664 				free(pp->pv_simple);
    665 				break;
    666 			case PROP_VAL_COMPLEX:
    667 				free_complex(pp->pv_complex);
    668 				break;
    669 			case PROP_VAL_LIST:
    670 				free_list(pp->pv_list);
    671 				break;
    672 			}
    673 		}
    674 	for (i = 0; i < cmd->cmd_argc; i++)
    675 		free(cmd->cmd_argv[i]);
    676 	free(cmd);
    677 }
    678 
    679 complex_property_ptr_t
    680 alloc_complex(void)
    681 {
    682 	return (calloc(1, sizeof (complex_property_t)));
    683 }
    684 
    685 void
    686 free_complex(complex_property_ptr_t complex)
    687 {
    688 	if (complex == NULL)
    689 		return;
    690 	free_complex(complex->cp_next);
    691 	if (complex->cp_value != NULL)
    692 		free(complex->cp_value);
    693 	free(complex);
    694 }
    695 
    696 list_property_ptr_t
    697 alloc_list(void)
    698 {
    699 	return (calloc(1, sizeof (list_property_t)));
    700 }
    701 
    702 void
    703 free_list(list_property_ptr_t list)
    704 {
    705 	if (list == NULL)
    706 		return;
    707 	if (list->lp_simple != NULL)
    708 		free(list->lp_simple);
    709 	free_complex(list->lp_complex);
    710 	free_list(list->lp_next);
    711 	free(list);
    712 }
    713 
    714 void
    715 free_outer_list(list_property_ptr_t list)
    716 {
    717 	if (list == NULL)
    718 		return;
    719 	free_outer_list(list->lp_next);
    720 	free(list);
    721 }
    722 
    723 static struct zone_rctlvaltab *
    724 alloc_rctlvaltab(void)
    725 {
    726 	return (calloc(1, sizeof (struct zone_rctlvaltab)));
    727 }
    728 
    729 static char *
    730 rt_to_str(int res_type)
    731 {
    732 	assert(res_type >= RT_MIN && res_type <= RT_MAX);
    733 	return (res_types[res_type]);
    734 }
    735 
    736 static char *
    737 pt_to_str(int prop_type)
    738 {
    739 	assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
    740 	return (prop_types[prop_type]);
    741 }
    742 
    743 static char *
    744 pvt_to_str(int pv_type)
    745 {
    746 	assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
    747 	return (prop_val_types[pv_type]);
    748 }
    749 
    750 static char *
    751 cmd_to_str(int cmd_num)
    752 {
    753 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
    754 	return (helptab[cmd_num].cmd_name);
    755 }
    756 
    757 /*
    758  * This is a separate function rather than a set of define's because of the
    759  * gettext() wrapping.
    760  */
    761 
    762 /*
    763  * TRANSLATION_NOTE
    764  * Each string below should have \t follow \n whenever needed; the
    765  * initial \t and the terminal \n will be provided by the calling function.
    766  */
    767 
    768 static char *
    769 long_help(int cmd_num)
    770 {
    771 	static char line[1024];	/* arbitrary large amount */
    772 
    773 	assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
    774 	switch (cmd_num) {
    775 		case CMD_HELP:
    776 			return (gettext("Prints help message."));
    777 		case CMD_CREATE:
    778 			(void) snprintf(line, sizeof (line),
    779 			    gettext("Creates a configuration for the "
    780 			    "specified zone.  %s should be\n\tused to "
    781 			    "begin configuring a new zone.  If overwriting an "
    782 			    "existing\n\tconfiguration, the -F flag can be "
    783 			    "used to force the action.  If\n\t-t template is "
    784 			    "given, creates a configuration identical to the\n"
    785 			    "\tspecified template, except that the zone name "
    786 			    "is changed from\n\ttemplate to zonename.  '%s -a' "
    787 			    "creates a configuration from a\n\tdetached "
    788 			    "zonepath.  '%s -b' results in a blank "
    789 			    "configuration.\n\t'%s' with no arguments applies "
    790 			    "the Sun default settings."),
    791 			    cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
    792 			    cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
    793 			return (line);
    794 		case CMD_EXIT:
    795 			return (gettext("Exits the program.  The -F flag can "
    796 			    "be used to force the action."));
    797 		case CMD_EXPORT:
    798 			return (gettext("Prints configuration to standard "
    799 			    "output, or to output-file if\n\tspecified, in "
    800 			    "a form suitable for use in a command-file."));
    801 		case CMD_ADD:
    802 			return (gettext("Add specified resource to "
    803 			    "configuration."));
    804 		case CMD_DELETE:
    805 			return (gettext("Deletes the specified zone.  The -F "
    806 			    "flag can be used to force the\n\taction."));
    807 		case CMD_REMOVE:
    808 			return (gettext("Remove specified resource from "
    809 			    "configuration.  The -F flag can be used\n\tto "
    810 			    "force the action."));
    811 		case CMD_SELECT:
    812 			(void) snprintf(line, sizeof (line),
    813 			    gettext("Selects a resource to modify.  "
    814 			    "Resource modification is completed\n\twith the "
    815 			    "command \"%s\".  The property name/value pairs "
    816 			    "must uniquely\n\tidentify a resource.  Note that "
    817 			    "the curly braces ('{', '}') mean one\n\tor more "
    818 			    "of whatever is between them."),
    819 			    cmd_to_str(CMD_END));
    820 			return (line);
    821 		case CMD_SET:
    822 			return (gettext("Sets property values."));
    823 		case CMD_CLEAR:
    824 			return (gettext("Clears property values."));
    825 		case CMD_INFO:
    826 			return (gettext("Displays information about the "
    827 			    "current configuration.  If resource\n\ttype is "
    828 			    "specified, displays only information about "
    829 			    "resources of\n\tthe relevant type.  If resource "
    830 			    "id is specified, displays only\n\tinformation "
    831 			    "about that resource."));
    832 		case CMD_VERIFY:
    833 			return (gettext("Verifies current configuration "
    834 			    "for correctness (some resource types\n\thave "
    835 			    "required properties)."));
    836 		case CMD_COMMIT:
    837 			(void) snprintf(line, sizeof (line),
    838 			    gettext("Commits current configuration.  "
    839 			    "Configuration must be committed to\n\tbe used by "
    840 			    "%s.  Until the configuration is committed, "
    841 			    "changes \n\tcan be removed with the %s "
    842 			    "command.  This operation is\n\tattempted "
    843 			    "automatically upon completion of a %s "
    844 			    "session."), "zoneadm", cmd_to_str(CMD_REVERT),
    845 			    "zonecfg");
    846 			return (line);
    847 		case CMD_REVERT:
    848 			return (gettext("Reverts configuration back to the "
    849 			    "last committed state.  The -F flag\n\tcan be "
    850 			    "used to force the action."));
    851 		case CMD_CANCEL:
    852 			return (gettext("Cancels resource/property "
    853 			    "specification."));
    854 		case CMD_END:
    855 			return (gettext("Ends resource/property "
    856 			    "specification."));
    857 	}
    858 	/* NOTREACHED */
    859 	return (NULL);
    860 }
    861 
    862 /*
    863  * Called with verbose TRUE when help is explicitly requested, FALSE for
    864  * unexpected errors.
    865  */
    866 
    867 void
    868 usage(boolean_t verbose, uint_t flags)
    869 {
    870 	FILE *fp = verbose ? stdout : stderr, *newfp;
    871 	boolean_t need_to_close = B_FALSE;
    872 	char *pager;
    873 	int i;
    874 
    875 	/* don't page error output */
    876 	if (verbose && interactive_mode) {
    877 		if ((pager = getenv("PAGER")) == NULL)
    878 			pager = PAGER;
    879 		if ((newfp = popen(pager, "w")) != NULL) {
    880 			need_to_close = B_TRUE;
    881 			fp = newfp;
    882 		}
    883 	}
    884 	if (flags & HELP_META) {
    885 		(void) fprintf(fp, gettext("More help is available for the "
    886 		    "following:\n"));
    887 		(void) fprintf(fp, "\n\tcommands ('%s commands')\n",
    888 		    cmd_to_str(CMD_HELP));
    889 		(void) fprintf(fp, "\tsyntax ('%s syntax')\n",
    890 		    cmd_to_str(CMD_HELP));
    891 		(void) fprintf(fp, "\tusage ('%s usage')\n\n",
    892 		    cmd_to_str(CMD_HELP));
    893 		(void) fprintf(fp, gettext("You may also obtain help on any "
    894 		    "command by typing '%s <command-name>.'\n"),
    895 		    cmd_to_str(CMD_HELP));
    896 	}
    897 	if (flags & HELP_RES_SCOPE) {
    898 		switch (resource_scope) {
    899 		case RT_FS:
    900 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    901 			    "used to configure a file-system.\n"),
    902 			    rt_to_str(resource_scope));
    903 			(void) fprintf(fp, gettext("Valid commands:\n"));
    904 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    905 			    pt_to_str(PT_DIR), gettext("<path>"));
    906 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    907 			    pt_to_str(PT_SPECIAL), gettext("<path>"));
    908 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    909 			    pt_to_str(PT_RAW), gettext("<raw-device>"));
    910 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    911 			    pt_to_str(PT_TYPE), gettext("<file-system type>"));
    912 			(void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
    913 			    pt_to_str(PT_OPTIONS),
    914 			    gettext("<file-system options>"));
    915 			(void) fprintf(fp, "\t%s %s %s\n",
    916 			    cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
    917 			    gettext("<file-system options>"));
    918 			(void) fprintf(fp, gettext("Consult the file-system "
    919 			    "specific manual page, such as mount_ufs(1M), "
    920 			    "for\ndetails about file-system options.  Note "
    921 			    "that any file-system options with an\nembedded "
    922 			    "'=' character must be enclosed in double quotes, "
    923 			    /*CSTYLED*/
    924 			    "such as \"%s=5\".\n"), MNTOPT_RETRY);
    925 			break;
    926 		case RT_IPD:
    927 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    928 			    "used to configure a directory\ninherited from the "
    929 			    "global zone into a non-global zone in read-only "
    930 			    "mode.\n"), rt_to_str(resource_scope));
    931 			(void) fprintf(fp, gettext("Valid commands:\n"));
    932 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    933 			    pt_to_str(PT_DIR), gettext("<path>"));
    934 			break;
    935 		case RT_NET:
    936 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    937 			    "used to configure a network interface.\n"),
    938 			    rt_to_str(resource_scope));
    939 			(void) fprintf(fp, gettext("Valid commands:\n"));
    940 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    941 			    pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
    942 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    943 			    pt_to_str(PT_PHYSICAL), gettext("<interface>"));
    944 			(void) fprintf(fp, gettext("See ifconfig(1M) for "
    945 			    "details of the <interface> string.\n"));
    946 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    947 			    pt_to_str(PT_DEFROUTER), gettext("<IP-address>"));
    948 			(void) fprintf(fp, gettext("%s %s and %s %s are valid "
    949 			    "if the %s property is set to %s, otherwise they "
    950 			    "must not be set.\n"),
    951 			    cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
    952 			    cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
    953 			    pt_to_str(PT_IPTYPE), "shared");
    954 			break;
    955 		case RT_DEVICE:
    956 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    957 			    "used to configure a device node.\n"),
    958 			    rt_to_str(resource_scope));
    959 			(void) fprintf(fp, gettext("Valid commands:\n"));
    960 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    961 			    pt_to_str(PT_MATCH), gettext("<device-path>"));
    962 			break;
    963 		case RT_RCTL:
    964 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    965 			    "used to configure a resource control.\n"),
    966 			    rt_to_str(resource_scope));
    967 			(void) fprintf(fp, gettext("Valid commands:\n"));
    968 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    969 			    pt_to_str(PT_NAME), gettext("<string>"));
    970 			(void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
    971 			    cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
    972 			    pt_to_str(PT_PRIV), gettext("<priv-value>"),
    973 			    pt_to_str(PT_LIMIT), gettext("<number>"),
    974 			    pt_to_str(PT_ACTION), gettext("<action-value>"));
    975 			(void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
    976 			    cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
    977 			    pt_to_str(PT_PRIV), gettext("<priv-value>"),
    978 			    pt_to_str(PT_LIMIT), gettext("<number>"),
    979 			    pt_to_str(PT_ACTION), gettext("<action-value>"));
    980 			(void) fprintf(fp, "%s\n\t%s := privileged\n"
    981 			    "\t%s := none | deny\n", gettext("Where"),
    982 			    gettext("<priv-value>"), gettext("<action-value>"));
    983 			break;
    984 		case RT_ATTR:
    985 			(void) fprintf(fp, gettext("The '%s' resource scope is "
    986 			    "used to configure a generic attribute.\n"),
    987 			    rt_to_str(resource_scope));
    988 			(void) fprintf(fp, gettext("Valid commands:\n"));
    989 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    990 			    pt_to_str(PT_NAME), gettext("<name>"));
    991 			(void) fprintf(fp, "\t%s %s=boolean\n",
    992 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
    993 			(void) fprintf(fp, "\t%s %s=true | false\n",
    994 			    cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
    995 			(void) fprintf(fp, gettext("or\n"));
    996 			(void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
    997 			    pt_to_str(PT_TYPE));
    998 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
    999 			    pt_to_str(PT_VALUE), gettext("<integer>"));
   1000 			(void) fprintf(fp, gettext("or\n"));
   1001 			(void) fprintf(fp, "\t%s %s=string\n",
   1002 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
   1003 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1004 			    pt_to_str(PT_VALUE), gettext("<string>"));
   1005 			(void) fprintf(fp, gettext("or\n"));
   1006 			(void) fprintf(fp, "\t%s %s=uint\n",
   1007 			    cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
   1008 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1009 			    pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
   1010 			break;
   1011 		case RT_DATASET:
   1012 			(void) fprintf(fp, gettext("The '%s' resource scope is "
   1013 			    "used to export ZFS datasets.\n"),
   1014 			    rt_to_str(resource_scope));
   1015 			(void) fprintf(fp, gettext("Valid commands:\n"));
   1016 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1017 			    pt_to_str(PT_NAME), gettext("<name>"));
   1018 			break;
   1019 		case RT_DCPU:
   1020 			(void) fprintf(fp, gettext("The '%s' resource scope "
   1021 			    "configures the 'pools' facility to dedicate\na "
   1022 			    "subset of the system's processors to this zone "
   1023 			    "while it is running.\n"),
   1024 			    rt_to_str(resource_scope));
   1025 			(void) fprintf(fp, gettext("Valid commands:\n"));
   1026 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1027 			    pt_to_str(PT_NCPUS),
   1028 			    gettext("<unsigned integer | range>"));
   1029 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1030 			    pt_to_str(PT_IMPORTANCE),
   1031 			    gettext("<unsigned integer>"));
   1032 			break;
   1033 		case RT_PCAP:
   1034 			(void) fprintf(fp, gettext("The '%s' resource scope is "
   1035 			    "used to set an upper limit (a cap) on the\n"
   1036 			    "percentage of CPU that can be used by this zone.  "
   1037 			    "A '%s' value of 1\ncorresponds to one cpu.  The "
   1038 			    "value can be set higher than 1, up to the total\n"
   1039 			    "number of CPUs on the system.  The value can "
   1040 			    "also be less than 1,\nrepresenting a fraction of "
   1041 			    "a cpu.\n"),
   1042 			    rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
   1043 			(void) fprintf(fp, gettext("Valid commands:\n"));
   1044 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1045 			    pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
   1046 			break;
   1047 		case RT_MCAP:
   1048 			(void) fprintf(fp, gettext("The '%s' resource scope is "
   1049 			    "used to set an upper limit (a cap) on the\n"
   1050 			    "amount of physical memory, swap space and locked "
   1051 			    "memory that can be used by\nthis zone.\n"),
   1052 			    rt_to_str(resource_scope));
   1053 			(void) fprintf(fp, gettext("Valid commands:\n"));
   1054 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1055 			    pt_to_str(PT_PHYSICAL),
   1056 			    gettext("<qualified unsigned decimal>"));
   1057 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1058 			    pt_to_str(PT_SWAP),
   1059 			    gettext("<qualified unsigned decimal>"));
   1060 			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
   1061 			    pt_to_str(PT_LOCKED),
   1062 			    gettext("<qualified unsigned decimal>"));
   1063 			break;
   1064 		}
   1065 		(void) fprintf(fp, gettext("And from any resource scope, you "
   1066 		    "can:\n"));
   1067 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
   1068 		    gettext("(to conclude this operation)"));
   1069 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
   1070 		    gettext("(to cancel this operation)"));
   1071 		(void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
   1072 		    gettext("(to exit the zonecfg utility)"));
   1073 	}
   1074 	if (flags & HELP_USAGE) {
   1075 		(void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
   1076 		    execname, cmd_to_str(CMD_HELP));
   1077 		(void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
   1078 		    execname, gettext("interactive"));
   1079 		(void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
   1080 		(void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
   1081 		    execname);
   1082 	}
   1083 	if (flags & HELP_SUBCMDS) {
   1084 		(void) fprintf(fp, "%s:\n\n", gettext("Commands"));
   1085 		for (i = 0; i <= CMD_MAX; i++) {
   1086 			(void) fprintf(fp, "%s\n", helptab[i].short_usage);
   1087 			if (verbose)
   1088 				(void) fprintf(fp, "\t%s\n\n", long_help(i));
   1089 		}
   1090 	}
   1091 	if (flags & HELP_SYNTAX) {
   1092 		if (!verbose)
   1093 			(void) fprintf(fp, "\n");
   1094 		(void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
   1095 		(void) fprintf(fp, gettext("\t(except the reserved words "
   1096 		    "'%s' and anything starting with '%s')\n"), "global",
   1097 		    "SUNW");
   1098 		(void) fprintf(fp,
   1099 		    gettext("\tName must be less than %d characters.\n"),
   1100 		    ZONENAME_MAX);
   1101 		if (verbose)
   1102 			(void) fprintf(fp, "\n");
   1103 	}
   1104 	if (flags & HELP_NETADDR) {
   1105 		(void) fprintf(fp, gettext("\n<net-addr> :="));
   1106 		(void) fprintf(fp,
   1107 		    gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
   1108 		(void) fprintf(fp,
   1109 		    gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
   1110 		(void) fprintf(fp,
   1111 		    gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
   1112 		(void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
   1113 		    "IPv6 address syntax.\n"));
   1114 		(void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
   1115 		(void) fprintf(fp,
   1116 		    gettext("<IPv6-prefix-length> := [0-128]\n"));
   1117 		(void) fprintf(fp,
   1118 		    gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
   1119 	}
   1120 	if (flags & HELP_RESOURCES) {
   1121 		(void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t"
   1122 		    "%s | %s | %s | %s\n\n",
   1123 		    gettext("resource type"), rt_to_str(RT_FS),
   1124 		    rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
   1125 		    rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
   1126 		    rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
   1127 		    rt_to_str(RT_PCAP), rt_to_str(RT_MCAP));
   1128 	}
   1129 	if (flags & HELP_PROPS) {
   1130 		(void) fprintf(fp, gettext("For resource type ... there are "
   1131 		    "property types ...:\n"));
   1132 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1133 		    pt_to_str(PT_ZONENAME));
   1134 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1135 		    pt_to_str(PT_ZONEPATH));
   1136 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1137 		    pt_to_str(PT_BRAND));
   1138 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1139 		    pt_to_str(PT_AUTOBOOT));
   1140 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1141 		    pt_to_str(PT_BOOTARGS));
   1142 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1143 		    pt_to_str(PT_POOL));
   1144 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1145 		    pt_to_str(PT_LIMITPRIV));
   1146 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1147 		    pt_to_str(PT_SCHED));
   1148 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1149 		    pt_to_str(PT_IPTYPE));
   1150 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1151 		    pt_to_str(PT_HOSTID));
   1152 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1153 		    pt_to_str(PT_MAXLWPS));
   1154 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1155 		    pt_to_str(PT_MAXSHMMEM));
   1156 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1157 		    pt_to_str(PT_MAXSHMIDS));
   1158 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1159 		    pt_to_str(PT_MAXMSGIDS));
   1160 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1161 		    pt_to_str(PT_MAXSEMIDS));
   1162 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
   1163 		    pt_to_str(PT_SHARES));
   1164 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s\n", rt_to_str(RT_FS),
   1165 		    pt_to_str(PT_DIR), pt_to_str(PT_SPECIAL),
   1166 		    pt_to_str(PT_RAW), pt_to_str(PT_TYPE),
   1167 		    pt_to_str(PT_OPTIONS));
   1168 		(void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_IPD),
   1169 		    pt_to_str(PT_DIR));
   1170 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_NET),
   1171 		    pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL),
   1172 		    pt_to_str(PT_DEFROUTER));
   1173 		(void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
   1174 		    pt_to_str(PT_MATCH));
   1175 		(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
   1176 		    pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
   1177 		(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
   1178 		    pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
   1179 		    pt_to_str(PT_VALUE));
   1180 		(void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
   1181 		    pt_to_str(PT_NAME));
   1182 		(void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
   1183 		    pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
   1184 		(void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
   1185 		    pt_to_str(PT_NCPUS));
   1186 		(void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
   1187 		    pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
   1188 		    pt_to_str(PT_LOCKED));
   1189 	}
   1190 	if (need_to_close)
   1191 		(void) pclose(fp);
   1192 }
   1193 
   1194 /* PRINTFLIKE1 */
   1195 static void
   1196 zerr(const char *fmt, ...)
   1197 {
   1198 	va_list alist;
   1199 	static int last_lineno;
   1200 
   1201 	/* lex_lineno has already been incremented in the lexer; compensate */
   1202 	if (cmd_file_mode && lex_lineno > last_lineno) {
   1203 		if (strcmp(cmd_file_name, "-") == 0)
   1204 			(void) fprintf(stderr, gettext("On line %d:\n"),
   1205 			    lex_lineno - 1);
   1206 		else
   1207 			(void) fprintf(stderr, gettext("On line %d of %s:\n"),
   1208 			    lex_lineno - 1, cmd_file_name);
   1209 		last_lineno = lex_lineno;
   1210 	}
   1211 	va_start(alist, fmt);
   1212 	(void) vfprintf(stderr, fmt, alist);
   1213 	(void) fprintf(stderr, "\n");
   1214 	va_end(alist);
   1215 }
   1216 
   1217 static void
   1218 zone_perror(char *prefix, int err, boolean_t set_saw)
   1219 {
   1220 	zerr("%s: %s", prefix, zonecfg_strerror(err));
   1221 	if (set_saw)
   1222 		saw_error = B_TRUE;
   1223 }
   1224 
   1225 /*
   1226  * zone_perror() expects a single string, but for remove and select
   1227  * we have both the command and the resource type, so this wrapper
   1228  * function serves the same purpose in a slightly different way.
   1229  */
   1230 
   1231 static void
   1232 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
   1233 {
   1234 	zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
   1235 	    zonecfg_strerror(err));
   1236 	if (set_saw)
   1237 		saw_error = B_TRUE;
   1238 }
   1239 
   1240 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
   1241 static int
   1242 initialize(boolean_t handle_expected)
   1243 {
   1244 	int err;
   1245 	char brandname[MAXNAMELEN];
   1246 
   1247 	if (zonecfg_check_handle(handle) != Z_OK) {
   1248 		if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
   1249 			got_handle = B_TRUE;
   1250 			if (zonecfg_get_brand(handle, brandname,
   1251 			    sizeof (brandname)) != Z_OK) {
   1252 				zerr("Zone %s is inconsistent: missing "
   1253 				    "brand attribute", zone);
   1254 				exit(Z_ERR);
   1255 			}
   1256 			if ((brand = brand_open(brandname)) == NULL) {
   1257 				zerr("Zone %s uses non-existent brand \"%s\"."
   1258 				    "  Unable to continue", zone, brandname);
   1259 				exit(Z_ERR);
   1260 			}
   1261 		} else if (global_zone && err == Z_NO_ZONE && !got_handle &&
   1262 		    !read_only_mode) {
   1263 			/*
   1264 			 * We implicitly create the global zone config if it
   1265 			 * doesn't exist.
   1266 			 */
   1267 			zone_dochandle_t tmphandle;
   1268 
   1269 			if ((tmphandle = zonecfg_init_handle()) == NULL) {
   1270 				zone_perror(execname, Z_NOMEM, B_TRUE);
   1271 				exit(Z_ERR);
   1272 			}
   1273 
   1274 			err = zonecfg_get_template_handle("SUNWblank", zone,
   1275 			    tmphandle);
   1276 
   1277 			if (err != Z_OK) {
   1278 				zonecfg_fini_handle(tmphandle);
   1279 				zone_perror("SUNWblank", err, B_TRUE);
   1280 				return (err);
   1281 			}
   1282 
   1283 			need_to_commit = B_TRUE;
   1284 			zonecfg_fini_handle(handle);
   1285 			handle = tmphandle;
   1286 			got_handle = B_TRUE;
   1287 
   1288 		} else {
   1289 			zone_perror(zone, err, handle_expected || got_handle);
   1290 			if (err == Z_NO_ZONE && !got_handle &&
   1291 			    interactive_mode && !read_only_mode)
   1292 				(void) printf(gettext("Use '%s' to begin "
   1293 				    "configuring a new zone.\n"),
   1294 				    cmd_to_str(CMD_CREATE));
   1295 			return (err);
   1296 		}
   1297 	}
   1298 	return (Z_OK);
   1299 }
   1300 
   1301 static boolean_t
   1302 state_atleast(zone_state_t state)
   1303 {
   1304 	zone_state_t state_num;
   1305 	int err;
   1306 
   1307 	if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
   1308 		/* all states are greater than "non-existent" */
   1309 		if (err == Z_NO_ZONE)
   1310 			return (B_FALSE);
   1311 		zerr(gettext("Unexpectedly failed to determine state "
   1312 		    "of zone %s: %s"), zone, zonecfg_strerror(err));
   1313 		exit(Z_ERR);
   1314 	}
   1315 	return (state_num >= state);
   1316 }
   1317 
   1318 /*
   1319  * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
   1320  */
   1321 
   1322 void
   1323 short_usage(int command)
   1324 {
   1325 	/* lex_lineno has already been incremented in the lexer; compensate */
   1326 	if (cmd_file_mode) {
   1327 		if (strcmp(cmd_file_name, "-") == 0)
   1328 			(void) fprintf(stderr,
   1329 			    gettext("syntax error on line %d\n"),
   1330 			    lex_lineno - 1);
   1331 		else
   1332 			(void) fprintf(stderr,
   1333 			    gettext("syntax error on line %d of %s\n"),
   1334 			    lex_lineno - 1, cmd_file_name);
   1335 	}
   1336 	(void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
   1337 	    helptab[command].short_usage);
   1338 	saw_error = B_TRUE;
   1339 }
   1340 
   1341 /*
   1342  * long_usage() is for bad semantics: e.g., wrong property type for a given
   1343  * resource type.  It is also used by longer_usage() below.
   1344  */
   1345 
   1346 void
   1347 long_usage(uint_t cmd_num, boolean_t set_saw)
   1348 {
   1349 	(void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
   1350 	    helptab[cmd_num].short_usage);
   1351 	(void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
   1352 	if (set_saw)
   1353 		saw_error = B_TRUE;
   1354 }
   1355 
   1356 /*
   1357  * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
   1358  * any extra usage() flags as appropriate for whatever command.
   1359  */
   1360 
   1361 void
   1362 longer_usage(uint_t cmd_num)
   1363 {
   1364 	long_usage(cmd_num, B_FALSE);
   1365 	if (helptab[cmd_num].flags != 0) {
   1366 		(void) printf("\n");
   1367 		usage(B_TRUE, helptab[cmd_num].flags);
   1368 	}
   1369 }
   1370 
   1371 /*
   1372  * scope_usage() is simply used when a command is called from the wrong scope.
   1373  */
   1374 
   1375 static void
   1376 scope_usage(uint_t cmd_num)
   1377 {
   1378 	zerr(gettext("The %s command only makes sense in the %s scope."),
   1379 	    cmd_to_str(cmd_num),
   1380 	    global_scope ?  gettext("resource") : gettext("global"));
   1381 	saw_error = B_TRUE;
   1382 }
   1383 
   1384 /*
   1385  * On input, B_TRUE => yes, B_FALSE => no.
   1386  * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
   1387  */
   1388 
   1389 static int
   1390 ask_yesno(boolean_t default_answer, const char *question)
   1391 {
   1392 	char line[64];	/* should be enough to answer yes or no */
   1393 
   1394 	if (!ok_to_prompt) {
   1395 		saw_error = B_TRUE;
   1396 		return (-1);
   1397 	}
   1398 	for (;;) {
   1399 		if (printf("%s (%s)? ", question,
   1400 		    default_answer ? "[y]/n" : "y/[n]") < 0)
   1401 			return (-1);
   1402 		if (fgets(line, sizeof (line), stdin) == NULL)
   1403 			return (-1);
   1404 
   1405 		if (line[0] == '\n')
   1406 			return (default_answer ? 1 : 0);
   1407 		if (tolower(line[0]) == 'y')
   1408 			return (1);
   1409 		if (tolower(line[0]) == 'n')
   1410 			return (0);
   1411 	}
   1412 }
   1413 
   1414 /*
   1415  * Prints warning if zone already exists.
   1416  * In interactive mode, prompts if we should continue anyway and returns Z_OK
   1417  * if so, Z_ERR if not.  In non-interactive mode, exits with Z_ERR.
   1418  *
   1419  * Note that if a zone exists and its state is >= INSTALLED, an error message
   1420  * will be printed and this function will return Z_ERR regardless of mode.
   1421  */
   1422 
   1423 static int
   1424 check_if_zone_already_exists(boolean_t force)
   1425 {
   1426 	char line[ZONENAME_MAX + 128];	/* enough to ask a question */
   1427 	zone_dochandle_t tmphandle;
   1428 	int res, answer;
   1429 
   1430 	if ((tmphandle = zonecfg_init_handle()) == NULL) {
   1431 		zone_perror(execname, Z_NOMEM, B_TRUE);
   1432 		exit(Z_ERR);
   1433 	}
   1434 	res = zonecfg_get_handle(zone, tmphandle);
   1435 	zonecfg_fini_handle(tmphandle);
   1436 	if (res != Z_OK)
   1437 		return (Z_OK);
   1438 
   1439 	if (state_atleast(ZONE_STATE_INSTALLED)) {
   1440 		zerr(gettext("Zone %s already installed; %s not allowed."),
   1441 		    zone, cmd_to_str(CMD_CREATE));
   1442 		return (Z_ERR);
   1443 	}
   1444 
   1445 	if (force) {
   1446 		(void) printf(gettext("Zone %s already exists; overwriting.\n"),
   1447 		    zone);
   1448 		return (Z_OK);
   1449 	}
   1450 	(void) snprintf(line, sizeof (line),
   1451 	    gettext("Zone %s already exists; %s anyway"), zone,
   1452 	    cmd_to_str(CMD_CREATE));
   1453 	if ((answer = ask_yesno(B_FALSE, line)) == -1) {
   1454 		zerr(gettext("Zone exists, input not from terminal and -F not "
   1455 		    "specified:\n%s command ignored, exiting."),
   1456 		    cmd_to_str(CMD_CREATE));
   1457 		exit(Z_ERR);
   1458 	}
   1459 	return (answer == 1 ? Z_OK : Z_ERR);
   1460 }
   1461 
   1462 static boolean_t
   1463 zone_is_read_only(int cmd_num)
   1464 {
   1465 	if (strncmp(zone, "SUNW", 4) == 0) {
   1466 		zerr(gettext("%s: zones beginning with SUNW are read-only."),
   1467 		    zone);
   1468 		saw_error = B_TRUE;
   1469 		return (B_TRUE);
   1470 	}
   1471 	if (read_only_mode) {
   1472 		zerr(gettext("%s: cannot %s in read-only mode."), zone,
   1473 		    cmd_to_str(cmd_num));
   1474 		saw_error = B_TRUE;
   1475 		return (B_TRUE);
   1476 	}
   1477 	return (B_FALSE);
   1478 }
   1479 
   1480 /*
   1481  * Create a new configuration.
   1482  */
   1483 void
   1484 create_func(cmd_t *cmd)
   1485 {
   1486 	int err, arg;
   1487 	char zone_template[ZONENAME_MAX];
   1488 	char attach_path[MAXPATHLEN];
   1489 	zone_dochandle_t tmphandle;
   1490 	boolean_t force = B_FALSE;
   1491 	boolean_t attach = B_FALSE;
   1492 	boolean_t arg_err = B_FALSE;
   1493 
   1494 	assert(cmd != NULL);
   1495 
   1496 	/* This is the default if no arguments are given. */
   1497 	(void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
   1498 
   1499 	optind = 0;
   1500 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
   1501 	    != EOF) {
   1502 		switch (arg) {
   1503 		case '?':
   1504 			if (optopt == '?')
   1505 				longer_usage(CMD_CREATE);
   1506 			else
   1507 				short_usage(CMD_CREATE);
   1508 			arg_err = B_TRUE;
   1509 			break;
   1510 		case 'a':
   1511 			(void) strlcpy(attach_path, optarg,
   1512 			    sizeof (attach_path));
   1513 			attach = B_TRUE;
   1514 			break;
   1515 		case 'b':
   1516 			(void) strlcpy(zone_template, "SUNWblank",
   1517 			    sizeof (zone_template));
   1518 			break;
   1519 		case 'F':
   1520 			force = B_TRUE;
   1521 			break;
   1522 		case 't':
   1523 			(void) strlcpy(zone_template, optarg,
   1524 			    sizeof (zone_template));
   1525 			break;
   1526 		default:
   1527 			short_usage(CMD_CREATE);
   1528 			arg_err = B_TRUE;
   1529 			break;
   1530 		}
   1531 	}
   1532 	if (arg_err)
   1533 		return;
   1534 
   1535 	if (optind != cmd->cmd_argc) {
   1536 		short_usage(CMD_CREATE);
   1537 		return;
   1538 	}
   1539 
   1540 	if (zone_is_read_only(CMD_CREATE))
   1541 		return;
   1542 
   1543 	if (check_if_zone_already_exists(force) != Z_OK)
   1544 		return;
   1545 
   1546 	/*
   1547 	 * Get a temporary handle first.  If that fails, the old handle
   1548 	 * will not be lost.  Then finish whichever one we don't need,
   1549 	 * to avoid leaks.  Then get the handle for zone_template, and
   1550 	 * set the name to zone: this "copy, rename" method is how
   1551 	 * create -[b|t] works.
   1552 	 */
   1553 	if ((tmphandle = zonecfg_init_handle()) == NULL) {
   1554 		zone_perror(execname, Z_NOMEM, B_TRUE);
   1555 		exit(Z_ERR);
   1556 	}
   1557 
   1558 	if (attach)
   1559 		err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
   1560 		    zone, B_FALSE, tmphandle);
   1561 	else
   1562 		err = zonecfg_get_template_handle(zone_template, zone,
   1563 		    tmphandle);
   1564 
   1565 	if (err != Z_OK) {
   1566 		zonecfg_fini_handle(tmphandle);
   1567 		if (attach && err == Z_NO_ZONE)
   1568 			(void) fprintf(stderr, gettext("invalid path to "
   1569 			    "detached zone\n"));
   1570 		else if (attach && err == Z_INVALID_DOCUMENT)
   1571 			(void) fprintf(stderr, gettext("Cannot attach to an "
   1572 			    "earlier release of the operating system\n"));
   1573 		else
   1574 			zone_perror(zone_template, err, B_TRUE);
   1575 		return;
   1576 	}
   1577 
   1578 	need_to_commit = B_TRUE;
   1579 	zonecfg_fini_handle(handle);
   1580 	handle = tmphandle;
   1581 	got_handle = B_TRUE;
   1582 }
   1583 
   1584 /*
   1585  * This malloc()'s memory, which must be freed by the caller.
   1586  */
   1587 static char *
   1588 quoteit(char *instr)
   1589 {
   1590 	char *outstr;
   1591 	size_t outstrsize = strlen(instr) + 3;	/* 2 quotes + '\0' */
   1592 
   1593 	if ((outstr = malloc(outstrsize)) == NULL) {
   1594 		zone_perror(zone, Z_NOMEM, B_FALSE);
   1595 		exit(Z_ERR);
   1596 	}
   1597 	if (strchr(instr, ' ') == NULL) {
   1598 		(void) strlcpy(outstr, instr, outstrsize);
   1599 		return (outstr);
   1600 	}
   1601 	(void) snprintf(outstr, outstrsize, "\"%s\"", instr);
   1602 	return (outstr);
   1603 }
   1604 
   1605 static void
   1606 export_prop(FILE *of, int prop_num, char *prop_id)
   1607 {
   1608 	char *quote_str;
   1609 
   1610 	if (strlen(prop_id) == 0)
   1611 		return;
   1612 	quote_str = quoteit(prop_id);
   1613 	(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1614 	    pt_to_str(prop_num), quote_str);
   1615 	free(quote_str);
   1616 }
   1617 
   1618 void
   1619 export_func(cmd_t *cmd)
   1620 {
   1621 	struct zone_nwiftab nwiftab;
   1622 	struct zone_fstab fstab;
   1623 	struct zone_devtab devtab;
   1624 	struct zone_attrtab attrtab;
   1625 	struct zone_rctltab rctltab;
   1626 	struct zone_dstab dstab;
   1627 	struct zone_psettab psettab;
   1628 	struct zone_mcaptab mcaptab;
   1629 	struct zone_rctlvaltab *valptr;
   1630 	int err, arg;
   1631 	char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
   1632 	char bootargs[BOOTARGS_MAX];
   1633 	char sched[MAXNAMELEN];
   1634 	char brand[MAXNAMELEN];
   1635 	char hostidp[HW_HOSTID_LEN];
   1636 	char *limitpriv;
   1637 	FILE *of;
   1638 	boolean_t autoboot;
   1639 	zone_iptype_t iptype;
   1640 	boolean_t need_to_close = B_FALSE;
   1641 	boolean_t arg_err = B_FALSE;
   1642 
   1643 	assert(cmd != NULL);
   1644 
   1645 	outfile[0] = '\0';
   1646 	optind = 0;
   1647 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
   1648 		switch (arg) {
   1649 		case '?':
   1650 			if (optopt == '?')
   1651 				longer_usage(CMD_EXPORT);
   1652 			else
   1653 				short_usage(CMD_EXPORT);
   1654 			arg_err = B_TRUE;
   1655 			break;
   1656 		case 'f':
   1657 			(void) strlcpy(outfile, optarg, sizeof (outfile));
   1658 			break;
   1659 		default:
   1660 			short_usage(CMD_EXPORT);
   1661 			arg_err = B_TRUE;
   1662 			break;
   1663 		}
   1664 	}
   1665 	if (arg_err)
   1666 		return;
   1667 
   1668 	if (optind != cmd->cmd_argc) {
   1669 		short_usage(CMD_EXPORT);
   1670 		return;
   1671 	}
   1672 	if (strlen(outfile) == 0) {
   1673 		of = stdout;
   1674 	} else {
   1675 		if ((of = fopen(outfile, "w")) == NULL) {
   1676 			zerr(gettext("opening file %s: %s"),
   1677 			    outfile, strerror(errno));
   1678 			goto done;
   1679 		}
   1680 		setbuf(of, NULL);
   1681 		need_to_close = B_TRUE;
   1682 	}
   1683 
   1684 	if ((err = initialize(B_TRUE)) != Z_OK)
   1685 		goto done;
   1686 
   1687 	(void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
   1688 
   1689 	if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
   1690 	    strlen(zonepath) > 0)
   1691 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1692 		    pt_to_str(PT_ZONEPATH), zonepath);
   1693 
   1694 	if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
   1695 	    (strcmp(brand, NATIVE_BRAND_NAME) != 0))
   1696 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1697 		    pt_to_str(PT_BRAND), brand);
   1698 
   1699 	if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
   1700 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1701 		    pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
   1702 
   1703 	if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
   1704 	    strlen(bootargs) > 0) {
   1705 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1706 		    pt_to_str(PT_BOOTARGS), bootargs);
   1707 	}
   1708 
   1709 	if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
   1710 	    strlen(pool) > 0)
   1711 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1712 		    pt_to_str(PT_POOL), pool);
   1713 
   1714 	if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
   1715 	    strlen(limitpriv) > 0) {
   1716 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1717 		    pt_to_str(PT_LIMITPRIV), limitpriv);
   1718 		free(limitpriv);
   1719 	}
   1720 
   1721 	if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
   1722 	    strlen(sched) > 0)
   1723 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1724 		    pt_to_str(PT_SCHED), sched);
   1725 
   1726 	if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
   1727 		switch (iptype) {
   1728 		case ZS_SHARED:
   1729 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1730 			    pt_to_str(PT_IPTYPE), "shared");
   1731 			break;
   1732 		case ZS_EXCLUSIVE:
   1733 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1734 			    pt_to_str(PT_IPTYPE), "exclusive");
   1735 			break;
   1736 		}
   1737 	}
   1738 
   1739 	if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
   1740 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1741 		    pt_to_str(PT_HOSTID), hostidp);
   1742 	}
   1743 
   1744 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
   1745 		zone_perror(zone, err, B_FALSE);
   1746 		goto done;
   1747 	}
   1748 	while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
   1749 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1750 		    rt_to_str(RT_IPD));
   1751 		export_prop(of, PT_DIR, fstab.zone_fs_dir);
   1752 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1753 	}
   1754 	(void) zonecfg_endipdent(handle);
   1755 
   1756 	if ((err = zonecfg_setfsent(handle)) != Z_OK) {
   1757 		zone_perror(zone, err, B_FALSE);
   1758 		goto done;
   1759 	}
   1760 	while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
   1761 		zone_fsopt_t *optptr;
   1762 
   1763 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1764 		    rt_to_str(RT_FS));
   1765 		export_prop(of, PT_DIR, fstab.zone_fs_dir);
   1766 		export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
   1767 		export_prop(of, PT_RAW, fstab.zone_fs_raw);
   1768 		export_prop(of, PT_TYPE, fstab.zone_fs_type);
   1769 		for (optptr = fstab.zone_fs_options; optptr != NULL;
   1770 		    optptr = optptr->zone_fsopt_next) {
   1771 			/*
   1772 			 * Simple property values with embedded equal signs
   1773 			 * need to be quoted to prevent the lexer from
   1774 			 * mis-parsing them as complex name=value pairs.
   1775 			 */
   1776 			if (strchr(optptr->zone_fsopt_opt, '='))
   1777 				(void) fprintf(of, "%s %s \"%s\"\n",
   1778 				    cmd_to_str(CMD_ADD),
   1779 				    pt_to_str(PT_OPTIONS),
   1780 				    optptr->zone_fsopt_opt);
   1781 			else
   1782 				(void) fprintf(of, "%s %s %s\n",
   1783 				    cmd_to_str(CMD_ADD),
   1784 				    pt_to_str(PT_OPTIONS),
   1785 				    optptr->zone_fsopt_opt);
   1786 		}
   1787 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1788 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
   1789 	}
   1790 	(void) zonecfg_endfsent(handle);
   1791 
   1792 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
   1793 		zone_perror(zone, err, B_FALSE);
   1794 		goto done;
   1795 	}
   1796 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
   1797 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1798 		    rt_to_str(RT_NET));
   1799 		export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
   1800 		export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
   1801 		export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
   1802 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1803 	}
   1804 	(void) zonecfg_endnwifent(handle);
   1805 
   1806 	if ((err = zonecfg_setdevent(handle)) != Z_OK) {
   1807 		zone_perror(zone, err, B_FALSE);
   1808 		goto done;
   1809 	}
   1810 	while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
   1811 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1812 		    rt_to_str(RT_DEVICE));
   1813 		export_prop(of, PT_MATCH, devtab.zone_dev_match);
   1814 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1815 	}
   1816 	(void) zonecfg_enddevent(handle);
   1817 
   1818 	if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
   1819 		zone_perror(zone, err, B_FALSE);
   1820 		goto done;
   1821 	}
   1822 	while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
   1823 		(void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
   1824 		export_prop(of, PT_NAME, rctltab.zone_rctl_name);
   1825 		for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
   1826 		    valptr = valptr->zone_rctlval_next) {
   1827 			fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
   1828 			    cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
   1829 			    pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
   1830 			    pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
   1831 			    pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
   1832 		}
   1833 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1834 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
   1835 	}
   1836 	(void) zonecfg_endrctlent(handle);
   1837 
   1838 	if ((err = zonecfg_setattrent(handle)) != Z_OK) {
   1839 		zone_perror(zone, err, B_FALSE);
   1840 		goto done;
   1841 	}
   1842 	while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
   1843 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1844 		    rt_to_str(RT_ATTR));
   1845 		export_prop(of, PT_NAME, attrtab.zone_attr_name);
   1846 		export_prop(of, PT_TYPE, attrtab.zone_attr_type);
   1847 		export_prop(of, PT_VALUE, attrtab.zone_attr_value);
   1848 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1849 	}
   1850 	(void) zonecfg_endattrent(handle);
   1851 
   1852 	if ((err = zonecfg_setdsent(handle)) != Z_OK) {
   1853 		zone_perror(zone, err, B_FALSE);
   1854 		goto done;
   1855 	}
   1856 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
   1857 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1858 		    rt_to_str(RT_DATASET));
   1859 		export_prop(of, PT_NAME, dstab.zone_dataset_name);
   1860 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1861 	}
   1862 	(void) zonecfg_enddsent(handle);
   1863 
   1864 	if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
   1865 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1866 		    rt_to_str(RT_DCPU));
   1867 		if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
   1868 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1869 			    pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
   1870 		else
   1871 			(void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
   1872 			    pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
   1873 			    psettab.zone_ncpu_max);
   1874 		if (psettab.zone_importance[0] != '\0')
   1875 			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1876 			    pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
   1877 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1878 	}
   1879 
   1880 	if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
   1881 		char buf[128];
   1882 
   1883 		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
   1884 		    rt_to_str(RT_MCAP));
   1885 		bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
   1886 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
   1887 		    pt_to_str(PT_PHYSICAL), buf);
   1888 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
   1889 	}
   1890 
   1891 	/*
   1892 	 * There is nothing to export for pcap since this resource is just
   1893 	 * a container for an rctl alias.
   1894 	 */
   1895 
   1896 done:
   1897 	if (need_to_close)
   1898 		(void) fclose(of);
   1899 }
   1900 
   1901 void
   1902 exit_func(cmd_t *cmd)
   1903 {
   1904 	int arg, answer;
   1905 	boolean_t arg_err = B_FALSE;
   1906 
   1907 	optind = 0;
   1908 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
   1909 		switch (arg) {
   1910 		case '?':
   1911 			longer_usage(CMD_EXIT);
   1912 			arg_err = B_TRUE;
   1913 			break;
   1914 		case 'F':
   1915 			force_exit = B_TRUE;
   1916 			break;
   1917 		default:
   1918 			short_usage(CMD_EXIT);
   1919 			arg_err = B_TRUE;
   1920 			break;
   1921 		}
   1922 	}
   1923 	if (arg_err)
   1924 		return;
   1925 
   1926 	if (optind < cmd->cmd_argc) {
   1927 		short_usage(CMD_EXIT);
   1928 		return;
   1929 	}
   1930 
   1931 	if (global_scope || force_exit) {
   1932 		time_to_exit = B_TRUE;
   1933 		return;
   1934 	}
   1935 
   1936 	answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
   1937 	if (answer == -1) {
   1938 		zerr(gettext("Resource incomplete, input "
   1939 		    "not from terminal and -F not specified:\n%s command "
   1940 		    "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
   1941 		exit(Z_ERR);
   1942 	} else if (answer == 1) {
   1943 		time_to_exit = B_TRUE;
   1944 	}
   1945 	/* (answer == 0) => just return */
   1946 }
   1947 
   1948 static int
   1949 validate_zonepath_syntax(char *path)
   1950 {
   1951 	if (path[0] != '/') {
   1952 		zerr(gettext("%s is not an absolute path."), path);
   1953 		return (Z_ERR);
   1954 	}
   1955 	if (strcmp(path, "/") == 0) {
   1956 		zerr(gettext("/ is not allowed as a %s."),
   1957 		    pt_to_str(PT_ZONEPATH));
   1958 		return (Z_ERR);
   1959 	}
   1960 	return (Z_OK);
   1961 }
   1962 
   1963 static void
   1964 add_resource(cmd_t *cmd)
   1965 {
   1966 	int type;
   1967 	struct zone_psettab tmp_psettab;
   1968 	struct zone_mcaptab tmp_mcaptab;
   1969 	uint64_t tmp;
   1970 	uint64_t tmp_mcap;
   1971 	char pool[MAXNAMELEN];
   1972 
   1973 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
   1974 		long_usage(CMD_ADD, B_TRUE);
   1975 		goto bad;
   1976 	}
   1977 
   1978 	switch (type) {
   1979 	case RT_FS:
   1980 		bzero(&in_progress_fstab, sizeof (in_progress_fstab));
   1981 		return;
   1982 	case RT_IPD:
   1983 		if (state_atleast(ZONE_STATE_INSTALLED)) {
   1984 			zerr(gettext("Zone %s already installed; %s %s not "
   1985 			    "allowed."), zone, cmd_to_str(CMD_ADD),
   1986 			    rt_to_str(RT_IPD));
   1987 			goto bad;
   1988 		}
   1989 		bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab));
   1990 		return;
   1991 	case RT_NET:
   1992 		bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
   1993 		return;
   1994 	case RT_DEVICE:
   1995 		bzero(&in_progress_devtab, sizeof (in_progress_devtab));
   1996 		return;
   1997 	case RT_RCTL:
   1998 		if (global_zone)
   1999 			zerr(gettext("WARNING: Setting a global zone resource "
   2000 			    "control too low could deny\nservice "
   2001 			    "to even the root user; "
   2002 			    "this could render the system impossible\n"
   2003 			    "to administer.  Please use caution."));
   2004 		bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
   2005 		return;
   2006 	case RT_ATTR:
   2007 		bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
   2008 		return;
   2009 	case RT_DATASET:
   2010 		bzero(&in_progress_dstab, sizeof (in_progress_dstab));
   2011 		return;
   2012 	case RT_DCPU:
   2013 		/* Make sure there isn't already a cpu-set or cpu-cap entry. */
   2014 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
   2015 			zerr(gettext("The %s resource already exists."),
   2016 			    rt_to_str(RT_DCPU));
   2017 			goto bad;
   2018 		}
   2019 		if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
   2020 		    Z_NO_ENTRY) {
   2021 			zerr(gettext("The %s resource already exists."),
   2022 			    rt_to_str(RT_PCAP));
   2023 			goto bad;
   2024 		}
   2025 
   2026 		/* Make sure the pool property isn't set. */
   2027 		if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
   2028 		    strlen(pool) > 0) {
   2029 			zerr(gettext("The %s property is already set.  "
   2030 			    "A persistent pool is incompatible with\nthe %s "
   2031 			    "resource."),
   2032 			    pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
   2033 			goto bad;
   2034 		}
   2035 
   2036 		bzero(&in_progress_psettab, sizeof (in_progress_psettab));
   2037 		return;
   2038 	case RT_PCAP:
   2039 		/*
   2040 		 * Make sure there isn't already a cpu-set or incompatible
   2041 		 * cpu-cap rctls.
   2042 		 */
   2043 		if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
   2044 			zerr(gettext("The %s resource already exists."),
   2045 			    rt_to_str(RT_DCPU));
   2046 			goto bad;
   2047 		}
   2048 
   2049 		switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
   2050 		case Z_ALIAS_DISALLOW:
   2051 			zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
   2052 			    B_FALSE);
   2053 			goto bad;
   2054 
   2055 		case Z_OK:
   2056 			zerr(gettext("The %s resource already exists."),
   2057 			    rt_to_str(RT_PCAP));
   2058 			goto bad;
   2059 
   2060 		default:
   2061 			break;
   2062 		}
   2063 		return;
   2064 	case RT_MCAP:
   2065 		/*
   2066 		 * Make sure there isn't already a mem-cap entry or max-swap
   2067 		 * or max-locked rctl.
   2068 		 */
   2069 		if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
   2070 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
   2071 		    == Z_OK ||
   2072 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
   2073 		    &tmp_mcap) == Z_OK) {
   2074 			zerr(gettext("The %s resource or a related resource "
   2075 			    "control already exists."), rt_to_str(RT_MCAP));
   2076 			goto bad;
   2077 		}
   2078 		if (global_zone)
   2079 			zerr(gettext("WARNING: Setting a global zone memory "
   2080 			    "cap too low could deny\nservice "
   2081 			    "to even the root user; "
   2082 			    "this could render the system impossible\n"
   2083 			    "to administer.  Please use caution."));
   2084 		bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
   2085 		return;
   2086 	default:
   2087 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
   2088 		long_usage(CMD_ADD, B_TRUE);
   2089 		usage(B_FALSE, HELP_RESOURCES);
   2090 	}
   2091 bad:
   2092 	global_scope = B_TRUE;
   2093 	end_op = -1;
   2094 }
   2095 
   2096 static void
   2097 do_complex_rctl_val(complex_property_ptr_t cp)
   2098 {
   2099 	struct zone_rctlvaltab *rctlvaltab;
   2100 	complex_property_ptr_t cx;
   2101 	boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
   2102 	    seen_action = B_FALSE;
   2103 	rctlblk_t *rctlblk;
   2104 	int err;
   2105 
   2106 	if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
   2107 		zone_perror(zone, Z_NOMEM, B_TRUE);
   2108 		exit(Z_ERR);
   2109 	}
   2110 	for (cx = cp; cx != NULL; cx = cx->cp_next) {
   2111 		switch (cx->cp_type) {
   2112 		case PT_PRIV:
   2113 			if (seen_priv) {
   2114 				zerr(gettext("%s already specified"),
   2115 				    pt_to_str(PT_PRIV));
   2116 				goto bad;
   2117 			}
   2118 			(void) strlcpy(rctlvaltab->zone_rctlval_priv,
   2119 			    cx->cp_value,
   2120 			    sizeof (rctlvaltab->zone_rctlval_priv));
   2121 			seen_priv = B_TRUE;
   2122 			break;
   2123 		case PT_LIMIT:
   2124 			if (seen_limit) {
   2125 				zerr(gettext("%s already specified"),
   2126 				    pt_to_str(PT_LIMIT));
   2127 				goto bad;
   2128 			}
   2129 			(void) strlcpy(rctlvaltab->zone_rctlval_limit,
   2130 			    cx->cp_value,
   2131 			    sizeof (rctlvaltab->zone_rctlval_limit));
   2132 			seen_limit = B_TRUE;
   2133 			break;
   2134 		case PT_ACTION:
   2135 			if (seen_action) {
   2136 				zerr(gettext("%s already specified"),
   2137 				    pt_to_str(PT_ACTION));
   2138 				goto bad;
   2139 			}
   2140 			(void) strlcpy(rctlvaltab->zone_rctlval_action,
   2141 			    cx->cp_value,
   2142 			    sizeof (rctlvaltab->zone_rctlval_action));
   2143 			seen_action = B_TRUE;
   2144 			break;
   2145 		default:
   2146 			zone_perror(pt_to_str(PT_VALUE),
   2147 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2148 			long_usage(CMD_ADD, B_TRUE);
   2149 			usage(B_FALSE, HELP_PROPS);
   2150 			zonecfg_free_rctl_value_list(rctlvaltab);
   2151 			return;
   2152 		}
   2153 	}
   2154 	if (!seen_priv)
   2155 		zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
   2156 	if (!seen_limit)
   2157 		zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
   2158 	if (!seen_action)
   2159 		zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
   2160 	if (!seen_priv || !seen_limit || !seen_action)
   2161 		goto bad;
   2162 	rctlvaltab->zone_rctlval_next = NULL;
   2163 	rctlblk = alloca(rctlblk_size());
   2164 	/*
   2165 	 * Make sure the rctl value looks roughly correct; we won't know if
   2166 	 * it's truly OK until we verify the configuration on the target
   2167 	 * system.
   2168 	 */
   2169 	if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
   2170 	    !zonecfg_valid_rctlblk(rctlblk)) {
   2171 		zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
   2172 		    pt_to_str(PT_VALUE));
   2173 		goto bad;
   2174 	}
   2175 	err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
   2176 	if (err != Z_OK)
   2177 		zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
   2178 	return;
   2179 
   2180 bad:
   2181 	zonecfg_free_rctl_value_list(rctlvaltab);
   2182 }
   2183 
   2184 static void
   2185 add_property(cmd_t *cmd)
   2186 {
   2187 	char *prop_id;
   2188 	int err, res_type, prop_type;
   2189 	property_value_ptr_t pp;
   2190 	list_property_ptr_t l;
   2191 
   2192 	res_type = resource_scope;
   2193 	prop_type = cmd->cmd_prop_name[0];
   2194 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
   2195 		long_usage(CMD_ADD, B_TRUE);
   2196 		return;
   2197 	}
   2198 
   2199 	if (cmd->cmd_prop_nv_pairs != 1) {
   2200 		long_usage(CMD_ADD, B_TRUE);
   2201 		return;
   2202 	}
   2203 
   2204 	if (initialize(B_TRUE) != Z_OK)
   2205 		return;
   2206 
   2207 	switch (res_type) {
   2208 	case RT_FS:
   2209 		if (prop_type != PT_OPTIONS) {
   2210 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
   2211 			    B_TRUE);
   2212 			long_usage(CMD_ADD, B_TRUE);
   2213 			usage(B_FALSE, HELP_PROPS);
   2214 			return;
   2215 		}
   2216 		pp = cmd->cmd_property_ptr[0];
   2217 		if (pp->pv_type != PROP_VAL_SIMPLE &&
   2218 		    pp->pv_type != PROP_VAL_LIST) {
   2219 			zerr(gettext("A %s or %s value was expected here."),
   2220 			    pvt_to_str(PROP_VAL_SIMPLE),
   2221 			    pvt_to_str(PROP_VAL_LIST));
   2222 			saw_error = B_TRUE;
   2223 			return;
   2224 		}
   2225 		if (pp->pv_type == PROP_VAL_SIMPLE) {
   2226 			if (pp->pv_simple == NULL) {
   2227 				long_usage(CMD_ADD, B_TRUE);
   2228 				return;
   2229 			}
   2230 			prop_id = pp->pv_simple;
   2231 			err = zonecfg_add_fs_option(&in_progress_fstab,
   2232 			    prop_id);
   2233 			if (err != Z_OK)
   2234 				zone_perror(pt_to_str(prop_type), err, B_TRUE);
   2235 		} else {
   2236 			list_property_ptr_t list;
   2237 
   2238 			for (list = pp->pv_list; list != NULL;
   2239 			    list = list->lp_next) {
   2240 				prop_id = list->lp_simple;
   2241 				if (prop_id == NULL)
   2242 					break;
   2243 				err = zonecfg_add_fs_option(
   2244 				    &in_progress_fstab, prop_id);
   2245 				if (err != Z_OK)
   2246 					zone_perror(pt_to_str(prop_type), err,
   2247 					    B_TRUE);
   2248 			}
   2249 		}
   2250 		return;
   2251 	case RT_RCTL:
   2252 		if (prop_type != PT_VALUE) {
   2253 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
   2254 			    B_TRUE);
   2255 			long_usage(CMD_ADD, B_TRUE);
   2256 			usage(B_FALSE, HELP_PROPS);
   2257 			return;
   2258 		}
   2259 		pp = cmd->cmd_property_ptr[0];
   2260 		if (pp->pv_type != PROP_VAL_COMPLEX &&
   2261 		    pp->pv_type != PROP_VAL_LIST) {
   2262 			zerr(gettext("A %s or %s value was expected here."),
   2263 			    pvt_to_str(PROP_VAL_COMPLEX),
   2264 			    pvt_to_str(PROP_VAL_LIST));
   2265 			saw_error = B_TRUE;
   2266 			return;
   2267 		}
   2268 		if (pp->pv_type == PROP_VAL_COMPLEX) {
   2269 			do_complex_rctl_val(pp->pv_complex);
   2270 			return;
   2271 		}
   2272 		for (l = pp->pv_list; l != NULL; l = l->lp_next)
   2273 			do_complex_rctl_val(l->lp_complex);
   2274 		return;
   2275 	default:
   2276 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
   2277 		long_usage(CMD_ADD, B_TRUE);
   2278 		usage(B_FALSE, HELP_RESOURCES);
   2279 		return;
   2280 	}
   2281 }
   2282 
   2283 static boolean_t
   2284 gz_invalid_resource(int type)
   2285 {
   2286 	return (global_zone && (type == RT_FS || type == RT_IPD ||
   2287 	    type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
   2288 	    type == RT_DATASET));
   2289 }
   2290 
   2291 static boolean_t
   2292 gz_invalid_rt_property(int type)
   2293 {
   2294 	return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
   2295 	    type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
   2296 	    type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
   2297 	    type == RT_IPTYPE || type == RT_HOSTID));
   2298 }
   2299 
   2300 static boolean_t
   2301 gz_invalid_property(int type)
   2302 {
   2303 	return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
   2304 	    type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
   2305 	    type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
   2306 	    type == PT_IPTYPE || type == PT_HOSTID));
   2307 }
   2308 
   2309 void
   2310 add_func(cmd_t *cmd)
   2311 {
   2312 	int arg;
   2313 	boolean_t arg_err = B_FALSE;
   2314 
   2315 	assert(cmd != NULL);
   2316 
   2317 	optind = 0;
   2318 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
   2319 		switch (arg) {
   2320 		case '?':
   2321 			longer_usage(CMD_ADD);
   2322 			arg_err = B_TRUE;
   2323 			break;
   2324 		default:
   2325 			short_usage(CMD_ADD);
   2326 			arg_err = B_TRUE;
   2327 			break;
   2328 		}
   2329 	}
   2330 	if (arg_err)
   2331 		return;
   2332 
   2333 	if (optind != cmd->cmd_argc) {
   2334 		short_usage(CMD_ADD);
   2335 		return;
   2336 	}
   2337 
   2338 	if (zone_is_read_only(CMD_ADD))
   2339 		return;
   2340 
   2341 	if (initialize(B_TRUE) != Z_OK)
   2342 		return;
   2343 	if (global_scope) {
   2344 		if (gz_invalid_resource(cmd->cmd_res_type)) {
   2345 			zerr(gettext("Cannot add a %s resource to the "
   2346 			    "global zone."), rt_to_str(cmd->cmd_res_type));
   2347 			saw_error = B_TRUE;
   2348 			return;
   2349 		}
   2350 
   2351 		global_scope = B_FALSE;
   2352 		resource_scope = cmd->cmd_res_type;
   2353 		end_op = CMD_ADD;
   2354 		add_resource(cmd);
   2355 	} else
   2356 		add_property(cmd);
   2357 }
   2358 
   2359 /*
   2360  * This routine has an unusual implementation, because it tries very
   2361  * hard to succeed in the face of a variety of failure modes.
   2362  * The most common and most vexing occurs when the index file and
   2363  * the /etc/zones/<zonename.xml> file are not both present.  In
   2364  * this case, delete must eradicate as much of the zone state as is left
   2365  * so that the user can later create a new zone with the same name.
   2366  */
   2367 void
   2368 delete_func(cmd_t *cmd)
   2369 {
   2370 	int err, arg, answer;
   2371 	char line[ZONENAME_MAX + 128];	/* enough to ask a question */
   2372 	boolean_t force = B_FALSE;
   2373 	boolean_t arg_err = B_FALSE;
   2374 
   2375 	optind = 0;
   2376 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
   2377 		switch (arg) {
   2378 		case '?':
   2379 			longer_usage(CMD_DELETE);
   2380 			arg_err = B_TRUE;
   2381 			break;
   2382 		case 'F':
   2383 			force = B_TRUE;
   2384 			break;
   2385 		default:
   2386 			short_usage(CMD_DELETE);
   2387 			arg_err = B_TRUE;
   2388 			break;
   2389 		}
   2390 	}
   2391 	if (arg_err)
   2392 		return;
   2393 
   2394 	if (optind != cmd->cmd_argc) {
   2395 		short_usage(CMD_DELETE);
   2396 		return;
   2397 	}
   2398 
   2399 	if (zone_is_read_only(CMD_DELETE))
   2400 		return;
   2401 
   2402 	if (!force) {
   2403 		/*
   2404 		 * Initialize sets up the global called "handle" and warns the
   2405 		 * user if the zone is not configured.  In force mode, we don't
   2406 		 * trust that evaluation, and hence skip it.  (We don't need the
   2407 		 * handle to be loaded anyway, since zonecfg_destroy is done by
   2408 		 * zonename).  However, we also have to take care to emulate the
   2409 		 * messages spit out by initialize; see below.
   2410 		 */
   2411 		if (initialize(B_TRUE) != Z_OK)
   2412 			return;
   2413 
   2414 		(void) snprintf(line, sizeof (line),
   2415 		    gettext("Are you sure you want to delete zone %s"), zone);
   2416 		if ((answer = ask_yesno(B_FALSE, line)) == -1) {
   2417 			zerr(gettext("Input not from terminal and -F not "
   2418 			    "specified:\n%s command ignored, exiting."),
   2419 			    cmd_to_str(CMD_DELETE));
   2420 			exit(Z_ERR);
   2421 		}
   2422 		if (answer != 1)
   2423 			return;
   2424 	}
   2425 
   2426 	if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
   2427 		if ((err == Z_BAD_ZONE_STATE) && !force) {
   2428 			zerr(gettext("Zone %s not in %s state; %s not "
   2429 			    "allowed.  Use -F to force %s."),
   2430 			    zone, zone_state_str(ZONE_STATE_CONFIGURED),
   2431 			    cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
   2432 		} else {
   2433 			zone_perror(zone, err, B_TRUE);
   2434 		}
   2435 	}
   2436 	need_to_commit = B_FALSE;
   2437 
   2438 	/*
   2439 	 * Emulate initialize's messaging; if there wasn't a valid handle to
   2440 	 * begin with, then user had typed delete (or delete -F) multiple
   2441 	 * times.  So we emit a message.
   2442 	 *
   2443 	 * We only do this in the 'force' case because normally, initialize()
   2444 	 * takes care of this for us.
   2445 	 */
   2446 	if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
   2447 		(void) printf(gettext("Use '%s' to begin "
   2448 		    "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
   2449 
   2450 	/*
   2451 	 * Time for a new handle: finish the old one off first
   2452 	 * then get a new one properly to avoid leaks.
   2453 	 */
   2454 	if (got_handle) {
   2455 		zonecfg_fini_handle(handle);
   2456 		if ((handle = zonecfg_init_handle()) == NULL) {
   2457 			zone_perror(execname, Z_NOMEM, B_TRUE);
   2458 			exit(Z_ERR);
   2459 		}
   2460 		if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
   2461 			/* If there was no zone before, that's OK */
   2462 			if (err != Z_NO_ZONE)
   2463 				zone_perror(zone, err, B_TRUE);
   2464 			got_handle = B_FALSE;
   2465 		}
   2466 	}
   2467 }
   2468 
   2469 static int
   2470 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
   2471 {
   2472 	int err, i;
   2473 	property_value_ptr_t pp;
   2474 
   2475 	if ((err = initialize(B_TRUE)) != Z_OK)
   2476 		return (err);
   2477 
   2478 	bzero(fstab, sizeof (*fstab));
   2479 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2480 		pp = cmd->cmd_property_ptr[i];
   2481 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2482 			zerr(gettext("A simple value was expected here."));
   2483 			saw_error = B_TRUE;
   2484 			return (Z_INSUFFICIENT_SPEC);
   2485 		}
   2486 		switch (cmd->cmd_prop_name[i]) {
   2487 		case PT_DIR:
   2488 			(void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
   2489 			    sizeof (fstab->zone_fs_dir));
   2490 			break;
   2491 		case PT_SPECIAL:
   2492 			(void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
   2493 			    sizeof (fstab->zone_fs_special));
   2494 			break;
   2495 		case PT_RAW:
   2496 			(void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
   2497 			    sizeof (fstab->zone_fs_raw));
   2498 			break;
   2499 		case PT_TYPE:
   2500 			(void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
   2501 			    sizeof (fstab->zone_fs_type));
   2502 			break;
   2503 		default:
   2504 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2505 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2506 			return (Z_INSUFFICIENT_SPEC);
   2507 		}
   2508 	}
   2509 	if (fill_in_only)
   2510 		return (Z_OK);
   2511 	return (zonecfg_lookup_filesystem(handle, fstab));
   2512 }
   2513 
   2514 static int
   2515 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, boolean_t fill_in_only)
   2516 {
   2517 	int err, i;
   2518 	property_value_ptr_t pp;
   2519 
   2520 	if ((err = initialize(B_TRUE)) != Z_OK)
   2521 		return (err);
   2522 
   2523 	bzero(ipdtab, sizeof (*ipdtab));
   2524 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2525 		pp = cmd->cmd_property_ptr[i];
   2526 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2527 			zerr(gettext("A simple value was expected here."));
   2528 			saw_error = B_TRUE;
   2529 			return (Z_INSUFFICIENT_SPEC);
   2530 		}
   2531 		switch (cmd->cmd_prop_name[i]) {
   2532 		case PT_DIR:
   2533 			(void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple,
   2534 			    sizeof (ipdtab->zone_fs_dir));
   2535 			break;
   2536 		default:
   2537 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2538 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2539 			return (Z_INSUFFICIENT_SPEC);
   2540 		}
   2541 	}
   2542 	if (fill_in_only)
   2543 		return (Z_OK);
   2544 	return (zonecfg_lookup_ipd(handle, ipdtab));
   2545 }
   2546 
   2547 static int
   2548 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
   2549     boolean_t fill_in_only)
   2550 {
   2551 	int err, i;
   2552 	property_value_ptr_t pp;
   2553 
   2554 	if ((err = initialize(B_TRUE)) != Z_OK)
   2555 		return (err);
   2556 
   2557 	bzero(nwiftab, sizeof (*nwiftab));
   2558 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2559 		pp = cmd->cmd_property_ptr[i];
   2560 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2561 			zerr(gettext("A simple value was expected here."));
   2562 			saw_error = B_TRUE;
   2563 			return (Z_INSUFFICIENT_SPEC);
   2564 		}
   2565 		switch (cmd->cmd_prop_name[i]) {
   2566 		case PT_ADDRESS:
   2567 			(void) strlcpy(nwiftab->zone_nwif_address,
   2568 			    pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
   2569 			break;
   2570 		case PT_PHYSICAL:
   2571 			(void) strlcpy(nwiftab->zone_nwif_physical,
   2572 			    pp->pv_simple,
   2573 			    sizeof (nwiftab->zone_nwif_physical));
   2574 			break;
   2575 		case PT_DEFROUTER:
   2576 			(void) strlcpy(nwiftab->zone_nwif_defrouter,
   2577 			    pp->pv_simple,
   2578 			    sizeof (nwiftab->zone_nwif_defrouter));
   2579 			break;
   2580 		default:
   2581 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2582 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2583 			return (Z_INSUFFICIENT_SPEC);
   2584 		}
   2585 	}
   2586 	if (fill_in_only)
   2587 		return (Z_OK);
   2588 	err = zonecfg_lookup_nwif(handle, nwiftab);
   2589 	return (err);
   2590 }
   2591 
   2592 static int
   2593 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
   2594 {
   2595 	int err, i;
   2596 	property_value_ptr_t pp;
   2597 
   2598 	if ((err = initialize(B_TRUE)) != Z_OK)
   2599 		return (err);
   2600 
   2601 	bzero(devtab, sizeof (*devtab));
   2602 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2603 		pp = cmd->cmd_property_ptr[i];
   2604 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2605 			zerr(gettext("A simple value was expected here."));
   2606 			saw_error = B_TRUE;
   2607 			return (Z_INSUFFICIENT_SPEC);
   2608 		}
   2609 		switch (cmd->cmd_prop_name[i]) {
   2610 		case PT_MATCH:
   2611 			(void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
   2612 			    sizeof (devtab->zone_dev_match));
   2613 			break;
   2614 		default:
   2615 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2616 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2617 			return (Z_INSUFFICIENT_SPEC);
   2618 		}
   2619 	}
   2620 	if (fill_in_only)
   2621 		return (Z_OK);
   2622 	err = zonecfg_lookup_dev(handle, devtab);
   2623 	return (err);
   2624 }
   2625 
   2626 static int
   2627 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
   2628     boolean_t fill_in_only)
   2629 {
   2630 	int err, i;
   2631 	property_value_ptr_t pp;
   2632 
   2633 	if ((err = initialize(B_TRUE)) != Z_OK)
   2634 		return (err);
   2635 
   2636 	bzero(rctltab, sizeof (*rctltab));
   2637 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2638 		pp = cmd->cmd_property_ptr[i];
   2639 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2640 			zerr(gettext("A simple value was expected here."));
   2641 			saw_error = B_TRUE;
   2642 			return (Z_INSUFFICIENT_SPEC);
   2643 		}
   2644 		switch (cmd->cmd_prop_name[i]) {
   2645 		case PT_NAME:
   2646 			(void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
   2647 			    sizeof (rctltab->zone_rctl_name));
   2648 			break;
   2649 		default:
   2650 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2651 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2652 			return (Z_INSUFFICIENT_SPEC);
   2653 		}
   2654 	}
   2655 	if (fill_in_only)
   2656 		return (Z_OK);
   2657 	err = zonecfg_lookup_rctl(handle, rctltab);
   2658 	return (err);
   2659 }
   2660 
   2661 static int
   2662 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
   2663     boolean_t fill_in_only)
   2664 {
   2665 	int err, i;
   2666 	property_value_ptr_t pp;
   2667 
   2668 	if ((err = initialize(B_TRUE)) != Z_OK)
   2669 		return (err);
   2670 
   2671 	bzero(attrtab, sizeof (*attrtab));
   2672 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2673 		pp = cmd->cmd_property_ptr[i];
   2674 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2675 			zerr(gettext("A simple value was expected here."));
   2676 			saw_error = B_TRUE;
   2677 			return (Z_INSUFFICIENT_SPEC);
   2678 		}
   2679 		switch (cmd->cmd_prop_name[i]) {
   2680 		case PT_NAME:
   2681 			(void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
   2682 			    sizeof (attrtab->zone_attr_name));
   2683 			break;
   2684 		case PT_TYPE:
   2685 			(void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
   2686 			    sizeof (attrtab->zone_attr_type));
   2687 			break;
   2688 		case PT_VALUE:
   2689 			(void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
   2690 			    sizeof (attrtab->zone_attr_value));
   2691 			break;
   2692 		default:
   2693 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2694 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2695 			return (Z_INSUFFICIENT_SPEC);
   2696 		}
   2697 	}
   2698 	if (fill_in_only)
   2699 		return (Z_OK);
   2700 	err = zonecfg_lookup_attr(handle, attrtab);
   2701 	return (err);
   2702 }
   2703 
   2704 static int
   2705 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
   2706 {
   2707 	int err, i;
   2708 	property_value_ptr_t pp;
   2709 
   2710 	if ((err = initialize(B_TRUE)) != Z_OK)
   2711 		return (err);
   2712 
   2713 	dstab->zone_dataset_name[0] = '\0';
   2714 	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
   2715 		pp = cmd->cmd_property_ptr[i];
   2716 		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
   2717 			zerr(gettext("A simple value was expected here."));
   2718 			saw_error = B_TRUE;
   2719 			return (Z_INSUFFICIENT_SPEC);
   2720 		}
   2721 		switch (cmd->cmd_prop_name[i]) {
   2722 		case PT_NAME:
   2723 			(void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
   2724 			    sizeof (dstab->zone_dataset_name));
   2725 			break;
   2726 		default:
   2727 			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
   2728 			    Z_NO_PROPERTY_TYPE, B_TRUE);
   2729 			return (Z_INSUFFICIENT_SPEC);
   2730 		}
   2731 	}
   2732 	if (fill_in_only)
   2733 		return (Z_OK);
   2734 	return (zonecfg_lookup_ds(handle, dstab));
   2735 }
   2736 
   2737 static void
   2738 remove_aliased_rctl(int type, char *name)
   2739 {
   2740 	int err;
   2741 	uint64_t tmp;
   2742 
   2743 	if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
   2744 		zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
   2745 		    zonecfg_strerror(err));
   2746 		saw_error = B_TRUE;
   2747 		return;
   2748 	}
   2749 	if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
   2750 		zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
   2751 		    zonecfg_strerror(err));
   2752 		saw_error = B_TRUE;
   2753 	} else {
   2754 		need_to_commit = B_TRUE;
   2755 	}
   2756 }
   2757 
   2758 static boolean_t
   2759 prompt_remove_resource(cmd_t *cmd, char *rsrc)
   2760 {
   2761 	int num;
   2762 	int answer;
   2763 	int arg;
   2764 	boolean_t force = B_FALSE;
   2765 	char prompt[128];
   2766 	boolean_t arg_err = B_FALSE;
   2767 
   2768 	optind = 0;
   2769 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
   2770 		switch (arg) {
   2771 		case 'F':
   2772 			force = B_TRUE;
   2773 			break;
   2774 		default:
   2775 			arg_err = B_TRUE;
   2776 			break;
   2777 		}
   2778 	}
   2779 	if (arg_err)
   2780 		return (B_FALSE);
   2781 
   2782 
   2783 	num = zonecfg_num_resources(handle, rsrc);
   2784 
   2785 	if (num == 0) {
   2786 		z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
   2787 		    B_TRUE);
   2788 		return (B_FALSE);
   2789 	}
   2790 	if (num > 1 && !force) {
   2791 		if (!interactive_mode) {
   2792 			zerr(gettext("There are multiple instances of this "
   2793 			    "resource.  Either qualify the resource to\n"
   2794 			    "remove a single instance or use the -F option to "
   2795 			    "remove all instances."));
   2796 			saw_error = B_TRUE;
   2797 			return (B_FALSE);
   2798 		}
   2799 		(void) snprintf(prompt, sizeof (prompt), gettext(
   2800 		    "Are you sure you want to remove ALL '%s' resources"),
   2801 		    rsrc);
   2802 		answer = ask_yesno(B_FALSE, prompt);
   2803 		if (answer == -1) {
   2804 			zerr(gettext("Resource incomplete."));
   2805 			return (B_FALSE);
   2806 		}
   2807 		if (answer != 1)
   2808 			return (B_FALSE);
   2809 	}
   2810 	return (B_TRUE);
   2811 }
   2812 
   2813 static void
   2814 remove_fs(cmd_t *cmd)
   2815 {
   2816 	int err;
   2817 
   2818 	/* traditional, qualified fs removal */
   2819 	if (cmd->cmd_prop_nv_pairs > 0) {
   2820 		struct zone_fstab fstab;
   2821 
   2822 		if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
   2823 			z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
   2824 			return;
   2825 		}
   2826 		if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
   2827 			z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
   2828 		else
   2829 			need_to_commit = B_TRUE;
   2830 		zonecfg_free_fs_option_list(fstab.zone_fs_options);
   2831 		return;
   2832 	}
   2833 
   2834 	/*
   2835 	 * unqualified fs removal.  remove all fs's but prompt if more
   2836 	 * than one.
   2837 	 */
   2838 	if (!prompt_remove_resource(cmd, "fs"))
   2839 		return;
   2840 
   2841 	if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
   2842 		z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
   2843 	else
   2844 		need_to_commit = B_TRUE;
   2845 }
   2846 
   2847 static void
   2848 remove_ipd(cmd_t *cmd)
   2849 {
   2850 	int err;
   2851 
   2852 	if (state_atleast(ZONE_STATE_INSTALLED)) {
   2853 		zerr(gettext("Zone %s already installed; %s %s not allowed."),
   2854 		    zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD));
   2855 		return;
   2856 	}
   2857 
   2858 	/* traditional, qualified ipd removal */
   2859 	if (cmd->cmd_prop_nv_pairs > 0) {
   2860 		struct zone_fstab fstab;
   2861 
   2862 		if ((err = fill_in_ipdtab(cmd, &fstab, B_FALSE)) != Z_OK) {
   2863 			z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
   2864 			return;
   2865 		}
   2866 		if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK)
   2867 			z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
   2868 		else
   2869 			need_to_commit = B_TRUE;
   2870 		return;
   2871 	}
   2872 
   2873 	/*
   2874 	 * unqualified ipd removal.  remove all ipds but prompt if more
   2875 	 * than one.
   2876 	 */
   2877 	if (!prompt_remove_resource(cmd, "inherit-pkg-dir"))
   2878 		return;
   2879 
   2880 	if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir"))
   2881 	    != Z_OK)
   2882 		z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE);
   2883 	else
   2884 		need_to_commit = B_TRUE;
   2885 }
   2886 
   2887 static void
   2888 remove_net(cmd_t *cmd)
   2889 {
   2890 	int err;
   2891 
   2892 	/* traditional, qualified net removal */
   2893 	if (cmd->cmd_prop_nv_pairs > 0) {
   2894 		struct zone_nwiftab nwiftab;
   2895 
   2896 		if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
   2897 			z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
   2898 			return;
   2899 		}
   2900 		if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
   2901 			z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
   2902 		else
   2903 			need_to_commit = B_TRUE;
   2904 		return;
   2905 	}
   2906 
   2907 	/*
   2908 	 * unqualified net removal.  remove all nets but prompt if more
   2909 	 * than one.
   2910 	 */
   2911 	if (!prompt_remove_resource(cmd, "net"))
   2912 		return;
   2913 
   2914 	if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
   2915 		z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
   2916 	else
   2917 		need_to_commit = B_TRUE;
   2918 }
   2919 
   2920 static void
   2921 remove_device(cmd_t *cmd)
   2922 {
   2923 	int err;
   2924 
   2925 	/* traditional, qualified device removal */
   2926 	if (cmd->cmd_prop_nv_pairs > 0) {
   2927 		struct zone_devtab devtab;
   2928 
   2929 		if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
   2930 			z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
   2931 			return;
   2932 		}
   2933 		if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
   2934 			z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
   2935 		else
   2936 			need_to_commit = B_TRUE;
   2937 		return;
   2938 	}
   2939 
   2940 	/*
   2941 	 * unqualified device removal.  remove all devices but prompt if more
   2942 	 * than one.
   2943 	 */
   2944 	if (!prompt_remove_resource(cmd, "device"))
   2945 		return;
   2946 
   2947 	if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
   2948 		z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
   2949 	else
   2950 		need_to_commit = B_TRUE;
   2951 }
   2952 
   2953 static void
   2954 remove_attr(cmd_t *cmd)
   2955 {
   2956 	int err;
   2957 
   2958 	/* traditional, qualified attr removal */
   2959 	if (cmd->cmd_prop_nv_pairs > 0) {
   2960 		struct zone_attrtab attrtab;
   2961 
   2962 		if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
   2963 			z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
   2964 			return;
   2965 		}
   2966 		if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
   2967 			z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
   2968 		else
   2969 			need_to_commit = B_TRUE;
   2970 		return;
   2971 	}
   2972 
   2973 	/*
   2974 	 * unqualified attr removal.  remove all attrs but prompt if more
   2975 	 * than one.
   2976 	 */
   2977 	if (!prompt_remove_resource(cmd, "attr"))
   2978 		return;
   2979 
   2980 	if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
   2981 		z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
   2982 	else
   2983 		need_to_commit = B_TRUE;
   2984 }
   2985 
   2986 static void
   2987 remove_dataset(cmd_t *cmd)
   2988 {
   2989 	int err;
   2990 
   2991 	/* traditional, qualified dataset removal */
   2992 	if (cmd->cmd_prop_nv_pairs > 0) {
   2993 		struct zone_dstab dstab;
   2994 
   2995 		if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
   2996 			z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
   2997 			return;
   2998 		}
   2999 		if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
   3000 			z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
   3001 		else
   3002 			need_to_commit = B_TRUE;
   3003 		return;
   3004 	}
   3005 
   3006 	/*
   3007 	 * unqualified dataset removal.  remove all datasets but prompt if more
   3008 	 * than one.
   3009 	 */
   3010 	if (!prompt_remove_resource(cmd, "dataset"))
   3011 		return;
   3012 
   3013 	if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
   3014 		z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
   3015 	else
   3016 		need_to_commit = B_TRUE;
   3017 }
   3018 
   3019 static void
   3020 remove_rctl(cmd_t *cmd)
   3021 {
   3022 	int err;
   3023 
   3024 	/* traditional, qualified rctl removal */
   3025 	if (cmd->cmd_prop_nv_pairs > 0) {
   3026 		struct zone_rctltab rctltab;
   3027 
   3028 		if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
   3029 			z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
   3030 			return;
   3031 		}
   3032 		if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
   3033 			z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
   3034 		else
   3035 			need_to_commit = B_TRUE;
   3036 		zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
   3037 		return;
   3038 	}
   3039 
   3040 	/*
   3041 	 * unqualified rctl removal.  remove all rctls but prompt if more
   3042 	 * than one.
   3043 	 */
   3044 	if (!prompt_remove_resource(cmd, "rctl"))
   3045 		return;
   3046 
   3047 	if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
   3048 		z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
   3049 	else
   3050 		need_to_commit = B_TRUE;
   3051 }
   3052 
   3053 static void
   3054 remove_pset()
   3055 {
   3056 	int err;
   3057 	struct zone_psettab psettab;
   3058 
   3059 	if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
   3060 		z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
   3061 		return;
   3062 	}
   3063 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
   3064 		z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
   3065 	else
   3066 		need_to_commit = B_TRUE;
   3067 }
   3068 
   3069 static void
   3070 remove_pcap()
   3071 {
   3072 	int err;
   3073 	uint64_t tmp;
   3074 
   3075 	if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
   3076 		zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
   3077 		    zonecfg_strerror(Z_NO_RESOURCE_TYPE));
   3078 		saw_error = B_TRUE;
   3079 		return;
   3080 	}
   3081 
   3082 	if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
   3083 		z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
   3084 	else
   3085 		need_to_commit = B_TRUE;
   3086 }
   3087 
   3088 static void
   3089 remove_mcap()
   3090 {
   3091 	int err, res1, res2, res3;
   3092 	uint64_t tmp;
   3093 	struct zone_mcaptab mcaptab;
   3094 	boolean_t revert = B_FALSE;
   3095 
   3096 	res1 = zonecfg_lookup_mcap(handle, &mcaptab);
   3097 	res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
   3098 	res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
   3099 
   3100 	/* if none of these exist, there is no resource to remove */
   3101 	if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
   3102 		zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
   3103 		    zonecfg_strerror(Z_NO_RESOURCE_TYPE));
   3104 		saw_error = B_TRUE;
   3105 		return;
   3106 	}
   3107 	if (res1 == Z_OK) {
   3108 		if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
   3109 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
   3110 			revert = B_TRUE;
   3111 		} else {
   3112 			need_to_commit = B_TRUE;
   3113 		}
   3114 	}
   3115 	if (res2 == Z_OK) {
   3116 		if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
   3117 		    != Z_OK) {
   3118 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
   3119 			revert = B_TRUE;
   3120 		} else {
   3121 			need_to_commit = B_TRUE;
   3122 		}
   3123 	}
   3124 	if (res3 == Z_OK) {
   3125 		if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
   3126 		    != Z_OK) {
   3127 			z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
   3128 			revert = B_TRUE;
   3129 		} else {
   3130 			need_to_commit = B_TRUE;
   3131 		}
   3132 	}
   3133 
   3134 	if (revert)
   3135 		need_to_commit = B_FALSE;
   3136 }
   3137 
   3138 static void
   3139 remove_resource(cmd_t *cmd)
   3140 {
   3141 	int type;
   3142 	int arg;
   3143 	boolean_t arg_err = B_FALSE;
   3144 
   3145 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
   3146 		long_usage(CMD_REMOVE, B_TRUE);
   3147 		return;
   3148 	}
   3149 
   3150 	optind = 0;
   3151 	while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
   3152 		switch (arg) {
   3153 		case '?':
   3154 			longer_usage(CMD_REMOVE);
   3155 			arg_err = B_TRUE;
   3156 			break;
   3157 		case 'F':
   3158 			break;
   3159 		default:
   3160 			short_usage(CMD_REMOVE);
   3161 			arg_err = B_TRUE;
   3162 			break;
   3163 		}
   3164 	}
   3165 	if (arg_err)
   3166 		return;
   3167 
   3168 	if (initialize(B_TRUE) != Z_OK)
   3169 		return;
   3170 
   3171 	switch (type) {
   3172 	case RT_FS:
   3173 		remove_fs(cmd);
   3174 		return;
   3175 	case RT_IPD:
   3176 		remove_ipd(cmd);
   3177 		return;
   3178 	case RT_NET:
   3179 		remove_net(cmd);
   3180 		return;
   3181 	case RT_DEVICE:
   3182 		remove_device(cmd);
   3183 		return;
   3184 	case RT_RCTL:
   3185 		remove_rctl(cmd);
   3186 		return;
   3187 	case RT_ATTR:
   3188 		remove_attr(cmd);
   3189 		return;
   3190 	case RT_DATASET:
   3191 		remove_dataset(cmd);
   3192 		return;
   3193 	case RT_DCPU:
   3194 		remove_pset();
   3195 		return;
   3196 	case RT_PCAP:
   3197 		remove_pcap();
   3198 		return;
   3199 	case RT_MCAP:
   3200 		remove_mcap();
   3201 		return;
   3202 	default:
   3203 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
   3204 		long_usage(CMD_REMOVE, B_TRUE);
   3205 		usage(B_FALSE, HELP_RESOURCES);
   3206 		return;
   3207 	}
   3208 }
   3209 
   3210 static void
   3211 remove_property(cmd_t *cmd)
   3212 {
   3213 	char *prop_id;
   3214 	int err, res_type, prop_type;
   3215 	property_value_ptr_t pp;
   3216 	struct zone_rctlvaltab *rctlvaltab;
   3217 	complex_property_ptr_t cx;
   3218 
   3219 	res_type = resource_scope;
   3220 	prop_type = cmd->cmd_prop_name[0];
   3221 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
   3222 		long_usage(CMD_REMOVE, B_TRUE);
   3223 		return;
   3224 	}
   3225 
   3226 	if (cmd->cmd_prop_nv_pairs != 1) {
   3227 		long_usage(CMD_ADD, B_TRUE);
   3228 		return;
   3229 	}
   3230 
   3231 	if (initialize(B_TRUE) != Z_OK)
   3232 		return;
   3233 
   3234 	switch (res_type) {
   3235 	case RT_FS:
   3236 		if (prop_type != PT_OPTIONS) {
   3237 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
   3238 			    B_TRUE);
   3239 			long_usage(CMD_REMOVE, B_TRUE);
   3240 			usage(B_FALSE, HELP_PROPS);
   3241 			return;
   3242 		}
   3243 		pp = cmd->cmd_property_ptr[0];
   3244 		if (pp->pv_type == PROP_VAL_COMPLEX) {
   3245 			zerr(gettext("A %s or %s value was expected here."),
   3246 			    pvt_to_str(PROP_VAL_SIMPLE),
   3247 			    pvt_to_str(PROP_VAL_LIST));
   3248 			saw_error = B_TRUE;
   3249 			return;
   3250 		}
   3251 		if (pp->pv_type == PROP_VAL_SIMPLE) {
   3252 			if (pp->pv_simple == NULL) {
   3253 				long_usage(CMD_ADD, B_TRUE);
   3254 				return;
   3255 			}
   3256 			prop_id = pp->pv_simple;
   3257 			err = zonecfg_remove_fs_option(&in_progress_fstab,
   3258 			    prop_id);
   3259 			if (err != Z_OK)
   3260 				zone_perror(pt_to_str(prop_type), err, B_TRUE);
   3261 		} else {
   3262 			list_property_ptr_t list;
   3263 
   3264 			for (list = pp->pv_list; list != NULL;
   3265 			    list = list->lp_next) {
   3266 				prop_id = list->lp_simple;
   3267 				if (prop_id == NULL)
   3268 					break;
   3269 				err = zonecfg_remove_fs_option(
   3270 				    &in_progress_fstab, prop_id);
   3271 				if (err != Z_OK)
   3272 					zone_perror(pt_to_str(prop_type), err,
   3273 					    B_TRUE);
   3274 			}
   3275 		}
   3276 		return;
   3277 	case RT_RCTL:
   3278 		if (prop_type != PT_VALUE) {
   3279 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
   3280 			    B_TRUE);
   3281 			long_usage(CMD_REMOVE, B_TRUE);
   3282 			usage(B_FALSE, HELP_PROPS);
   3283 			return;
   3284 		}
   3285 		pp = cmd->cmd_property_ptr[0];
   3286 		if (pp->pv_type != PROP_VAL_COMPLEX) {
   3287 			zerr(gettext("A %s value was expected here."),
   3288 			    pvt_to_str(PROP_VAL_COMPLEX));
   3289 			saw_error = B_TRUE;
   3290 			return;
   3291 		}
   3292 		if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
   3293 			zone_perror(zone, Z_NOMEM, B_TRUE);
   3294 			exit(Z_ERR);
   3295 		}
   3296 		for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
   3297 			switch (cx->cp_type) {
   3298 			case PT_PRIV:
   3299 				(void) strlcpy(rctlvaltab->zone_rctlval_priv,
   3300 				    cx->cp_value,
   3301 				    sizeof (rctlvaltab->zone_rctlval_priv));
   3302 				break;
   3303 			case PT_LIMIT:
   3304 				(void) strlcpy(rctlvaltab->zone_rctlval_limit,
   3305 				    cx->cp_value,
   3306 				    sizeof (rctlvaltab->zone_rctlval_limit));
   3307 				break;
   3308 			case PT_ACTION:
   3309 				(void) strlcpy(rctlvaltab->zone_rctlval_action,
   3310 				    cx->cp_value,
   3311 				    sizeof (rctlvaltab->zone_rctlval_action));
   3312 				break;
   3313 			default:
   3314 				zone_perror(pt_to_str(prop_type),
   3315 				    Z_NO_PROPERTY_TYPE, B_TRUE);
   3316 				long_usage(CMD_ADD, B_TRUE);
   3317 				usage(B_FALSE, HELP_PROPS);
   3318 				zonecfg_free_rctl_value_list(rctlvaltab);
   3319 				return;
   3320 			}
   3321 		}
   3322 		rctlvaltab->zone_rctlval_next = NULL;
   3323 		err = zonecfg_remove_rctl_value(&in_progress_rctltab,
   3324 		    rctlvaltab);
   3325 		if (err != Z_OK)
   3326 			zone_perror(pt_to_str(prop_type), err, B_TRUE);
   3327 		zonecfg_free_rctl_value_list(rctlvaltab);
   3328 		return;
   3329 	case RT_NET:
   3330 		if (prop_type != PT_DEFROUTER) {
   3331 			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
   3332 			    B_TRUE);
   3333 			long_usage(CMD_REMOVE, B_TRUE);
   3334 			usage(B_FALSE, HELP_PROPS);
   3335 			return;
   3336 		} else {
   3337 			bzero(&in_progress_nwiftab.zone_nwif_defrouter,
   3338 			    sizeof (in_progress_nwiftab.zone_nwif_defrouter));
   3339 			return;
   3340 		}
   3341 	default:
   3342 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
   3343 		long_usage(CMD_REMOVE, B_TRUE);
   3344 		usage(B_FALSE, HELP_RESOURCES);
   3345 		return;
   3346 	}
   3347 }
   3348 
   3349 void
   3350 remove_func(cmd_t *cmd)
   3351 {
   3352 	if (zone_is_read_only(CMD_REMOVE))
   3353 		return;
   3354 
   3355 	assert(cmd != NULL);
   3356 
   3357 	if (global_scope) {
   3358 		if (gz_invalid_resource(cmd->cmd_res_type)) {
   3359 			zerr(gettext("%s is not a valid resource for the "
   3360 			    "global zone."), rt_to_str(cmd->cmd_res_type));
   3361 			saw_error = B_TRUE;
   3362 			return;
   3363 		}
   3364 		remove_resource(cmd);
   3365 	} else {
   3366 		remove_property(cmd);
   3367 	}
   3368 }
   3369 
   3370 static void
   3371 clear_property(cmd_t *cmd)
   3372 {
   3373 	int res_type, prop_type;
   3374 
   3375 	res_type = resource_scope;
   3376 	prop_type = cmd->cmd_res_type;
   3377 	if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
   3378 		long_usage(CMD_CLEAR, B_TRUE);
   3379 		return;
   3380 	}
   3381 
   3382 	if (initialize(B_TRUE) != Z_OK)
   3383 		return;
   3384 
   3385 	switch (res_type) {
   3386 	case RT_FS:
   3387 		if (prop_type == PT_RAW) {
   3388 			in_progress_fstab.zone_fs_raw[0] = '\0';
   3389 			need_to_commit = B_TRUE;
   3390 			return;
   3391 		}
   3392 		break;
   3393 	case RT_DCPU:
   3394 		if (prop_type == PT_IMPORTANCE) {
   3395 			in_progress_psettab.zone_importance[0] = '\0';
   3396 			need_to_commit = B_TRUE;
   3397 			return;
   3398 		}
   3399 		break;
   3400 	case RT_MCAP:
   3401 		switch (prop_type) {
   3402 		case PT_PHYSICAL:
   3403 			in_progress_mcaptab.zone_physmem_cap[0] = '\0';
   3404 			need_to_commit = B_TRUE;
   3405 			return;
   3406 		case PT_SWAP:
   3407 			remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
   3408 			return;
   3409 		case PT_LOCKED:
   3410 			remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
   3411 			return;
   3412 		}
   3413 		break;
   3414 	default:
   3415 		break;
   3416 	}
   3417 
   3418 	zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
   3419 }
   3420 
   3421 static void
   3422 clear_global(cmd_t *cmd)
   3423 {
   3424 	int err, type;
   3425 
   3426 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
   3427 		long_usage(CMD_CLEAR, B_TRUE);
   3428 		return;
   3429 	}
   3430 
   3431 	if (initialize(B_TRUE) != Z_OK)
   3432 		return;
   3433 
   3434 	switch (type) {
   3435 	case PT_ZONENAME:
   3436 		/* FALLTHRU */
   3437 	case PT_ZONEPATH:
   3438 		/* FALLTHRU */
   3439 	case PT_BRAND:
   3440 		zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
   3441 		return;
   3442 	case PT_AUTOBOOT:
   3443 		/* false is default; we'll treat as equivalent to clearing */
   3444 		if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
   3445 			z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
   3446 		else
   3447 			need_to_commit = B_TRUE;
   3448 		return;
   3449 	case PT_POOL:
   3450 		if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
   3451 			z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
   3452 		else
   3453 			need_to_commit = B_TRUE;
   3454 		return;
   3455 	case PT_LIMITPRIV:
   3456 		if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
   3457 			z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
   3458 		else
   3459 			need_to_commit = B_TRUE;
   3460 		return;
   3461 	case PT_BOOTARGS:
   3462 		if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
   3463 			z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
   3464 		else
   3465 			need_to_commit = B_TRUE;
   3466 		return;
   3467 	case PT_SCHED:
   3468 		if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
   3469 			z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
   3470 		else
   3471 			need_to_commit = B_TRUE;
   3472 		return;
   3473 	case PT_IPTYPE:
   3474 		/* shared is default; we'll treat as equivalent to clearing */
   3475 		if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
   3476 			z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
   3477 		else
   3478 			need_to_commit = B_TRUE;
   3479 		return;
   3480 	case PT_MAXLWPS:
   3481 		remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
   3482 		return;
   3483 	case PT_MAXSHMMEM:
   3484 		remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
   3485 		return;
   3486 	case PT_MAXSHMIDS:
   3487 		remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
   3488 		return;
   3489 	case PT_MAXMSGIDS:
   3490 		remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
   3491 		return;
   3492 	case PT_MAXSEMIDS:
   3493 		remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
   3494 		return;
   3495 	case PT_SHARES:
   3496 		remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
   3497 		return;
   3498 	case PT_HOSTID:
   3499 		if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
   3500 			z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
   3501 		else
   3502 			need_to_commit = B_TRUE;
   3503 		return;
   3504 	default:
   3505 		zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
   3506 		long_usage(CMD_CLEAR, B_TRUE);
   3507 		usage(B_FALSE, HELP_PROPS);
   3508 		return;
   3509 	}
   3510 }
   3511 
   3512 void
   3513 clear_func(cmd_t *cmd)
   3514 {
   3515 	if (zone_is_read_only(CMD_CLEAR))
   3516 		return;
   3517 
   3518 	assert(cmd != NULL);
   3519 
   3520 	if (global_scope) {
   3521 		if (gz_invalid_property(cmd->cmd_res_type)) {
   3522 			zerr(gettext("%s is not a valid property for the "
   3523 			    "global zone."), pt_to_str(cmd->cmd_res_type));
   3524 			saw_error = B_TRUE;
   3525 			return;
   3526 		}
   3527 
   3528 		clear_global(cmd);
   3529 	} else {
   3530 		clear_property(cmd);
   3531 	}
   3532 }
   3533 
   3534 void
   3535 select_func(cmd_t *cmd)
   3536 {
   3537 	int type, err, res;
   3538 	uint64_t limit;
   3539 	uint64_t tmp;
   3540 
   3541 	if (zone_is_read_only(CMD_SELECT))
   3542 		return;
   3543 
   3544 	assert(cmd != NULL);
   3545 
   3546 	if (global_scope) {
   3547 		global_scope = B_FALSE;
   3548 		resource_scope = cmd->cmd_res_type;
   3549 		end_op = CMD_SELECT;
   3550 	} else {
   3551 		scope_usage(CMD_SELECT);
   3552 		return;
   3553 	}
   3554 
   3555 	if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
   3556 		long_usage(CMD_SELECT, B_TRUE);
   3557 		return;
   3558 	}
   3559 
   3560 	if (initialize(B_TRUE) != Z_OK)
   3561 		return;
   3562 
   3563 	switch (type) {
   3564 	case RT_FS:
   3565 		if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
   3566 			z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
   3567 			global_scope = B_TRUE;
   3568 		}
   3569 		bcopy(&old_fstab, &in_progress_fstab,
   3570 		    sizeof (struct zone_fstab));
   3571 		return;
   3572 	case RT_IPD:
   3573 		if (state_atleast(ZONE_STATE_INCOMPLETE)) {
   3574 			zerr(gettext("Zone %s not in %s state; %s %s not "
   3575 			    "allowed."), zone,
   3576 			    zone_state_str(ZONE_STATE_CONFIGURED),
   3577 			    cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD));
   3578 			global_scope = B_TRUE;
   3579 			end_op = -1;
   3580 			return;
   3581 		}
   3582 		if ((err = fill_in_ipdtab(cmd, &old_ipdtab, B_FALSE)) != Z_OK) {
   3583 			z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, B_TRUE);
   3584 			global_scope = B_TRUE;
   3585 		}
   3586 		bcopy(&old_ipdtab, &in_progress_ipdtab,
   3587 		    sizeof (struct zone_fstab));
   3588 		return;
   3589 	case RT_NET:
   3590 		if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
   3591 		    != Z_OK) {
   3592 			z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
   3593 			global_scope = B_TRUE;
   3594 		}
   3595 		bcopy(&old_nwiftab, &in_progress_nwiftab,
   3596 		    sizeof (struct zone_nwiftab));
   3597 		return;
   3598 	case RT_DEVICE:
   3599 		if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
   3600 			z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
   3601 			global_scope = B_TRUE;
   3602 		}
   3603 		bcopy(&old_devtab, &in_progress_devtab,
   3604 		    sizeof (struct zone_devtab));
   3605 		return;
   3606 	case RT_RCTL:
   3607 		if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
   3608 		    != Z_OK) {
   3609 			z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
   3610 			global_scope = B_TRUE;
   3611 		}
   3612 		bcopy(&old_rctltab, &in_progress_rctltab,
   3613 		    sizeof (struct zone_rctltab));
   3614 		return;
   3615 	case RT_ATTR:
   3616 		if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
   3617 		    != Z_OK) {
   3618 			z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
   3619 			global_scope = B_TRUE;
   3620 		}
   3621 		bcopy(&old_attrtab, &in_progress_attrtab,
   3622 		    sizeof (struct zone_attrtab));
   3623 		return;
   3624 	case RT_DATASET:
   3625 		if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
   3626 			z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
   3627 			global_scope = B_TRUE;
   3628 		}
   3629 		bcopy(&old_dstab, &in_progress_dstab,
   3630 		    sizeof (struct zone_dstab));
   3631 		return;
   3632 	case RT_DCPU:
   3633 		if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
   3634 			z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
   3635 			global_scope = B_TRUE;
   3636 		}
   3637 		bcopy(&old_psettab, &in_progress_psettab,
   3638 		    sizeof (struct zone_psettab));
   3639 		return;
   3640 	case RT_PCAP:
   3641 		if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
   3642 		    != Z_OK) {
   3643 			z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
   3644 			global_scope = B_TRUE;
   3645 		}
   3646 		return;
   3647 	case RT_MCAP:
   3648 		/* if none of these exist, there is no resource to select */
   3649 		if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
   3650 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
   3651 		    != Z_OK &&
   3652 		    zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
   3653 		    != Z_OK) {
   3654 			z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
   3655 			    B_TRUE);
   3656 			global_scope = B_TRUE;
   3657 		}
   3658 		if (res == Z_OK)
   3659 			bcopy(&old_mcaptab, &in_progress_mcaptab,
   3660 			    sizeof (struct zone_mcaptab));
   3661 		else
   3662 			bzero(&in_progress_mcaptab,
   3663 			    sizeof (in_progress_mcaptab));
   3664 		return;
   3665 	default:
   3666 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
   3667 		long_usage(CMD_SELECT, B_TRUE);
   3668 		usage(B_FALSE, HELP_RESOURCES);
   3669 		return;
   3670 	}
   3671 }
   3672 
   3673 /*
   3674  * Network "addresses" can be one of the following forms:
   3675  *	<IPv4 address>
   3676  *	<IPv4 address>/<prefix length>
   3677  *	<IPv6 address>/<prefix length>
   3678  *	<host name>
   3679  *	<host name>/<prefix length>
   3680  * In other words, the "/" followed by a prefix length is allowed but not
   3681  * required for IPv4 addresses and host names, and required for IPv6 addresses.
   3682  * If a prefix length is given, it must be in the allowable range: 0 to 32 for
   3683  * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
   3684  * Host names must start with an alpha-numeric character, and all subsequent
   3685  * characters must be either alpha-numeric or "-".
   3686  */
   3687 
   3688 static int
   3689 validate_net_address_syntax(char *address)
   3690 {
   3691 	char *slashp, part1[MAXHOSTNAMELEN];
   3692 	struct in6_addr in6;
   3693 	struct in_addr in4;
   3694 	int prefixlen, i;
   3695 
   3696 	/*
   3697 	 * Copy the part before any '/' into part1 or copy the whole
   3698 	 * thing if there is no '/'.
   3699 	 */
   3700 	if ((slashp = strchr(address, '/')) != NULL) {
   3701 		*slashp = '\0';
   3702 		(void) strlcpy(part1, address, sizeof (part1));
   3703 		*slashp = '/';
   3704 		prefixlen = atoi(++slashp);
   3705 	} else {
   3706 		(void) strlcpy(part1, address, sizeof (part1));
   3707 	}
   3708 
   3709 	if (inet_pton(AF_INET6, part1, &in6) == 1) {
   3710 		if (slashp == NULL) {
   3711 			zerr(gettext("%s: IPv6 addresses "
   3712 			    "require /prefix-length suffix."), address);
   3713 			return (Z_ERR);
   3714 		}
   3715 		if (prefixlen < 0 || prefixlen > 128) {
   3716 			zerr(gettext("%s: IPv6 address "
   3717 			    "prefix lengths must be 0 - 128."), address);
   3718 			return (Z_ERR);
   3719 		}
   3720 		return (Z_OK);
   3721 	}
   3722 
   3723 	/* At this point, any /prefix must be for IPv4. */
   3724 	if (slashp != NULL) {
   3725 		if (prefixlen < 0 || prefixlen > 32) {
   3726 			zerr(gettext("%s: IPv4 address "
   3727 			    "prefix lengths must be 0 - 32."), address);
   3728 			return (Z_ERR);
   3729 		}
   3730 	}
   3731 	if (inet_pton(AF_INET, part1, &in4) == 1)
   3732 		return (Z_OK);
   3733 
   3734 	/* address may also be a host name */
   3735 	if (!isalnum(part1[0])) {
   3736 		zerr(gettext("%s: bogus host name or network address syntax"),
   3737 		    part1);
   3738 		saw_error = B_TRUE;
   3739 		usage(B_FALSE, HELP_NETADDR);
   3740 		return (Z_ERR);
   3741 	}
   3742 	for (i = 1; part1[i]; i++)
   3743 		if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
   3744 			zerr(gettext("%s: bogus host name or "
   3745 			    "network address syntax"), part1);
   3746 			saw_error = B_TRUE;
   3747 			usage(B_FALSE, HELP_NETADDR);
   3748 			return (Z_ERR);
   3749 		}
   3750 	return (Z_OK);
   3751 }
   3752 
   3753 static int
   3754 validate_net_physical_syntax(const char *ifname)
   3755 {
   3756 	ifspec_t ifnameprop;
   3757 	zone_iptype_t iptype;
   3758 
   3759 	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
   3760 		zerr(gettext("zone configuration has an invalid or nonexistent "
   3761 		    "ip-type property"));
   3762 		return (Z_ERR);
   3763 	}
   3764 	switch (iptype) {
   3765 	case ZS_SHARED:
   3766 		if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
   3767 			zerr(gettext("%s: invalid physical interface name"),
   3768 			    ifname);
   3769 			return (Z_ERR);
   3770 		}
   3771 		if (ifnameprop.ifsp_lunvalid) {
   3772 			zerr(gettext("%s: LUNs not allowed in physical "
   3773 			    "interface names"), ifname);
   3774 			return (Z_ERR);
   3775 		}
   3776 		break;
   3777 	case ZS_EXCLUSIVE:
   3778 		if (dladm_valid_linkname(ifname) == B_FALSE) {
   3779 			if (strchr(ifname, ':') != NULL)
   3780 				zerr(gettext("%s: physical interface name "
   3781 				    "required; logical interface name not "
   3782 				    "allowed"), ifname);
   3783 			else
   3784 				zerr(gettext("%s: invalid physical interface "
   3785 				    "name"), ifname);
   3786 			return (Z_ERR);
   3787 		}
   3788 		break;
   3789 	}
   3790 	return (Z_OK);
   3791 }
   3792 
   3793 static boolean_t
   3794 valid_fs_type(const char *type)
   3795 {
   3796 	/*
   3797 	 * Is this a valid path component?
   3798 	 */
   3799 	if (strlen(type) + 1 > MAXNAMELEN)
   3800 		return (B_FALSE);
   3801 	/*
   3802 	 * Make sure a bad value for "type" doesn't make
   3803 	 * /usr/lib/fs/<type>/mount turn into something else.
   3804 	 */
   3805 	if (strchr(type, '/') != NULL || type[0] == '\0' ||
   3806 	    strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
   3807 		return (B_FALSE);
   3808 	/*
   3809 	 * More detailed verification happens later by zoneadm(1m).
   3810 	 */
   3811 	return (B_TRUE);
   3812 }
   3813 
   3814 static boolean_t
   3815 allow_exclusive()
   3816 {
   3817 	brand_handle_t	bh;
   3818 	char		brand[MAXNAMELEN];
   3819 	boolean_t	ret;
   3820 
   3821 	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
   3822 		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
   3823 		return (B_FALSE);
   3824 	}
   3825 	if ((bh = brand_open(brand)) == NULL) {
   3826 		zerr("%s: %s\n", zone, gettext("unknown brand."));
   3827 		return (B_FALSE);
   3828 	}
   3829 	ret = brand_allow_exclusive_ip(bh);
   3830 	brand_close(bh);
   3831 	if (!ret)
   3832 		zerr(gettext("%s cannot be '%s' when %s is '%s'."),
   3833 		    pt_to_str(PT_IPTYPE), "exclusive",
   3834 		    pt_to_str(PT_BRAND), brand);
   3835 	return (ret);
   3836 }
   3837 
   3838 static void
   3839 set_aliased_rctl(char *alias, int prop_type, char *s)
   3840 {
   3841 	uint64_t limit;
   3842 	int err;
   3843 	char tmp[128];
   3844 
   3845 	if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
   3846 		zerr(gettext("WARNING: Setting a global zone resource "
   3847 		    "control too low could deny\nservice "
   3848 		    "to even the root user; "
   3849 		    "this could render the system impossible\n"
   3850 		    "to administer.  Please use caution."));
   3851 
   3852 	/* convert memory based properties */
   3853 	if (prop_type == PT_MAXSHMMEM) {
   3854 		if (!zonecfg_valid_memlimit(s, &limit)) {
   3855 			zerr(gettext("A non-negative number with a required "
   3856 			    "scale suffix (K, M, G or T) was expected\nhere."));
   3857 			saw_error = B_TRUE;
   3858 			return;
   3859 		}
   3860 
   3861 		(void) snprintf(tmp, sizeof (tmp), "%llu", limit);