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