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