dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / zonecfg / zonecfg.c
blobcf45604c0b4c14e287c2efe7a59f9fc542e3fa2b
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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
29 * zonecfg is a lex/yacc based command interpreter used to manage zone
30 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
31 * the grammar (see zonecfg_grammar.y) builds up into commands, some of
32 * which takes resources and/or properties as arguments. See the block
33 * comments near the end of zonecfg_grammar.y for how the data structures
34 * which keep track of these resources and properties are built up.
36 * The resource/property data structures are inserted into a command
37 * structure (see zonecfg.h), which also keeps track of command names,
38 * miscellaneous arguments, and function handlers. The grammar selects
39 * the appropriate function handler, each of which takes a pointer to a
40 * command structure as its sole argument, and invokes it. The grammar
41 * itself is "entered" (a la the Matrix) by yyparse(), which is called
42 * from read_input(), our main driving function. That in turn is called
43 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
44 * of which is called from main() depending on how the program was invoked.
46 * The rest of this module consists of the various function handlers and
47 * their helper functions. Some of these functions, particularly the
48 * X_to_str() functions, which maps command, resource and property numbers
49 * to strings, are used quite liberally, as doing so results in a better
50 * program w/rt I18N, reducing the need for translation notes.
53 #include <sys/mntent.h>
54 #include <sys/varargs.h>
55 #include <sys/sysmacros.h>
56 #include <sys/secflags.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <strings.h>
61 #include <unistd.h>
62 #include <ctype.h>
63 #include <stdlib.h>
64 #include <assert.h>
65 #include <sys/stat.h>
66 #include <zone.h>
67 #include <arpa/inet.h>
68 #include <netdb.h>
69 #include <locale.h>
70 #include <libintl.h>
71 #include <alloca.h>
72 #include <signal.h>
73 #include <wait.h>
74 #include <libtecla.h>
75 #include <libzfs.h>
76 #include <sys/brand.h>
77 #include <libbrand.h>
78 #include <sys/systeminfo.h>
79 #include <libdladm.h>
80 #include <libinetutil.h>
81 #include <pwd.h>
82 #include <inet/ip.h>
84 #include <libzonecfg.h>
85 #include "zonecfg.h"
87 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
88 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
89 #endif
91 #define PAGER "/usr/bin/more"
92 #define EXEC_PREFIX "exec "
93 #define EXEC_LEN (strlen(EXEC_PREFIX))
95 struct help {
96 uint_t cmd_num;
97 char *cmd_name;
98 uint_t flags;
99 char *short_usage;
102 extern int yyparse(void);
103 extern int lex_lineno;
105 #define MAX_LINE_LEN 1024
106 #define MAX_CMD_HIST 1024
107 #define MAX_CMD_LEN 1024
109 #define ONE_MB 1048576
112 * Each SHELP_ should be a simple string.
115 #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \
116 "add <property-name> <property-value>\n\t(resource scope)"
117 #define SHELP_CANCEL "cancel"
118 #define SHELP_CLEAR "clear <property-name>"
119 #define SHELP_COMMIT "commit"
120 #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]"
121 #define SHELP_DELETE "delete [-F]"
122 #define SHELP_END "end"
123 #define SHELP_EXIT "exit [-F]"
124 #define SHELP_EXPORT "export [-f output-file]"
125 #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]"
126 #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]"
127 #define SHELP_REMOVE "remove [-F] <resource-type> " \
128 "[ <property-name>=<property-value> ]*\n" \
129 "\t(global scope)\n" \
130 "remove <property-name> <property-value>\n" \
131 "\t(resource scope)"
132 #define SHELP_REVERT "revert [-F]"
133 #define SHELP_SELECT "select <resource-type> { <property-name>=" \
134 "<property-value> }"
135 #define SHELP_SET "set <property-name>=<property-value>"
136 #define SHELP_VERIFY "verify"
138 static struct help helptab[] = {
139 { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, },
140 { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, },
141 { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, },
142 { CMD_COMMIT, "commit", 0, SHELP_COMMIT, },
143 { CMD_CREATE, "create", 0, SHELP_CREATE, },
144 { CMD_DELETE, "delete", 0, SHELP_DELETE, },
145 { CMD_END, "end", 0, SHELP_END, },
146 { CMD_EXIT, "exit", 0, SHELP_EXIT, },
147 { CMD_EXPORT, "export", 0, SHELP_EXPORT, },
148 { CMD_HELP, "help", 0, SHELP_HELP },
149 { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, },
150 { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, },
151 { CMD_REVERT, "revert", 0, SHELP_REVERT, },
152 { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, },
153 { CMD_SET, "set", HELP_PROPS, SHELP_SET, },
154 { CMD_VERIFY, "verify", 0, SHELP_VERIFY, },
155 { 0 },
158 #define MAX_RT_STRLEN 16
160 /* These *must* match the order of the RT_ define's from zonecfg.h */
161 char *res_types[] = {
162 "unknown",
163 "zonename",
164 "zonepath",
165 "autoboot",
166 "pool",
167 "fs",
168 "net",
169 "device",
170 "rctl",
171 "attr",
172 "dataset",
173 "limitpriv",
174 "bootargs",
175 "brand",
176 "dedicated-cpu",
177 "capped-memory",
178 ALIAS_MAXLWPS,
179 ALIAS_MAXSHMMEM,
180 ALIAS_MAXSHMIDS,
181 ALIAS_MAXMSGIDS,
182 ALIAS_MAXSEMIDS,
183 ALIAS_SHARES,
184 "scheduling-class",
185 "ip-type",
186 "capped-cpu",
187 "hostid",
188 "admin",
189 "fs-allowed",
190 ALIAS_MAXPROCS,
191 "security-flags",
192 NULL
195 /* These *must* match the order of the PT_ define's from zonecfg.h */
196 char *prop_types[] = {
197 "unknown",
198 "zonename",
199 "zonepath",
200 "autoboot",
201 "pool",
202 "dir",
203 "special",
204 "type",
205 "options",
206 "address",
207 "physical",
208 "name",
209 "value",
210 "match",
211 "priv",
212 "limit",
213 "action",
214 "raw",
215 "limitpriv",
216 "bootargs",
217 "brand",
218 "ncpus",
219 "importance",
220 "swap",
221 "locked",
222 ALIAS_SHARES,
223 ALIAS_MAXLWPS,
224 ALIAS_MAXSHMMEM,
225 ALIAS_MAXSHMIDS,
226 ALIAS_MAXMSGIDS,
227 ALIAS_MAXSEMIDS,
228 ALIAS_MAXLOCKEDMEM,
229 ALIAS_MAXSWAP,
230 "scheduling-class",
231 "ip-type",
232 "defrouter",
233 "hostid",
234 "user",
235 "auths",
236 "fs-allowed",
237 ALIAS_MAXPROCS,
238 "allowed-address",
239 "default",
240 "lower",
241 "upper",
242 NULL
245 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
246 static char *prop_val_types[] = {
247 "simple",
248 "complex",
249 "list",
253 * The various _cmds[] lists below are for command tab-completion.
257 * remove has a space afterwards because it has qualifiers; the other commands
258 * that have qualifiers (add, select, etc.) don't need a space here because
259 * they have their own _cmds[] lists below.
261 static const char *global_scope_cmds[] = {
262 "add",
263 "clear",
264 "commit",
265 "create",
266 "delete",
267 "exit",
268 "export",
269 "help",
270 "info",
271 "remove ",
272 "revert",
273 "select",
274 "set",
275 "verify",
276 NULL
279 static const char *add_cmds[] = {
280 "add fs",
281 "add net",
282 "add device",
283 "add rctl",
284 "add attr",
285 "add dataset",
286 "add dedicated-cpu",
287 "add capped-cpu",
288 "add capped-memory",
289 "add admin",
290 "add security-flags",
291 NULL
294 static const char *clear_cmds[] = {
295 "clear autoboot",
296 "clear pool",
297 "clear limitpriv",
298 "clear bootargs",
299 "clear scheduling-class",
300 "clear ip-type",
301 "clear " ALIAS_MAXLWPS,
302 "clear " ALIAS_MAXSHMMEM,
303 "clear " ALIAS_MAXSHMIDS,
304 "clear " ALIAS_MAXMSGIDS,
305 "clear " ALIAS_MAXSEMIDS,
306 "clear " ALIAS_SHARES,
307 "clear " ALIAS_MAXPROCS,
308 NULL
311 static const char *remove_cmds[] = {
312 "remove fs ",
313 "remove net ",
314 "remove device ",
315 "remove rctl ",
316 "remove attr ",
317 "remove dataset ",
318 "remove dedicated-cpu ",
319 "remove capped-cpu ",
320 "remove capped-memory ",
321 "remove admin ",
322 "remove security-flags",
323 NULL
326 static const char *select_cmds[] = {
327 "select fs ",
328 "select net ",
329 "select device ",
330 "select rctl ",
331 "select attr ",
332 "select dataset ",
333 "select dedicated-cpu",
334 "select capped-cpu",
335 "select capped-memory",
336 "select admin",
337 "select security-flags",
338 NULL
341 static const char *set_cmds[] = {
342 "set zonename=",
343 "set zonepath=",
344 "set brand=",
345 "set autoboot=",
346 "set pool=",
347 "set limitpriv=",
348 "set bootargs=",
349 "set scheduling-class=",
350 "set ip-type=",
351 "set " ALIAS_MAXLWPS "=",
352 "set " ALIAS_MAXSHMMEM "=",
353 "set " ALIAS_MAXSHMIDS "=",
354 "set " ALIAS_MAXMSGIDS "=",
355 "set " ALIAS_MAXSEMIDS "=",
356 "set " ALIAS_SHARES "=",
357 "set hostid=",
358 "set fs-allowed=",
359 "set " ALIAS_MAXPROCS "=",
360 NULL
363 static const char *info_cmds[] = {
364 "info fs ",
365 "info net ",
366 "info device ",
367 "info rctl ",
368 "info attr ",
369 "info dataset ",
370 "info capped-memory",
371 "info dedicated-cpu",
372 "info capped-cpu",
373 "info security-flags",
374 "info zonename",
375 "info zonepath",
376 "info autoboot",
377 "info pool",
378 "info limitpriv",
379 "info bootargs",
380 "info brand",
381 "info scheduling-class",
382 "info ip-type",
383 "info max-lwps",
384 "info max-shm-memory",
385 "info max-shm-ids",
386 "info max-msg-ids",
387 "info max-sem-ids",
388 "info cpu-shares",
389 "info hostid",
390 "info admin",
391 "info fs-allowed",
392 "info max-processes",
393 NULL
396 static const char *fs_res_scope_cmds[] = {
397 "add options ",
398 "cancel",
399 "end",
400 "exit",
401 "help",
402 "info",
403 "remove options ",
404 "set dir=",
405 "set raw=",
406 "set special=",
407 "set type=",
408 "clear raw",
409 NULL
412 static const char *net_res_scope_cmds[] = {
413 "cancel",
414 "end",
415 "exit",
416 "help",
417 "info",
418 "set address=",
419 "set physical=",
420 "set defrouter=",
421 NULL
424 static const char *device_res_scope_cmds[] = {
425 "cancel",
426 "end",
427 "exit",
428 "help",
429 "info",
430 "set match=",
431 NULL
434 static const char *attr_res_scope_cmds[] = {
435 "cancel",
436 "end",
437 "exit",
438 "help",
439 "info",
440 "set name=",
441 "set type=",
442 "set value=",
443 NULL
446 static const char *rctl_res_scope_cmds[] = {
447 "add value ",
448 "cancel",
449 "end",
450 "exit",
451 "help",
452 "info",
453 "remove value ",
454 "set name=",
455 NULL
458 static const char *dataset_res_scope_cmds[] = {
459 "cancel",
460 "end",
461 "exit",
462 "help",
463 "info",
464 "set name=",
465 NULL
468 static const char *pset_res_scope_cmds[] = {
469 "cancel",
470 "end",
471 "exit",
472 "help",
473 "info",
474 "set ncpus=",
475 "set importance=",
476 "clear importance",
477 NULL
480 static const char *pcap_res_scope_cmds[] = {
481 "cancel",
482 "end",
483 "exit",
484 "help",
485 "info",
486 "set ncpus=",
487 NULL
490 static const char *mcap_res_scope_cmds[] = {
491 "cancel",
492 "end",
493 "exit",
494 "help",
495 "info",
496 "set physical=",
497 "set swap=",
498 "set locked=",
499 "clear physical",
500 "clear swap",
501 "clear locked",
502 NULL
505 static const char *admin_res_scope_cmds[] = {
506 "cancel",
507 "end",
508 "exit",
509 "help",
510 "info",
511 "set user=",
512 "set auths=",
513 NULL
516 static const char *secflags_res_scope_cmds[] = {
517 "cancel",
518 "end",
519 "exit",
520 "set default=",
521 "set lower=",
522 "set upper=",
523 NULL
526 struct xif {
527 struct xif *xif_next;
528 char xif_name[LIFNAMSIZ];
529 boolean_t xif_has_address;
530 boolean_t xif_has_defrouter;
533 /* Global variables */
535 /* list of network interfaces specified for exclusive IP zone */
536 struct xif *xif;
538 /* set early in main(), never modified thereafter, used all over the place */
539 static char *execname;
541 /* set in main(), used all over the place */
542 static zone_dochandle_t handle;
544 /* used all over the place */
545 static char zone[ZONENAME_MAX];
546 static char revert_zone[ZONENAME_MAX];
548 /* global brand operations */
549 static brand_handle_t brand;
551 /* set in modifying functions, checked in read_input() */
552 static boolean_t need_to_commit = B_FALSE;
553 boolean_t saw_error;
555 /* set in yacc parser, checked in read_input() */
556 boolean_t newline_terminated;
558 /* set in main(), checked in lex error handler */
559 boolean_t cmd_file_mode;
561 /* set in exit_func(), checked in read_input() */
562 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
564 /* used in short_usage() and zerr() */
565 static char *cmd_file_name = NULL;
567 /* checked in read_input() and other places */
568 static boolean_t ok_to_prompt = B_FALSE;
570 /* set and checked in initialize() */
571 static boolean_t got_handle = B_FALSE;
573 /* initialized in do_interactive(), checked in initialize() */
574 static boolean_t interactive_mode;
576 /* set if configuring the global zone */
577 static boolean_t global_zone = B_FALSE;
579 /* set in main(), checked in multiple places */
580 static boolean_t read_only_mode;
582 /* scope is outer/global or inner/resource */
583 static boolean_t global_scope = B_TRUE;
584 static int resource_scope; /* should be in the RT_ list from zonecfg.h */
585 static int end_op = -1; /* operation on end is either add or modify */
587 int num_prop_vals; /* for grammar */
590 * These are for keeping track of resources as they are specified as part of
591 * the multi-step process. They should be initialized by add_resource() or
592 * select_func() and filled in by add_property() or set_func().
594 static struct zone_fstab old_fstab, in_progress_fstab;
595 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab;
596 static struct zone_devtab old_devtab, in_progress_devtab;
597 static struct zone_rctltab old_rctltab, in_progress_rctltab;
598 static struct zone_attrtab old_attrtab, in_progress_attrtab;
599 static struct zone_dstab old_dstab, in_progress_dstab;
600 static struct zone_psettab old_psettab, in_progress_psettab;
601 static struct zone_mcaptab old_mcaptab, in_progress_mcaptab;
602 static struct zone_admintab old_admintab, in_progress_admintab;
603 static struct zone_secflagstab old_secflagstab, in_progress_secflagstab;
605 static GetLine *gl; /* The gl_get_line() resource object */
607 static void bytes_to_units(char *str, char *buf, int bufsize);
609 /* Functions begin here */
611 static boolean_t
612 initial_match(const char *line1, const char *line2, int word_end)
614 if (word_end <= 0)
615 return (B_TRUE);
616 return (strncmp(line1, line2, word_end) == 0);
619 static int
620 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
621 int word_end)
623 int i, err;
625 for (i = 0; list[i] != NULL; i++) {
626 if (initial_match(line1, list[i], word_end)) {
627 err = cpl_add_completion(cpl, line1, 0, word_end,
628 list[i] + word_end, "", "");
629 if (err != 0)
630 return (err);
633 return (0);
636 static
637 /* ARGSUSED */
638 CPL_MATCH_FN(cmd_cpl_fn)
640 if (global_scope) {
642 * The MAX/MIN tests below are to make sure we have at least
643 * enough characters to distinguish from other prefixes (MAX)
644 * but only check MIN(what we have, what we're checking).
646 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
647 return (add_stuff(cpl, line, add_cmds, word_end));
648 if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
649 return (add_stuff(cpl, line, clear_cmds, word_end));
650 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
651 return (add_stuff(cpl, line, select_cmds, word_end));
652 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
653 return (add_stuff(cpl, line, set_cmds, word_end));
654 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
655 return (add_stuff(cpl, line, remove_cmds, word_end));
656 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
657 return (add_stuff(cpl, line, info_cmds, word_end));
658 return (add_stuff(cpl, line, global_scope_cmds, word_end));
660 switch (resource_scope) {
661 case RT_FS:
662 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
663 case RT_NET:
664 return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
665 case RT_DEVICE:
666 return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
667 case RT_RCTL:
668 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
669 case RT_ATTR:
670 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
671 case RT_DATASET:
672 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
673 case RT_DCPU:
674 return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
675 case RT_PCAP:
676 return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
677 case RT_MCAP:
678 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
679 case RT_ADMIN:
680 return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
681 case RT_SECFLAGS:
682 return (add_stuff(cpl, line, secflags_res_scope_cmds,
683 word_end));
686 return (0);
690 * For the main CMD_func() functions below, several of them call getopt()
691 * then check optind against argc to make sure an extra parameter was not
692 * passed in. The reason this is not caught in the grammar is that the
693 * grammar just checks for a miscellaneous TOKEN, which is *expected* to
694 * be "-F" (for example), but could be anything. So (for example) this
695 * check will prevent "create bogus".
698 cmd_t *
699 alloc_cmd(void)
701 return (calloc(1, sizeof (cmd_t)));
704 void
705 free_cmd(cmd_t *cmd)
707 int i;
709 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
710 if (cmd->cmd_property_ptr[i] != NULL) {
711 property_value_ptr_t pp = cmd->cmd_property_ptr[i];
713 switch (pp->pv_type) {
714 case PROP_VAL_SIMPLE:
715 free(pp->pv_simple);
716 break;
717 case PROP_VAL_COMPLEX:
718 free_complex(pp->pv_complex);
719 break;
720 case PROP_VAL_LIST:
721 free_list(pp->pv_list);
722 break;
725 for (i = 0; i < cmd->cmd_argc; i++)
726 free(cmd->cmd_argv[i]);
727 free(cmd);
730 complex_property_ptr_t
731 alloc_complex(void)
733 return (calloc(1, sizeof (complex_property_t)));
736 void
737 free_complex(complex_property_ptr_t complex)
739 if (complex == NULL)
740 return;
741 free_complex(complex->cp_next);
742 free(complex->cp_value);
743 free(complex);
746 list_property_ptr_t
747 alloc_list(void)
749 return (calloc(1, sizeof (list_property_t)));
752 void
753 free_list(list_property_ptr_t list)
755 if (list == NULL)
756 return;
757 free(list->lp_simple);
758 free_complex(list->lp_complex);
759 free_list(list->lp_next);
760 free(list);
763 void
764 free_outer_list(list_property_ptr_t list)
766 if (list == NULL)
767 return;
768 free_outer_list(list->lp_next);
769 free(list);
772 static struct zone_rctlvaltab *
773 alloc_rctlvaltab(void)
775 return (calloc(1, sizeof (struct zone_rctlvaltab)));
778 static char *
779 rt_to_str(int res_type)
781 assert(res_type >= RT_MIN && res_type <= RT_MAX);
782 return (res_types[res_type]);
785 static char *
786 pt_to_str(int prop_type)
788 assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
789 return (prop_types[prop_type]);
792 static char *
793 pvt_to_str(int pv_type)
795 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
796 return (prop_val_types[pv_type]);
799 static char *
800 cmd_to_str(int cmd_num)
802 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
803 return (helptab[cmd_num].cmd_name);
806 /* PRINTFLIKE1 */
807 static void
808 zerr(const char *fmt, ...)
810 va_list alist;
811 static int last_lineno;
813 /* lex_lineno has already been incremented in the lexer; compensate */
814 if (cmd_file_mode && lex_lineno > last_lineno) {
815 if (strcmp(cmd_file_name, "-") == 0)
816 (void) fprintf(stderr, gettext("On line %d:\n"),
817 lex_lineno - 1);
818 else
819 (void) fprintf(stderr, gettext("On line %d of %s:\n"),
820 lex_lineno - 1, cmd_file_name);
821 last_lineno = lex_lineno;
823 va_start(alist, fmt);
824 (void) vfprintf(stderr, fmt, alist);
825 (void) fprintf(stderr, "\n");
826 va_end(alist);
830 * This is a separate function rather than a set of define's because of the
831 * gettext() wrapping.
835 * TRANSLATION_NOTE
836 * Each string below should have \t follow \n whenever needed; the
837 * initial \t and the terminal \n will be provided by the calling function.
840 static char *
841 long_help(int cmd_num)
843 static char line[1024]; /* arbitrary large amount */
845 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
846 switch (cmd_num) {
847 case CMD_HELP:
848 return (gettext("Prints help message."));
849 case CMD_CREATE:
850 (void) snprintf(line, sizeof (line),
851 gettext("Creates a configuration for the "
852 "specified zone. %s should be\n\tused to "
853 "begin configuring a new zone. If overwriting an "
854 "existing\n\tconfiguration, the -F flag can be "
855 "used to force the action. If\n\t-t template is "
856 "given, creates a configuration identical to the\n"
857 "\tspecified template, except that the zone name "
858 "is changed from\n\ttemplate to zonename. '%s -a' "
859 "creates a configuration from a\n\tdetached "
860 "zonepath. '%s -b' results in a blank "
861 "configuration.\n\t'%s' with no arguments applies "
862 "the Sun default settings."),
863 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
864 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
865 return (line);
866 case CMD_EXIT:
867 return (gettext("Exits the program. The -F flag can "
868 "be used to force the action."));
869 case CMD_EXPORT:
870 return (gettext("Prints configuration to standard "
871 "output, or to output-file if\n\tspecified, in "
872 "a form suitable for use in a command-file."));
873 case CMD_ADD:
874 return (gettext("Add specified resource to "
875 "configuration."));
876 case CMD_DELETE:
877 return (gettext("Deletes the specified zone. The -F "
878 "flag can be used to force the\n\taction."));
879 case CMD_REMOVE:
880 return (gettext("Remove specified resource from "
881 "configuration. The -F flag can be used\n\tto "
882 "force the action."));
883 case CMD_SELECT:
884 (void) snprintf(line, sizeof (line),
885 gettext("Selects a resource to modify. "
886 "Resource modification is completed\n\twith the "
887 "command \"%s\". The property name/value pairs "
888 "must uniquely\n\tidentify a resource. Note that "
889 "the curly braces ('{', '}') mean one\n\tor more "
890 "of whatever is between them."),
891 cmd_to_str(CMD_END));
892 return (line);
893 case CMD_SET:
894 return (gettext("Sets property values."));
895 case CMD_CLEAR:
896 return (gettext("Clears property values."));
897 case CMD_INFO:
898 return (gettext("Displays information about the "
899 "current configuration. If resource\n\ttype is "
900 "specified, displays only information about "
901 "resources of\n\tthe relevant type. If resource "
902 "id is specified, displays only\n\tinformation "
903 "about that resource."));
904 case CMD_VERIFY:
905 return (gettext("Verifies current configuration "
906 "for correctness (some resource types\n\thave "
907 "required properties)."));
908 case CMD_COMMIT:
909 (void) snprintf(line, sizeof (line),
910 gettext("Commits current configuration. "
911 "Configuration must be committed to\n\tbe used by "
912 "%s. Until the configuration is committed, "
913 "changes \n\tcan be removed with the %s "
914 "command. This operation is\n\tattempted "
915 "automatically upon completion of a %s "
916 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
917 "zonecfg");
918 return (line);
919 case CMD_REVERT:
920 return (gettext("Reverts configuration back to the "
921 "last committed state. The -F flag\n\tcan be "
922 "used to force the action."));
923 case CMD_CANCEL:
924 return (gettext("Cancels resource/property "
925 "specification."));
926 case CMD_END:
927 return (gettext("Ends resource/property "
928 "specification."));
930 /* NOTREACHED */
931 return (NULL);
935 * Return the input filename appended to each component of the path
936 * or the filename itself if it is absolute.
937 * Parameters: path string, file name, output string.
939 static const char *
940 exec_cat(const char *s1, const char *s2, char *si)
942 char *s;
943 /* Number of remaining characters in s */
944 int cnt = PATH_MAX + 1;
946 s = si;
947 while (*s1 && *s1 != ':') { /* Copy first component of path to si */
948 if (cnt > 0) {
949 *s++ = *s1++;
950 cnt--;
951 } else {
952 s1++;
955 if (si != s && cnt > 0) { /* Add slash if s2 is not absolute */
956 *s++ = '/';
957 cnt--;
959 while (*s2 && cnt > 0) { /* Copy s2 to si */
960 *s++ = *s2++;
961 cnt--;
963 *s = '\0'; /* Terminate the output string */
964 return (*s1 ? ++s1 : NULL); /* Return next path component or NULL */
967 /* Determine that a name exists in PATH */
968 static int
969 path_find(const char *name)
971 const char *pathstr;
972 char fname[PATH_MAX + 2];
973 const char *cp;
974 struct stat stat_buf;
976 if ((pathstr = getenv("PATH")) == NULL) {
977 if (geteuid() == 0 || getuid() == 0)
978 pathstr = "/usr/sbin:/usr/bin";
979 else
980 pathstr = "/usr/bin:";
982 cp = strchr(name, '/') ? (const char *) "" : pathstr;
984 do {
985 cp = exec_cat(cp, name, fname);
986 if (stat(fname, &stat_buf) != -1) {
987 /* successful find of the file */
988 return (0);
990 } while (cp != NULL);
992 return (-1);
995 static FILE *
996 pager_open(void)
998 FILE *newfp;
999 char *pager, *space;
1001 pager = getenv("PAGER");
1002 if (pager == NULL || *pager == '\0')
1003 pager = PAGER;
1005 space = strchr(pager, ' ');
1006 if (space)
1007 *space = '\0';
1008 if (path_find(pager) == 0) {
1009 if (space)
1010 *space = ' ';
1011 if ((newfp = popen(pager, "w")) == NULL)
1012 zerr(gettext("PAGER open failed (%s)."),
1013 strerror(errno));
1014 return (newfp);
1015 } else {
1016 zerr(gettext("PAGER %s does not exist (%s)."),
1017 pager, strerror(errno));
1019 return (NULL);
1022 static void
1023 pager_close(FILE *fp)
1025 int status;
1027 status = pclose(fp);
1028 if (status == -1)
1029 zerr(gettext("PAGER close failed (%s)."),
1030 strerror(errno));
1034 * Called with verbose TRUE when help is explicitly requested, FALSE for
1035 * unexpected errors.
1038 void
1039 usage(boolean_t verbose, uint_t flags)
1041 FILE *fp = verbose ? stdout : stderr;
1042 FILE *newfp;
1043 boolean_t need_to_close = B_FALSE;
1044 int i;
1046 /* don't page error output */
1047 if (verbose && interactive_mode) {
1048 if ((newfp = pager_open()) != NULL) {
1049 need_to_close = B_TRUE;
1050 fp = newfp;
1054 if (flags & HELP_META) {
1055 (void) fprintf(fp, gettext("More help is available for the "
1056 "following:\n"));
1057 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1058 cmd_to_str(CMD_HELP));
1059 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1060 cmd_to_str(CMD_HELP));
1061 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1062 cmd_to_str(CMD_HELP));
1063 (void) fprintf(fp, gettext("You may also obtain help on any "
1064 "command by typing '%s <command-name>.'\n"),
1065 cmd_to_str(CMD_HELP));
1067 if (flags & HELP_RES_SCOPE) {
1068 switch (resource_scope) {
1069 case RT_FS:
1070 (void) fprintf(fp, gettext("The '%s' resource scope is "
1071 "used to configure a file-system.\n"),
1072 rt_to_str(resource_scope));
1073 (void) fprintf(fp, gettext("Valid commands:\n"));
1074 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1075 pt_to_str(PT_DIR), gettext("<path>"));
1076 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1077 pt_to_str(PT_SPECIAL), gettext("<path>"));
1078 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1079 pt_to_str(PT_RAW), gettext("<raw-device>"));
1080 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1081 pt_to_str(PT_TYPE), gettext("<file-system type>"));
1082 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
1083 pt_to_str(PT_OPTIONS),
1084 gettext("<file-system options>"));
1085 (void) fprintf(fp, "\t%s %s %s\n",
1086 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
1087 gettext("<file-system options>"));
1088 (void) fprintf(fp, gettext("Consult the file-system "
1089 "specific manual page, such as mount_ufs(1M), "
1090 "for\ndetails about file-system options. Note "
1091 "that any file-system options with an\nembedded "
1092 "'=' character must be enclosed in double quotes, "
1093 /*CSTYLED*/
1094 "such as \"%s=5\".\n"), MNTOPT_RETRY);
1095 break;
1096 case RT_NET:
1097 (void) fprintf(fp, gettext("The '%s' resource scope is "
1098 "used to configure a network interface.\n"),
1099 rt_to_str(resource_scope));
1100 (void) fprintf(fp, gettext("Valid commands:\n"));
1101 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1102 pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
1103 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1104 pt_to_str(PT_ALLOWED_ADDRESS),
1105 gettext("<IP-address>"));
1106 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1107 pt_to_str(PT_PHYSICAL), gettext("<interface>"));
1108 (void) fprintf(fp, gettext("See ifconfig(1M) for "
1109 "details of the <interface> string.\n"));
1110 (void) fprintf(fp, gettext("%s %s is valid "
1111 "if the %s property is set to %s, otherwise it "
1112 "must not be set.\n"),
1113 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
1114 pt_to_str(PT_IPTYPE), gettext("shared"));
1115 (void) fprintf(fp, gettext("%s %s is valid "
1116 "if the %s property is set to %s, otherwise it "
1117 "must not be set.\n"),
1118 cmd_to_str(CMD_SET), pt_to_str(PT_ALLOWED_ADDRESS),
1119 pt_to_str(PT_IPTYPE), gettext("exclusive"));
1120 (void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
1121 "is valid if the %s or %s property is set, "
1122 "otherwise it must not be set\n"),
1123 cmd_to_str(CMD_SET),
1124 pt_to_str(PT_DEFROUTER), gettext("<IP-address>"),
1125 cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
1126 gettext(pt_to_str(PT_ADDRESS)),
1127 gettext(pt_to_str(PT_ALLOWED_ADDRESS)));
1128 break;
1129 case RT_DEVICE:
1130 (void) fprintf(fp, gettext("The '%s' resource scope is "
1131 "used to configure a device node.\n"),
1132 rt_to_str(resource_scope));
1133 (void) fprintf(fp, gettext("Valid commands:\n"));
1134 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1135 pt_to_str(PT_MATCH), gettext("<device-path>"));
1136 break;
1137 case RT_RCTL:
1138 (void) fprintf(fp, gettext("The '%s' resource scope is "
1139 "used to configure a resource control.\n"),
1140 rt_to_str(resource_scope));
1141 (void) fprintf(fp, gettext("Valid commands:\n"));
1142 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1143 pt_to_str(PT_NAME), gettext("<string>"));
1144 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1145 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1146 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1147 pt_to_str(PT_LIMIT), gettext("<number>"),
1148 pt_to_str(PT_ACTION), gettext("<action-value>"));
1149 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1150 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
1151 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1152 pt_to_str(PT_LIMIT), gettext("<number>"),
1153 pt_to_str(PT_ACTION), gettext("<action-value>"));
1154 (void) fprintf(fp, "%s\n\t%s := privileged\n"
1155 "\t%s := none | deny\n", gettext("Where"),
1156 gettext("<priv-value>"), gettext("<action-value>"));
1157 break;
1158 case RT_ATTR:
1159 (void) fprintf(fp, gettext("The '%s' resource scope is "
1160 "used to configure a generic attribute.\n"),
1161 rt_to_str(resource_scope));
1162 (void) fprintf(fp, gettext("Valid commands:\n"));
1163 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1164 pt_to_str(PT_NAME), gettext("<name>"));
1165 (void) fprintf(fp, "\t%s %s=boolean\n",
1166 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1167 (void) fprintf(fp, "\t%s %s=true | false\n",
1168 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
1169 (void) fprintf(fp, gettext("or\n"));
1170 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
1171 pt_to_str(PT_TYPE));
1172 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1173 pt_to_str(PT_VALUE), gettext("<integer>"));
1174 (void) fprintf(fp, gettext("or\n"));
1175 (void) fprintf(fp, "\t%s %s=string\n",
1176 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1177 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1178 pt_to_str(PT_VALUE), gettext("<string>"));
1179 (void) fprintf(fp, gettext("or\n"));
1180 (void) fprintf(fp, "\t%s %s=uint\n",
1181 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1182 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1183 pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
1184 break;
1185 case RT_DATASET:
1186 (void) fprintf(fp, gettext("The '%s' resource scope is "
1187 "used to export ZFS datasets.\n"),
1188 rt_to_str(resource_scope));
1189 (void) fprintf(fp, gettext("Valid commands:\n"));
1190 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1191 pt_to_str(PT_NAME), gettext("<name>"));
1192 break;
1193 case RT_DCPU:
1194 (void) fprintf(fp, gettext("The '%s' resource scope "
1195 "configures the 'pools' facility to dedicate\na "
1196 "subset of the system's processors to this zone "
1197 "while it is running.\n"),
1198 rt_to_str(resource_scope));
1199 (void) fprintf(fp, gettext("Valid commands:\n"));
1200 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1201 pt_to_str(PT_NCPUS),
1202 gettext("<unsigned integer | range>"));
1203 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1204 pt_to_str(PT_IMPORTANCE),
1205 gettext("<unsigned integer>"));
1206 break;
1207 case RT_PCAP:
1208 (void) fprintf(fp, gettext("The '%s' resource scope is "
1209 "used to set an upper limit (a cap) on the\n"
1210 "percentage of CPU that can be used by this zone. "
1211 "A '%s' value of 1\ncorresponds to one cpu. The "
1212 "value can be set higher than 1, up to the total\n"
1213 "number of CPUs on the system. The value can "
1214 "also be less than 1,\nrepresenting a fraction of "
1215 "a cpu.\n"),
1216 rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
1217 (void) fprintf(fp, gettext("Valid commands:\n"));
1218 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1219 pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
1220 break;
1221 case RT_MCAP:
1222 (void) fprintf(fp, gettext("The '%s' resource scope is "
1223 "used to set an upper limit (a cap) on the\n"
1224 "amount of physical memory, swap space and locked "
1225 "memory that can be used by\nthis zone.\n"),
1226 rt_to_str(resource_scope));
1227 (void) fprintf(fp, gettext("Valid commands:\n"));
1228 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1229 pt_to_str(PT_PHYSICAL),
1230 gettext("<qualified unsigned decimal>"));
1231 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1232 pt_to_str(PT_SWAP),
1233 gettext("<qualified unsigned decimal>"));
1234 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1235 pt_to_str(PT_LOCKED),
1236 gettext("<qualified unsigned decimal>"));
1237 break;
1238 case RT_ADMIN:
1239 (void) fprintf(fp, gettext("The '%s' resource scope is "
1240 "used to delegate specific zone management\n"
1241 "rights to users and roles. These rights are "
1242 "only applicable to this zone.\n"),
1243 rt_to_str(resource_scope));
1244 (void) fprintf(fp, gettext("Valid commands:\n"));
1245 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1246 pt_to_str(PT_USER),
1247 gettext("<single user or role name>"));
1248 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1249 pt_to_str(PT_AUTHS),
1250 gettext("<comma separated list>"));
1251 break;
1252 case RT_SECFLAGS:
1253 (void) fprintf(fp, gettext("The '%s' resource scope is "
1254 "used to specify the default security-flags\n"
1255 "of this zone, and their upper and lower bound.\n"),
1256 rt_to_str(resource_scope));
1257 (void) fprintf(fp, "\t%s %s=%s\n",
1258 cmd_to_str(CMD_SET), pt_to_str(PT_DEFAULT),
1259 gettext("<security flags>"));
1260 (void) fprintf(fp, "\t%s %s=%s\n",
1261 cmd_to_str(CMD_SET), pt_to_str(PT_LOWER),
1262 gettext("<security flags>"));
1263 (void) fprintf(fp, "\t%s %s=%s\n",
1264 cmd_to_str(CMD_SET), pt_to_str(PT_UPPER),
1265 gettext("<security flags>"));
1266 break;
1268 (void) fprintf(fp, gettext("And from any resource scope, you "
1269 "can:\n"));
1270 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
1271 gettext("(to conclude this operation)"));
1272 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
1273 gettext("(to cancel this operation)"));
1274 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
1275 gettext("(to exit the zonecfg utility)"));
1277 if (flags & HELP_USAGE) {
1278 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
1279 execname, cmd_to_str(CMD_HELP));
1280 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
1281 execname, gettext("interactive"));
1282 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
1283 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
1284 execname);
1286 if (flags & HELP_SUBCMDS) {
1287 (void) fprintf(fp, "%s:\n\n", gettext("Commands"));
1288 for (i = 0; i <= CMD_MAX; i++) {
1289 (void) fprintf(fp, "%s\n", helptab[i].short_usage);
1290 if (verbose)
1291 (void) fprintf(fp, "\t%s\n\n", long_help(i));
1294 if (flags & HELP_SYNTAX) {
1295 if (!verbose)
1296 (void) fprintf(fp, "\n");
1297 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
1298 (void) fprintf(fp, gettext("\t(except the reserved words "
1299 "'%s' and anything starting with '%s')\n"), "global",
1300 "SUNW");
1301 (void) fprintf(fp,
1302 gettext("\tName must be less than %d characters.\n"),
1303 ZONENAME_MAX);
1304 if (verbose)
1305 (void) fprintf(fp, "\n");
1307 if (flags & HELP_NETADDR) {
1308 (void) fprintf(fp, gettext("\n<net-addr> :="));
1309 (void) fprintf(fp,
1310 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
1311 (void) fprintf(fp,
1312 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
1313 (void) fprintf(fp,
1314 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
1315 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
1316 "IPv6 address syntax.\n"));
1317 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
1318 (void) fprintf(fp,
1319 gettext("<IPv6-prefix-length> := [0-128]\n"));
1320 (void) fprintf(fp,
1321 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
1323 if (flags & HELP_RESOURCES) {
1324 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s |\n\t"
1325 "%s | %s | %s | %s | %s\n\n",
1326 gettext("resource type"), rt_to_str(RT_FS),
1327 rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
1328 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
1329 rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
1330 rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
1331 rt_to_str(RT_ADMIN), rt_to_str(RT_SECFLAGS));
1333 if (flags & HELP_PROPS) {
1334 (void) fprintf(fp, gettext("For resource type ... there are "
1335 "property types ...:\n"));
1336 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1337 pt_to_str(PT_ZONENAME));
1338 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1339 pt_to_str(PT_ZONEPATH));
1340 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1341 pt_to_str(PT_BRAND));
1342 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1343 pt_to_str(PT_AUTOBOOT));
1344 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1345 pt_to_str(PT_BOOTARGS));
1346 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1347 pt_to_str(PT_POOL));
1348 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1349 pt_to_str(PT_LIMITPRIV));
1350 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1351 pt_to_str(PT_SCHED));
1352 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1353 pt_to_str(PT_IPTYPE));
1354 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1355 pt_to_str(PT_HOSTID));
1356 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1357 pt_to_str(PT_FS_ALLOWED));
1358 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1359 pt_to_str(PT_MAXLWPS));
1360 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1361 pt_to_str(PT_MAXPROCS));
1362 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1363 pt_to_str(PT_MAXSHMMEM));
1364 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1365 pt_to_str(PT_MAXSHMIDS));
1366 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1367 pt_to_str(PT_MAXMSGIDS));
1368 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1369 pt_to_str(PT_MAXSEMIDS));
1370 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1371 pt_to_str(PT_SHARES));
1372 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
1373 rt_to_str(RT_FS), pt_to_str(PT_DIR),
1374 pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
1375 pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
1376 (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
1377 pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
1378 pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
1379 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1380 pt_to_str(PT_MATCH));
1381 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1382 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1383 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1384 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1385 pt_to_str(PT_VALUE));
1386 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1387 pt_to_str(PT_NAME));
1388 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1389 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1390 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1391 pt_to_str(PT_NCPUS));
1392 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1393 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1394 pt_to_str(PT_LOCKED));
1395 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1396 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1397 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n",
1398 rt_to_str(RT_SECFLAGS), pt_to_str(PT_DEFAULT),
1399 pt_to_str(PT_LOWER), pt_to_str(PT_UPPER));
1401 if (need_to_close)
1402 (void) pager_close(fp);
1405 static void
1406 zone_perror(char *prefix, int err, boolean_t set_saw)
1408 zerr("%s: %s", prefix, zonecfg_strerror(err));
1409 if (set_saw)
1410 saw_error = B_TRUE;
1414 * zone_perror() expects a single string, but for remove and select
1415 * we have both the command and the resource type, so this wrapper
1416 * function serves the same purpose in a slightly different way.
1419 static void
1420 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1422 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
1423 zonecfg_strerror(err));
1424 if (set_saw)
1425 saw_error = B_TRUE;
1428 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
1429 static int
1430 initialize(boolean_t handle_expected)
1432 int err;
1433 char brandname[MAXNAMELEN];
1435 if (zonecfg_check_handle(handle) != Z_OK) {
1436 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
1437 got_handle = B_TRUE;
1438 if (zonecfg_get_brand(handle, brandname,
1439 sizeof (brandname)) != Z_OK) {
1440 zerr("Zone %s is inconsistent: missing "
1441 "brand attribute", zone);
1442 exit(Z_ERR);
1444 if ((brand = brand_open(brandname)) == NULL) {
1445 zerr("Zone %s uses non-existent brand \"%s\"."
1446 " Unable to continue", zone, brandname);
1447 exit(Z_ERR);
1450 * If the user_attr file is newer than
1451 * the zone config file, the admins
1452 * may need to be updated since the
1453 * RBAC files are authoritative for
1454 * authorization checks.
1456 err = zonecfg_update_userauths(handle, zone);
1457 if (err == Z_OK) {
1458 zerr(gettext("The administrative rights "
1459 "were updated to match "
1460 "the current RBAC configuration.\n"
1461 "Use \"info admin\" and \"revert\" to "
1462 "compare with the previous settings."));
1463 need_to_commit = B_TRUE;
1464 } else if (err != Z_NO_ENTRY) {
1465 zerr(gettext("failed to update "
1466 "admin rights."));
1467 exit(Z_ERR);
1468 } else if (need_to_commit) {
1469 zerr(gettext("admin rights were updated "
1470 "to match RBAC configuration."));
1473 } else if (global_zone && err == Z_NO_ZONE && !got_handle &&
1474 !read_only_mode) {
1476 * We implicitly create the global zone config if it
1477 * doesn't exist.
1479 zone_dochandle_t tmphandle;
1481 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1482 zone_perror(execname, Z_NOMEM, B_TRUE);
1483 exit(Z_ERR);
1486 err = zonecfg_get_template_handle("SUNWblank", zone,
1487 tmphandle);
1489 if (err != Z_OK) {
1490 zonecfg_fini_handle(tmphandle);
1491 zone_perror("SUNWblank", err, B_TRUE);
1492 return (err);
1495 need_to_commit = B_TRUE;
1496 zonecfg_fini_handle(handle);
1497 handle = tmphandle;
1498 got_handle = B_TRUE;
1500 } else {
1501 zone_perror(zone, err, handle_expected || got_handle);
1502 if (err == Z_NO_ZONE && !got_handle &&
1503 interactive_mode && !read_only_mode)
1504 (void) printf(gettext("Use '%s' to begin "
1505 "configuring a new zone.\n"),
1506 cmd_to_str(CMD_CREATE));
1507 return (err);
1510 return (Z_OK);
1513 static boolean_t
1514 state_atleast(zone_state_t state)
1516 zone_state_t state_num;
1517 int err;
1519 if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
1520 /* all states are greater than "non-existent" */
1521 if (err == Z_NO_ZONE)
1522 return (B_FALSE);
1523 zerr(gettext("Unexpectedly failed to determine state "
1524 "of zone %s: %s"), zone, zonecfg_strerror(err));
1525 exit(Z_ERR);
1527 return (state_num >= state);
1531 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
1534 void
1535 short_usage(int command)
1537 /* lex_lineno has already been incremented in the lexer; compensate */
1538 if (cmd_file_mode) {
1539 if (strcmp(cmd_file_name, "-") == 0)
1540 (void) fprintf(stderr,
1541 gettext("syntax error on line %d\n"),
1542 lex_lineno - 1);
1543 else
1544 (void) fprintf(stderr,
1545 gettext("syntax error on line %d of %s\n"),
1546 lex_lineno - 1, cmd_file_name);
1548 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
1549 helptab[command].short_usage);
1550 saw_error = B_TRUE;
1554 * long_usage() is for bad semantics: e.g., wrong property type for a given
1555 * resource type. It is also used by longer_usage() below.
1558 void
1559 long_usage(uint_t cmd_num, boolean_t set_saw)
1561 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
1562 helptab[cmd_num].short_usage);
1563 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
1564 if (set_saw)
1565 saw_error = B_TRUE;
1569 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
1570 * any extra usage() flags as appropriate for whatever command.
1573 void
1574 longer_usage(uint_t cmd_num)
1576 long_usage(cmd_num, B_FALSE);
1577 if (helptab[cmd_num].flags != 0) {
1578 (void) printf("\n");
1579 usage(B_TRUE, helptab[cmd_num].flags);
1584 * scope_usage() is simply used when a command is called from the wrong scope.
1587 static void
1588 scope_usage(uint_t cmd_num)
1590 zerr(gettext("The %s command only makes sense in the %s scope."),
1591 cmd_to_str(cmd_num),
1592 global_scope ? gettext("resource") : gettext("global"));
1593 saw_error = B_TRUE;
1597 * On input, B_TRUE => yes, B_FALSE => no.
1598 * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
1601 static int
1602 ask_yesno(boolean_t default_answer, const char *question)
1604 char line[64]; /* should be enough to answer yes or no */
1606 if (!ok_to_prompt) {
1607 saw_error = B_TRUE;
1608 return (-1);
1610 for (;;) {
1611 if (printf("%s (%s)? ", question,
1612 default_answer ? "[y]/n" : "y/[n]") < 0)
1613 return (-1);
1614 if (fgets(line, sizeof (line), stdin) == NULL)
1615 return (-1);
1617 if (line[0] == '\n')
1618 return (default_answer ? 1 : 0);
1619 if (tolower(line[0]) == 'y')
1620 return (1);
1621 if (tolower(line[0]) == 'n')
1622 return (0);
1627 * Prints warning if zone already exists.
1628 * In interactive mode, prompts if we should continue anyway and returns Z_OK
1629 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR.
1631 * Note that if a zone exists and its state is >= INSTALLED, an error message
1632 * will be printed and this function will return Z_ERR regardless of mode.
1635 static int
1636 check_if_zone_already_exists(boolean_t force)
1638 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
1639 zone_dochandle_t tmphandle;
1640 int res, answer;
1642 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1643 zone_perror(execname, Z_NOMEM, B_TRUE);
1644 exit(Z_ERR);
1646 res = zonecfg_get_handle(zone, tmphandle);
1647 zonecfg_fini_handle(tmphandle);
1648 if (res != Z_OK)
1649 return (Z_OK);
1651 if (state_atleast(ZONE_STATE_INSTALLED)) {
1652 zerr(gettext("Zone %s already installed; %s not allowed."),
1653 zone, cmd_to_str(CMD_CREATE));
1654 return (Z_ERR);
1657 if (force) {
1658 (void) printf(gettext("Zone %s already exists; overwriting.\n"),
1659 zone);
1660 return (Z_OK);
1662 (void) snprintf(line, sizeof (line),
1663 gettext("Zone %s already exists; %s anyway"), zone,
1664 cmd_to_str(CMD_CREATE));
1665 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
1666 zerr(gettext("Zone exists, input not from terminal and -F not "
1667 "specified:\n%s command ignored, exiting."),
1668 cmd_to_str(CMD_CREATE));
1669 exit(Z_ERR);
1671 return (answer == 1 ? Z_OK : Z_ERR);
1674 static boolean_t
1675 zone_is_read_only(int cmd_num)
1677 if (strncmp(zone, "SUNW", 4) == 0) {
1678 zerr(gettext("%s: zones beginning with SUNW are read-only."),
1679 zone);
1680 saw_error = B_TRUE;
1681 return (B_TRUE);
1683 if (read_only_mode) {
1684 zerr(gettext("%s: cannot %s in read-only mode."), zone,
1685 cmd_to_str(cmd_num));
1686 saw_error = B_TRUE;
1687 return (B_TRUE);
1689 return (B_FALSE);
1693 * Create a new configuration.
1695 void
1696 create_func(cmd_t *cmd)
1698 int err, arg;
1699 char zone_template[ZONENAME_MAX];
1700 char attach_path[MAXPATHLEN];
1701 zone_dochandle_t tmphandle;
1702 boolean_t force = B_FALSE;
1703 boolean_t attach = B_FALSE;
1704 boolean_t arg_err = B_FALSE;
1706 assert(cmd != NULL);
1708 /* This is the default if no arguments are given. */
1709 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
1711 optind = 0;
1712 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
1713 != EOF) {
1714 switch (arg) {
1715 case '?':
1716 if (optopt == '?')
1717 longer_usage(CMD_CREATE);
1718 else
1719 short_usage(CMD_CREATE);
1720 arg_err = B_TRUE;
1721 break;
1722 case 'a':
1723 (void) strlcpy(attach_path, optarg,
1724 sizeof (attach_path));
1725 attach = B_TRUE;
1726 break;
1727 case 'b':
1728 (void) strlcpy(zone_template, "SUNWblank",
1729 sizeof (zone_template));
1730 break;
1731 case 'F':
1732 force = B_TRUE;
1733 break;
1734 case 't':
1735 (void) strlcpy(zone_template, optarg,
1736 sizeof (zone_template));
1737 break;
1738 default:
1739 short_usage(CMD_CREATE);
1740 arg_err = B_TRUE;
1741 break;
1744 if (arg_err)
1745 return;
1747 if (optind != cmd->cmd_argc) {
1748 short_usage(CMD_CREATE);
1749 return;
1752 if (zone_is_read_only(CMD_CREATE))
1753 return;
1755 if (check_if_zone_already_exists(force) != Z_OK)
1756 return;
1759 * Get a temporary handle first. If that fails, the old handle
1760 * will not be lost. Then finish whichever one we don't need,
1761 * to avoid leaks. Then get the handle for zone_template, and
1762 * set the name to zone: this "copy, rename" method is how
1763 * create -[b|t] works.
1765 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1766 zone_perror(execname, Z_NOMEM, B_TRUE);
1767 exit(Z_ERR);
1770 if (attach)
1771 err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
1772 zone, B_FALSE, tmphandle);
1773 else
1774 err = zonecfg_get_template_handle(zone_template, zone,
1775 tmphandle);
1777 if (err != Z_OK) {
1778 zonecfg_fini_handle(tmphandle);
1779 if (attach && err == Z_NO_ZONE)
1780 (void) fprintf(stderr, gettext("invalid path to "
1781 "detached zone\n"));
1782 else if (attach && err == Z_INVALID_DOCUMENT)
1783 (void) fprintf(stderr, gettext("Cannot attach to an "
1784 "earlier release of the operating system\n"));
1785 else
1786 zone_perror(zone_template, err, B_TRUE);
1787 return;
1790 need_to_commit = B_TRUE;
1791 zonecfg_fini_handle(handle);
1792 handle = tmphandle;
1793 got_handle = B_TRUE;
1797 * This malloc()'s memory, which must be freed by the caller.
1799 static char *
1800 quoteit(char *instr)
1802 char *outstr;
1803 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */
1805 if ((outstr = malloc(outstrsize)) == NULL) {
1806 zone_perror(zone, Z_NOMEM, B_FALSE);
1807 exit(Z_ERR);
1809 if (strchr(instr, ' ') == NULL) {
1810 (void) strlcpy(outstr, instr, outstrsize);
1811 return (outstr);
1813 (void) snprintf(outstr, outstrsize, "\"%s\"", instr);
1814 return (outstr);
1817 static void
1818 export_prop(FILE *of, int prop_num, char *prop_id)
1820 char *quote_str;
1822 if (strlen(prop_id) == 0)
1823 return;
1824 quote_str = quoteit(prop_id);
1825 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1826 pt_to_str(prop_num), quote_str);
1827 free(quote_str);
1830 void
1831 export_func(cmd_t *cmd)
1833 struct zone_nwiftab nwiftab;
1834 struct zone_fstab fstab;
1835 struct zone_devtab devtab;
1836 struct zone_attrtab attrtab;
1837 struct zone_rctltab rctltab;
1838 struct zone_dstab dstab;
1839 struct zone_psettab psettab;
1840 struct zone_mcaptab mcaptab;
1841 struct zone_rctlvaltab *valptr;
1842 struct zone_admintab admintab;
1843 struct zone_secflagstab secflagstab;
1844 int err, arg;
1845 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
1846 char bootargs[BOOTARGS_MAX];
1847 char sched[MAXNAMELEN];
1848 char brand[MAXNAMELEN];
1849 char hostidp[HW_HOSTID_LEN];
1850 char fsallowedp[ZONE_FS_ALLOWED_MAX];
1851 char *limitpriv;
1852 FILE *of;
1853 boolean_t autoboot;
1854 zone_iptype_t iptype;
1855 boolean_t need_to_close = B_FALSE;
1856 boolean_t arg_err = B_FALSE;
1858 assert(cmd != NULL);
1860 outfile[0] = '\0';
1861 optind = 0;
1862 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
1863 switch (arg) {
1864 case '?':
1865 if (optopt == '?')
1866 longer_usage(CMD_EXPORT);
1867 else
1868 short_usage(CMD_EXPORT);
1869 arg_err = B_TRUE;
1870 break;
1871 case 'f':
1872 (void) strlcpy(outfile, optarg, sizeof (outfile));
1873 break;
1874 default:
1875 short_usage(CMD_EXPORT);
1876 arg_err = B_TRUE;
1877 break;
1880 if (arg_err)
1881 return;
1883 if (optind != cmd->cmd_argc) {
1884 short_usage(CMD_EXPORT);
1885 return;
1887 if (strlen(outfile) == 0) {
1888 of = stdout;
1889 } else {
1890 if ((of = fopen(outfile, "w")) == NULL) {
1891 zerr(gettext("opening file %s: %s"),
1892 outfile, strerror(errno));
1893 goto done;
1895 setbuf(of, NULL);
1896 need_to_close = B_TRUE;
1899 if ((err = initialize(B_TRUE)) != Z_OK)
1900 goto done;
1902 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
1904 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
1905 strlen(zonepath) > 0)
1906 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1907 pt_to_str(PT_ZONEPATH), zonepath);
1909 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
1910 (strcmp(brand, NATIVE_BRAND_NAME) != 0))
1911 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1912 pt_to_str(PT_BRAND), brand);
1914 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
1915 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1916 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
1918 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
1919 strlen(bootargs) > 0) {
1920 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1921 pt_to_str(PT_BOOTARGS), bootargs);
1924 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
1925 strlen(pool) > 0)
1926 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1927 pt_to_str(PT_POOL), pool);
1929 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
1930 strlen(limitpriv) > 0) {
1931 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1932 pt_to_str(PT_LIMITPRIV), limitpriv);
1933 free(limitpriv);
1936 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
1937 strlen(sched) > 0)
1938 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1939 pt_to_str(PT_SCHED), sched);
1941 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
1942 switch (iptype) {
1943 case ZS_SHARED:
1944 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1945 pt_to_str(PT_IPTYPE), "shared");
1946 break;
1947 case ZS_EXCLUSIVE:
1948 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1949 pt_to_str(PT_IPTYPE), "exclusive");
1950 break;
1954 if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
1955 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1956 pt_to_str(PT_HOSTID), hostidp);
1959 if (zonecfg_get_fs_allowed(handle, fsallowedp,
1960 sizeof (fsallowedp)) == Z_OK) {
1961 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1962 pt_to_str(PT_FS_ALLOWED), fsallowedp);
1965 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
1966 zone_perror(zone, err, B_FALSE);
1967 goto done;
1969 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1970 zone_fsopt_t *optptr;
1972 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1973 rt_to_str(RT_FS));
1974 export_prop(of, PT_DIR, fstab.zone_fs_dir);
1975 export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
1976 export_prop(of, PT_RAW, fstab.zone_fs_raw);
1977 export_prop(of, PT_TYPE, fstab.zone_fs_type);
1978 for (optptr = fstab.zone_fs_options; optptr != NULL;
1979 optptr = optptr->zone_fsopt_next) {
1981 * Simple property values with embedded equal signs
1982 * need to be quoted to prevent the lexer from
1983 * mis-parsing them as complex name=value pairs.
1985 if (strchr(optptr->zone_fsopt_opt, '='))
1986 (void) fprintf(of, "%s %s \"%s\"\n",
1987 cmd_to_str(CMD_ADD),
1988 pt_to_str(PT_OPTIONS),
1989 optptr->zone_fsopt_opt);
1990 else
1991 (void) fprintf(of, "%s %s %s\n",
1992 cmd_to_str(CMD_ADD),
1993 pt_to_str(PT_OPTIONS),
1994 optptr->zone_fsopt_opt);
1996 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1997 zonecfg_free_fs_option_list(fstab.zone_fs_options);
1999 (void) zonecfg_endfsent(handle);
2001 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2002 zone_perror(zone, err, B_FALSE);
2003 goto done;
2005 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2006 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2007 rt_to_str(RT_NET));
2008 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
2009 export_prop(of, PT_ALLOWED_ADDRESS,
2010 nwiftab.zone_nwif_allowed_address);
2011 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
2012 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
2013 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2015 (void) zonecfg_endnwifent(handle);
2017 if ((err = zonecfg_setdevent(handle)) != Z_OK) {
2018 zone_perror(zone, err, B_FALSE);
2019 goto done;
2021 while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
2022 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2023 rt_to_str(RT_DEVICE));
2024 export_prop(of, PT_MATCH, devtab.zone_dev_match);
2025 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2027 (void) zonecfg_enddevent(handle);
2029 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
2030 char buf[128];
2032 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2033 rt_to_str(RT_MCAP));
2034 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
2035 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2036 pt_to_str(PT_PHYSICAL), buf);
2037 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2040 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
2041 zone_perror(zone, err, B_FALSE);
2042 goto done;
2044 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
2045 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
2046 export_prop(of, PT_NAME, rctltab.zone_rctl_name);
2047 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
2048 valptr = valptr->zone_rctlval_next) {
2049 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
2050 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
2051 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
2052 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
2053 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
2055 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2056 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2058 (void) zonecfg_endrctlent(handle);
2060 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
2061 zone_perror(zone, err, B_FALSE);
2062 goto done;
2064 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
2065 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2066 rt_to_str(RT_ATTR));
2067 export_prop(of, PT_NAME, attrtab.zone_attr_name);
2068 export_prop(of, PT_TYPE, attrtab.zone_attr_type);
2069 export_prop(of, PT_VALUE, attrtab.zone_attr_value);
2070 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2072 (void) zonecfg_endattrent(handle);
2074 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
2075 zone_perror(zone, err, B_FALSE);
2076 goto done;
2078 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
2079 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2080 rt_to_str(RT_DATASET));
2081 export_prop(of, PT_NAME, dstab.zone_dataset_name);
2082 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2084 (void) zonecfg_enddsent(handle);
2086 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
2087 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2088 rt_to_str(RT_DCPU));
2089 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
2090 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2091 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
2092 else
2093 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
2094 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
2095 psettab.zone_ncpu_max);
2096 if (psettab.zone_importance[0] != '\0')
2097 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2098 pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
2099 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2102 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
2103 zone_perror(zone, err, B_FALSE);
2104 goto done;
2106 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
2107 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2108 rt_to_str(RT_ADMIN));
2109 export_prop(of, PT_USER, admintab.zone_admin_user);
2110 export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
2111 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2114 (void) zonecfg_endadminent(handle);
2116 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
2117 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2118 rt_to_str(RT_SECFLAGS));
2119 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
2120 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
2121 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
2122 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2126 * There is nothing to export for pcap since this resource is just
2127 * a container for an rctl alias.
2130 done:
2131 if (need_to_close)
2132 (void) fclose(of);
2135 void
2136 exit_func(cmd_t *cmd)
2138 int arg, answer;
2139 boolean_t arg_err = B_FALSE;
2141 optind = 0;
2142 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2143 switch (arg) {
2144 case '?':
2145 longer_usage(CMD_EXIT);
2146 arg_err = B_TRUE;
2147 break;
2148 case 'F':
2149 force_exit = B_TRUE;
2150 break;
2151 default:
2152 short_usage(CMD_EXIT);
2153 arg_err = B_TRUE;
2154 break;
2157 if (arg_err)
2158 return;
2160 if (optind < cmd->cmd_argc) {
2161 short_usage(CMD_EXIT);
2162 return;
2165 if (global_scope || force_exit) {
2166 time_to_exit = B_TRUE;
2167 return;
2170 answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2171 if (answer == -1) {
2172 zerr(gettext("Resource incomplete, input "
2173 "not from terminal and -F not specified:\n%s command "
2174 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2175 exit(Z_ERR);
2176 } else if (answer == 1) {
2177 time_to_exit = B_TRUE;
2179 /* (answer == 0) => just return */
2182 static int
2183 validate_zonepath_syntax(char *path)
2185 if (path[0] != '/') {
2186 zerr(gettext("%s is not an absolute path."), path);
2187 return (Z_ERR);
2189 /* If path is all slashes, then fail */
2190 if (strspn(path, "/") == strlen(path)) {
2191 zerr(gettext("/ is not allowed as a %s."),
2192 pt_to_str(PT_ZONEPATH));
2193 return (Z_ERR);
2195 return (Z_OK);
2198 static void
2199 add_resource(cmd_t *cmd)
2201 int type;
2202 struct zone_psettab tmp_psettab;
2203 struct zone_mcaptab tmp_mcaptab;
2204 struct zone_secflagstab tmp_secflagstab;
2205 uint64_t tmp;
2206 uint64_t tmp_mcap;
2207 char pool[MAXNAMELEN];
2209 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2210 long_usage(CMD_ADD, B_TRUE);
2211 goto bad;
2214 switch (type) {
2215 case RT_FS:
2216 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2217 return;
2218 case RT_NET:
2219 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2220 return;
2221 case RT_DEVICE:
2222 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2223 return;
2224 case RT_RCTL:
2225 if (global_zone)
2226 zerr(gettext("WARNING: Setting a global zone resource "
2227 "control too low could deny\nservice "
2228 "to even the root user; "
2229 "this could render the system impossible\n"
2230 "to administer. Please use caution."));
2231 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2232 return;
2233 case RT_ATTR:
2234 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2235 return;
2236 case RT_DATASET:
2237 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2238 return;
2239 case RT_DCPU:
2240 /* Make sure there isn't already a cpu-set or cpu-cap entry. */
2241 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2242 zerr(gettext("The %s resource already exists."),
2243 rt_to_str(RT_DCPU));
2244 goto bad;
2246 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2247 Z_NO_ENTRY) {
2248 zerr(gettext("The %s resource already exists."),
2249 rt_to_str(RT_PCAP));
2250 goto bad;
2253 /* Make sure the pool property isn't set. */
2254 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2255 strlen(pool) > 0) {
2256 zerr(gettext("The %s property is already set. "
2257 "A persistent pool is incompatible with\nthe %s "
2258 "resource."),
2259 pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2260 goto bad;
2263 bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2264 return;
2265 case RT_PCAP:
2267 * Make sure there isn't already a cpu-set or incompatible
2268 * cpu-cap rctls.
2270 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2271 zerr(gettext("The %s resource already exists."),
2272 rt_to_str(RT_DCPU));
2273 goto bad;
2276 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2277 case Z_ALIAS_DISALLOW:
2278 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2279 B_FALSE);
2280 goto bad;
2282 case Z_OK:
2283 zerr(gettext("The %s resource already exists."),
2284 rt_to_str(RT_PCAP));
2285 goto bad;
2287 default:
2288 break;
2290 return;
2291 case RT_MCAP:
2293 * Make sure there isn't already a mem-cap entry or max-swap
2294 * or max-locked rctl.
2296 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2297 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2298 == Z_OK ||
2299 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2300 &tmp_mcap) == Z_OK) {
2301 zerr(gettext("The %s resource or a related resource "
2302 "control already exists."), rt_to_str(RT_MCAP));
2303 goto bad;
2305 if (global_zone)
2306 zerr(gettext("WARNING: Setting a global zone memory "
2307 "cap too low could deny\nservice "
2308 "to even the root user; "
2309 "this could render the system impossible\n"
2310 "to administer. Please use caution."));
2311 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2312 return;
2313 case RT_ADMIN:
2314 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2315 return;
2316 case RT_SECFLAGS:
2317 /* Make sure we haven't already set this */
2318 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
2319 zerr(gettext("The %s resource already exists."),
2320 rt_to_str(RT_SECFLAGS));
2321 bzero(&in_progress_secflagstab,
2322 sizeof (in_progress_secflagstab));
2323 return;
2324 default:
2325 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2326 long_usage(CMD_ADD, B_TRUE);
2327 usage(B_FALSE, HELP_RESOURCES);
2329 bad:
2330 global_scope = B_TRUE;
2331 end_op = -1;
2334 static void
2335 do_complex_rctl_val(complex_property_ptr_t cp)
2337 struct zone_rctlvaltab *rctlvaltab;
2338 complex_property_ptr_t cx;
2339 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2340 seen_action = B_FALSE;
2341 rctlblk_t *rctlblk;
2342 int err;
2344 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2345 zone_perror(zone, Z_NOMEM, B_TRUE);
2346 exit(Z_ERR);
2348 for (cx = cp; cx != NULL; cx = cx->cp_next) {
2349 switch (cx->cp_type) {
2350 case PT_PRIV:
2351 if (seen_priv) {
2352 zerr(gettext("%s already specified"),
2353 pt_to_str(PT_PRIV));
2354 goto bad;
2356 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
2357 cx->cp_value,
2358 sizeof (rctlvaltab->zone_rctlval_priv));
2359 seen_priv = B_TRUE;
2360 break;
2361 case PT_LIMIT:
2362 if (seen_limit) {
2363 zerr(gettext("%s already specified"),
2364 pt_to_str(PT_LIMIT));
2365 goto bad;
2367 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
2368 cx->cp_value,
2369 sizeof (rctlvaltab->zone_rctlval_limit));
2370 seen_limit = B_TRUE;
2371 break;
2372 case PT_ACTION:
2373 if (seen_action) {
2374 zerr(gettext("%s already specified"),
2375 pt_to_str(PT_ACTION));
2376 goto bad;
2378 (void) strlcpy(rctlvaltab->zone_rctlval_action,
2379 cx->cp_value,
2380 sizeof (rctlvaltab->zone_rctlval_action));
2381 seen_action = B_TRUE;
2382 break;
2383 default:
2384 zone_perror(pt_to_str(PT_VALUE),
2385 Z_NO_PROPERTY_TYPE, B_TRUE);
2386 long_usage(CMD_ADD, B_TRUE);
2387 usage(B_FALSE, HELP_PROPS);
2388 zonecfg_free_rctl_value_list(rctlvaltab);
2389 return;
2392 if (!seen_priv)
2393 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2394 if (!seen_limit)
2395 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2396 if (!seen_action)
2397 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2398 if (!seen_priv || !seen_limit || !seen_action)
2399 goto bad;
2400 rctlvaltab->zone_rctlval_next = NULL;
2401 rctlblk = alloca(rctlblk_size());
2403 * Make sure the rctl value looks roughly correct; we won't know if
2404 * it's truly OK until we verify the configuration on the target
2405 * system.
2407 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2408 !zonecfg_valid_rctlblk(rctlblk)) {
2409 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2410 pt_to_str(PT_VALUE));
2411 goto bad;
2413 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2414 if (err != Z_OK)
2415 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2416 return;
2418 bad:
2419 zonecfg_free_rctl_value_list(rctlvaltab);
2422 static void
2423 add_property(cmd_t *cmd)
2425 char *prop_id;
2426 int err, res_type, prop_type;
2427 property_value_ptr_t pp;
2428 list_property_ptr_t l;
2430 res_type = resource_scope;
2431 prop_type = cmd->cmd_prop_name[0];
2432 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2433 long_usage(CMD_ADD, B_TRUE);
2434 return;
2437 if (cmd->cmd_prop_nv_pairs != 1) {
2438 long_usage(CMD_ADD, B_TRUE);
2439 return;
2442 if (initialize(B_TRUE) != Z_OK)
2443 return;
2445 switch (res_type) {
2446 case RT_FS:
2447 if (prop_type != PT_OPTIONS) {
2448 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2449 B_TRUE);
2450 long_usage(CMD_ADD, B_TRUE);
2451 usage(B_FALSE, HELP_PROPS);
2452 return;
2454 pp = cmd->cmd_property_ptr[0];
2455 if (pp->pv_type != PROP_VAL_SIMPLE &&
2456 pp->pv_type != PROP_VAL_LIST) {
2457 zerr(gettext("A %s or %s value was expected here."),
2458 pvt_to_str(PROP_VAL_SIMPLE),
2459 pvt_to_str(PROP_VAL_LIST));
2460 saw_error = B_TRUE;
2461 return;
2463 if (pp->pv_type == PROP_VAL_SIMPLE) {
2464 if (pp->pv_simple == NULL) {
2465 long_usage(CMD_ADD, B_TRUE);
2466 return;
2468 prop_id = pp->pv_simple;
2469 err = zonecfg_add_fs_option(&in_progress_fstab,
2470 prop_id);
2471 if (err != Z_OK)
2472 zone_perror(pt_to_str(prop_type), err, B_TRUE);
2473 } else {
2474 list_property_ptr_t list;
2476 for (list = pp->pv_list; list != NULL;
2477 list = list->lp_next) {
2478 prop_id = list->lp_simple;
2479 if (prop_id == NULL)
2480 break;
2481 err = zonecfg_add_fs_option(
2482 &in_progress_fstab, prop_id);
2483 if (err != Z_OK)
2484 zone_perror(pt_to_str(prop_type), err,
2485 B_TRUE);
2488 return;
2489 case RT_RCTL:
2490 if (prop_type != PT_VALUE) {
2491 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2492 B_TRUE);
2493 long_usage(CMD_ADD, B_TRUE);
2494 usage(B_FALSE, HELP_PROPS);
2495 return;
2497 pp = cmd->cmd_property_ptr[0];
2498 if (pp->pv_type != PROP_VAL_COMPLEX &&
2499 pp->pv_type != PROP_VAL_LIST) {
2500 zerr(gettext("A %s or %s value was expected here."),
2501 pvt_to_str(PROP_VAL_COMPLEX),
2502 pvt_to_str(PROP_VAL_LIST));
2503 saw_error = B_TRUE;
2504 return;
2506 if (pp->pv_type == PROP_VAL_COMPLEX) {
2507 do_complex_rctl_val(pp->pv_complex);
2508 return;
2510 for (l = pp->pv_list; l != NULL; l = l->lp_next)
2511 do_complex_rctl_val(l->lp_complex);
2512 return;
2513 default:
2514 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2515 long_usage(CMD_ADD, B_TRUE);
2516 usage(B_FALSE, HELP_RESOURCES);
2517 return;
2521 static boolean_t
2522 gz_invalid_resource(int type)
2524 return (global_zone && (type == RT_FS ||
2525 type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2526 type == RT_DATASET));
2529 static boolean_t
2530 gz_invalid_rt_property(int type)
2532 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2533 type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2534 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2535 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2538 static boolean_t
2539 gz_invalid_property(int type)
2541 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2542 type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2543 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2544 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2547 void
2548 add_func(cmd_t *cmd)
2550 int arg;
2551 boolean_t arg_err = B_FALSE;
2553 assert(cmd != NULL);
2555 optind = 0;
2556 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2557 switch (arg) {
2558 case '?':
2559 longer_usage(CMD_ADD);
2560 arg_err = B_TRUE;
2561 break;
2562 default:
2563 short_usage(CMD_ADD);
2564 arg_err = B_TRUE;
2565 break;
2568 if (arg_err)
2569 return;
2571 if (optind != cmd->cmd_argc) {
2572 short_usage(CMD_ADD);
2573 return;
2576 if (zone_is_read_only(CMD_ADD))
2577 return;
2579 if (initialize(B_TRUE) != Z_OK)
2580 return;
2581 if (global_scope) {
2582 if (gz_invalid_resource(cmd->cmd_res_type)) {
2583 zerr(gettext("Cannot add a %s resource to the "
2584 "global zone."), rt_to_str(cmd->cmd_res_type));
2585 saw_error = B_TRUE;
2586 return;
2589 global_scope = B_FALSE;
2590 resource_scope = cmd->cmd_res_type;
2591 end_op = CMD_ADD;
2592 add_resource(cmd);
2593 } else
2594 add_property(cmd);
2598 * This routine has an unusual implementation, because it tries very
2599 * hard to succeed in the face of a variety of failure modes.
2600 * The most common and most vexing occurs when the index file and
2601 * the /etc/zones/<zonename.xml> file are not both present. In
2602 * this case, delete must eradicate as much of the zone state as is left
2603 * so that the user can later create a new zone with the same name.
2605 void
2606 delete_func(cmd_t *cmd)
2608 int err, arg, answer;
2609 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
2610 boolean_t force = B_FALSE;
2611 boolean_t arg_err = B_FALSE;
2613 optind = 0;
2614 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2615 switch (arg) {
2616 case '?':
2617 longer_usage(CMD_DELETE);
2618 arg_err = B_TRUE;
2619 break;
2620 case 'F':
2621 force = B_TRUE;
2622 break;
2623 default:
2624 short_usage(CMD_DELETE);
2625 arg_err = B_TRUE;
2626 break;
2629 if (arg_err)
2630 return;
2632 if (optind != cmd->cmd_argc) {
2633 short_usage(CMD_DELETE);
2634 return;
2637 if (zone_is_read_only(CMD_DELETE))
2638 return;
2640 if (!force) {
2642 * Initialize sets up the global called "handle" and warns the
2643 * user if the zone is not configured. In force mode, we don't
2644 * trust that evaluation, and hence skip it. (We don't need the
2645 * handle to be loaded anyway, since zonecfg_destroy is done by
2646 * zonename). However, we also have to take care to emulate the
2647 * messages spit out by initialize; see below.
2649 if (initialize(B_TRUE) != Z_OK)
2650 return;
2652 (void) snprintf(line, sizeof (line),
2653 gettext("Are you sure you want to delete zone %s"), zone);
2654 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2655 zerr(gettext("Input not from terminal and -F not "
2656 "specified:\n%s command ignored, exiting."),
2657 cmd_to_str(CMD_DELETE));
2658 exit(Z_ERR);
2660 if (answer != 1)
2661 return;
2665 * This function removes the authorizations from user_attr
2666 * that correspond to those specified in the configuration
2668 if (initialize(B_TRUE) == Z_OK) {
2669 (void) zonecfg_deauthorize_users(handle, zone);
2671 if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2672 if ((err == Z_BAD_ZONE_STATE) && !force) {
2673 zerr(gettext("Zone %s not in %s state; %s not "
2674 "allowed. Use -F to force %s."),
2675 zone, zone_state_str(ZONE_STATE_CONFIGURED),
2676 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2677 } else {
2678 zone_perror(zone, err, B_TRUE);
2681 need_to_commit = B_FALSE;
2684 * Emulate initialize's messaging; if there wasn't a valid handle to
2685 * begin with, then user had typed delete (or delete -F) multiple
2686 * times. So we emit a message.
2688 * We only do this in the 'force' case because normally, initialize()
2689 * takes care of this for us.
2691 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2692 (void) printf(gettext("Use '%s' to begin "
2693 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2696 * Time for a new handle: finish the old one off first
2697 * then get a new one properly to avoid leaks.
2699 if (got_handle) {
2700 zonecfg_fini_handle(handle);
2701 if ((handle = zonecfg_init_handle()) == NULL) {
2702 zone_perror(execname, Z_NOMEM, B_TRUE);
2703 exit(Z_ERR);
2705 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2706 /* If there was no zone before, that's OK */
2707 if (err != Z_NO_ZONE)
2708 zone_perror(zone, err, B_TRUE);
2709 got_handle = B_FALSE;
2714 static int
2715 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2717 int err, i;
2718 property_value_ptr_t pp;
2720 if ((err = initialize(B_TRUE)) != Z_OK)
2721 return (err);
2723 bzero(fstab, sizeof (*fstab));
2724 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2725 pp = cmd->cmd_property_ptr[i];
2726 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2727 zerr(gettext("A simple value was expected here."));
2728 saw_error = B_TRUE;
2729 return (Z_INSUFFICIENT_SPEC);
2731 switch (cmd->cmd_prop_name[i]) {
2732 case PT_DIR:
2733 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2734 sizeof (fstab->zone_fs_dir));
2735 break;
2736 case PT_SPECIAL:
2737 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2738 sizeof (fstab->zone_fs_special));
2739 break;
2740 case PT_RAW:
2741 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2742 sizeof (fstab->zone_fs_raw));
2743 break;
2744 case PT_TYPE:
2745 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2746 sizeof (fstab->zone_fs_type));
2747 break;
2748 default:
2749 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2750 Z_NO_PROPERTY_TYPE, B_TRUE);
2751 return (Z_INSUFFICIENT_SPEC);
2754 if (fill_in_only)
2755 return (Z_OK);
2756 return (zonecfg_lookup_filesystem(handle, fstab));
2759 static int
2760 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2761 boolean_t fill_in_only)
2763 int err, i;
2764 property_value_ptr_t pp;
2766 if ((err = initialize(B_TRUE)) != Z_OK)
2767 return (err);
2769 bzero(nwiftab, sizeof (*nwiftab));
2770 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2771 pp = cmd->cmd_property_ptr[i];
2772 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2773 zerr(gettext("A simple value was expected here."));
2774 saw_error = B_TRUE;
2775 return (Z_INSUFFICIENT_SPEC);
2777 switch (cmd->cmd_prop_name[i]) {
2778 case PT_ADDRESS:
2779 (void) strlcpy(nwiftab->zone_nwif_address,
2780 pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2781 break;
2782 case PT_ALLOWED_ADDRESS:
2783 (void) strlcpy(nwiftab->zone_nwif_allowed_address,
2784 pp->pv_simple,
2785 sizeof (nwiftab->zone_nwif_allowed_address));
2786 break;
2787 case PT_PHYSICAL:
2788 (void) strlcpy(nwiftab->zone_nwif_physical,
2789 pp->pv_simple,
2790 sizeof (nwiftab->zone_nwif_physical));
2791 break;
2792 case PT_DEFROUTER:
2793 (void) strlcpy(nwiftab->zone_nwif_defrouter,
2794 pp->pv_simple,
2795 sizeof (nwiftab->zone_nwif_defrouter));
2796 break;
2797 default:
2798 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2799 Z_NO_PROPERTY_TYPE, B_TRUE);
2800 return (Z_INSUFFICIENT_SPEC);
2803 if (fill_in_only)
2804 return (Z_OK);
2805 err = zonecfg_lookup_nwif(handle, nwiftab);
2806 return (err);
2809 static int
2810 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2812 int err, i;
2813 property_value_ptr_t pp;
2815 if ((err = initialize(B_TRUE)) != Z_OK)
2816 return (err);
2818 bzero(devtab, sizeof (*devtab));
2819 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2820 pp = cmd->cmd_property_ptr[i];
2821 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2822 zerr(gettext("A simple value was expected here."));
2823 saw_error = B_TRUE;
2824 return (Z_INSUFFICIENT_SPEC);
2826 switch (cmd->cmd_prop_name[i]) {
2827 case PT_MATCH:
2828 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2829 sizeof (devtab->zone_dev_match));
2830 break;
2831 default:
2832 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2833 Z_NO_PROPERTY_TYPE, B_TRUE);
2834 return (Z_INSUFFICIENT_SPEC);
2837 if (fill_in_only)
2838 return (Z_OK);
2839 err = zonecfg_lookup_dev(handle, devtab);
2840 return (err);
2843 static int
2844 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2845 boolean_t fill_in_only)
2847 int err, i;
2848 property_value_ptr_t pp;
2850 if ((err = initialize(B_TRUE)) != Z_OK)
2851 return (err);
2853 bzero(rctltab, sizeof (*rctltab));
2854 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2855 pp = cmd->cmd_property_ptr[i];
2856 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2857 zerr(gettext("A simple value was expected here."));
2858 saw_error = B_TRUE;
2859 return (Z_INSUFFICIENT_SPEC);
2861 switch (cmd->cmd_prop_name[i]) {
2862 case PT_NAME:
2863 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2864 sizeof (rctltab->zone_rctl_name));
2865 break;
2866 default:
2867 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2868 Z_NO_PROPERTY_TYPE, B_TRUE);
2869 return (Z_INSUFFICIENT_SPEC);
2872 if (fill_in_only)
2873 return (Z_OK);
2874 err = zonecfg_lookup_rctl(handle, rctltab);
2875 return (err);
2878 static int
2879 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2880 boolean_t fill_in_only)
2882 int err, i;
2883 property_value_ptr_t pp;
2885 if ((err = initialize(B_TRUE)) != Z_OK)
2886 return (err);
2888 bzero(attrtab, sizeof (*attrtab));
2889 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2890 pp = cmd->cmd_property_ptr[i];
2891 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2892 zerr(gettext("A simple value was expected here."));
2893 saw_error = B_TRUE;
2894 return (Z_INSUFFICIENT_SPEC);
2896 switch (cmd->cmd_prop_name[i]) {
2897 case PT_NAME:
2898 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2899 sizeof (attrtab->zone_attr_name));
2900 break;
2901 case PT_TYPE:
2902 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2903 sizeof (attrtab->zone_attr_type));
2904 break;
2905 case PT_VALUE:
2906 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2907 sizeof (attrtab->zone_attr_value));
2908 break;
2909 default:
2910 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2911 Z_NO_PROPERTY_TYPE, B_TRUE);
2912 return (Z_INSUFFICIENT_SPEC);
2915 if (fill_in_only)
2916 return (Z_OK);
2917 err = zonecfg_lookup_attr(handle, attrtab);
2918 return (err);
2921 static int
2922 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2924 int err, i;
2925 property_value_ptr_t pp;
2927 if ((err = initialize(B_TRUE)) != Z_OK)
2928 return (err);
2930 dstab->zone_dataset_name[0] = '\0';
2931 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2932 pp = cmd->cmd_property_ptr[i];
2933 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2934 zerr(gettext("A simple value was expected here."));
2935 saw_error = B_TRUE;
2936 return (Z_INSUFFICIENT_SPEC);
2938 switch (cmd->cmd_prop_name[i]) {
2939 case PT_NAME:
2940 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2941 sizeof (dstab->zone_dataset_name));
2942 break;
2943 default:
2944 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2945 Z_NO_PROPERTY_TYPE, B_TRUE);
2946 return (Z_INSUFFICIENT_SPEC);
2949 if (fill_in_only)
2950 return (Z_OK);
2951 return (zonecfg_lookup_ds(handle, dstab));
2954 static int
2955 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2956 boolean_t fill_in_only)
2958 int err, i;
2959 property_value_ptr_t pp;
2961 if ((err = initialize(B_TRUE)) != Z_OK)
2962 return (err);
2964 bzero(admintab, sizeof (*admintab));
2965 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2966 pp = cmd->cmd_property_ptr[i];
2967 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2968 zerr(gettext("A simple value was expected here."));
2969 saw_error = B_TRUE;
2970 return (Z_INSUFFICIENT_SPEC);
2972 switch (cmd->cmd_prop_name[i]) {
2973 case PT_USER:
2974 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2975 sizeof (admintab->zone_admin_user));
2976 break;
2977 case PT_AUTHS:
2978 (void) strlcpy(admintab->zone_admin_auths,
2979 pp->pv_simple, sizeof (admintab->zone_admin_auths));
2980 break;
2981 default:
2982 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2983 Z_NO_PROPERTY_TYPE, B_TRUE);
2984 return (Z_INSUFFICIENT_SPEC);
2987 if (fill_in_only)
2988 return (Z_OK);
2989 err = zonecfg_lookup_admin(handle, admintab);
2990 return (err);
2993 static int
2994 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
2995 boolean_t fill_in_only)
2997 int err, i;
2998 property_value_ptr_t pp;
3000 if ((err = initialize(B_TRUE)) != Z_OK)
3001 return (err);
3003 bzero(secflagstab, sizeof (*secflagstab));
3004 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
3005 pp = cmd->cmd_property_ptr[i];
3006 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
3007 zerr(gettext("A simple value was expected here."));
3008 saw_error = B_TRUE;
3009 return (Z_INSUFFICIENT_SPEC);
3011 switch (cmd->cmd_prop_name[i]) {
3012 case PT_DEFAULT:
3013 (void) strlcpy(secflagstab->zone_secflags_default,
3014 pp->pv_simple,
3015 sizeof (secflagstab->zone_secflags_default));
3016 break;
3017 case PT_LOWER:
3018 (void) strlcpy(secflagstab->zone_secflags_lower,
3019 pp->pv_simple,
3020 sizeof (secflagstab->zone_secflags_lower));
3021 break;
3022 case PT_UPPER:
3023 (void) strlcpy(secflagstab->zone_secflags_upper,
3024 pp->pv_simple,
3025 sizeof (secflagstab->zone_secflags_upper));
3026 break;
3027 default:
3028 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
3029 Z_NO_PROPERTY_TYPE, B_TRUE);
3030 return (Z_INSUFFICIENT_SPEC);
3033 if (fill_in_only)
3034 return (Z_OK);
3036 err = zonecfg_lookup_secflags(handle, secflagstab);
3038 return (err);
3041 static void
3042 remove_aliased_rctl(int type, char *name)
3044 int err;
3045 uint64_t tmp;
3047 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
3048 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3049 zonecfg_strerror(err));
3050 saw_error = B_TRUE;
3051 return;
3053 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
3054 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3055 zonecfg_strerror(err));
3056 saw_error = B_TRUE;
3057 } else {
3058 need_to_commit = B_TRUE;
3062 static boolean_t
3063 prompt_remove_resource(cmd_t *cmd, char *rsrc)
3065 int num;
3066 int answer;
3067 int arg;
3068 boolean_t force = B_FALSE;
3069 char prompt[128];
3070 boolean_t arg_err = B_FALSE;
3072 optind = 0;
3073 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3074 switch (arg) {
3075 case 'F':
3076 force = B_TRUE;
3077 break;
3078 default:
3079 arg_err = B_TRUE;
3080 break;
3083 if (arg_err)
3084 return (B_FALSE);
3087 num = zonecfg_num_resources(handle, rsrc);
3089 if (num == 0) {
3090 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
3091 B_TRUE);
3092 return (B_FALSE);
3094 if (num > 1 && !force) {
3095 if (!interactive_mode) {
3096 zerr(gettext("There are multiple instances of this "
3097 "resource. Either qualify the resource to\n"
3098 "remove a single instance or use the -F option to "
3099 "remove all instances."));
3100 saw_error = B_TRUE;
3101 return (B_FALSE);
3103 (void) snprintf(prompt, sizeof (prompt), gettext(
3104 "Are you sure you want to remove ALL '%s' resources"),
3105 rsrc);
3106 answer = ask_yesno(B_FALSE, prompt);
3107 if (answer == -1) {
3108 zerr(gettext("Resource incomplete."));
3109 return (B_FALSE);
3111 if (answer != 1)
3112 return (B_FALSE);
3114 return (B_TRUE);
3117 static void
3118 remove_fs(cmd_t *cmd)
3120 int err;
3122 /* traditional, qualified fs removal */
3123 if (cmd->cmd_prop_nv_pairs > 0) {
3124 struct zone_fstab fstab;
3126 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
3127 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3128 return;
3130 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
3131 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3132 else
3133 need_to_commit = B_TRUE;
3134 zonecfg_free_fs_option_list(fstab.zone_fs_options);
3135 return;
3139 * unqualified fs removal. remove all fs's but prompt if more
3140 * than one.
3142 if (!prompt_remove_resource(cmd, "fs"))
3143 return;
3145 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
3146 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3147 else
3148 need_to_commit = B_TRUE;
3151 static void
3152 remove_net(cmd_t *cmd)
3154 int err;
3156 /* traditional, qualified net removal */
3157 if (cmd->cmd_prop_nv_pairs > 0) {
3158 struct zone_nwiftab nwiftab;
3160 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3161 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3162 return;
3164 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3165 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3166 else
3167 need_to_commit = B_TRUE;
3168 return;
3172 * unqualified net removal. remove all nets but prompt if more
3173 * than one.
3175 if (!prompt_remove_resource(cmd, "net"))
3176 return;
3178 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3179 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3180 else
3181 need_to_commit = B_TRUE;
3184 static void
3185 remove_device(cmd_t *cmd)
3187 int err;
3189 /* traditional, qualified device removal */
3190 if (cmd->cmd_prop_nv_pairs > 0) {
3191 struct zone_devtab devtab;
3193 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3194 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3195 return;
3197 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3198 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3199 else
3200 need_to_commit = B_TRUE;
3201 return;
3205 * unqualified device removal. remove all devices but prompt if more
3206 * than one.
3208 if (!prompt_remove_resource(cmd, "device"))
3209 return;
3211 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3212 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3213 else
3214 need_to_commit = B_TRUE;
3217 static void
3218 remove_attr(cmd_t *cmd)
3220 int err;
3222 /* traditional, qualified attr removal */
3223 if (cmd->cmd_prop_nv_pairs > 0) {
3224 struct zone_attrtab attrtab;
3226 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3227 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3228 return;
3230 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3231 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3232 else
3233 need_to_commit = B_TRUE;
3234 return;
3238 * unqualified attr removal. remove all attrs but prompt if more
3239 * than one.
3241 if (!prompt_remove_resource(cmd, "attr"))
3242 return;
3244 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3245 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3246 else
3247 need_to_commit = B_TRUE;
3250 static void
3251 remove_dataset(cmd_t *cmd)
3253 int err;
3255 /* traditional, qualified dataset removal */
3256 if (cmd->cmd_prop_nv_pairs > 0) {
3257 struct zone_dstab dstab;
3259 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3260 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3261 return;
3263 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3264 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3265 else
3266 need_to_commit = B_TRUE;
3267 return;
3271 * unqualified dataset removal. remove all datasets but prompt if more
3272 * than one.
3274 if (!prompt_remove_resource(cmd, "dataset"))
3275 return;
3277 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3278 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3279 else
3280 need_to_commit = B_TRUE;
3283 static void
3284 remove_rctl(cmd_t *cmd)
3286 int err;
3288 /* traditional, qualified rctl removal */
3289 if (cmd->cmd_prop_nv_pairs > 0) {
3290 struct zone_rctltab rctltab;
3292 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3293 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3294 return;
3296 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3297 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3298 else
3299 need_to_commit = B_TRUE;
3300 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3301 return;
3305 * unqualified rctl removal. remove all rctls but prompt if more
3306 * than one.
3308 if (!prompt_remove_resource(cmd, "rctl"))
3309 return;
3311 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3312 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3313 else
3314 need_to_commit = B_TRUE;
3317 static void
3318 remove_pset()
3320 int err;
3321 struct zone_psettab psettab;
3323 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3324 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3325 return;
3327 if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3328 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3329 else
3330 need_to_commit = B_TRUE;
3333 static void
3334 remove_pcap()
3336 int err;
3337 uint64_t tmp;
3339 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3340 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3341 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3342 saw_error = B_TRUE;
3343 return;
3346 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3347 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3348 else
3349 need_to_commit = B_TRUE;
3352 static void
3353 remove_mcap()
3355 int err, res1, res2, res3;
3356 uint64_t tmp;
3357 struct zone_mcaptab mcaptab;
3358 boolean_t revert = B_FALSE;
3360 res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3361 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3362 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3364 /* if none of these exist, there is no resource to remove */
3365 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3366 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3367 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3368 saw_error = B_TRUE;
3369 return;
3371 if (res1 == Z_OK) {
3372 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3373 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3374 revert = B_TRUE;
3375 } else {
3376 need_to_commit = B_TRUE;
3379 if (res2 == Z_OK) {
3380 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3381 != Z_OK) {
3382 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3383 revert = B_TRUE;
3384 } else {
3385 need_to_commit = B_TRUE;
3388 if (res3 == Z_OK) {
3389 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3390 != Z_OK) {
3391 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3392 revert = B_TRUE;
3393 } else {
3394 need_to_commit = B_TRUE;
3398 if (revert)
3399 need_to_commit = B_FALSE;
3402 static void
3403 remove_admin(cmd_t *cmd)
3405 int err;
3407 /* traditional, qualified attr removal */
3408 if (cmd->cmd_prop_nv_pairs > 0) {
3409 struct zone_admintab admintab;
3411 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3412 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3413 err, B_TRUE);
3414 return;
3416 if ((err = zonecfg_delete_admin(handle, &admintab,
3417 zone))
3418 != Z_OK)
3419 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3420 err, B_TRUE);
3421 else
3422 need_to_commit = B_TRUE;
3423 return;
3424 } else {
3426 * unqualified admin removal.
3427 * remove all admins but prompt if more
3428 * than one.
3430 if (!prompt_remove_resource(cmd, "admin"))
3431 return;
3433 if ((err = zonecfg_delete_admins(handle, zone))
3434 != Z_OK)
3435 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3436 err, B_TRUE);
3437 else
3438 need_to_commit = B_TRUE;
3442 static void
3443 remove_secflags()
3445 int err;
3446 struct zone_secflagstab sectab = { 0 };
3448 if (zonecfg_lookup_secflags(handle, &sectab) != Z_OK) {
3449 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
3450 rt_to_str(RT_SECFLAGS),
3451 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3452 return;
3455 if ((err = zonecfg_delete_secflags(handle, &sectab)) != Z_OK) {
3456 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
3457 return;
3460 need_to_commit = B_TRUE;
3463 static void
3464 remove_resource(cmd_t *cmd)
3466 int type;
3467 int arg;
3468 boolean_t arg_err = B_FALSE;
3470 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3471 long_usage(CMD_REMOVE, B_TRUE);
3472 return;
3475 optind = 0;
3476 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3477 switch (arg) {
3478 case '?':
3479 longer_usage(CMD_REMOVE);
3480 arg_err = B_TRUE;
3481 break;
3482 case 'F':
3483 break;
3484 default:
3485 short_usage(CMD_REMOVE);
3486 arg_err = B_TRUE;
3487 break;
3490 if (arg_err)
3491 return;
3493 if (initialize(B_TRUE) != Z_OK)
3494 return;
3496 switch (type) {
3497 case RT_FS:
3498 remove_fs(cmd);
3499 return;
3500 case RT_NET:
3501 remove_net(cmd);
3502 return;
3503 case RT_DEVICE:
3504 remove_device(cmd);
3505 return;
3506 case RT_RCTL:
3507 remove_rctl(cmd);
3508 return;
3509 case RT_ATTR:
3510 remove_attr(cmd);
3511 return;
3512 case RT_DATASET:
3513 remove_dataset(cmd);
3514 return;
3515 case RT_DCPU:
3516 remove_pset();
3517 return;
3518 case RT_PCAP:
3519 remove_pcap();
3520 return;
3521 case RT_MCAP:
3522 remove_mcap();
3523 return;
3524 case RT_ADMIN:
3525 remove_admin(cmd);
3526 return;
3527 case RT_SECFLAGS:
3528 remove_secflags();
3529 return;
3530 default:
3531 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3532 long_usage(CMD_REMOVE, B_TRUE);
3533 usage(B_FALSE, HELP_RESOURCES);
3534 return;
3538 static void
3539 remove_property(cmd_t *cmd)
3541 char *prop_id;
3542 int err, res_type, prop_type;
3543 property_value_ptr_t pp;
3544 struct zone_rctlvaltab *rctlvaltab;
3545 complex_property_ptr_t cx;
3547 res_type = resource_scope;
3548 prop_type = cmd->cmd_prop_name[0];
3549 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3550 long_usage(CMD_REMOVE, B_TRUE);
3551 return;
3554 if (cmd->cmd_prop_nv_pairs != 1) {
3555 long_usage(CMD_ADD, B_TRUE);
3556 return;
3559 if (initialize(B_TRUE) != Z_OK)
3560 return;
3562 switch (res_type) {
3563 case RT_FS:
3564 if (prop_type != PT_OPTIONS) {
3565 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3566 B_TRUE);
3567 long_usage(CMD_REMOVE, B_TRUE);
3568 usage(B_FALSE, HELP_PROPS);
3569 return;
3571 pp = cmd->cmd_property_ptr[0];
3572 if (pp->pv_type == PROP_VAL_COMPLEX) {
3573 zerr(gettext("A %s or %s value was expected here."),
3574 pvt_to_str(PROP_VAL_SIMPLE),
3575 pvt_to_str(PROP_VAL_LIST));
3576 saw_error = B_TRUE;
3577 return;
3579 if (pp->pv_type == PROP_VAL_SIMPLE) {
3580 if (pp->pv_simple == NULL) {
3581 long_usage(CMD_ADD, B_TRUE);
3582 return;
3584 prop_id = pp->pv_simple;
3585 err = zonecfg_remove_fs_option(&in_progress_fstab,
3586 prop_id);
3587 if (err != Z_OK)
3588 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3589 } else {
3590 list_property_ptr_t list;
3592 for (list = pp->pv_list; list != NULL;
3593 list = list->lp_next) {
3594 prop_id = list->lp_simple;
3595 if (prop_id == NULL)
3596 break;
3597 err = zonecfg_remove_fs_option(
3598 &in_progress_fstab, prop_id);
3599 if (err != Z_OK)
3600 zone_perror(pt_to_str(prop_type), err,
3601 B_TRUE);
3604 return;
3605 case RT_RCTL:
3606 if (prop_type != PT_VALUE) {
3607 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3608 B_TRUE);
3609 long_usage(CMD_REMOVE, B_TRUE);
3610 usage(B_FALSE, HELP_PROPS);
3611 return;
3613 pp = cmd->cmd_property_ptr[0];
3614 if (pp->pv_type != PROP_VAL_COMPLEX) {
3615 zerr(gettext("A %s value was expected here."),
3616 pvt_to_str(PROP_VAL_COMPLEX));
3617 saw_error = B_TRUE;
3618 return;
3620 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3621 zone_perror(zone, Z_NOMEM, B_TRUE);
3622 exit(Z_ERR);
3624 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3625 switch (cx->cp_type) {
3626 case PT_PRIV:
3627 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
3628 cx->cp_value,
3629 sizeof (rctlvaltab->zone_rctlval_priv));
3630 break;
3631 case PT_LIMIT:
3632 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
3633 cx->cp_value,
3634 sizeof (rctlvaltab->zone_rctlval_limit));
3635 break;
3636 case PT_ACTION:
3637 (void) strlcpy(rctlvaltab->zone_rctlval_action,
3638 cx->cp_value,
3639 sizeof (rctlvaltab->zone_rctlval_action));
3640 break;
3641 default:
3642 zone_perror(pt_to_str(prop_type),
3643 Z_NO_PROPERTY_TYPE, B_TRUE);
3644 long_usage(CMD_ADD, B_TRUE);
3645 usage(B_FALSE, HELP_PROPS);
3646 zonecfg_free_rctl_value_list(rctlvaltab);
3647 return;
3650 rctlvaltab->zone_rctlval_next = NULL;
3651 err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3652 rctlvaltab);
3653 if (err != Z_OK)
3654 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3655 zonecfg_free_rctl_value_list(rctlvaltab);
3656 return;
3657 case RT_NET:
3658 if (prop_type != PT_DEFROUTER) {
3659 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3660 B_TRUE);
3661 long_usage(CMD_REMOVE, B_TRUE);
3662 usage(B_FALSE, HELP_PROPS);
3663 return;
3664 } else {
3665 bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3666 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3667 return;
3669 default:
3670 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3671 long_usage(CMD_REMOVE, B_TRUE);
3672 usage(B_FALSE, HELP_RESOURCES);
3673 return;
3677 void
3678 remove_func(cmd_t *cmd)
3680 if (zone_is_read_only(CMD_REMOVE))
3681 return;
3683 assert(cmd != NULL);
3685 if (global_scope) {
3686 if (gz_invalid_resource(cmd->cmd_res_type)) {
3687 zerr(gettext("%s is not a valid resource for the "
3688 "global zone."), rt_to_str(cmd->cmd_res_type));
3689 saw_error = B_TRUE;
3690 return;
3692 remove_resource(cmd);
3693 } else {
3694 remove_property(cmd);
3698 static void
3699 clear_property(cmd_t *cmd)
3701 int res_type, prop_type;
3703 res_type = resource_scope;
3704 prop_type = cmd->cmd_res_type;
3705 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3706 long_usage(CMD_CLEAR, B_TRUE);
3707 return;
3710 if (initialize(B_TRUE) != Z_OK)
3711 return;
3713 switch (res_type) {
3714 case RT_FS:
3715 if (prop_type == PT_RAW) {
3716 in_progress_fstab.zone_fs_raw[0] = '\0';
3717 need_to_commit = B_TRUE;
3718 return;
3720 break;
3721 case RT_DCPU:
3722 if (prop_type == PT_IMPORTANCE) {
3723 in_progress_psettab.zone_importance[0] = '\0';
3724 need_to_commit = B_TRUE;
3725 return;
3727 break;
3728 case RT_MCAP:
3729 switch (prop_type) {
3730 case PT_PHYSICAL:
3731 in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3732 need_to_commit = B_TRUE;
3733 return;
3734 case PT_SWAP:
3735 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3736 return;
3737 case PT_LOCKED:
3738 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3739 return;
3741 break;
3742 case RT_SECFLAGS:
3743 switch (prop_type) {
3744 case PT_LOWER:
3745 in_progress_secflagstab.zone_secflags_lower[0] = '\0';
3746 need_to_commit = B_TRUE;
3747 return;
3748 case PT_DEFAULT:
3749 in_progress_secflagstab.zone_secflags_default[0] = '\0';
3750 need_to_commit = B_TRUE;
3751 return;
3752 case PT_UPPER:
3753 in_progress_secflagstab.zone_secflags_upper[0] = '\0';
3754 need_to_commit = B_TRUE;
3755 return;
3757 break;
3758 default:
3759 break;
3762 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3765 static void
3766 clear_global(cmd_t *cmd)
3768 int err, type;
3770 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3771 long_usage(CMD_CLEAR, B_TRUE);
3772 return;
3775 if (initialize(B_TRUE) != Z_OK)
3776 return;
3778 switch (type) {
3779 case PT_ZONENAME:
3780 /* FALLTHRU */
3781 case PT_ZONEPATH:
3782 /* FALLTHRU */
3783 case PT_BRAND:
3784 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3785 return;
3786 case PT_AUTOBOOT:
3787 /* false is default; we'll treat as equivalent to clearing */
3788 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3789 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3790 else
3791 need_to_commit = B_TRUE;
3792 return;
3793 case PT_POOL:
3794 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3795 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3796 else
3797 need_to_commit = B_TRUE;
3798 return;
3799 case PT_LIMITPRIV:
3800 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3801 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3802 else
3803 need_to_commit = B_TRUE;
3804 return;
3805 case PT_BOOTARGS:
3806 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3807 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3808 else
3809 need_to_commit = B_TRUE;
3810 return;
3811 case PT_SCHED:
3812 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3813 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3814 else
3815 need_to_commit = B_TRUE;
3816 return;
3817 case PT_IPTYPE:
3818 /* shared is default; we'll treat as equivalent to clearing */
3819 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3820 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3821 else
3822 need_to_commit = B_TRUE;
3823 return;
3824 case PT_MAXLWPS:
3825 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3826 return;
3827 case PT_MAXPROCS:
3828 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS);
3829 return;
3830 case PT_MAXSHMMEM:
3831 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3832 return;
3833 case PT_MAXSHMIDS:
3834 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3835 return;
3836 case PT_MAXMSGIDS:
3837 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3838 return;
3839 case PT_MAXSEMIDS:
3840 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3841 return;
3842 case PT_SHARES:
3843 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3844 return;
3845 case PT_HOSTID:
3846 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3847 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3848 else
3849 need_to_commit = B_TRUE;
3850 return;
3851 case PT_FS_ALLOWED:
3852 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3853 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3854 else
3855 need_to_commit = B_TRUE;
3856 return;
3857 default:
3858 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3859 long_usage(CMD_CLEAR, B_TRUE);
3860 usage(B_FALSE, HELP_PROPS);
3861 return;
3865 void
3866 clear_func(cmd_t *cmd)
3868 if (zone_is_read_only(CMD_CLEAR))
3869 return;
3871 assert(cmd != NULL);
3873 if (global_scope) {
3874 if (gz_invalid_property(cmd->cmd_res_type)) {
3875 zerr(gettext("%s is not a valid property for the "
3876 "global zone."), pt_to_str(cmd->cmd_res_type));
3877 saw_error = B_TRUE;
3878 return;
3881 clear_global(cmd);
3882 } else {
3883 clear_property(cmd);
3887 void
3888 select_func(cmd_t *cmd)
3890 int type, err, res;
3891 uint64_t limit;
3892 uint64_t tmp;
3894 if (zone_is_read_only(CMD_SELECT))
3895 return;
3897 assert(cmd != NULL);
3899 if (global_scope) {
3900 global_scope = B_FALSE;
3901 resource_scope = cmd->cmd_res_type;
3902 end_op = CMD_SELECT;
3903 } else {
3904 scope_usage(CMD_SELECT);
3905 return;
3908 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3909 long_usage(CMD_SELECT, B_TRUE);
3910 return;
3913 if (initialize(B_TRUE) != Z_OK)
3914 return;
3916 switch (type) {
3917 case RT_FS:
3918 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3919 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3920 global_scope = B_TRUE;
3922 bcopy(&old_fstab, &in_progress_fstab,
3923 sizeof (struct zone_fstab));
3924 return;
3925 case RT_NET:
3926 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3927 != Z_OK) {
3928 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3929 global_scope = B_TRUE;
3931 bcopy(&old_nwiftab, &in_progress_nwiftab,
3932 sizeof (struct zone_nwiftab));
3933 return;
3934 case RT_DEVICE:
3935 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3936 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3937 global_scope = B_TRUE;
3939 bcopy(&old_devtab, &in_progress_devtab,
3940 sizeof (struct zone_devtab));
3941 return;
3942 case RT_RCTL:
3943 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3944 != Z_OK) {
3945 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3946 global_scope = B_TRUE;
3948 bcopy(&old_rctltab, &in_progress_rctltab,
3949 sizeof (struct zone_rctltab));
3950 return;
3951 case RT_ATTR:
3952 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3953 != Z_OK) {
3954 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3955 global_scope = B_TRUE;
3957 bcopy(&old_attrtab, &in_progress_attrtab,
3958 sizeof (struct zone_attrtab));
3959 return;
3960 case RT_DATASET:
3961 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3962 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3963 global_scope = B_TRUE;
3965 bcopy(&old_dstab, &in_progress_dstab,
3966 sizeof (struct zone_dstab));
3967 return;
3968 case RT_DCPU:
3969 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3970 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3971 global_scope = B_TRUE;
3973 bcopy(&old_psettab, &in_progress_psettab,
3974 sizeof (struct zone_psettab));
3975 return;
3976 case RT_PCAP:
3977 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3978 != Z_OK) {
3979 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3980 global_scope = B_TRUE;
3982 return;
3983 case RT_MCAP:
3984 /* if none of these exist, there is no resource to select */
3985 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3986 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3987 != Z_OK &&
3988 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3989 != Z_OK) {
3990 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3991 B_TRUE);
3992 global_scope = B_TRUE;
3994 if (res == Z_OK)
3995 bcopy(&old_mcaptab, &in_progress_mcaptab,
3996 sizeof (struct zone_mcaptab));
3997 else
3998 bzero(&in_progress_mcaptab,
3999 sizeof (in_progress_mcaptab));
4000 return;
4001 case RT_ADMIN:
4002 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
4003 != Z_OK) {
4004 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
4005 B_TRUE);
4006 global_scope = B_TRUE;
4008 bcopy(&old_admintab, &in_progress_admintab,
4009 sizeof (struct zone_admintab));
4010 return;
4011 case RT_SECFLAGS:
4012 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
4013 != Z_OK) {
4014 z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
4015 B_TRUE);
4016 global_scope = B_TRUE;
4018 bcopy(&old_secflagstab, &in_progress_secflagstab,
4019 sizeof (struct zone_secflagstab));
4020 return;
4021 default:
4022 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
4023 long_usage(CMD_SELECT, B_TRUE);
4024 usage(B_FALSE, HELP_RESOURCES);
4025 return;
4030 * Network "addresses" can be one of the following forms:
4031 * <IPv4 address>
4032 * <IPv4 address>/<prefix length>
4033 * <IPv6 address>/<prefix length>
4034 * <host name>
4035 * <host name>/<prefix length>
4036 * In other words, the "/" followed by a prefix length is allowed but not
4037 * required for IPv4 addresses and host names, and required for IPv6 addresses.
4038 * If a prefix length is given, it must be in the allowable range: 0 to 32 for
4039 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
4040 * Host names must start with an alpha-numeric character, and all subsequent
4041 * characters must be either alpha-numeric or "-".
4043 * In some cases, e.g., the nexthop for the defrouter, the context indicates
4044 * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
4045 * require the /<prefix length> (and should ignore it if provided).
4048 static int
4049 validate_net_address_syntax(char *address, boolean_t ishost)
4051 char *slashp, part1[MAXHOSTNAMELEN];
4052 struct in6_addr in6;
4053 struct in_addr in4;
4054 int prefixlen, i;
4057 * Copy the part before any '/' into part1 or copy the whole
4058 * thing if there is no '/'.
4060 if ((slashp = strchr(address, '/')) != NULL) {
4061 *slashp = '\0';
4062 (void) strlcpy(part1, address, sizeof (part1));
4063 *slashp = '/';
4064 prefixlen = atoi(++slashp);
4065 } else {
4066 (void) strlcpy(part1, address, sizeof (part1));
4069 if (ishost && slashp != NULL) {
4070 zerr(gettext("Warning: prefix length in %s is not required and "
4071 "will be ignored. The default host-prefix length "
4072 "will be used"), address);
4076 if (inet_pton(AF_INET6, part1, &in6) == 1) {
4077 if (ishost) {
4078 prefixlen = IPV6_ABITS;
4079 } else if (slashp == NULL) {
4080 zerr(gettext("%s: IPv6 addresses "
4081 "require /prefix-length suffix."), address);
4082 return (Z_ERR);
4084 if (prefixlen < 0 || prefixlen > 128) {
4085 zerr(gettext("%s: IPv6 address "
4086 "prefix lengths must be 0 - 128."), address);
4087 return (Z_ERR);
4089 return (Z_OK);
4092 /* At this point, any /prefix must be for IPv4. */
4093 if (ishost)
4094 prefixlen = IPV4_ABITS;
4095 else if (slashp != NULL) {
4096 if (prefixlen < 0 || prefixlen > 32) {
4097 zerr(gettext("%s: IPv4 address "
4098 "prefix lengths must be 0 - 32."), address);
4099 return (Z_ERR);
4103 if (inet_pton(AF_INET, part1, &in4) == 1)
4104 return (Z_OK);
4106 /* address may also be a host name */
4107 if (!isalnum(part1[0])) {
4108 zerr(gettext("%s: bogus host name or network address syntax"),
4109 part1);
4110 saw_error = B_TRUE;
4111 usage(B_FALSE, HELP_NETADDR);
4112 return (Z_ERR);
4114 for (i = 1; part1[i]; i++)
4115 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
4116 zerr(gettext("%s: bogus host name or "
4117 "network address syntax"), part1);
4118 saw_error = B_TRUE;
4119 usage(B_FALSE, HELP_NETADDR);
4120 return (Z_ERR);
4122 return (Z_OK);
4125 static int
4126 validate_net_physical_syntax(const char *ifname)
4128 ifspec_t ifnameprop;
4129 zone_iptype_t iptype;
4131 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
4132 zerr(gettext("zone configuration has an invalid or nonexistent "
4133 "ip-type property"));
4134 return (Z_ERR);
4136 switch (iptype) {
4137 case ZS_SHARED:
4138 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
4139 zerr(gettext("%s: invalid physical interface name"),
4140 ifname);
4141 return (Z_ERR);
4143 if (ifnameprop.ifsp_lunvalid) {
4144 zerr(gettext("%s: LUNs not allowed in physical "
4145 "interface names"), ifname);
4146 return (Z_ERR);
4148 break;
4149 case ZS_EXCLUSIVE:
4150 if (dladm_valid_linkname(ifname) == B_FALSE) {
4151 if (strchr(ifname, ':') != NULL)
4152 zerr(gettext("%s: physical interface name "
4153 "required; logical interface name not "
4154 "allowed"), ifname);
4155 else
4156 zerr(gettext("%s: invalid physical interface "
4157 "name"), ifname);
4158 return (Z_ERR);
4160 break;
4162 return (Z_OK);
4165 static boolean_t
4166 valid_fs_type(const char *type)
4169 * Is this a valid path component?
4171 if (strlen(type) + 1 > MAXNAMELEN)
4172 return (B_FALSE);
4174 * Make sure a bad value for "type" doesn't make
4175 * /usr/lib/fs/<type>/mount turn into something else.
4177 if (strchr(type, '/') != NULL || type[0] == '\0' ||
4178 strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4179 return (B_FALSE);
4181 * More detailed verification happens later by zoneadm(1m).
4183 return (B_TRUE);
4186 static boolean_t
4187 allow_exclusive()
4189 brand_handle_t bh;
4190 char brand[MAXNAMELEN];
4191 boolean_t ret;
4193 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4194 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4195 return (B_FALSE);
4197 if ((bh = brand_open(brand)) == NULL) {
4198 zerr("%s: %s\n", zone, gettext("unknown brand."));
4199 return (B_FALSE);
4201 ret = brand_allow_exclusive_ip(bh);
4202 brand_close(bh);
4203 if (!ret)
4204 zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4205 pt_to_str(PT_IPTYPE), "exclusive",
4206 pt_to_str(PT_BRAND), brand);
4207 return (ret);
4210 static void
4211 set_aliased_rctl(char *alias, int prop_type, char *s)
4213 uint64_t limit;
4214 int err;
4215 char tmp[128];
4217 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4218 zerr(gettext("WARNING: Setting a global zone resource "
4219 "control too low could deny\nservice "
4220 "to even the root user; "
4221 "this could render the system impossible\n"
4222 "to administer. Please use caution."));
4224 /* convert memory based properties */
4225 if (prop_type == PT_MAXSHMMEM) {
4226 if (!zonecfg_valid_memlimit(s, &limit)) {
4227 zerr(gettext("A non-negative number with a required "
4228 "scale suffix (K, M, G or T) was expected\nhere."));
4229 saw_error = B_TRUE;
4230 return;
4233 (void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4234 s = tmp;
4237 if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4238 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4239 saw_error = B_TRUE;
4240 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4241 zerr(gettext("%s property is out of range."),
4242 pt_to_str(prop_type));
4243 saw_error = B_TRUE;
4244 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4245 != Z_OK) {
4246 zone_perror(zone, err, B_TRUE);
4247 saw_error = B_TRUE;
4248 } else {
4249 need_to_commit = B_TRUE;
4253 static void
4254 set_in_progress_nwiftab_address(char *prop_id, int prop_type)
4256 if (prop_type == PT_ADDRESS) {
4257 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
4258 sizeof (in_progress_nwiftab.zone_nwif_address));
4259 } else {
4260 assert(prop_type == PT_ALLOWED_ADDRESS);
4261 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
4262 prop_id,
4263 sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
4267 void
4268 set_func(cmd_t *cmd)
4270 char *prop_id;
4271 int arg, err, res_type, prop_type;
4272 property_value_ptr_t pp;
4273 boolean_t autoboot;
4274 zone_iptype_t iptype;
4275 boolean_t force_set = B_FALSE;
4276 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4277 uint64_t mem_cap, mem_limit;
4278 float cap;
4279 char *unitp;
4280 struct zone_psettab tmp_psettab;
4281 boolean_t arg_err = B_FALSE;
4283 if (zone_is_read_only(CMD_SET))
4284 return;
4286 assert(cmd != NULL);
4288 optind = opterr = 0;
4289 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4290 switch (arg) {
4291 case 'F':
4292 force_set = B_TRUE;
4293 break;
4294 default:
4295 if (optopt == '?')
4296 longer_usage(CMD_SET);
4297 else
4298 short_usage(CMD_SET);
4299 arg_err = B_TRUE;
4300 break;
4303 if (arg_err)
4304 return;
4306 prop_type = cmd->cmd_prop_name[0];
4307 if (global_scope) {
4308 if (gz_invalid_property(prop_type)) {
4309 zerr(gettext("%s is not a valid property for the "
4310 "global zone."), pt_to_str(prop_type));
4311 saw_error = B_TRUE;
4312 return;
4315 if (prop_type == PT_ZONENAME) {
4316 res_type = RT_ZONENAME;
4317 } else if (prop_type == PT_ZONEPATH) {
4318 res_type = RT_ZONEPATH;
4319 } else if (prop_type == PT_AUTOBOOT) {
4320 res_type = RT_AUTOBOOT;
4321 } else if (prop_type == PT_BRAND) {
4322 res_type = RT_BRAND;
4323 } else if (prop_type == PT_POOL) {
4324 res_type = RT_POOL;
4325 } else if (prop_type == PT_LIMITPRIV) {
4326 res_type = RT_LIMITPRIV;
4327 } else if (prop_type == PT_BOOTARGS) {
4328 res_type = RT_BOOTARGS;
4329 } else if (prop_type == PT_SCHED) {
4330 res_type = RT_SCHED;
4331 } else if (prop_type == PT_IPTYPE) {
4332 res_type = RT_IPTYPE;
4333 } else if (prop_type == PT_MAXLWPS) {
4334 res_type = RT_MAXLWPS;
4335 } else if (prop_type == PT_MAXPROCS) {
4336 res_type = RT_MAXPROCS;
4337 } else if (prop_type == PT_MAXSHMMEM) {
4338 res_type = RT_MAXSHMMEM;
4339 } else if (prop_type == PT_MAXSHMIDS) {
4340 res_type = RT_MAXSHMIDS;
4341 } else if (prop_type == PT_MAXMSGIDS) {
4342 res_type = RT_MAXMSGIDS;
4343 } else if (prop_type == PT_MAXSEMIDS) {
4344 res_type = RT_MAXSEMIDS;
4345 } else if (prop_type == PT_SHARES) {
4346 res_type = RT_SHARES;
4347 } else if (prop_type == PT_HOSTID) {
4348 res_type = RT_HOSTID;
4349 } else if (prop_type == PT_FS_ALLOWED) {
4350 res_type = RT_FS_ALLOWED;
4351 } else {
4352 zerr(gettext("Cannot set a resource-specific property "
4353 "from the global scope."));
4354 saw_error = B_TRUE;
4355 return;
4357 } else {
4358 res_type = resource_scope;
4361 if (force_set) {
4362 if (res_type != RT_ZONEPATH) {
4363 zerr(gettext("Only zonepath setting can be forced."));
4364 saw_error = B_TRUE;
4365 return;
4367 if (!zonecfg_in_alt_root()) {
4368 zerr(gettext("Zonepath is changeable only in an "
4369 "alternate root."));
4370 saw_error = B_TRUE;
4371 return;
4375 pp = cmd->cmd_property_ptr[0];
4377 * A nasty expression but not that complicated:
4378 * 1. fs options are simple or list (tested below)
4379 * 2. rctl value's are complex or list (tested below)
4380 * Anything else should be simple.
4382 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4383 !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4384 (pp->pv_type != PROP_VAL_SIMPLE ||
4385 (prop_id = pp->pv_simple) == NULL)) {
4386 zerr(gettext("A %s value was expected here."),
4387 pvt_to_str(PROP_VAL_SIMPLE));
4388 saw_error = B_TRUE;
4389 return;
4391 if (prop_type == PT_UNKNOWN) {
4392 long_usage(CMD_SET, B_TRUE);
4393 return;
4397 * Special case: the user can change the zone name prior to 'create';
4398 * if the zone already exists, we fall through letting initialize()
4399 * and the rest of the logic run.
4401 if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4402 !state_atleast(ZONE_STATE_CONFIGURED)) {
4403 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4404 zone_perror(prop_id, err, B_TRUE);
4405 usage(B_FALSE, HELP_SYNTAX);
4406 return;
4408 (void) strlcpy(zone, prop_id, sizeof (zone));
4409 return;
4412 if (initialize(B_TRUE) != Z_OK)
4413 return;
4415 switch (res_type) {
4416 case RT_ZONENAME:
4417 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4419 * Use prop_id instead of 'zone' here, since we're
4420 * reporting a problem about the *new* zonename.
4422 zone_perror(prop_id, err, B_TRUE);
4423 usage(B_FALSE, HELP_SYNTAX);
4424 } else {
4425 need_to_commit = B_TRUE;
4426 (void) strlcpy(zone, prop_id, sizeof (zone));
4428 return;
4429 case RT_ZONEPATH:
4430 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4431 zerr(gettext("Zone %s already installed; %s %s not "
4432 "allowed."), zone, cmd_to_str(CMD_SET),
4433 rt_to_str(RT_ZONEPATH));
4434 return;
4436 if (validate_zonepath_syntax(prop_id) != Z_OK) {
4437 saw_error = B_TRUE;
4438 return;
4440 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4441 zone_perror(zone, err, B_TRUE);
4442 else
4443 need_to_commit = B_TRUE;
4444 return;
4445 case RT_BRAND:
4446 if (state_atleast(ZONE_STATE_INSTALLED)) {
4447 zerr(gettext("Zone %s already installed; %s %s not "
4448 "allowed."), zone, cmd_to_str(CMD_SET),
4449 rt_to_str(RT_BRAND));
4450 return;
4452 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4453 zone_perror(zone, err, B_TRUE);
4454 else
4455 need_to_commit = B_TRUE;
4456 return;
4457 case RT_AUTOBOOT:
4458 if (strcmp(prop_id, "true") == 0) {
4459 autoboot = B_TRUE;
4460 } else if (strcmp(prop_id, "false") == 0) {
4461 autoboot = B_FALSE;
4462 } else {
4463 zerr(gettext("%s value must be '%s' or '%s'."),
4464 pt_to_str(PT_AUTOBOOT), "true", "false");
4465 saw_error = B_TRUE;
4466 return;
4468 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4469 zone_perror(zone, err, B_TRUE);
4470 else
4471 need_to_commit = B_TRUE;
4472 return;
4473 case RT_POOL:
4474 /* don't allow use of the reserved temporary pool names */
4475 if (strncmp("SUNW", prop_id, 4) == 0) {
4476 zerr(gettext("pool names starting with SUNW are "
4477 "reserved."));
4478 saw_error = B_TRUE;
4479 return;
4482 /* can't set pool if dedicated-cpu exists */
4483 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4484 zerr(gettext("The %s resource already exists. "
4485 "A persistent pool is incompatible\nwith the %s "
4486 "resource."), rt_to_str(RT_DCPU),
4487 rt_to_str(RT_DCPU));
4488 saw_error = B_TRUE;
4489 return;
4492 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4493 zone_perror(zone, err, B_TRUE);
4494 else
4495 need_to_commit = B_TRUE;
4496 return;
4497 case RT_LIMITPRIV:
4498 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4499 zone_perror(zone, err, B_TRUE);
4500 else
4501 need_to_commit = B_TRUE;
4502 return;
4503 case RT_BOOTARGS:
4504 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4505 zone_perror(zone, err, B_TRUE);
4506 else
4507 need_to_commit = B_TRUE;
4508 return;
4509 case RT_SCHED:
4510 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4511 zone_perror(zone, err, B_TRUE);
4512 else
4513 need_to_commit = B_TRUE;
4514 return;
4515 case RT_IPTYPE:
4516 if (strcmp(prop_id, "shared") == 0) {
4517 iptype = ZS_SHARED;
4518 } else if (strcmp(prop_id, "exclusive") == 0) {
4519 iptype = ZS_EXCLUSIVE;
4520 } else {
4521 zerr(gettext("%s value must be '%s' or '%s'."),
4522 pt_to_str(PT_IPTYPE), "shared", "exclusive");
4523 saw_error = B_TRUE;
4524 return;
4526 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4527 saw_error = B_TRUE;
4528 return;
4530 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4531 zone_perror(zone, err, B_TRUE);
4532 else
4533 need_to_commit = B_TRUE;
4534 return;
4535 case RT_MAXLWPS:
4536 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4537 return;
4538 case RT_MAXPROCS:
4539 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id);
4540 return;
4541 case RT_MAXSHMMEM:
4542 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4543 return;
4544 case RT_MAXSHMIDS:
4545 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4546 return;
4547 case RT_MAXMSGIDS:
4548 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4549 return;
4550 case RT_MAXSEMIDS:
4551 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4552 return;
4553 case RT_SHARES:
4554 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4555 return;
4556 case RT_HOSTID:
4557 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4558 if (err == Z_TOO_BIG) {
4559 zerr(gettext("hostid string is too large: %s"),
4560 prop_id);
4561 saw_error = B_TRUE;
4562 } else {
4563 zone_perror(pt_to_str(prop_type), err, B_TRUE);
4565 return;
4567 need_to_commit = B_TRUE;
4568 return;
4569 case RT_FS_ALLOWED:
4570 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4571 zone_perror(zone, err, B_TRUE);
4572 else
4573 need_to_commit = B_TRUE;
4574 return;
4575 case RT_FS:
4576 switch (prop_type) {
4577 case PT_DIR:
4578 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4579 sizeof (in_progress_fstab.zone_fs_dir));
4580 return;
4581 case PT_SPECIAL:
4582 (void) strlcpy(in_progress_fstab.zone_fs_special,
4583 prop_id,
4584 sizeof (in_progress_fstab.zone_fs_special));
4585 return;
4586 case PT_RAW:
4587 (void) strlcpy(in_progress_fstab.zone_fs_raw,
4588 prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4589 return;
4590 case PT_TYPE:
4591 if (!valid_fs_type(prop_id)) {
4592 zerr(gettext("\"%s\" is not a valid %s."),
4593 prop_id, pt_to_str(PT_TYPE));
4594 saw_error = B_TRUE;
4595 return;
4597 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4598 sizeof (in_progress_fstab.zone_fs_type));
4599 return;
4600 case PT_OPTIONS:
4601 if (pp->pv_type != PROP_VAL_SIMPLE &&
4602 pp->pv_type != PROP_VAL_LIST) {
4603 zerr(gettext("A %s or %s value was expected "
4604 "here."), pvt_to_str(PROP_VAL_SIMPLE),
4605 pvt_to_str(PROP_VAL_LIST));
4606 saw_error = B_TRUE;
4607 return;
4609 zonecfg_free_fs_option_list(
4610 in_progress_fstab.zone_fs_options);
4611 in_progress_fstab.zone_fs_options = NULL;
4612 if (!(pp->pv_type == PROP_VAL_LIST &&
4613 pp->pv_list == NULL))
4614 add_property(cmd);
4615 return;
4616 default:
4617 break;
4619 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4620 long_usage(CMD_SET, B_TRUE);
4621 usage(B_FALSE, HELP_PROPS);
4622 return;
4623 case RT_NET:
4624 switch (prop_type) {
4625 case PT_ADDRESS:
4626 case PT_ALLOWED_ADDRESS:
4627 if (validate_net_address_syntax(prop_id, B_FALSE)
4628 != Z_OK) {
4629 saw_error = B_TRUE;
4630 return;
4632 set_in_progress_nwiftab_address(prop_id, prop_type);
4633 break;
4634 case PT_PHYSICAL:
4635 if (validate_net_physical_syntax(prop_id) != Z_OK) {
4636 saw_error = B_TRUE;
4637 return;
4639 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4640 prop_id,
4641 sizeof (in_progress_nwiftab.zone_nwif_physical));
4642 break;
4643 case PT_DEFROUTER:
4644 if (validate_net_address_syntax(prop_id, B_TRUE)
4645 != Z_OK) {
4646 saw_error = B_TRUE;
4647 return;
4649 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4650 prop_id,
4651 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4652 break;
4653 default:
4654 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4655 B_TRUE);
4656 long_usage(CMD_SET, B_TRUE);
4657 usage(B_FALSE, HELP_PROPS);
4658 return;
4660 return;
4661 case RT_DEVICE:
4662 switch (prop_type) {
4663 case PT_MATCH:
4664 (void) strlcpy(in_progress_devtab.zone_dev_match,
4665 prop_id,
4666 sizeof (in_progress_devtab.zone_dev_match));
4667 break;
4668 default:
4669 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4670 B_TRUE);
4671 long_usage(CMD_SET, B_TRUE);
4672 usage(B_FALSE, HELP_PROPS);
4673 return;
4675 return;
4676 case RT_RCTL:
4677 switch (prop_type) {
4678 case PT_NAME:
4679 if (!zonecfg_valid_rctlname(prop_id)) {
4680 zerr(gettext("'%s' is not a valid zone %s "
4681 "name."), prop_id, rt_to_str(RT_RCTL));
4682 return;
4684 (void) strlcpy(in_progress_rctltab.zone_rctl_name,
4685 prop_id,
4686 sizeof (in_progress_rctltab.zone_rctl_name));
4687 break;
4688 case PT_VALUE:
4689 if (pp->pv_type != PROP_VAL_COMPLEX &&
4690 pp->pv_type != PROP_VAL_LIST) {
4691 zerr(gettext("A %s or %s value was expected "
4692 "here."), pvt_to_str(PROP_VAL_COMPLEX),
4693 pvt_to_str(PROP_VAL_LIST));
4694 saw_error = B_TRUE;
4695 return;
4697 zonecfg_free_rctl_value_list(
4698 in_progress_rctltab.zone_rctl_valptr);
4699 in_progress_rctltab.zone_rctl_valptr = NULL;
4700 if (!(pp->pv_type == PROP_VAL_LIST &&
4701 pp->pv_list == NULL))
4702 add_property(cmd);
4703 break;
4704 default:
4705 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4706 B_TRUE);
4707 long_usage(CMD_SET, B_TRUE);
4708 usage(B_FALSE, HELP_PROPS);
4709 return;
4711 return;
4712 case RT_ATTR:
4713 switch (prop_type) {
4714 case PT_NAME:
4715 (void) strlcpy(in_progress_attrtab.zone_attr_name,
4716 prop_id,
4717 sizeof (in_progress_attrtab.zone_attr_name));
4718 break;
4719 case PT_TYPE:
4720 (void) strlcpy(in_progress_attrtab.zone_attr_type,
4721 prop_id,
4722 sizeof (in_progress_attrtab.zone_attr_type));
4723 break;
4724 case PT_VALUE:
4725 (void) strlcpy(in_progress_attrtab.zone_attr_value,
4726 prop_id,
4727 sizeof (in_progress_attrtab.zone_attr_value));
4728 break;
4729 default:
4730 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4731 B_TRUE);
4732 long_usage(CMD_SET, B_TRUE);
4733 usage(B_FALSE, HELP_PROPS);
4734 return;
4736 return;
4737 case RT_DATASET:
4738 switch (prop_type) {
4739 case PT_NAME:
4740 (void) strlcpy(in_progress_dstab.zone_dataset_name,
4741 prop_id,
4742 sizeof (in_progress_dstab.zone_dataset_name));
4743 return;
4744 default:
4745 break;
4747 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4748 long_usage(CMD_SET, B_TRUE);
4749 usage(B_FALSE, HELP_PROPS);
4750 return;
4751 case RT_DCPU:
4752 switch (prop_type) {
4753 char *lowp, *highp;
4755 case PT_NCPUS:
4756 lowp = prop_id;
4757 if ((highp = strchr(prop_id, '-')) != NULL)
4758 *highp++ = '\0';
4759 else
4760 highp = lowp;
4762 /* Make sure the input makes sense. */
4763 if (!zonecfg_valid_ncpus(lowp, highp)) {
4764 zerr(gettext("%s property is out of range."),
4765 pt_to_str(PT_NCPUS));
4766 saw_error = B_TRUE;
4767 return;
4770 (void) strlcpy(
4771 in_progress_psettab.zone_ncpu_min, lowp,
4772 sizeof (in_progress_psettab.zone_ncpu_min));
4773 (void) strlcpy(
4774 in_progress_psettab.zone_ncpu_max, highp,
4775 sizeof (in_progress_psettab.zone_ncpu_max));
4776 return;
4777 case PT_IMPORTANCE:
4778 /* Make sure the value makes sense. */
4779 if (!zonecfg_valid_importance(prop_id)) {
4780 zerr(gettext("%s property is out of range."),
4781 pt_to_str(PT_IMPORTANCE));
4782 saw_error = B_TRUE;
4783 return;
4786 (void) strlcpy(in_progress_psettab.zone_importance,
4787 prop_id,
4788 sizeof (in_progress_psettab.zone_importance));
4789 return;
4790 default:
4791 break;
4793 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4794 long_usage(CMD_SET, B_TRUE);
4795 usage(B_FALSE, HELP_PROPS);
4796 return;
4797 case RT_PCAP:
4798 if (prop_type != PT_NCPUS) {
4799 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4800 B_TRUE);
4801 long_usage(CMD_SET, B_TRUE);
4802 usage(B_FALSE, HELP_PROPS);
4803 return;
4807 * We already checked that an rctl alias is allowed in
4808 * the add_resource() function.
4811 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4812 (int)(cap * 100) < 1) {
4813 zerr(gettext("%s property is out of range."),
4814 pt_to_str(PT_NCPUS));
4815 saw_error = B_TRUE;
4816 return;
4819 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4820 (int)(cap * 100))) != Z_OK)
4821 zone_perror(zone, err, B_TRUE);
4822 else
4823 need_to_commit = B_TRUE;
4824 return;
4825 case RT_MCAP:
4826 switch (prop_type) {
4827 case PT_PHYSICAL:
4828 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4829 zerr(gettext("A positive number with a "
4830 "required scale suffix (K, M, G or T) was "
4831 "expected here."));
4832 saw_error = B_TRUE;
4833 } else if (mem_cap < ONE_MB) {
4834 zerr(gettext("%s value is too small. It must "
4835 "be at least 1M."), pt_to_str(PT_PHYSICAL));
4836 saw_error = B_TRUE;
4837 } else {
4838 snprintf(in_progress_mcaptab.zone_physmem_cap,
4839 physmem_size, "%llu", mem_cap);
4841 break;
4842 case PT_SWAP:
4844 * We have to check if an rctl is allowed here since
4845 * there might already be a rctl defined that blocks
4846 * the alias.
4848 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4849 zone_perror(pt_to_str(PT_MAXSWAP),
4850 Z_ALIAS_DISALLOW, B_FALSE);
4851 saw_error = B_TRUE;
4852 return;
4855 if (global_zone)
4856 mem_limit = ONE_MB * 100;
4857 else
4858 mem_limit = ONE_MB * 50;
4860 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4861 zerr(gettext("A positive number with a "
4862 "required scale suffix (K, M, G or T) was "
4863 "expected here."));
4864 saw_error = B_TRUE;
4865 } else if (mem_cap < mem_limit) {
4866 char buf[128];
4868 (void) snprintf(buf, sizeof (buf), "%llu",
4869 mem_limit);
4870 bytes_to_units(buf, buf, sizeof (buf));
4871 zerr(gettext("%s value is too small. It must "
4872 "be at least %s."), pt_to_str(PT_SWAP),
4873 buf);
4874 saw_error = B_TRUE;
4875 } else {
4876 if ((err = zonecfg_set_aliased_rctl(handle,
4877 ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4878 zone_perror(zone, err, B_TRUE);
4879 else
4880 need_to_commit = B_TRUE;
4882 break;
4883 case PT_LOCKED:
4885 * We have to check if an rctl is allowed here since
4886 * there might already be a rctl defined that blocks
4887 * the alias.
4889 if (!zonecfg_aliased_rctl_ok(handle,
4890 ALIAS_MAXLOCKEDMEM)) {
4891 zone_perror(pt_to_str(PT_LOCKED),
4892 Z_ALIAS_DISALLOW, B_FALSE);
4893 saw_error = B_TRUE;
4894 return;
4897 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4898 zerr(gettext("A non-negative number with a "
4899 "required scale suffix (K, M, G or T) was "
4900 "expected\nhere."));
4901 saw_error = B_TRUE;
4902 } else {
4903 if ((err = zonecfg_set_aliased_rctl(handle,
4904 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4905 zone_perror(zone, err, B_TRUE);
4906 else
4907 need_to_commit = B_TRUE;
4909 break;
4910 default:
4911 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4912 B_TRUE);
4913 long_usage(CMD_SET, B_TRUE);
4914 usage(B_FALSE, HELP_PROPS);
4915 return;
4917 return;
4918 case RT_ADMIN:
4919 switch (prop_type) {
4920 case PT_USER:
4921 (void) strlcpy(in_progress_admintab.zone_admin_user,
4922 prop_id,
4923 sizeof (in_progress_admintab.zone_admin_user));
4924 return;
4925 case PT_AUTHS:
4926 (void) strlcpy(in_progress_admintab.zone_admin_auths,
4927 prop_id,
4928 sizeof (in_progress_admintab.zone_admin_auths));
4929 return;
4930 default:
4931 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4932 B_TRUE);
4933 long_usage(CMD_SET, B_TRUE);
4934 usage(B_FALSE, HELP_PROPS);
4935 return;
4937 case RT_SECFLAGS: {
4938 char *propstr;
4940 switch (prop_type) {
4941 case PT_DEFAULT:
4942 propstr = in_progress_secflagstab.zone_secflags_default;
4943 break;
4944 case PT_UPPER:
4945 propstr = in_progress_secflagstab.zone_secflags_upper;
4946 break;
4947 case PT_LOWER:
4948 propstr = in_progress_secflagstab.zone_secflags_lower;
4949 break;
4950 default:
4951 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4952 B_TRUE);
4953 long_usage(CMD_SET, B_TRUE);
4954 usage(B_FALSE, HELP_PROPS);
4955 return;
4957 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
4958 return;
4960 default:
4961 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4962 long_usage(CMD_SET, B_TRUE);
4963 usage(B_FALSE, HELP_RESOURCES);
4964 return;
4968 static void
4969 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4971 char *qstr;
4973 if (*pval != '\0') {
4974 qstr = quoteit(pval);
4975 if (pnum == PT_SWAP || pnum == PT_LOCKED)
4976 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4977 qstr);
4978 else
4979 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4980 free(qstr);
4981 } else if (print_notspec)
4982 (void) fprintf(fp, gettext("\t%s not specified\n"),
4983 pt_to_str(pnum));
4986 static void
4987 info_zonename(zone_dochandle_t handle, FILE *fp)
4989 char zonename[ZONENAME_MAX];
4991 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4992 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4993 zonename);
4994 else
4995 (void) fprintf(fp, gettext("%s not specified\n"),
4996 pt_to_str(PT_ZONENAME));
4999 static void
5000 info_zonepath(zone_dochandle_t handle, FILE *fp)
5002 char zonepath[MAXPATHLEN];
5004 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
5005 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
5006 zonepath);
5007 else {
5008 (void) fprintf(fp, gettext("%s not specified\n"),
5009 pt_to_str(PT_ZONEPATH));
5013 static void
5014 info_brand(zone_dochandle_t handle, FILE *fp)
5016 char brand[MAXNAMELEN];
5018 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
5019 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
5020 brand);
5021 else
5022 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
5023 gettext("not specified"));
5026 static void
5027 info_autoboot(zone_dochandle_t handle, FILE *fp)
5029 boolean_t autoboot;
5030 int err;
5032 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
5033 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
5034 autoboot ? "true" : "false");
5035 else
5036 zone_perror(zone, err, B_TRUE);
5039 static void
5040 info_pool(zone_dochandle_t handle, FILE *fp)
5042 char pool[MAXNAMELEN];
5043 int err;
5045 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
5046 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
5047 else
5048 zone_perror(zone, err, B_TRUE);
5051 static void
5052 info_limitpriv(zone_dochandle_t handle, FILE *fp)
5054 char *limitpriv;
5055 int err;
5057 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
5058 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
5059 limitpriv);
5060 free(limitpriv);
5061 } else {
5062 zone_perror(zone, err, B_TRUE);
5066 static void
5067 info_bootargs(zone_dochandle_t handle, FILE *fp)
5069 char bootargs[BOOTARGS_MAX];
5070 int err;
5072 if ((err = zonecfg_get_bootargs(handle, bootargs,
5073 sizeof (bootargs))) == Z_OK) {
5074 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
5075 bootargs);
5076 } else {
5077 zone_perror(zone, err, B_TRUE);
5081 static void
5082 info_sched(zone_dochandle_t handle, FILE *fp)
5084 char sched[MAXNAMELEN];
5085 int err;
5087 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
5088 == Z_OK) {
5089 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
5090 } else {
5091 zone_perror(zone, err, B_TRUE);
5095 static void
5096 info_iptype(zone_dochandle_t handle, FILE *fp)
5098 zone_iptype_t iptype;
5099 int err;
5101 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
5102 switch (iptype) {
5103 case ZS_SHARED:
5104 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5105 "shared");
5106 break;
5107 case ZS_EXCLUSIVE:
5108 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5109 "exclusive");
5110 break;
5112 } else {
5113 zone_perror(zone, err, B_TRUE);
5117 static void
5118 info_hostid(zone_dochandle_t handle, FILE *fp)
5120 char hostidp[HW_HOSTID_LEN];
5121 int err;
5123 if ((err = zonecfg_get_hostid(handle, hostidp,
5124 sizeof (hostidp))) == Z_OK) {
5125 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
5126 } else if (err == Z_BAD_PROPERTY) {
5127 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
5128 } else {
5129 zone_perror(zone, err, B_TRUE);
5133 static void
5134 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
5136 char fsallowedp[ZONE_FS_ALLOWED_MAX];
5137 int err;
5139 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
5140 sizeof (fsallowedp))) == Z_OK) {
5141 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
5142 fsallowedp);
5143 } else if (err == Z_BAD_PROPERTY) {
5144 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
5145 } else {
5146 zone_perror(zone, err, B_TRUE);
5150 static void
5151 output_fs(FILE *fp, struct zone_fstab *fstab)
5153 zone_fsopt_t *this;
5155 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
5156 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
5157 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
5158 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
5159 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
5160 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
5161 for (this = fstab->zone_fs_options; this != NULL;
5162 this = this->zone_fsopt_next) {
5163 if (strchr(this->zone_fsopt_opt, '='))
5164 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
5165 else
5166 (void) fprintf(fp, "%s", this->zone_fsopt_opt);
5167 if (this->zone_fsopt_next != NULL)
5168 (void) fprintf(fp, ",");
5170 (void) fprintf(fp, "]\n");
5173 static void
5174 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5176 struct zone_fstab lookup, user;
5177 boolean_t output = B_FALSE;
5179 if (zonecfg_setfsent(handle) != Z_OK)
5180 return;
5181 while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
5182 if (cmd->cmd_prop_nv_pairs == 0) {
5183 output_fs(fp, &lookup);
5184 goto loopend;
5186 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
5187 goto loopend;
5188 if (strlen(user.zone_fs_dir) > 0 &&
5189 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5190 goto loopend; /* no match */
5191 if (strlen(user.zone_fs_special) > 0 &&
5192 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5193 goto loopend; /* no match */
5194 if (strlen(user.zone_fs_type) > 0 &&
5195 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5196 goto loopend; /* no match */
5197 output_fs(fp, &lookup);
5198 output = B_TRUE;
5199 loopend:
5200 zonecfg_free_fs_option_list(lookup.zone_fs_options);
5202 (void) zonecfg_endfsent(handle);
5204 * If a property n/v pair was specified, warn the user if there was
5205 * nothing to output.
5207 if (!output && cmd->cmd_prop_nv_pairs > 0)
5208 (void) printf(gettext("No such %s resource.\n"),
5209 rt_to_str(RT_FS));
5212 static void
5213 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5215 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5216 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5217 output_prop(fp, PT_ALLOWED_ADDRESS,
5218 nwiftab->zone_nwif_allowed_address, B_TRUE);
5219 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5220 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5223 static void
5224 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5226 struct zone_nwiftab lookup, user;
5227 boolean_t output = B_FALSE;
5229 if (zonecfg_setnwifent(handle) != Z_OK)
5230 return;
5231 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5232 if (cmd->cmd_prop_nv_pairs == 0) {
5233 output_net(fp, &lookup);
5234 continue;
5236 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5237 continue;
5238 if (strlen(user.zone_nwif_physical) > 0 &&
5239 strcmp(user.zone_nwif_physical,
5240 lookup.zone_nwif_physical) != 0)
5241 continue; /* no match */
5242 /* If present make sure it matches */
5243 if (strlen(user.zone_nwif_address) > 0 &&
5244 !zonecfg_same_net_address(user.zone_nwif_address,
5245 lookup.zone_nwif_address))
5246 continue; /* no match */
5247 output_net(fp, &lookup);
5248 output = B_TRUE;
5250 (void) zonecfg_endnwifent(handle);
5252 * If a property n/v pair was specified, warn the user if there was
5253 * nothing to output.
5255 if (!output && cmd->cmd_prop_nv_pairs > 0)
5256 (void) printf(gettext("No such %s resource.\n"),
5257 rt_to_str(RT_NET));
5260 static void
5261 output_dev(FILE *fp, struct zone_devtab *devtab)
5263 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5264 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5267 static void
5268 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5270 struct zone_devtab lookup, user;
5271 boolean_t output = B_FALSE;
5273 if (zonecfg_setdevent(handle) != Z_OK)
5274 return;
5275 while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5276 if (cmd->cmd_prop_nv_pairs == 0) {
5277 output_dev(fp, &lookup);
5278 continue;
5280 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5281 continue;
5282 if (strlen(user.zone_dev_match) > 0 &&
5283 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5284 continue; /* no match */
5285 output_dev(fp, &lookup);
5286 output = B_TRUE;
5288 (void) zonecfg_enddevent(handle);
5290 * If a property n/v pair was specified, warn the user if there was
5291 * nothing to output.
5293 if (!output && cmd->cmd_prop_nv_pairs > 0)
5294 (void) printf(gettext("No such %s resource.\n"),
5295 rt_to_str(RT_DEVICE));
5298 static void
5299 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5301 struct zone_rctlvaltab *valptr;
5303 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5304 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5305 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5306 valptr = valptr->zone_rctlval_next) {
5307 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5308 pt_to_str(PT_VALUE),
5309 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5310 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5311 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5315 static void
5316 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5318 struct zone_rctltab lookup, user;
5319 boolean_t output = B_FALSE;
5321 if (zonecfg_setrctlent(handle) != Z_OK)
5322 return;
5323 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5324 if (cmd->cmd_prop_nv_pairs == 0) {
5325 output_rctl(fp, &lookup);
5326 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5327 (strlen(user.zone_rctl_name) == 0 ||
5328 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5329 output_rctl(fp, &lookup);
5330 output = B_TRUE;
5332 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5334 (void) zonecfg_endrctlent(handle);
5336 * If a property n/v pair was specified, warn the user if there was
5337 * nothing to output.
5339 if (!output && cmd->cmd_prop_nv_pairs > 0)
5340 (void) printf(gettext("No such %s resource.\n"),
5341 rt_to_str(RT_RCTL));
5344 static void
5345 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5347 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5348 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5349 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5350 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5353 static void
5354 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5356 struct zone_attrtab lookup, user;
5357 boolean_t output = B_FALSE;
5359 if (zonecfg_setattrent(handle) != Z_OK)
5360 return;
5361 while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5362 if (cmd->cmd_prop_nv_pairs == 0) {
5363 output_attr(fp, &lookup);
5364 continue;
5366 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5367 continue;
5368 if (strlen(user.zone_attr_name) > 0 &&
5369 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5370 continue; /* no match */
5371 if (strlen(user.zone_attr_type) > 0 &&
5372 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5373 continue; /* no match */
5374 if (strlen(user.zone_attr_value) > 0 &&
5375 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5376 continue; /* no match */
5377 output_attr(fp, &lookup);
5378 output = B_TRUE;
5380 (void) zonecfg_endattrent(handle);
5382 * If a property n/v pair was specified, warn the user if there was
5383 * nothing to output.
5385 if (!output && cmd->cmd_prop_nv_pairs > 0)
5386 (void) printf(gettext("No such %s resource.\n"),
5387 rt_to_str(RT_ATTR));
5390 static void
5391 output_ds(FILE *fp, struct zone_dstab *dstab)
5393 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5394 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5397 static void
5398 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5400 struct zone_dstab lookup, user;
5401 boolean_t output = B_FALSE;
5403 if (zonecfg_setdsent(handle) != Z_OK)
5404 return;
5405 while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5406 if (cmd->cmd_prop_nv_pairs == 0) {
5407 output_ds(fp, &lookup);
5408 continue;
5410 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5411 continue;
5412 if (strlen(user.zone_dataset_name) > 0 &&
5413 strcmp(user.zone_dataset_name,
5414 lookup.zone_dataset_name) != 0)
5415 continue; /* no match */
5416 output_ds(fp, &lookup);
5417 output = B_TRUE;
5419 (void) zonecfg_enddsent(handle);
5421 * If a property n/v pair was specified, warn the user if there was
5422 * nothing to output.
5424 if (!output && cmd->cmd_prop_nv_pairs > 0)
5425 (void) printf(gettext("No such %s resource.\n"),
5426 rt_to_str(RT_DATASET));
5429 static void
5430 output_pset(FILE *fp, struct zone_psettab *psettab)
5432 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5433 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5434 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5435 psettab->zone_ncpu_max);
5436 else
5437 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5438 psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5439 if (psettab->zone_importance[0] != '\0')
5440 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5441 psettab->zone_importance);
5444 static void
5445 info_pset(zone_dochandle_t handle, FILE *fp)
5447 struct zone_psettab lookup;
5449 if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5450 output_pset(fp, &lookup);
5453 static void
5454 output_pcap(FILE *fp)
5456 uint64_t cap;
5458 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5459 float scaled = (float)cap / 100;
5460 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5461 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5462 scaled);
5466 static void
5467 info_pcap(FILE *fp)
5469 output_pcap(fp);
5473 static void
5474 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5476 uint64_t limit;
5478 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5479 /* convert memory based properties */
5480 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5481 char buf[128];
5483 (void) snprintf(buf, sizeof (buf), "%llu", limit);
5484 bytes_to_units(buf, buf, sizeof (buf));
5485 (void) fprintf(fp, "[%s: %s]\n", alias, buf);
5486 return;
5489 (void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5493 static void
5494 bytes_to_units(char *str, char *buf, int bufsize)
5496 unsigned long long num;
5497 unsigned long long save = 0;
5498 char *units = "BKMGT";
5499 char *up = units;
5501 num = strtoll(str, NULL, 10);
5503 if (num < 1024) {
5504 (void) snprintf(buf, bufsize, "%llu", num);
5505 return;
5508 while ((num >= 1024) && (*up != 'T')) {
5509 up++; /* next unit of measurement */
5510 save = num;
5511 num = (num + 512) >> 10;
5514 /* check if we should output a fraction. snprintf will round for us */
5515 if (save % 1024 != 0 && ((save >> 10) < 10))
5516 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5517 *up);
5518 else
5519 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
5522 static void
5523 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5524 uint64_t maxswap, int showlocked, uint64_t maxlocked)
5526 char buf[128];
5528 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5529 if (mcaptab->zone_physmem_cap[0] != '\0') {
5530 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5531 output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5534 if (showswap == Z_OK) {
5535 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5536 bytes_to_units(buf, buf, sizeof (buf));
5537 output_prop(fp, PT_SWAP, buf, B_TRUE);
5540 if (showlocked == Z_OK) {
5541 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5542 bytes_to_units(buf, buf, sizeof (buf));
5543 output_prop(fp, PT_LOCKED, buf, B_TRUE);
5547 static void
5548 info_mcap(zone_dochandle_t handle, FILE *fp)
5550 int res1, res2, res3;
5551 uint64_t swap_limit;
5552 uint64_t locked_limit;
5553 struct zone_mcaptab lookup;
5555 bzero(&lookup, sizeof (lookup));
5556 res1 = zonecfg_getmcapent(handle, &lookup);
5557 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5558 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5559 &locked_limit);
5561 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5562 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5565 static void
5566 output_auth(FILE *fp, struct zone_admintab *admintab)
5568 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5569 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5570 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5573 static void
5574 output_secflags(FILE *fp, struct zone_secflagstab *sftab)
5576 (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
5577 output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
5578 output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
5579 output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
5582 static void
5583 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5585 struct zone_admintab lookup, user;
5586 boolean_t output = B_FALSE;
5587 int err;
5589 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5590 zone_perror(zone, err, B_TRUE);
5591 return;
5593 while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5594 if (cmd->cmd_prop_nv_pairs == 0) {
5595 output_auth(fp, &lookup);
5596 continue;
5598 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5599 continue;
5600 if (strlen(user.zone_admin_user) > 0 &&
5601 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5602 continue; /* no match */
5603 output_auth(fp, &lookup);
5604 output = B_TRUE;
5606 (void) zonecfg_endadminent(handle);
5608 * If a property n/v pair was specified, warn the user if there was
5609 * nothing to output.
5611 if (!output && cmd->cmd_prop_nv_pairs > 0)
5612 (void) printf(gettext("No such %s resource.\n"),
5613 rt_to_str(RT_ADMIN));
5616 static void
5617 info_secflags(zone_dochandle_t handle, FILE *fp)
5619 struct zone_secflagstab sftab;
5621 if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) {
5622 output_secflags(fp, &sftab);
5626 void
5627 info_func(cmd_t *cmd)
5629 FILE *fp = stdout;
5630 boolean_t need_to_close = B_FALSE;
5631 int type;
5632 int res1, res2;
5633 uint64_t swap_limit;
5634 uint64_t locked_limit;
5636 assert(cmd != NULL);
5638 if (initialize(B_TRUE) != Z_OK)
5639 return;
5641 /* don't page error output */
5642 if (interactive_mode) {
5643 if ((fp = pager_open()) != NULL)
5644 need_to_close = B_TRUE;
5645 else
5646 fp = stdout;
5648 setbuf(fp, NULL);
5651 if (!global_scope) {
5652 switch (resource_scope) {
5653 case RT_FS:
5654 output_fs(fp, &in_progress_fstab);
5655 break;
5656 case RT_NET:
5657 output_net(fp, &in_progress_nwiftab);
5658 break;
5659 case RT_DEVICE:
5660 output_dev(fp, &in_progress_devtab);
5661 break;
5662 case RT_RCTL:
5663 output_rctl(fp, &in_progress_rctltab);
5664 break;
5665 case RT_ATTR:
5666 output_attr(fp, &in_progress_attrtab);
5667 break;
5668 case RT_DATASET:
5669 output_ds(fp, &in_progress_dstab);
5670 break;
5671 case RT_DCPU:
5672 output_pset(fp, &in_progress_psettab);
5673 break;
5674 case RT_PCAP:
5675 output_pcap(fp);
5676 break;
5677 case RT_MCAP:
5678 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5679 &swap_limit);
5680 res2 = zonecfg_get_aliased_rctl(handle,
5681 ALIAS_MAXLOCKEDMEM, &locked_limit);
5682 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5683 res2, locked_limit);
5684 break;
5685 case RT_ADMIN:
5686 output_auth(fp, &in_progress_admintab);
5687 break;
5688 case RT_SECFLAGS:
5689 output_secflags(fp, &in_progress_secflagstab);
5690 break;
5692 goto cleanup;
5695 type = cmd->cmd_res_type;
5697 if (gz_invalid_rt_property(type)) {
5698 zerr(gettext("%s is not a valid property for the global zone."),
5699 rt_to_str(type));
5700 goto cleanup;
5703 if (gz_invalid_resource(type)) {
5704 zerr(gettext("%s is not a valid resource for the global zone."),
5705 rt_to_str(type));
5706 goto cleanup;
5709 switch (cmd->cmd_res_type) {
5710 case RT_UNKNOWN:
5711 info_zonename(handle, fp);
5712 if (!global_zone) {
5713 info_zonepath(handle, fp);
5714 info_brand(handle, fp);
5715 info_autoboot(handle, fp);
5716 info_bootargs(handle, fp);
5718 info_pool(handle, fp);
5719 if (!global_zone) {
5720 info_limitpriv(handle, fp);
5721 info_sched(handle, fp);
5722 info_iptype(handle, fp);
5723 info_hostid(handle, fp);
5724 info_fs_allowed(handle, fp);
5726 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5727 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5728 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5729 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5730 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5731 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5732 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5733 if (!global_zone) {
5734 info_fs(handle, fp, cmd);
5735 info_net(handle, fp, cmd);
5736 info_dev(handle, fp, cmd);
5738 info_pset(handle, fp);
5739 info_pcap(fp);
5740 info_mcap(handle, fp);
5741 if (!global_zone) {
5742 info_attr(handle, fp, cmd);
5743 info_ds(handle, fp, cmd);
5744 info_auth(handle, fp, cmd);
5746 info_rctl(handle, fp, cmd);
5747 info_secflags(handle, fp);
5748 break;
5749 case RT_ZONENAME:
5750 info_zonename(handle, fp);
5751 break;
5752 case RT_ZONEPATH:
5753 info_zonepath(handle, fp);
5754 break;
5755 case RT_BRAND:
5756 info_brand(handle, fp);
5757 break;
5758 case RT_AUTOBOOT:
5759 info_autoboot(handle, fp);
5760 break;
5761 case RT_POOL:
5762 info_pool(handle, fp);
5763 break;
5764 case RT_LIMITPRIV:
5765 info_limitpriv(handle, fp);
5766 break;
5767 case RT_BOOTARGS:
5768 info_bootargs(handle, fp);
5769 break;
5770 case RT_SCHED:
5771 info_sched(handle, fp);
5772 break;
5773 case RT_IPTYPE:
5774 info_iptype(handle, fp);
5775 break;
5776 case RT_MAXLWPS:
5777 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5778 break;
5779 case RT_MAXPROCS:
5780 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5781 break;
5782 case RT_MAXSHMMEM:
5783 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5784 break;
5785 case RT_MAXSHMIDS:
5786 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5787 break;
5788 case RT_MAXMSGIDS:
5789 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5790 break;
5791 case RT_MAXSEMIDS:
5792 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5793 break;
5794 case RT_SHARES:
5795 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5796 break;
5797 case RT_FS:
5798 info_fs(handle, fp, cmd);
5799 break;
5800 case RT_NET:
5801 info_net(handle, fp, cmd);
5802 break;
5803 case RT_DEVICE:
5804 info_dev(handle, fp, cmd);
5805 break;
5806 case RT_RCTL:
5807 info_rctl(handle, fp, cmd);
5808 break;
5809 case RT_ATTR:
5810 info_attr(handle, fp, cmd);
5811 break;
5812 case RT_DATASET:
5813 info_ds(handle, fp, cmd);
5814 break;
5815 case RT_DCPU:
5816 info_pset(handle, fp);
5817 break;
5818 case RT_PCAP:
5819 info_pcap(fp);
5820 break;
5821 case RT_MCAP:
5822 info_mcap(handle, fp);
5823 break;
5824 case RT_HOSTID:
5825 info_hostid(handle, fp);
5826 break;
5827 case RT_ADMIN:
5828 info_auth(handle, fp, cmd);
5829 break;
5830 case RT_FS_ALLOWED:
5831 info_fs_allowed(handle, fp);
5832 break;
5833 case RT_SECFLAGS:
5834 info_secflags(handle, fp);
5835 break;
5836 default:
5837 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5838 B_TRUE);
5841 cleanup:
5842 if (need_to_close)
5843 (void) pager_close(fp);
5847 * Helper function for verify-- checks that a required string property
5848 * exists.
5850 static void
5851 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5853 if (strlen(attr) == 0) {
5854 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5855 pt_to_str(pt));
5856 saw_error = B_TRUE;
5857 if (*ret_val == Z_OK)
5858 *ret_val = Z_REQD_PROPERTY_MISSING;
5862 static int
5863 do_subproc(char *cmdbuf)
5865 char inbuf[MAX_CMD_LEN];
5866 FILE *file;
5867 int status;
5869 file = popen(cmdbuf, "r");
5870 if (file == NULL) {
5871 zerr(gettext("Could not launch: %s"), cmdbuf);
5872 return (-1);
5875 while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5876 fprintf(stderr, "%s", inbuf);
5877 status = pclose(file);
5879 if (WIFSIGNALED(status)) {
5880 zerr(gettext("%s unexpectedly terminated due to signal %d"),
5881 cmdbuf, WTERMSIG(status));
5882 return (-1);
5884 assert(WIFEXITED(status));
5885 return (WEXITSTATUS(status));
5888 static int
5889 brand_verify(zone_dochandle_t handle)
5891 char xml_file[32];
5892 char cmdbuf[MAX_CMD_LEN];
5893 brand_handle_t bh;
5894 char brand[MAXNAMELEN];
5895 int err;
5897 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5898 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5899 return (Z_INVALID_DOCUMENT);
5901 if ((bh = brand_open(brand)) == NULL) {
5902 zerr("%s: %s\n", zone, gettext("unknown brand."));
5903 return (Z_INVALID_DOCUMENT);
5907 * Fetch the verify command, if any, from the brand configuration
5908 * and build the command line to execute it.
5910 strcpy(cmdbuf, EXEC_PREFIX);
5911 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5912 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5913 brand_close(bh);
5914 if (err != Z_OK) {
5915 zerr("%s: %s\n", zone,
5916 gettext("could not get brand verification command"));
5917 return (Z_INVALID_DOCUMENT);
5921 * If the brand doesn't provide a verification routine, we just
5922 * return success.
5924 if (strlen(cmdbuf) == EXEC_LEN)
5925 return (Z_OK);
5928 * Dump the current config information for this zone to a file.
5930 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5931 if (mkstemp(xml_file) == 0)
5932 return (Z_TEMP_FILE);
5933 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5934 (void) unlink(xml_file);
5935 return (err);
5939 * Execute the verification command.
5941 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5942 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5943 err = Z_BRAND_ERROR;
5944 } else {
5945 err = do_subproc(cmdbuf);
5948 (void) unlink(xml_file);
5949 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5953 * Track the network interfaces listed in zonecfg(1m) in a linked list
5954 * so that we can later check that defrouter is specified for an exclusive IP
5955 * zone if and only if at least one allowed-address has been specified.
5957 static boolean_t
5958 add_nwif(struct zone_nwiftab *nwif)
5960 struct xif *tmp;
5962 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5963 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
5964 if (strlen(nwif->zone_nwif_allowed_address) > 0)
5965 tmp->xif_has_address = B_TRUE;
5966 if (strlen(nwif->zone_nwif_defrouter) > 0)
5967 tmp->xif_has_defrouter = B_TRUE;
5968 return (B_TRUE);
5972 tmp = malloc(sizeof (*tmp));
5973 if (tmp == NULL) {
5974 zerr(gettext("memory allocation failed for %s"),
5975 nwif->zone_nwif_physical);
5976 return (B_FALSE);
5978 strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
5979 sizeof (tmp->xif_name));
5980 tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
5981 tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
5982 tmp->xif_next = xif;
5983 xif = tmp;
5984 return (B_TRUE);
5987 boolean_t
5988 verify_secflags(struct zone_secflagstab *tab)
5990 secflagdelta_t def = {0};
5991 secflagdelta_t upper = {0};
5992 secflagdelta_t lower = {0};
5993 boolean_t def_set = B_FALSE;
5994 boolean_t upper_set = B_FALSE;
5995 boolean_t lower_set = B_FALSE;
5996 boolean_t ret = B_TRUE;
5998 if (strlen(tab->zone_secflags_default) > 0) {
5999 def_set = B_TRUE;
6000 if (secflags_parse(NULL, tab->zone_secflags_default,
6001 &def) == -1) {
6002 zerr(gettext("default security flags '%s' are invalid"),
6003 tab->zone_secflags_default);
6004 ret = B_FALSE;
6006 } else {
6007 secflags_zero(&def.psd_assign);
6008 def.psd_ass_active = B_TRUE;
6011 if (strlen(tab->zone_secflags_upper) > 0) {
6012 upper_set = B_TRUE;
6013 if (secflags_parse(NULL, tab->zone_secflags_upper,
6014 &upper) == -1) {
6015 zerr(gettext("upper security flags '%s' are invalid"),
6016 tab->zone_secflags_upper);
6017 ret = B_FALSE;
6019 } else {
6020 secflags_fullset(&upper.psd_assign);
6021 upper.psd_ass_active = B_TRUE;
6024 if (strlen(tab->zone_secflags_lower) > 0) {
6025 lower_set = B_TRUE;
6026 if (secflags_parse(NULL, tab->zone_secflags_lower,
6027 &lower) == -1) {
6028 zerr(gettext("lower security flags '%s' are invalid"),
6029 tab->zone_secflags_lower);
6030 ret = B_FALSE;
6032 } else {
6033 secflags_zero(&lower.psd_assign);
6034 lower.psd_ass_active = B_TRUE;
6037 if (def_set && !def.psd_ass_active) {
6038 zerr(gettext("only assignment of security flags is "
6039 "allowed (default: %s)"), tab->zone_secflags_default);
6042 if (lower_set && !lower.psd_ass_active) {
6043 zerr(gettext("only assignment of security flags is "
6044 "allowed (lower: %s)"), tab->zone_secflags_lower);
6047 if (upper_set && !upper.psd_ass_active) {
6048 zerr(gettext("only assignment of security flags is "
6049 "allowed (upper: %s)"), tab->zone_secflags_upper);
6052 if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */
6053 zerr(gettext("default secflags must be within the "
6054 "upper limit"));
6055 ret = B_FALSE;
6057 if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
6058 zerr(gettext("default secflags must be above the lower limit"));
6059 ret = B_FALSE;
6061 if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
6062 zerr(gettext("lower secflags must be within the upper limit"));
6063 ret = B_FALSE;
6066 return (ret);
6070 * See the DTD for which attributes are required for which resources.
6072 * This function can be called by commit_func(), which needs to save things,
6073 * in addition to the general call from parse_and_run(), which doesn't need
6074 * things saved. Since the parameters are standardized, we distinguish by
6075 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
6076 * that a save is needed.
6078 void
6079 verify_func(cmd_t *cmd)
6081 struct zone_nwiftab nwiftab;
6082 struct zone_fstab fstab;
6083 struct zone_attrtab attrtab;
6084 struct zone_rctltab rctltab;
6085 struct zone_dstab dstab;
6086 struct zone_psettab psettab;
6087 struct zone_admintab admintab;
6088 struct zone_secflagstab secflagstab;
6089 char zonepath[MAXPATHLEN];
6090 char sched[MAXNAMELEN];
6091 char brand[MAXNAMELEN];
6092 char hostidp[HW_HOSTID_LEN];
6093 char fsallowedp[ZONE_FS_ALLOWED_MAX];
6094 priv_set_t *privs;
6095 char *privname = NULL;
6096 int err, ret_val = Z_OK, arg;
6097 int pset_res;
6098 boolean_t save = B_FALSE;
6099 boolean_t arg_err = B_FALSE;
6100 zone_iptype_t iptype;
6101 boolean_t has_cpu_shares = B_FALSE;
6102 boolean_t has_cpu_cap = B_FALSE;
6103 struct xif *tmp;
6105 optind = 0;
6106 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6107 switch (arg) {
6108 case '?':
6109 longer_usage(CMD_VERIFY);
6110 arg_err = B_TRUE;
6111 break;
6112 default:
6113 short_usage(CMD_VERIFY);
6114 arg_err = B_TRUE;
6115 break;
6118 if (arg_err)
6119 return;
6121 if (optind > cmd->cmd_argc) {
6122 short_usage(CMD_VERIFY);
6123 return;
6126 if (zone_is_read_only(CMD_VERIFY))
6127 return;
6129 assert(cmd != NULL);
6131 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
6132 save = B_TRUE;
6133 if (initialize(B_TRUE) != Z_OK)
6134 return;
6136 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
6137 !global_zone) {
6138 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
6139 ret_val = Z_REQD_RESOURCE_MISSING;
6140 saw_error = B_TRUE;
6142 if (strlen(zonepath) == 0 && !global_zone) {
6143 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
6144 ret_val = Z_REQD_RESOURCE_MISSING;
6145 saw_error = B_TRUE;
6148 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
6149 zone_perror(zone, err, B_TRUE);
6150 return;
6152 if ((err = brand_verify(handle)) != Z_OK) {
6153 zone_perror(zone, err, B_TRUE);
6154 return;
6157 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
6158 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
6159 ret_val = Z_REQD_RESOURCE_MISSING;
6160 saw_error = B_TRUE;
6163 if ((privs = priv_allocset()) == NULL) {
6164 zerr(gettext("%s: priv_allocset failed"), zone);
6165 return;
6167 if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) {
6168 zerr(gettext("%s: invalid privilege: %s"), zone, privname);
6169 priv_freeset(privs);
6170 free(privname);
6171 return;
6173 priv_freeset(privs);
6175 if (zonecfg_get_hostid(handle, hostidp,
6176 sizeof (hostidp)) == Z_INVALID_PROPERTY) {
6177 zerr(gettext("%s: invalid hostid: %s"),
6178 zone, hostidp);
6179 return;
6182 if (zonecfg_get_fs_allowed(handle, fsallowedp,
6183 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
6184 zerr(gettext("%s: invalid fs-allowed: %s"),
6185 zone, fsallowedp);
6186 return;
6189 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
6190 zone_perror(zone, err, B_TRUE);
6191 return;
6193 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
6194 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
6195 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
6196 &ret_val);
6197 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
6199 zonecfg_free_fs_option_list(fstab.zone_fs_options);
6201 (void) zonecfg_endfsent(handle);
6203 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
6204 zone_perror(zone, err, B_TRUE);
6205 return;
6207 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
6209 * physical is required in all cases.
6210 * A shared IP requires an address,
6211 * and may include a default router, while
6212 * an exclusive IP must have neither an address
6213 * nor a default router.
6214 * The physical interface name must be valid in all cases.
6216 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
6217 PT_PHYSICAL, &ret_val);
6218 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
6219 Z_OK) {
6220 saw_error = B_TRUE;
6221 if (ret_val == Z_OK)
6222 ret_val = Z_INVAL;
6225 switch (iptype) {
6226 case ZS_SHARED:
6227 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
6228 PT_ADDRESS, &ret_val);
6229 if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
6230 zerr(gettext("%s: %s cannot be specified "
6231 "for a shared IP type"),
6232 rt_to_str(RT_NET),
6233 pt_to_str(PT_ALLOWED_ADDRESS));
6234 saw_error = B_TRUE;
6235 if (ret_val == Z_OK)
6236 ret_val = Z_INVAL;
6238 break;
6239 case ZS_EXCLUSIVE:
6240 if (strlen(nwiftab.zone_nwif_address) > 0) {
6241 zerr(gettext("%s: %s cannot be specified "
6242 "for an exclusive IP type"),
6243 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
6244 saw_error = B_TRUE;
6245 if (ret_val == Z_OK)
6246 ret_val = Z_INVAL;
6247 } else {
6248 if (!add_nwif(&nwiftab)) {
6249 saw_error = B_TRUE;
6250 if (ret_val == Z_OK)
6251 ret_val = Z_INVAL;
6254 break;
6257 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
6258 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
6259 zerr(gettext("%s: %s for %s cannot be specified "
6260 "without %s for an exclusive IP type"),
6261 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
6262 tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
6263 saw_error = B_TRUE;
6264 ret_val = Z_INVAL;
6267 free(xif);
6268 xif = NULL;
6269 (void) zonecfg_endnwifent(handle);
6271 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
6272 zone_perror(zone, err, B_TRUE);
6273 return;
6275 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
6276 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
6277 &ret_val);
6279 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
6280 has_cpu_shares = B_TRUE;
6282 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
6283 has_cpu_cap = B_TRUE;
6285 if (rctltab.zone_rctl_valptr == NULL) {
6286 zerr(gettext("%s: no %s specified"),
6287 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
6288 saw_error = B_TRUE;
6289 if (ret_val == Z_OK)
6290 ret_val = Z_REQD_PROPERTY_MISSING;
6291 } else {
6292 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
6295 (void) zonecfg_endrctlent(handle);
6297 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
6298 has_cpu_shares) {
6299 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
6300 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6301 saw_error = B_TRUE;
6302 if (ret_val == Z_OK)
6303 ret_val = Z_INCOMPATIBLE;
6306 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
6307 sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
6308 strcmp(sched, "FSS") != 0) {
6309 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
6310 "incompatible"),
6311 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
6312 saw_error = B_TRUE;
6313 if (ret_val == Z_OK)
6314 ret_val = Z_INCOMPATIBLE;
6317 if (pset_res == Z_OK && has_cpu_cap) {
6318 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6319 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6320 saw_error = B_TRUE;
6321 if (ret_val == Z_OK)
6322 ret_val = Z_INCOMPATIBLE;
6325 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6326 zone_perror(zone, err, B_TRUE);
6327 return;
6329 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6330 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6331 &ret_val);
6332 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6333 &ret_val);
6334 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6335 &ret_val);
6337 (void) zonecfg_endattrent(handle);
6339 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6340 zone_perror(zone, err, B_TRUE);
6341 return;
6343 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6344 if (strlen(dstab.zone_dataset_name) == 0) {
6345 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6346 pt_to_str(PT_NAME), gettext("not specified"));
6347 saw_error = B_TRUE;
6348 if (ret_val == Z_OK)
6349 ret_val = Z_REQD_PROPERTY_MISSING;
6350 } else if (!zfs_name_valid(dstab.zone_dataset_name,
6351 ZFS_TYPE_FILESYSTEM)) {
6352 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6353 pt_to_str(PT_NAME), gettext("invalid"));
6354 saw_error = B_TRUE;
6355 if (ret_val == Z_OK)
6356 ret_val = Z_BAD_PROPERTY;
6360 (void) zonecfg_enddsent(handle);
6362 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6363 zone_perror(zone, err, B_TRUE);
6364 return;
6366 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6367 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6368 PT_USER, &ret_val);
6369 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6370 PT_AUTHS, &ret_val);
6371 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6372 == NULL)) {
6373 zerr(gettext("%s %s is not a valid username"),
6374 pt_to_str(PT_USER),
6375 admintab.zone_admin_user);
6376 ret_val = Z_BAD_PROPERTY;
6378 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6379 admintab.zone_admin_auths, zone))) {
6380 ret_val = Z_BAD_PROPERTY;
6383 (void) zonecfg_endadminent(handle);
6385 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
6387 * No properties are required, but any specified should be
6388 * valid
6390 if (verify_secflags(&secflagstab) != B_TRUE) {
6391 /* Error is reported from verify_secflags */
6392 ret_val = Z_BAD_PROPERTY;
6396 if (!global_scope) {
6397 zerr(gettext("resource specification incomplete"));
6398 saw_error = B_TRUE;
6399 if (ret_val == Z_OK)
6400 ret_val = Z_INSUFFICIENT_SPEC;
6403 if (save) {
6404 if (ret_val == Z_OK) {
6405 if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6406 need_to_commit = B_FALSE;
6407 (void) strlcpy(revert_zone, zone,
6408 sizeof (revert_zone));
6410 } else {
6411 zerr(gettext("Zone %s failed to verify"), zone);
6414 if (ret_val != Z_OK)
6415 zone_perror(zone, ret_val, B_TRUE);
6418 void
6419 cancel_func(cmd_t *cmd)
6421 int arg;
6422 boolean_t arg_err = B_FALSE;
6424 assert(cmd != NULL);
6426 optind = 0;
6427 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6428 switch (arg) {
6429 case '?':
6430 longer_usage(CMD_CANCEL);
6431 arg_err = B_TRUE;
6432 break;
6433 default:
6434 short_usage(CMD_CANCEL);
6435 arg_err = B_TRUE;
6436 break;
6439 if (arg_err)
6440 return;
6442 if (optind != cmd->cmd_argc) {
6443 short_usage(CMD_CANCEL);
6444 return;
6447 if (global_scope)
6448 scope_usage(CMD_CANCEL);
6449 global_scope = B_TRUE;
6450 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6451 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6452 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6453 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6454 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6455 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6456 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6457 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6460 static int
6461 validate_attr_name(char *name)
6463 int i;
6465 if (!isalnum(name[0])) {
6466 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6467 "numeric character."), rt_to_str(RT_ATTR),
6468 pt_to_str(PT_NAME), name);
6469 return (Z_INVAL);
6471 for (i = 1; name[i]; i++)
6472 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6473 zerr(gettext("Invalid %s %s %s: can only contain "
6474 "alpha-numeric characters, plus '-' and '.'."),
6475 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6476 return (Z_INVAL);
6478 return (Z_OK);
6481 static int
6482 validate_attr_type_val(struct zone_attrtab *attrtab)
6484 boolean_t boolval;
6485 int64_t intval;
6486 char strval[MAXNAMELEN];
6487 uint64_t uintval;
6489 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6490 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6491 return (Z_OK);
6492 zerr(gettext("invalid %s value for %s=%s"),
6493 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6494 return (Z_ERR);
6497 if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6498 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6499 return (Z_OK);
6500 zerr(gettext("invalid %s value for %s=%s"),
6501 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6502 return (Z_ERR);
6505 if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6506 if (zonecfg_get_attr_string(attrtab, strval,
6507 sizeof (strval)) == Z_OK)
6508 return (Z_OK);
6509 zerr(gettext("invalid %s value for %s=%s"),
6510 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6511 return (Z_ERR);
6514 if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6515 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6516 return (Z_OK);
6517 zerr(gettext("invalid %s value for %s=%s"),
6518 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6519 return (Z_ERR);
6522 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6523 pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6524 return (Z_ERR);
6528 * Helper function for end_func-- checks the existence of a given property
6529 * and emits a message if not specified.
6531 static int
6532 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6534 if (strlen(attr) == 0) {
6535 *validation_failed = B_TRUE;
6536 zerr(gettext("%s not specified"), pt_to_str(pt));
6537 return (Z_ERR);
6539 return (Z_OK);
6542 static void
6543 net_exists_error(struct zone_nwiftab nwif)
6545 if (strlen(nwif.zone_nwif_address) > 0) {
6546 zerr(gettext("A %s resource with the %s '%s', "
6547 "and %s '%s' already exists."),
6548 rt_to_str(RT_NET),
6549 pt_to_str(PT_PHYSICAL),
6550 nwif.zone_nwif_physical,
6551 pt_to_str(PT_ADDRESS),
6552 in_progress_nwiftab.zone_nwif_address);
6553 } else {
6554 zerr(gettext("A %s resource with the %s '%s', "
6555 "and %s '%s' already exists."),
6556 rt_to_str(RT_NET),
6557 pt_to_str(PT_PHYSICAL),
6558 nwif.zone_nwif_physical,
6559 pt_to_str(PT_ALLOWED_ADDRESS),
6560 nwif.zone_nwif_allowed_address);
6564 void
6565 end_func(cmd_t *cmd)
6567 boolean_t validation_failed = B_FALSE;
6568 boolean_t arg_err = B_FALSE;
6569 struct zone_fstab tmp_fstab;
6570 struct zone_nwiftab tmp_nwiftab;
6571 struct zone_devtab tmp_devtab;
6572 struct zone_rctltab tmp_rctltab;
6573 struct zone_attrtab tmp_attrtab;
6574 struct zone_dstab tmp_dstab;
6575 struct zone_admintab tmp_admintab;
6576 int err, arg, res1, res2, res3;
6577 uint64_t swap_limit;
6578 uint64_t locked_limit;
6579 uint64_t proc_cap;
6581 assert(cmd != NULL);
6583 optind = 0;
6584 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6585 switch (arg) {
6586 case '?':
6587 longer_usage(CMD_END);
6588 arg_err = B_TRUE;
6589 break;
6590 default:
6591 short_usage(CMD_END);
6592 arg_err = B_TRUE;
6593 break;
6596 if (arg_err)
6597 return;
6599 if (optind != cmd->cmd_argc) {
6600 short_usage(CMD_END);
6601 return;
6604 if (global_scope) {
6605 scope_usage(CMD_END);
6606 return;
6609 assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6611 switch (resource_scope) {
6612 case RT_FS:
6613 /* First make sure everything was filled in. */
6614 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6615 PT_DIR, &validation_failed) == Z_OK) {
6616 if (in_progress_fstab.zone_fs_dir[0] != '/') {
6617 zerr(gettext("%s %s is not an absolute path."),
6618 pt_to_str(PT_DIR),
6619 in_progress_fstab.zone_fs_dir);
6620 validation_failed = B_TRUE;
6624 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6625 PT_SPECIAL, &validation_failed);
6627 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6628 in_progress_fstab.zone_fs_raw[0] != '/') {
6629 zerr(gettext("%s %s is not an absolute path."),
6630 pt_to_str(PT_RAW),
6631 in_progress_fstab.zone_fs_raw);
6632 validation_failed = B_TRUE;
6635 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6636 &validation_failed);
6638 if (validation_failed) {
6639 saw_error = B_TRUE;
6640 return;
6643 if (end_op == CMD_ADD) {
6644 /* Make sure there isn't already one like this. */
6645 bzero(&tmp_fstab, sizeof (tmp_fstab));
6646 (void) strlcpy(tmp_fstab.zone_fs_dir,
6647 in_progress_fstab.zone_fs_dir,
6648 sizeof (tmp_fstab.zone_fs_dir));
6649 err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6650 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6651 if (err == Z_OK) {
6652 zerr(gettext("A %s resource "
6653 "with the %s '%s' already exists."),
6654 rt_to_str(RT_FS), pt_to_str(PT_DIR),
6655 in_progress_fstab.zone_fs_dir);
6656 saw_error = B_TRUE;
6657 return;
6659 err = zonecfg_add_filesystem(handle,
6660 &in_progress_fstab);
6661 } else {
6662 err = zonecfg_modify_filesystem(handle, &old_fstab,
6663 &in_progress_fstab);
6665 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6666 in_progress_fstab.zone_fs_options = NULL;
6667 break;
6669 case RT_NET:
6671 * First make sure everything was filled in.
6672 * Since we don't know whether IP will be shared
6673 * or exclusive here, some checks are deferred until
6674 * the verify command.
6676 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6677 PT_PHYSICAL, &validation_failed);
6679 if (validation_failed) {
6680 saw_error = B_TRUE;
6681 return;
6683 if (end_op == CMD_ADD) {
6684 /* Make sure there isn't already one like this. */
6685 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6686 (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6687 in_progress_nwiftab.zone_nwif_physical,
6688 sizeof (tmp_nwiftab.zone_nwif_physical));
6689 (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6690 in_progress_nwiftab.zone_nwif_address,
6691 sizeof (tmp_nwiftab.zone_nwif_address));
6692 (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6693 in_progress_nwiftab.zone_nwif_allowed_address,
6694 sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6695 (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6696 in_progress_nwiftab.zone_nwif_defrouter,
6697 sizeof (tmp_nwiftab.zone_nwif_defrouter));
6698 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6699 net_exists_error(in_progress_nwiftab);
6700 saw_error = B_TRUE;
6701 return;
6703 err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6704 } else {
6705 err = zonecfg_modify_nwif(handle, &old_nwiftab,
6706 &in_progress_nwiftab);
6708 break;
6710 case RT_DEVICE:
6711 /* First make sure everything was filled in. */
6712 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6713 PT_MATCH, &validation_failed);
6715 if (validation_failed) {
6716 saw_error = B_TRUE;
6717 return;
6720 if (end_op == CMD_ADD) {
6721 /* Make sure there isn't already one like this. */
6722 (void) strlcpy(tmp_devtab.zone_dev_match,
6723 in_progress_devtab.zone_dev_match,
6724 sizeof (tmp_devtab.zone_dev_match));
6725 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6726 zerr(gettext("A %s resource with the %s '%s' "
6727 "already exists."), rt_to_str(RT_DEVICE),
6728 pt_to_str(PT_MATCH),
6729 in_progress_devtab.zone_dev_match);
6730 saw_error = B_TRUE;
6731 return;
6733 err = zonecfg_add_dev(handle, &in_progress_devtab);
6734 } else {
6735 err = zonecfg_modify_dev(handle, &old_devtab,
6736 &in_progress_devtab);
6738 break;
6740 case RT_RCTL:
6741 /* First make sure everything was filled in. */
6742 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6743 PT_NAME, &validation_failed);
6745 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6746 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6747 validation_failed = B_TRUE;
6750 if (validation_failed) {
6751 saw_error = B_TRUE;
6752 return;
6755 if (end_op == CMD_ADD) {
6756 /* Make sure there isn't already one like this. */
6757 (void) strlcpy(tmp_rctltab.zone_rctl_name,
6758 in_progress_rctltab.zone_rctl_name,
6759 sizeof (tmp_rctltab.zone_rctl_name));
6760 tmp_rctltab.zone_rctl_valptr = NULL;
6761 err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6762 zonecfg_free_rctl_value_list(
6763 tmp_rctltab.zone_rctl_valptr);
6764 if (err == Z_OK) {
6765 zerr(gettext("A %s resource "
6766 "with the %s '%s' already exists."),
6767 rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6768 in_progress_rctltab.zone_rctl_name);
6769 saw_error = B_TRUE;
6770 return;
6772 err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6773 } else {
6774 err = zonecfg_modify_rctl(handle, &old_rctltab,
6775 &in_progress_rctltab);
6777 if (err == Z_OK) {
6778 zonecfg_free_rctl_value_list(
6779 in_progress_rctltab.zone_rctl_valptr);
6780 in_progress_rctltab.zone_rctl_valptr = NULL;
6782 break;
6784 case RT_ATTR:
6785 /* First make sure everything was filled in. */
6786 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6787 PT_NAME, &validation_failed);
6788 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6789 PT_TYPE, &validation_failed);
6790 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6791 PT_VALUE, &validation_failed);
6793 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6794 Z_OK)
6795 validation_failed = B_TRUE;
6797 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6798 validation_failed = B_TRUE;
6800 if (validation_failed) {
6801 saw_error = B_TRUE;
6802 return;
6804 if (end_op == CMD_ADD) {
6805 /* Make sure there isn't already one like this. */
6806 bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6807 (void) strlcpy(tmp_attrtab.zone_attr_name,
6808 in_progress_attrtab.zone_attr_name,
6809 sizeof (tmp_attrtab.zone_attr_name));
6810 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6811 zerr(gettext("An %s resource "
6812 "with the %s '%s' already exists."),
6813 rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6814 in_progress_attrtab.zone_attr_name);
6815 saw_error = B_TRUE;
6816 return;
6818 err = zonecfg_add_attr(handle, &in_progress_attrtab);
6819 } else {
6820 err = zonecfg_modify_attr(handle, &old_attrtab,
6821 &in_progress_attrtab);
6823 break;
6824 case RT_DATASET:
6825 /* First make sure everything was filled in. */
6826 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6827 zerr("%s %s", pt_to_str(PT_NAME),
6828 gettext("not specified"));
6829 saw_error = B_TRUE;
6830 validation_failed = B_TRUE;
6832 if (validation_failed)
6833 return;
6834 if (end_op == CMD_ADD) {
6835 /* Make sure there isn't already one like this. */
6836 bzero(&tmp_dstab, sizeof (tmp_dstab));
6837 (void) strlcpy(tmp_dstab.zone_dataset_name,
6838 in_progress_dstab.zone_dataset_name,
6839 sizeof (tmp_dstab.zone_dataset_name));
6840 err = zonecfg_lookup_ds(handle, &tmp_dstab);
6841 if (err == Z_OK) {
6842 zerr(gettext("A %s resource "
6843 "with the %s '%s' already exists."),
6844 rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6845 in_progress_dstab.zone_dataset_name);
6846 saw_error = B_TRUE;
6847 return;
6849 err = zonecfg_add_ds(handle, &in_progress_dstab);
6850 } else {
6851 err = zonecfg_modify_ds(handle, &old_dstab,
6852 &in_progress_dstab);
6854 break;
6855 case RT_DCPU:
6856 /* Make sure everything was filled in. */
6857 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6858 PT_NCPUS, &validation_failed) != Z_OK) {
6859 saw_error = B_TRUE;
6860 return;
6863 if (end_op == CMD_ADD) {
6864 err = zonecfg_add_pset(handle, &in_progress_psettab);
6865 } else {
6866 err = zonecfg_modify_pset(handle, &in_progress_psettab);
6868 break;
6869 case RT_PCAP:
6870 /* Make sure everything was filled in. */
6871 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6872 != Z_OK) {
6873 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6874 saw_error = B_TRUE;
6875 validation_failed = B_TRUE;
6876 return;
6878 err = Z_OK;
6879 break;
6880 case RT_MCAP:
6881 /* Make sure everything was filled in. */
6882 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6883 Z_ERR : Z_OK;
6884 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6885 &swap_limit);
6886 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6887 &locked_limit);
6889 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6890 zerr(gettext("No property was specified. One of %s, "
6891 "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6892 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6893 saw_error = B_TRUE;
6894 return;
6897 /* if phys & locked are both set, verify locked <= phys */
6898 if (res1 == Z_OK && res3 == Z_OK) {
6899 uint64_t phys_limit;
6900 char *endp;
6902 phys_limit = strtoull(
6903 in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6904 if (phys_limit < locked_limit) {
6905 zerr(gettext("The %s cap must be less than or "
6906 "equal to the %s cap."),
6907 pt_to_str(PT_LOCKED),
6908 pt_to_str(PT_PHYSICAL));
6909 saw_error = B_TRUE;
6910 return;
6914 err = Z_OK;
6915 if (res1 == Z_OK) {
6917 * We could be ending from either an add operation
6918 * or a select operation. Since all of the properties
6919 * within this resource are optional, we always use
6920 * modify on the mcap entry. zonecfg_modify_mcap()
6921 * will handle both adding and modifying a memory cap.
6923 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6924 } else if (end_op == CMD_SELECT) {
6926 * If we're ending from a select and the physical
6927 * memory cap is empty then the user could have cleared
6928 * the physical cap value, so try to delete the entry.
6930 (void) zonecfg_delete_mcap(handle);
6932 break;
6933 case RT_ADMIN:
6934 /* First make sure everything was filled in. */
6935 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6936 PT_USER, &validation_failed) == Z_OK) {
6937 if (getpwnam(in_progress_admintab.zone_admin_user)
6938 == NULL) {
6939 zerr(gettext("%s %s is not a valid username"),
6940 pt_to_str(PT_USER),
6941 in_progress_admintab.zone_admin_user);
6942 validation_failed = B_TRUE;
6946 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6947 PT_AUTHS, &validation_failed) == Z_OK) {
6948 if (!zonecfg_valid_auths(
6949 in_progress_admintab.zone_admin_auths,
6950 zone)) {
6951 validation_failed = B_TRUE;
6955 if (validation_failed) {
6956 saw_error = B_TRUE;
6957 return;
6960 if (end_op == CMD_ADD) {
6961 /* Make sure there isn't already one like this. */
6962 bzero(&tmp_admintab, sizeof (tmp_admintab));
6963 (void) strlcpy(tmp_admintab.zone_admin_user,
6964 in_progress_admintab.zone_admin_user,
6965 sizeof (tmp_admintab.zone_admin_user));
6966 err = zonecfg_lookup_admin(
6967 handle, &tmp_admintab);
6968 if (err == Z_OK) {
6969 zerr(gettext("A %s resource "
6970 "with the %s '%s' already exists."),
6971 rt_to_str(RT_ADMIN),
6972 pt_to_str(PT_USER),
6973 in_progress_admintab.zone_admin_user);
6974 saw_error = B_TRUE;
6975 return;
6977 err = zonecfg_add_admin(handle,
6978 &in_progress_admintab, zone);
6979 } else {
6980 err = zonecfg_modify_admin(handle,
6981 &old_admintab, &in_progress_admintab,
6982 zone);
6984 break;
6985 case RT_SECFLAGS:
6986 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
6987 saw_error = B_TRUE;
6988 return;
6991 if (end_op == CMD_ADD) {
6992 err = zonecfg_add_secflags(handle,
6993 &in_progress_secflagstab);
6994 } else {
6995 err = zonecfg_modify_secflags(handle,
6996 &old_secflagstab, &in_progress_secflagstab);
6998 break;
6999 default:
7000 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
7001 B_TRUE);
7002 saw_error = B_TRUE;
7003 return;
7006 if (err != Z_OK) {
7007 zone_perror(zone, err, B_TRUE);
7008 } else {
7009 need_to_commit = B_TRUE;
7010 global_scope = B_TRUE;
7011 end_op = -1;
7015 void
7016 commit_func(cmd_t *cmd)
7018 int arg;
7019 boolean_t arg_err = B_FALSE;
7021 optind = 0;
7022 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
7023 switch (arg) {
7024 case '?':
7025 longer_usage(CMD_COMMIT);
7026 arg_err = B_TRUE;
7027 break;
7028 default:
7029 short_usage(CMD_COMMIT);
7030 arg_err = B_TRUE;
7031 break;
7034 if (arg_err)
7035 return;
7037 if (optind != cmd->cmd_argc) {
7038 short_usage(CMD_COMMIT);
7039 return;
7042 if (zone_is_read_only(CMD_COMMIT))
7043 return;
7045 assert(cmd != NULL);
7047 cmd->cmd_argc = 1;
7049 * cmd_arg normally comes from a strdup() in the lexer, and the
7050 * whole cmd structure and its (char *) attributes are freed at
7051 * the completion of each command, so the strdup() below is needed
7052 * to match this and prevent a core dump from trying to free()
7053 * something that can't be.
7055 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
7056 zone_perror(zone, Z_NOMEM, B_TRUE);
7057 exit(Z_ERR);
7059 cmd->cmd_argv[1] = NULL;
7060 verify_func(cmd);
7063 void
7064 revert_func(cmd_t *cmd)
7066 char line[128]; /* enough to ask a question */
7067 boolean_t force = B_FALSE;
7068 boolean_t arg_err = B_FALSE;
7069 int err, arg, answer;
7071 optind = 0;
7072 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
7073 switch (arg) {
7074 case '?':
7075 longer_usage(CMD_REVERT);
7076 arg_err = B_TRUE;
7077 break;
7078 case 'F':
7079 force = B_TRUE;
7080 break;
7081 default:
7082 short_usage(CMD_REVERT);
7083 arg_err = B_TRUE;
7084 break;
7087 if (arg_err)
7088 return;
7090 if (optind != cmd->cmd_argc) {
7091 short_usage(CMD_REVERT);
7092 return;
7095 if (zone_is_read_only(CMD_REVERT))
7096 return;
7098 if (!global_scope) {
7099 zerr(gettext("You can only use %s in the global scope.\nUse"
7100 " '%s' to cancel changes to a resource specification."),
7101 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
7102 saw_error = B_TRUE;
7103 return;
7106 if (zonecfg_check_handle(handle) != Z_OK) {
7107 zerr(gettext("No changes to revert."));
7108 saw_error = B_TRUE;
7109 return;
7112 if (!force) {
7113 (void) snprintf(line, sizeof (line),
7114 gettext("Are you sure you want to revert"));
7115 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
7116 zerr(gettext("Input not from terminal and -F not "
7117 "specified:\n%s command ignored, exiting."),
7118 cmd_to_str(CMD_REVERT));
7119 exit(Z_ERR);
7121 if (answer != 1)
7122 return;
7126 * Reset any pending admins that were
7127 * removed from the previous zone
7129 zonecfg_remove_userauths(handle, "", zone, B_FALSE);
7132 * Time for a new handle: finish the old one off first
7133 * then get a new one properly to avoid leaks.
7135 zonecfg_fini_handle(handle);
7136 if ((handle = zonecfg_init_handle()) == NULL) {
7137 zone_perror(execname, Z_NOMEM, B_TRUE);
7138 exit(Z_ERR);
7141 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
7142 saw_error = B_TRUE;
7143 got_handle = B_FALSE;
7144 if (err == Z_NO_ZONE)
7145 zerr(gettext("%s: no such saved zone to revert to."),
7146 revert_zone);
7147 else
7148 zone_perror(zone, err, B_TRUE);
7150 (void) strlcpy(zone, revert_zone, sizeof (zone));
7153 void
7154 help_func(cmd_t *cmd)
7156 int i;
7158 assert(cmd != NULL);
7160 if (cmd->cmd_argc == 0) {
7161 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
7162 return;
7164 if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
7165 usage(B_TRUE, HELP_USAGE);
7166 return;
7168 if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
7169 usage(B_TRUE, HELP_SUBCMDS);
7170 return;
7172 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
7173 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
7174 return;
7176 if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
7177 longer_usage(CMD_HELP);
7178 return;
7181 for (i = 0; i <= CMD_MAX; i++) {
7182 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
7183 longer_usage(i);
7184 return;
7187 /* We do not use zerr() here because we do not want its extra \n. */
7188 (void) fprintf(stderr, gettext("Unknown help subject %s. "),
7189 cmd->cmd_argv[0]);
7190 usage(B_FALSE, HELP_META);
7193 static int
7194 string_to_yyin(char *string)
7196 if ((yyin = tmpfile()) == NULL) {
7197 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7198 return (Z_ERR);
7200 if (fwrite(string, strlen(string), 1, yyin) != 1) {
7201 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7202 return (Z_ERR);
7204 if (fseek(yyin, 0, SEEK_SET) != 0) {
7205 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7206 return (Z_ERR);
7208 return (Z_OK);
7211 /* This is the back-end helper function for read_input() below. */
7213 static int
7214 cleanup()
7216 int answer;
7217 cmd_t *cmd;
7219 if (!interactive_mode && !cmd_file_mode) {
7221 * If we're not in interactive mode, and we're not in command
7222 * file mode, then we must be in commands-from-the-command-line
7223 * mode. As such, we can't loop back and ask for more input.
7224 * It was OK to prompt for such things as whether or not to
7225 * really delete a zone in the command handler called from
7226 * yyparse() above, but "really quit?" makes no sense in this
7227 * context. So disable prompting.
7229 ok_to_prompt = B_FALSE;
7231 if (!global_scope) {
7232 if (!time_to_exit) {
7234 * Just print a simple error message in the -1 case,
7235 * since exit_func() already handles that case, and
7236 * EOF means we are finished anyway.
7238 answer = ask_yesno(B_FALSE,
7239 gettext("Resource incomplete; really quit"));
7240 if (answer == -1) {
7241 zerr(gettext("Resource incomplete."));
7242 return (Z_ERR);
7244 if (answer != 1) {
7245 yyin = stdin;
7246 return (Z_REPEAT);
7248 } else {
7249 saw_error = B_TRUE;
7253 * Make sure we tried something and that the handle checks
7254 * out, or we would get a false error trying to commit.
7256 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
7257 if ((cmd = alloc_cmd()) == NULL) {
7258 zone_perror(zone, Z_NOMEM, B_TRUE);
7259 return (Z_ERR);
7261 cmd->cmd_argc = 0;
7262 cmd->cmd_argv[0] = NULL;
7263 commit_func(cmd);
7264 free_cmd(cmd);
7266 * need_to_commit will get set back to FALSE if the
7267 * configuration is saved successfully.
7269 if (need_to_commit) {
7270 if (force_exit) {
7271 zerr(gettext("Configuration not saved."));
7272 return (Z_ERR);
7274 answer = ask_yesno(B_FALSE,
7275 gettext("Configuration not saved; really quit"));
7276 if (answer == -1) {
7277 zerr(gettext("Configuration not saved."));
7278 return (Z_ERR);
7280 if (answer != 1) {
7281 time_to_exit = B_FALSE;
7282 yyin = stdin;
7283 return (Z_REPEAT);
7287 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
7291 * read_input() is the driver of this program. It is a wrapper around
7292 * yyparse(), printing appropriate prompts when needed, checking for
7293 * exit conditions and reacting appropriately [the latter in its cleanup()
7294 * helper function].
7296 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
7297 * so do_interactive() knows that we are not really done (i.e, we asked
7298 * the user if we should really quit and the user said no).
7300 static int
7301 read_input()
7303 boolean_t yyin_is_a_tty = isatty(fileno(yyin));
7305 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
7306 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
7308 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
7310 /* yyin should have been set to the appropriate (FILE *) if not stdin */
7311 newline_terminated = B_TRUE;
7312 for (;;) {
7313 if (yyin_is_a_tty) {
7314 if (newline_terminated) {
7315 if (global_scope)
7316 (void) snprintf(prompt, sizeof (prompt),
7317 "%s:%s> ", execname, zone);
7318 else
7319 (void) snprintf(prompt, sizeof (prompt),
7320 "%s:%s:%s> ", execname, zone,
7321 rt_to_str(resource_scope));
7324 * If the user hits ^C then we want to catch it and
7325 * start over. If the user hits EOF then we want to
7326 * bail out.
7328 line = gl_get_line(gl, prompt, NULL, -1);
7329 if (gl_return_status(gl) == GLR_SIGNAL) {
7330 gl_abandon_line(gl);
7331 continue;
7333 if (line == NULL)
7334 break;
7335 (void) string_to_yyin(line);
7336 while (!feof(yyin))
7337 yyparse();
7338 } else {
7339 yyparse();
7341 /* Bail out on an error in command file mode. */
7342 if (saw_error && cmd_file_mode && !interactive_mode)
7343 time_to_exit = B_TRUE;
7344 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7345 break;
7347 return (cleanup());
7351 * This function is used in the zonecfg-interactive-mode scenario: it just
7352 * calls read_input() until we are done.
7355 static int
7356 do_interactive(void)
7358 int err;
7360 interactive_mode = B_TRUE;
7361 if (!read_only_mode) {
7363 * Try to set things up proactively in interactive mode, so
7364 * that if the zone in question does not exist yet, we can
7365 * provide the user with a clue.
7367 (void) initialize(B_FALSE);
7369 do {
7370 err = read_input();
7371 } while (err == Z_REPEAT);
7372 return (err);
7376 * cmd_file is slightly more complicated, as it has to open the command file
7377 * and set yyin appropriately. Once that is done, though, it just calls
7378 * read_input(), and only once, since prompting is not possible.
7381 static int
7382 cmd_file(char *file)
7384 FILE *infile;
7385 int err;
7386 struct stat statbuf;
7387 boolean_t using_real_file = (strcmp(file, "-") != 0);
7389 if (using_real_file) {
7391 * zerr() prints a line number in cmd_file_mode, which we do
7392 * not want here, so temporarily unset it.
7394 cmd_file_mode = B_FALSE;
7395 if ((infile = fopen(file, "r")) == NULL) {
7396 zerr(gettext("could not open file %s: %s"),
7397 file, strerror(errno));
7398 return (Z_ERR);
7400 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7401 zerr(gettext("could not stat file %s: %s"),
7402 file, strerror(errno));
7403 err = Z_ERR;
7404 goto done;
7406 if (!S_ISREG(statbuf.st_mode)) {
7407 zerr(gettext("%s is not a regular file."), file);
7408 err = Z_ERR;
7409 goto done;
7411 yyin = infile;
7412 cmd_file_mode = B_TRUE;
7413 ok_to_prompt = B_FALSE;
7414 } else {
7416 * "-f -" is essentially the same as interactive mode,
7417 * so treat it that way.
7419 interactive_mode = B_TRUE;
7421 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7422 if ((err = read_input()) == Z_REPEAT)
7423 err = Z_ERR;
7424 done:
7425 if (using_real_file)
7426 (void) fclose(infile);
7427 return (err);
7431 * Since yacc is based on reading from a (FILE *) whereas what we get from
7432 * the command line is in argv format, we need to convert when the user
7433 * gives us commands directly from the command line. That is done here by
7434 * concatenating the argv list into a space-separated string, writing it
7435 * to a temp file, and rewinding the file so yyin can be set to it. Then
7436 * we call read_input(), and only once, since prompting about whether to
7437 * continue or quit would make no sense in this context.
7440 static int
7441 one_command_at_a_time(int argc, char *argv[])
7443 char *command;
7444 size_t len = 2; /* terminal \n\0 */
7445 int i, err;
7447 for (i = 0; i < argc; i++)
7448 len += strlen(argv[i]) + 1;
7449 if ((command = malloc(len)) == NULL) {
7450 zone_perror(execname, Z_NOMEM, B_TRUE);
7451 return (Z_ERR);
7453 (void) strlcpy(command, argv[0], len);
7454 for (i = 1; i < argc; i++) {
7455 (void) strlcat(command, " ", len);
7456 (void) strlcat(command, argv[i], len);
7458 (void) strlcat(command, "\n", len);
7459 err = string_to_yyin(command);
7460 free(command);
7461 if (err != Z_OK)
7462 return (err);
7463 while (!feof(yyin))
7464 yyparse();
7465 return (cleanup());
7468 static char *
7469 get_execbasename(char *execfullname)
7471 char *last_slash, *execbasename;
7473 /* guard against '/' at end of command invocation */
7474 for (;;) {
7475 last_slash = strrchr(execfullname, '/');
7476 if (last_slash == NULL) {
7477 execbasename = execfullname;
7478 break;
7479 } else {
7480 execbasename = last_slash + 1;
7481 if (*execbasename == '\0') {
7482 *last_slash = '\0';
7483 continue;
7485 break;
7488 return (execbasename);
7492 main(int argc, char *argv[])
7494 int err, arg;
7495 struct stat st;
7497 /* This must be before anything goes to stdout. */
7498 setbuf(stdout, NULL);
7500 saw_error = B_FALSE;
7501 cmd_file_mode = B_FALSE;
7502 execname = get_execbasename(argv[0]);
7504 (void) setlocale(LC_ALL, "");
7505 (void) textdomain(TEXT_DOMAIN);
7507 if (getzoneid() != GLOBAL_ZONEID) {
7508 zerr(gettext("%s can only be run from the global zone."),
7509 execname);
7510 exit(Z_ERR);
7513 if (argc < 2) {
7514 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7515 exit(Z_USAGE);
7517 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7518 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7519 exit(Z_OK);
7522 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7523 switch (arg) {
7524 case '?':
7525 if (optopt == '?')
7526 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7527 else
7528 usage(B_FALSE, HELP_USAGE);
7529 exit(Z_USAGE);
7530 /* NOTREACHED */
7531 case 'f':
7532 cmd_file_name = optarg;
7533 cmd_file_mode = B_TRUE;
7534 break;
7535 case 'R':
7536 if (*optarg != '/') {
7537 zerr(gettext("root path must be absolute: %s"),
7538 optarg);
7539 exit(Z_USAGE);
7541 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7542 zerr(gettext(
7543 "root path must be a directory: %s"),
7544 optarg);
7545 exit(Z_USAGE);
7547 zonecfg_set_root(optarg);
7548 break;
7549 case 'z':
7550 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7551 global_zone = B_TRUE;
7552 } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7553 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7554 usage(B_FALSE, HELP_SYNTAX);
7555 exit(Z_USAGE);
7557 (void) strlcpy(zone, optarg, sizeof (zone));
7558 (void) strlcpy(revert_zone, optarg, sizeof (zone));
7559 break;
7560 default:
7561 usage(B_FALSE, HELP_USAGE);
7562 exit(Z_USAGE);
7566 if (optind > argc || strcmp(zone, "") == 0) {
7567 usage(B_FALSE, HELP_USAGE);
7568 exit(Z_USAGE);
7571 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7572 read_only_mode = B_FALSE;
7573 } else if (err == Z_ACCES) {
7574 read_only_mode = B_TRUE;
7575 /* skip this message in one-off from command line mode */
7576 if (optind == argc)
7577 (void) fprintf(stderr, gettext("WARNING: you do not "
7578 "have write access to this zone's configuration "
7579 "file;\ngoing into read-only mode.\n"));
7580 } else {
7581 fprintf(stderr, "%s: Could not access zone configuration "
7582 "store: %s\n", execname, zonecfg_strerror(err));
7583 exit(Z_ERR);
7586 if ((handle = zonecfg_init_handle()) == NULL) {
7587 zone_perror(execname, Z_NOMEM, B_TRUE);
7588 exit(Z_ERR);
7592 * This may get set back to FALSE again in cmd_file() if cmd_file_name
7593 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7595 if (isatty(STDIN_FILENO))
7596 ok_to_prompt = B_TRUE;
7597 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7598 exit(Z_ERR);
7599 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7600 exit(Z_ERR);
7601 (void) sigset(SIGINT, SIG_IGN);
7602 if (optind == argc) {
7603 if (!cmd_file_mode)
7604 err = do_interactive();
7605 else
7606 err = cmd_file(cmd_file_name);
7607 } else {
7608 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7610 zonecfg_fini_handle(handle);
7611 if (brand != NULL)
7612 brand_close(brand);
7613 (void) del_GetLine(gl);
7614 return (err);