xref: /illumos-gate/usr/src/cmd/zonecfg/zonecfg.c (revision bbf21555)
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 
96 struct help {
97 	uint_t	cmd_num;
98 	char	*cmd_name;
99 	uint_t	flags;
100 	char	*short_usage;
101 };
102 
103 extern int yyparse(void);
104 extern 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 
139 static 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 */
162 char *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 */
197 char *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 */
247 static 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  */
262 static 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 
280 static 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 
295 static 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 
312 static 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 
327 static 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 
342 static 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 
364 static 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 
397 static 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 
413 static 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 
426 static const char *device_res_scope_cmds[] = {
427 	"cancel",
428 	"end",
429 	"exit",
430 	"help",
431 	"info",
432 	"set match=",
433 	NULL
434 };
435 
436 static 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 
448 static 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 
460 static const char *dataset_res_scope_cmds[] = {
461 	"cancel",
462 	"end",
463 	"exit",
464 	"help",
465 	"info",
466 	"set name=",
467 	NULL
468 };
469 
470 static 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 
482 static const char *pcap_res_scope_cmds[] = {
483 	"cancel",
484 	"end",
485 	"exit",
486 	"help",
487 	"info",
488 	"set ncpus=",
489 	NULL
490 };
491 
492 static 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 
507 static 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 
518 static 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 
528 struct 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 */
538 struct xif *xif;
539 
540 /* set early in main(), never modified thereafter, used all over the place */
541 static char *execname;
542 
543 /* set in main(), used all over the place */
544 static zone_dochandle_t handle;
545 
546 /* used all over the place */
547 static char zone[ZONENAME_MAX];
548 static char revert_zone[ZONENAME_MAX];
549 
550 /* global brand operations */
551 static brand_handle_t brand;
552 
553 /* set in modifying functions, checked in read_input() */
554 static boolean_t need_to_commit = B_FALSE;
555 boolean_t saw_error;
556 
557 /* set in yacc parser, checked in read_input() */
558 boolean_t newline_terminated;
559 
560 /* set in main(), checked in lex error handler */
561 boolean_t cmd_file_mode;
562 
563 /* set in exit_func(), checked in read_input() */
564 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
565 
566 /* used in short_usage() and zerr() */
567 static char *cmd_file_name = NULL;
568 
569 /* checked in read_input() and other places */
570 static boolean_t ok_to_prompt = B_FALSE;
571 
572 /* set and checked in initialize() */
573 static boolean_t got_handle = B_FALSE;
574 
575 /* initialized in do_interactive(), checked in initialize() */
576 static boolean_t interactive_mode;
577 
578 /* set if configuring the global zone */
579 static boolean_t global_zone = B_FALSE;
580 
581 /* set in main(), checked in multiple places */
582 static boolean_t read_only_mode;
583 
584 /* scope is outer/global or inner/resource */
585 static boolean_t global_scope = B_TRUE;
586 static int resource_scope;	/* should be in the RT_ list from zonecfg.h */
587 static int end_op = -1;		/* operation on end is either add or modify */
588 
589 int 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  */
596 static struct zone_fstab	old_fstab, in_progress_fstab;
597 static struct zone_nwiftab	old_nwiftab, in_progress_nwiftab;
598 static struct zone_devtab	old_devtab, in_progress_devtab;
599 static struct zone_rctltab	old_rctltab, in_progress_rctltab;
600 static struct zone_attrtab	old_attrtab, in_progress_attrtab;
601 static struct zone_dstab	old_dstab, in_progress_dstab;
602 static struct zone_psettab	old_psettab, in_progress_psettab;
603 static struct zone_mcaptab	old_mcaptab, in_progress_mcaptab;
604 static struct zone_admintab	old_admintab, in_progress_admintab;
605 static struct zone_secflagstab	old_secflagstab, in_progress_secflagstab;
606 
607 static GetLine *gl;	/* The gl_get_line() resource object */
608 
609 static void bytes_to_units(char *str, char *buf, int bufsize);
610 
611 /* Functions begin here */
612 
613 static boolean_t
initial_match(const char * line1,const char * line2,int word_end)614 initial_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 
621 static int
add_stuff(WordCompletion * cpl,const char * line1,const char ** list,int word_end)622 add_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 
638 static
639 /* ARGSUSED */
CPL_MATCH_FN(cmd_cpl_fn)640 CPL_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 
700 cmd_t *
alloc_cmd(void)701 alloc_cmd(void)
702 {
703 	return (calloc(1, sizeof (cmd_t)));
704 }
705 
706 void
free_cmd(cmd_t * cmd)707 free_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 
732 complex_property_ptr_t
alloc_complex(void)733 alloc_complex(void)
734 {
735 	return (calloc(1, sizeof (complex_property_t)));
736 }
737 
738 void
free_complex(complex_property_ptr_t complex)739 free_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 
749 list_property_ptr_t
alloc_list(void)750 alloc_list(void)
751 {
752 	return (calloc(1, sizeof (list_property_t)));
753 }
754 
755 void
free_list(list_property_ptr_t list)756 free_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 
767 void
free_outer_list(list_property_ptr_t list)768 free_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 
776 static struct zone_rctlvaltab *
alloc_rctlvaltab(void)777 alloc_rctlvaltab(void)
778 {
779 	return (calloc(1, sizeof (struct zone_rctlvaltab)));
780 }
781 
782 static char *
rt_to_str(int res_type)783 rt_to_str(int res_type)
784 {
785 	assert(res_type >= RT_MIN && res_type <= RT_MAX);
786 	return (res_types[res_type]);
787 }
788 
789 static char *
pt_to_str(int prop_type)790 pt_to_str(int prop_type)
791 {
792 	assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
793 	return (prop_types[prop_type]);
794 }
795 
796 static char *
pvt_to_str(int pv_type)797 pvt_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 
803 static char *
cmd_to_str(int cmd_num)804 cmd_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 */
811 static void
zerr(const char * fmt,...)812 zerr(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 
844 static char *
long_help(int cmd_num)845 long_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 */
944 static const char *
exec_cat(const char * s1,const char * s2,char * si)945 exec_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 */
974 static int
path_find(const char * name)975 path_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 
1001 static FILE *
pager_open(void)1002 pager_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 
1028 static void
pager_close(FILE * fp)1029 pager_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 
1044 void
usage(boolean_t verbose,uint_t flags)1045 usage(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(8), "
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(8) 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 
1411 static void
zone_perror(char * prefix,int err,boolean_t set_saw)1412 zone_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 
1425 static void
z_cmd_rt_perror(int cmd_num,int res_num,int err,boolean_t set_saw)1426 z_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 */
1435 static int
initialize(boolean_t handle_expected)1436 initialize(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 
1519 static boolean_t
state_atleast(zone_state_t state)1520 state_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 
1540 void
short_usage(int command)1541 short_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 
1564 void
long_usage(uint_t cmd_num,boolean_t set_saw)1565 long_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 
1579 void
longer_usage(uint_t cmd_num)1580 longer_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 
1593 static void
scope_usage(uint_t cmd_num)1594 scope_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 
1607 static int
ask_yesno(boolean_t default_answer,const char * question)1608 ask_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 
1641 static int
check_if_zone_already_exists(boolean_t force)1642 check_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 
1680 static boolean_t
zone_is_read_only(int cmd_num)1681 zone_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  */
1701 void
create_func(cmd_t * cmd)1702 create_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  */
1805 static char *
quoteit(char * instr)1806 quoteit(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 
1823 static void
export_prop(FILE * of,int prop_num,char * prop_id)1824 export_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 
1838 void
export_func(cmd_t * cmd)1839 export_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 
2138 done:
2139 	if (need_to_close)
2140 		(void) fclose(of);
2141 }
2142 
2143 void
exit_func(cmd_t * cmd)2144 exit_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 
2190 static int
validate_zonepath_syntax(char * path)2191 validate_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 
2206 static void
add_resource(cmd_t * cmd)2207 add_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 	}
2337 bad:
2338 	global_scope = B_TRUE;
2339 	end_op = -1;
2340 }
2341 
2342 static void
do_complex_rctl_val(complex_property_ptr_t cp)2343 do_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 
2426 bad:
2427 	zonecfg_free_rctl_value_list(rctlvaltab);
2428 }
2429 
2430 static void
add_property(cmd_t * cmd)2431 add_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 
2529 static boolean_t
gz_invalid_resource(int type)2530 gz_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 
2537 static boolean_t
gz_invalid_rt_property(int type)2538 gz_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 
2546 static boolean_t
gz_invalid_property(int type)2547 gz_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 
2555 void
add_func(cmd_t * cmd)2556 add_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  */
2613 void
delete_func(cmd_t * cmd)2614 delete_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 
2722 static int
fill_in_fstab(cmd_t * cmd,struct zone_fstab * fstab,boolean_t fill_in_only)2723 fill_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 
2767 static int
fill_in_nwiftab(cmd_t * cmd,struct zone_nwiftab * nwiftab,boolean_t fill_in_only)2768 fill_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 
2817 static int
fill_in_devtab(cmd_t * cmd,struct zone_devtab * devtab,boolean_t fill_in_only)2818 fill_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 
2851 static int
fill_in_rctltab(cmd_t * cmd,struct zone_rctltab * rctltab,boolean_t fill_in_only)2852 fill_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 
2886 static int
fill_in_attrtab(cmd_t * cmd,struct zone_attrtab * attrtab,boolean_t fill_in_only)2887 fill_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 
2929 static int
fill_in_dstab(cmd_t * cmd,struct zone_dstab * dstab,boolean_t fill_in_only)2930 fill_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 
2962 static int
fill_in_admintab(cmd_t * cmd,struct zone_admintab * admintab,boolean_t fill_in_only)2963 fill_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 
3001 static int
fill_in_secflagstab(cmd_t * cmd,struct zone_secflagstab * secflagstab,boolean_t fill_in_only)3002 fill_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 
3049 static void
remove_aliased_rctl(int type,char * name)3050 remove_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 
3070 static boolean_t
prompt_remove_resource(cmd_t * cmd,char * rsrc)3071 prompt_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 
3125 static void
remove_fs(cmd_t * cmd)3126 remove_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 
3159 static void
remove_net(cmd_t * cmd)3160 remove_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 
3192 static void
remove_device(cmd_t * cmd)3193 remove_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 
3225 static void
remove_attr(cmd_t * cmd)3226 remove_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 
3258 static void
remove_dataset(cmd_t * cmd)3259 remove_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 
3291 static void
remove_rctl(cmd_t * cmd)3292 remove_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 
3325 static void
remove_pset()3326 remove_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 
3341 static void
remove_pcap()3342 remove_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 
3360 static void
remove_mcap()3361 remove_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) {