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