Merge commit 'a9bfd41d542f15c474711abb8b0ca66a4cef9918'
[unleashed.git] / usr / src / cmd / zonecfg / zonecfg.c
blobf988ae67391ac6e1e324f79b63ab6366592d91ea
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 allowed-address=",
420 "set physical=",
421 "set defrouter=",
422 NULL
425 static const char *device_res_scope_cmds[] = {
426 "cancel",
427 "end",
428 "exit",
429 "help",
430 "info",
431 "set match=",
432 NULL
435 static const char *attr_res_scope_cmds[] = {
436 "cancel",
437 "end",
438 "exit",
439 "help",
440 "info",
441 "set name=",
442 "set type=",
443 "set value=",
444 NULL
447 static const char *rctl_res_scope_cmds[] = {
448 "add value ",
449 "cancel",
450 "end",
451 "exit",
452 "help",
453 "info",
454 "remove value ",
455 "set name=",
456 NULL
459 static const char *dataset_res_scope_cmds[] = {
460 "cancel",
461 "end",
462 "exit",
463 "help",
464 "info",
465 "set name=",
466 NULL
469 static const char *pset_res_scope_cmds[] = {
470 "cancel",
471 "end",
472 "exit",
473 "help",
474 "info",
475 "set ncpus=",
476 "set importance=",
477 "clear importance",
478 NULL
481 static const char *pcap_res_scope_cmds[] = {
482 "cancel",
483 "end",
484 "exit",
485 "help",
486 "info",
487 "set ncpus=",
488 NULL
491 static const char *mcap_res_scope_cmds[] = {
492 "cancel",
493 "end",
494 "exit",
495 "help",
496 "info",
497 "set physical=",
498 "set swap=",
499 "set locked=",
500 "clear physical",
501 "clear swap",
502 "clear locked",
503 NULL
506 static const char *admin_res_scope_cmds[] = {
507 "cancel",
508 "end",
509 "exit",
510 "help",
511 "info",
512 "set user=",
513 "set auths=",
514 NULL
517 static const char *secflags_res_scope_cmds[] = {
518 "cancel",
519 "end",
520 "exit",
521 "set default=",
522 "set lower=",
523 "set upper=",
524 NULL
527 struct xif {
528 struct xif *xif_next;
529 char xif_name[LIFNAMSIZ];
530 boolean_t xif_has_address;
531 boolean_t xif_has_defrouter;
534 /* Global variables */
536 /* list of network interfaces specified for exclusive IP zone */
537 struct xif *xif;
539 /* set early in main(), never modified thereafter, used all over the place */
540 static char *execname;
542 /* set in main(), used all over the place */
543 static zone_dochandle_t handle;
545 /* used all over the place */
546 static char zone[ZONENAME_MAX];
547 static char revert_zone[ZONENAME_MAX];
549 /* global brand operations */
550 static brand_handle_t brand;
552 /* set in modifying functions, checked in read_input() */
553 static boolean_t need_to_commit = B_FALSE;
554 boolean_t saw_error;
556 /* set in yacc parser, checked in read_input() */
557 boolean_t newline_terminated;
559 /* set in main(), checked in lex error handler */
560 boolean_t cmd_file_mode;
562 /* set in exit_func(), checked in read_input() */
563 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
565 /* used in short_usage() and zerr() */
566 static char *cmd_file_name = NULL;
568 /* checked in read_input() and other places */
569 static boolean_t ok_to_prompt = B_FALSE;
571 /* set and checked in initialize() */
572 static boolean_t got_handle = B_FALSE;
574 /* initialized in do_interactive(), checked in initialize() */
575 static boolean_t interactive_mode;
577 /* set if configuring the global zone */
578 static boolean_t global_zone = B_FALSE;
580 /* set in main(), checked in multiple places */
581 static boolean_t read_only_mode;
583 /* scope is outer/global or inner/resource */
584 static boolean_t global_scope = B_TRUE;
585 static int resource_scope; /* should be in the RT_ list from zonecfg.h */
586 static int end_op = -1; /* operation on end is either add or modify */
588 int num_prop_vals; /* for grammar */
591 * These are for keeping track of resources as they are specified as part of
592 * the multi-step process. They should be initialized by add_resource() or
593 * select_func() and filled in by add_property() or set_func().
595 static struct zone_fstab old_fstab, in_progress_fstab;
596 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab;
597 static struct zone_devtab old_devtab, in_progress_devtab;
598 static struct zone_rctltab old_rctltab, in_progress_rctltab;
599 static struct zone_attrtab old_attrtab, in_progress_attrtab;
600 static struct zone_dstab old_dstab, in_progress_dstab;
601 static struct zone_psettab old_psettab, in_progress_psettab;
602 static struct zone_mcaptab old_mcaptab, in_progress_mcaptab;
603 static struct zone_admintab old_admintab, in_progress_admintab;
604 static struct zone_secflagstab old_secflagstab, in_progress_secflagstab;
606 static GetLine *gl; /* The gl_get_line() resource object */
608 static void bytes_to_units(char *str, char *buf, int bufsize);
610 /* Functions begin here */
612 static boolean_t
613 initial_match(const char *line1, const char *line2, int word_end)
615 if (word_end <= 0)
616 return (B_TRUE);
617 return (strncmp(line1, line2, word_end) == 0);
620 static int
621 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
622 int word_end)
624 int i, err;
626 for (i = 0; list[i] != NULL; i++) {
627 if (initial_match(line1, list[i], word_end)) {
628 err = cpl_add_completion(cpl, line1, 0, word_end,
629 list[i] + word_end, "", "");
630 if (err != 0)
631 return (err);
634 return (0);
637 static
638 /* ARGSUSED */
639 CPL_MATCH_FN(cmd_cpl_fn)
641 if (global_scope) {
643 * The MAX/MIN tests below are to make sure we have at least
644 * enough characters to distinguish from other prefixes (MAX)
645 * but only check MIN(what we have, what we're checking).
647 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
648 return (add_stuff(cpl, line, add_cmds, word_end));
649 if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
650 return (add_stuff(cpl, line, clear_cmds, word_end));
651 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
652 return (add_stuff(cpl, line, select_cmds, word_end));
653 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
654 return (add_stuff(cpl, line, set_cmds, word_end));
655 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
656 return (add_stuff(cpl, line, remove_cmds, word_end));
657 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
658 return (add_stuff(cpl, line, info_cmds, word_end));
659 return (add_stuff(cpl, line, global_scope_cmds, word_end));
661 switch (resource_scope) {
662 case RT_FS:
663 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
664 case RT_NET:
665 return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
666 case RT_DEVICE:
667 return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
668 case RT_RCTL:
669 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
670 case RT_ATTR:
671 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
672 case RT_DATASET:
673 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
674 case RT_DCPU:
675 return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
676 case RT_PCAP:
677 return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
678 case RT_MCAP:
679 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
680 case RT_ADMIN:
681 return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
682 case RT_SECFLAGS:
683 return (add_stuff(cpl, line, secflags_res_scope_cmds,
684 word_end));
687 return (0);
691 * For the main CMD_func() functions below, several of them call getopt()
692 * then check optind against argc to make sure an extra parameter was not
693 * passed in. The reason this is not caught in the grammar is that the
694 * grammar just checks for a miscellaneous TOKEN, which is *expected* to
695 * be "-F" (for example), but could be anything. So (for example) this
696 * check will prevent "create bogus".
699 cmd_t *
700 alloc_cmd(void)
702 return (calloc(1, sizeof (cmd_t)));
705 void
706 free_cmd(cmd_t *cmd)
708 int i;
710 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
711 if (cmd->cmd_property_ptr[i] != NULL) {
712 property_value_ptr_t pp = cmd->cmd_property_ptr[i];
714 switch (pp->pv_type) {
715 case PROP_VAL_SIMPLE:
716 free(pp->pv_simple);
717 break;
718 case PROP_VAL_COMPLEX:
719 free_complex(pp->pv_complex);
720 break;
721 case PROP_VAL_LIST:
722 free_list(pp->pv_list);
723 break;
726 for (i = 0; i < cmd->cmd_argc; i++)
727 free(cmd->cmd_argv[i]);
728 free(cmd);
731 complex_property_ptr_t
732 alloc_complex(void)
734 return (calloc(1, sizeof (complex_property_t)));
737 void
738 free_complex(complex_property_ptr_t complex)
740 if (complex == NULL)
741 return;
742 free_complex(complex->cp_next);
743 free(complex->cp_value);
744 free(complex);
747 list_property_ptr_t
748 alloc_list(void)
750 return (calloc(1, sizeof (list_property_t)));
753 void
754 free_list(list_property_ptr_t list)
756 if (list == NULL)
757 return;
758 free(list->lp_simple);
759 free_complex(list->lp_complex);
760 free_list(list->lp_next);
761 free(list);
764 void
765 free_outer_list(list_property_ptr_t list)
767 if (list == NULL)
768 return;
769 free_outer_list(list->lp_next);
770 free(list);
773 static struct zone_rctlvaltab *
774 alloc_rctlvaltab(void)
776 return (calloc(1, sizeof (struct zone_rctlvaltab)));
779 static char *
780 rt_to_str(int res_type)
782 assert(res_type >= RT_MIN && res_type <= RT_MAX);
783 return (res_types[res_type]);
786 static char *
787 pt_to_str(int prop_type)
789 assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
790 return (prop_types[prop_type]);
793 static char *
794 pvt_to_str(int pv_type)
796 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
797 return (prop_val_types[pv_type]);
800 static char *
801 cmd_to_str(int cmd_num)
803 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
804 return (helptab[cmd_num].cmd_name);
807 /* PRINTFLIKE1 */
808 static void
809 zerr(const char *fmt, ...)
811 va_list alist;
812 static int last_lineno;
814 /* lex_lineno has already been incremented in the lexer; compensate */
815 if (cmd_file_mode && lex_lineno > last_lineno) {
816 if (strcmp(cmd_file_name, "-") == 0)
817 (void) fprintf(stderr, gettext("On line %d:\n"),
818 lex_lineno - 1);
819 else
820 (void) fprintf(stderr, gettext("On line %d of %s:\n"),
821 lex_lineno - 1, cmd_file_name);
822 last_lineno = lex_lineno;
824 va_start(alist, fmt);
825 (void) vfprintf(stderr, fmt, alist);
826 (void) fprintf(stderr, "\n");
827 va_end(alist);
831 * This is a separate function rather than a set of define's because of the
832 * gettext() wrapping.
836 * TRANSLATION_NOTE
837 * Each string below should have \t follow \n whenever needed; the
838 * initial \t and the terminal \n will be provided by the calling function.
841 static char *
842 long_help(int cmd_num)
844 static char line[1024]; /* arbitrary large amount */
846 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
847 switch (cmd_num) {
848 case CMD_HELP:
849 return (gettext("Prints help message."));
850 case CMD_CREATE:
851 (void) snprintf(line, sizeof (line),
852 gettext("Creates a configuration for the "
853 "specified zone. %s should be\n\tused to "
854 "begin configuring a new zone. If overwriting an "
855 "existing\n\tconfiguration, the -F flag can be "
856 "used to force the action. If\n\t-t template is "
857 "given, creates a configuration identical to the\n"
858 "\tspecified template, except that the zone name "
859 "is changed from\n\ttemplate to zonename. '%s -a' "
860 "creates a configuration from a\n\tdetached "
861 "zonepath. '%s -b' results in a blank "
862 "configuration.\n\t'%s' with no arguments applies "
863 "the Sun default settings."),
864 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
865 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
866 return (line);
867 case CMD_EXIT:
868 return (gettext("Exits the program. The -F flag can "
869 "be used to force the action."));
870 case CMD_EXPORT:
871 return (gettext("Prints configuration to standard "
872 "output, or to output-file if\n\tspecified, in "
873 "a form suitable for use in a command-file."));
874 case CMD_ADD:
875 return (gettext("Add specified resource to "
876 "configuration."));
877 case CMD_DELETE:
878 return (gettext("Deletes the specified zone. The -F "
879 "flag can be used to force the\n\taction."));
880 case CMD_REMOVE:
881 return (gettext("Remove specified resource from "
882 "configuration. The -F flag can be used\n\tto "
883 "force the action."));
884 case CMD_SELECT:
885 (void) snprintf(line, sizeof (line),
886 gettext("Selects a resource to modify. "
887 "Resource modification is completed\n\twith the "
888 "command \"%s\". The property name/value pairs "
889 "must uniquely\n\tidentify a resource. Note that "
890 "the curly braces ('{', '}') mean one\n\tor more "
891 "of whatever is between them."),
892 cmd_to_str(CMD_END));
893 return (line);
894 case CMD_SET:
895 return (gettext("Sets property values."));
896 case CMD_CLEAR:
897 return (gettext("Clears property values."));
898 case CMD_INFO:
899 return (gettext("Displays information about the "
900 "current configuration. If resource\n\ttype is "
901 "specified, displays only information about "
902 "resources of\n\tthe relevant type. If resource "
903 "id is specified, displays only\n\tinformation "
904 "about that resource."));
905 case CMD_VERIFY:
906 return (gettext("Verifies current configuration "
907 "for correctness (some resource types\n\thave "
908 "required properties)."));
909 case CMD_COMMIT:
910 (void) snprintf(line, sizeof (line),
911 gettext("Commits current configuration. "
912 "Configuration must be committed to\n\tbe used by "
913 "%s. Until the configuration is committed, "
914 "changes \n\tcan be removed with the %s "
915 "command. This operation is\n\tattempted "
916 "automatically upon completion of a %s "
917 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
918 "zonecfg");
919 return (line);
920 case CMD_REVERT:
921 return (gettext("Reverts configuration back to the "
922 "last committed state. The -F flag\n\tcan be "
923 "used to force the action."));
924 case CMD_CANCEL:
925 return (gettext("Cancels resource/property "
926 "specification."));
927 case CMD_END:
928 return (gettext("Ends resource/property "
929 "specification."));
931 /* NOTREACHED */
932 return (NULL);
936 * Return the input filename appended to each component of the path
937 * or the filename itself if it is absolute.
938 * Parameters: path string, file name, output string.
940 static const char *
941 exec_cat(const char *s1, const char *s2, char *si)
943 char *s;
944 /* Number of remaining characters in s */
945 int cnt = PATH_MAX + 1;
947 s = si;
948 while (*s1 && *s1 != ':') { /* Copy first component of path to si */
949 if (cnt > 0) {
950 *s++ = *s1++;
951 cnt--;
952 } else {
953 s1++;
956 if (si != s && cnt > 0) { /* Add slash if s2 is not absolute */
957 *s++ = '/';
958 cnt--;
960 while (*s2 && cnt > 0) { /* Copy s2 to si */
961 *s++ = *s2++;
962 cnt--;
964 *s = '\0'; /* Terminate the output string */
965 return (*s1 ? ++s1 : NULL); /* Return next path component or NULL */
968 /* Determine that a name exists in PATH */
969 static int
970 path_find(const char *name)
972 const char *pathstr;
973 char fname[PATH_MAX + 2];
974 const char *cp;
975 struct stat stat_buf;
977 if ((pathstr = getenv("PATH")) == NULL) {
978 if (geteuid() == 0 || getuid() == 0)
979 pathstr = "/usr/sbin:/usr/bin";
980 else
981 pathstr = "/usr/bin:";
983 cp = strchr(name, '/') ? (const char *) "" : pathstr;
985 do {
986 cp = exec_cat(cp, name, fname);
987 if (stat(fname, &stat_buf) != -1) {
988 /* successful find of the file */
989 return (0);
991 } while (cp != NULL);
993 return (-1);
996 static FILE *
997 pager_open(void)
999 FILE *newfp;
1000 char *pager, *space;
1002 pager = getenv("PAGER");
1003 if (pager == NULL || *pager == '\0')
1004 pager = PAGER;
1006 space = strchr(pager, ' ');
1007 if (space)
1008 *space = '\0';
1009 if (path_find(pager) == 0) {
1010 if (space)
1011 *space = ' ';
1012 if ((newfp = popen(pager, "w")) == NULL)
1013 zerr(gettext("PAGER open failed (%s)."),
1014 strerror(errno));
1015 return (newfp);
1016 } else {
1017 zerr(gettext("PAGER %s does not exist (%s)."),
1018 pager, strerror(errno));
1020 return (NULL);
1023 static void
1024 pager_close(FILE *fp)
1026 int status;
1028 status = pclose(fp);
1029 if (status == -1)
1030 zerr(gettext("PAGER close failed (%s)."),
1031 strerror(errno));
1035 * Called with verbose TRUE when help is explicitly requested, FALSE for
1036 * unexpected errors.
1039 void
1040 usage(boolean_t verbose, uint_t flags)
1042 FILE *fp = verbose ? stdout : stderr;
1043 FILE *newfp;
1044 boolean_t need_to_close = B_FALSE;
1045 int i;
1047 /* don't page error output */
1048 if (verbose && interactive_mode) {
1049 if ((newfp = pager_open()) != NULL) {
1050 need_to_close = B_TRUE;
1051 fp = newfp;
1055 if (flags & HELP_META) {
1056 (void) fprintf(fp, gettext("More help is available for the "
1057 "following:\n"));
1058 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1059 cmd_to_str(CMD_HELP));
1060 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1061 cmd_to_str(CMD_HELP));
1062 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1063 cmd_to_str(CMD_HELP));
1064 (void) fprintf(fp, gettext("You may also obtain help on any "
1065 "command by typing '%s <command-name>.'\n"),
1066 cmd_to_str(CMD_HELP));
1068 if (flags & HELP_RES_SCOPE) {
1069 switch (resource_scope) {
1070 case RT_FS:
1071 (void) fprintf(fp, gettext("The '%s' resource scope is "
1072 "used to configure a file-system.\n"),
1073 rt_to_str(resource_scope));
1074 (void) fprintf(fp, gettext("Valid commands:\n"));
1075 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1076 pt_to_str(PT_DIR), gettext("<path>"));
1077 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1078 pt_to_str(PT_SPECIAL), gettext("<path>"));
1079 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1080 pt_to_str(PT_RAW), gettext("<raw-device>"));
1081 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1082 pt_to_str(PT_TYPE), gettext("<file-system type>"));
1083 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
1084 pt_to_str(PT_OPTIONS),
1085 gettext("<file-system options>"));
1086 (void) fprintf(fp, "\t%s %s %s\n",
1087 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
1088 gettext("<file-system options>"));
1089 (void) fprintf(fp, gettext("Consult the file-system "
1090 "specific manual page, such as mount_ufs(8), "
1091 "for\ndetails about file-system options. Note "
1092 "that any file-system options with an\nembedded "
1093 "'=' character must be enclosed in double quotes, "
1094 /*CSTYLED*/
1095 "such as \"%s=5\".\n"), MNTOPT_RETRY);
1096 break;
1097 case RT_NET:
1098 (void) fprintf(fp, gettext("The '%s' resource scope is "
1099 "used to configure a network interface.\n"),
1100 rt_to_str(resource_scope));
1101 (void) fprintf(fp, gettext("Valid commands:\n"));
1102 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1103 pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
1104 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1105 pt_to_str(PT_ALLOWED_ADDRESS),
1106 gettext("<IP-address>"));
1107 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1108 pt_to_str(PT_PHYSICAL), gettext("<interface>"));
1109 (void) fprintf(fp, gettext("See ifconfig(8) for "
1110 "details of the <interface> string.\n"));
1111 (void) fprintf(fp, gettext("%s %s is valid "
1112 "if the %s property is set to %s, otherwise it "
1113 "must not be set.\n"),
1114 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
1115 pt_to_str(PT_IPTYPE), gettext("shared"));
1116 (void) fprintf(fp, gettext("%s %s is valid "
1117 "if the %s property is set to %s, otherwise it "
1118 "must not be set.\n"),
1119 cmd_to_str(CMD_SET), pt_to_str(PT_ALLOWED_ADDRESS),
1120 pt_to_str(PT_IPTYPE), gettext("exclusive"));
1121 (void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
1122 "is valid if the %s or %s property is set, "
1123 "otherwise it must not be set\n"),
1124 cmd_to_str(CMD_SET),
1125 pt_to_str(PT_DEFROUTER), gettext("<IP-address>"),
1126 cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
1127 gettext(pt_to_str(PT_ADDRESS)),
1128 gettext(pt_to_str(PT_ALLOWED_ADDRESS)));
1129 break;
1130 case RT_DEVICE:
1131 (void) fprintf(fp, gettext("The '%s' resource scope is "
1132 "used to configure a device node.\n"),
1133 rt_to_str(resource_scope));
1134 (void) fprintf(fp, gettext("Valid commands:\n"));
1135 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1136 pt_to_str(PT_MATCH), gettext("<device-path>"));
1137 break;
1138 case RT_RCTL:
1139 (void) fprintf(fp, gettext("The '%s' resource scope is "
1140 "used to configure a resource control.\n"),
1141 rt_to_str(resource_scope));
1142 (void) fprintf(fp, gettext("Valid commands:\n"));
1143 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1144 pt_to_str(PT_NAME), gettext("<string>"));
1145 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1146 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1147 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1148 pt_to_str(PT_LIMIT), gettext("<number>"),
1149 pt_to_str(PT_ACTION), gettext("<action-value>"));
1150 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1151 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
1152 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1153 pt_to_str(PT_LIMIT), gettext("<number>"),
1154 pt_to_str(PT_ACTION), gettext("<action-value>"));
1155 (void) fprintf(fp, "%s\n\t%s := privileged\n"
1156 "\t%s := none | deny\n", gettext("Where"),
1157 gettext("<priv-value>"), gettext("<action-value>"));
1158 break;
1159 case RT_ATTR:
1160 (void) fprintf(fp, gettext("The '%s' resource scope is "
1161 "used to configure a generic attribute.\n"),
1162 rt_to_str(resource_scope));
1163 (void) fprintf(fp, gettext("Valid commands:\n"));
1164 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1165 pt_to_str(PT_NAME), gettext("<name>"));
1166 (void) fprintf(fp, "\t%s %s=boolean\n",
1167 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1168 (void) fprintf(fp, "\t%s %s=true | false\n",
1169 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
1170 (void) fprintf(fp, gettext("or\n"));
1171 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
1172 pt_to_str(PT_TYPE));
1173 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1174 pt_to_str(PT_VALUE), gettext("<integer>"));
1175 (void) fprintf(fp, gettext("or\n"));
1176 (void) fprintf(fp, "\t%s %s=string\n",
1177 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1178 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1179 pt_to_str(PT_VALUE), gettext("<string>"));
1180 (void) fprintf(fp, gettext("or\n"));
1181 (void) fprintf(fp, "\t%s %s=uint\n",
1182 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1183 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1184 pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
1185 break;
1186 case RT_DATASET:
1187 (void) fprintf(fp, gettext("The '%s' resource scope is "
1188 "used to export ZFS datasets.\n"),
1189 rt_to_str(resource_scope));
1190 (void) fprintf(fp, gettext("Valid commands:\n"));
1191 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1192 pt_to_str(PT_NAME), gettext("<name>"));
1193 break;
1194 case RT_DCPU:
1195 (void) fprintf(fp, gettext("The '%s' resource scope "
1196 "configures the 'pools' facility to dedicate\na "
1197 "subset of the system's processors to this zone "
1198 "while it is running.\n"),
1199 rt_to_str(resource_scope));
1200 (void) fprintf(fp, gettext("Valid commands:\n"));
1201 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1202 pt_to_str(PT_NCPUS),
1203 gettext("<unsigned integer | range>"));
1204 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1205 pt_to_str(PT_IMPORTANCE),
1206 gettext("<unsigned integer>"));
1207 break;
1208 case RT_PCAP:
1209 (void) fprintf(fp, gettext("The '%s' resource scope is "
1210 "used to set an upper limit (a cap) on the\n"
1211 "percentage of CPU that can be used by this zone. "
1212 "A '%s' value of 1\ncorresponds to one cpu. The "
1213 "value can be set higher than 1, up to the total\n"
1214 "number of CPUs on the system. The value can "
1215 "also be less than 1,\nrepresenting a fraction of "
1216 "a cpu.\n"),
1217 rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
1218 (void) fprintf(fp, gettext("Valid commands:\n"));
1219 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1220 pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
1221 break;
1222 case RT_MCAP:
1223 (void) fprintf(fp, gettext("The '%s' resource scope is "
1224 "used to set an upper limit (a cap) on the\n"
1225 "amount of physical memory, swap space and locked "
1226 "memory that can be used by\nthis zone.\n"),
1227 rt_to_str(resource_scope));
1228 (void) fprintf(fp, gettext("Valid commands:\n"));
1229 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1230 pt_to_str(PT_PHYSICAL),
1231 gettext("<qualified unsigned decimal>"));
1232 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1233 pt_to_str(PT_SWAP),
1234 gettext("<qualified unsigned decimal>"));
1235 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1236 pt_to_str(PT_LOCKED),
1237 gettext("<qualified unsigned decimal>"));
1238 break;
1239 case RT_ADMIN:
1240 (void) fprintf(fp, gettext("The '%s' resource scope is "
1241 "used to delegate specific zone management\n"
1242 "rights to users and roles. These rights are "
1243 "only applicable to this zone.\n"),
1244 rt_to_str(resource_scope));
1245 (void) fprintf(fp, gettext("Valid commands:\n"));
1246 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1247 pt_to_str(PT_USER),
1248 gettext("<single user or role name>"));
1249 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1250 pt_to_str(PT_AUTHS),
1251 gettext("<comma separated list>"));
1252 break;
1253 case RT_SECFLAGS:
1254 (void) fprintf(fp, gettext("The '%s' resource scope is "
1255 "used to specify the default security-flags\n"
1256 "of this zone, and their upper and lower bound.\n"),
1257 rt_to_str(resource_scope));
1258 (void) fprintf(fp, "\t%s %s=%s\n",
1259 cmd_to_str(CMD_SET), pt_to_str(PT_DEFAULT),
1260 gettext("<security flags>"));
1261 (void) fprintf(fp, "\t%s %s=%s\n",
1262 cmd_to_str(CMD_SET), pt_to_str(PT_LOWER),
1263 gettext("<security flags>"));
1264 (void) fprintf(fp, "\t%s %s=%s\n",
1265 cmd_to_str(CMD_SET), pt_to_str(PT_UPPER),
1266 gettext("<security flags>"));
1267 break;
1269 (void) fprintf(fp, gettext("And from any resource scope, you "
1270 "can:\n"));
1271 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
1272 gettext("(to conclude this operation)"));
1273 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
1274 gettext("(to cancel this operation)"));
1275 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
1276 gettext("(to exit the zonecfg utility)"));
1278 if (flags & HELP_USAGE) {
1279 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
1280 execname, cmd_to_str(CMD_HELP));
1281 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
1282 execname, gettext("interactive"));
1283 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
1284 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
1285 execname);
1287 if (flags & HELP_SUBCMDS) {
1288 (void) fprintf(fp, "%s:\n\n", gettext("Commands"));
1289 for (i = 0; i <= CMD_MAX; i++) {
1290 (void) fprintf(fp, "%s\n", helptab[i].short_usage);
1291 if (verbose)
1292 (void) fprintf(fp, "\t%s\n\n", long_help(i));
1295 if (flags & HELP_SYNTAX) {
1296 if (!verbose)
1297 (void) fprintf(fp, "\n");
1298 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
1299 (void) fprintf(fp, gettext("\t(except the reserved words "
1300 "'%s' and anything starting with '%s')\n"), "global",
1301 "SUNW");
1302 (void) fprintf(fp,
1303 gettext("\tName must be less than %d characters.\n"),
1304 ZONENAME_MAX);
1305 if (verbose)
1306 (void) fprintf(fp, "\n");
1308 if (flags & HELP_NETADDR) {
1309 (void) fprintf(fp, gettext("\n<net-addr> :="));
1310 (void) fprintf(fp,
1311 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
1312 (void) fprintf(fp,
1313 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
1314 (void) fprintf(fp,
1315 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
1316 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
1317 "IPv6 address syntax.\n"));
1318 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
1319 (void) fprintf(fp,
1320 gettext("<IPv6-prefix-length> := [0-128]\n"));
1321 (void) fprintf(fp,
1322 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
1324 if (flags & HELP_RESOURCES) {
1325 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s |\n\t"
1326 "%s | %s | %s | %s | %s\n\n",
1327 gettext("resource type"), rt_to_str(RT_FS),
1328 rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
1329 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
1330 rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
1331 rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
1332 rt_to_str(RT_ADMIN), rt_to_str(RT_SECFLAGS));
1334 if (flags & HELP_PROPS) {
1335 (void) fprintf(fp, gettext("For resource type ... there are "
1336 "property types ...:\n"));
1337 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1338 pt_to_str(PT_ZONENAME));
1339 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1340 pt_to_str(PT_ZONEPATH));
1341 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1342 pt_to_str(PT_BRAND));
1343 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1344 pt_to_str(PT_AUTOBOOT));
1345 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1346 pt_to_str(PT_BOOTARGS));
1347 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1348 pt_to_str(PT_POOL));
1349 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1350 pt_to_str(PT_LIMITPRIV));
1351 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1352 pt_to_str(PT_SCHED));
1353 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1354 pt_to_str(PT_IPTYPE));
1355 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1356 pt_to_str(PT_HOSTID));
1357 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1358 pt_to_str(PT_FS_ALLOWED));
1359 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1360 pt_to_str(PT_MAXLWPS));
1361 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1362 pt_to_str(PT_MAXPROCS));
1363 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1364 pt_to_str(PT_MAXSHMMEM));
1365 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1366 pt_to_str(PT_MAXSHMIDS));
1367 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1368 pt_to_str(PT_MAXMSGIDS));
1369 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1370 pt_to_str(PT_MAXSEMIDS));
1371 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1372 pt_to_str(PT_SHARES));
1373 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
1374 rt_to_str(RT_FS), pt_to_str(PT_DIR),
1375 pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
1376 pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
1377 (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
1378 pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
1379 pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
1380 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1381 pt_to_str(PT_MATCH));
1382 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1383 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1384 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1385 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1386 pt_to_str(PT_VALUE));
1387 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1388 pt_to_str(PT_NAME));
1389 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1390 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1391 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1392 pt_to_str(PT_NCPUS));
1393 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1394 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1395 pt_to_str(PT_LOCKED));
1396 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1397 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1398 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n",
1399 rt_to_str(RT_SECFLAGS), pt_to_str(PT_DEFAULT),
1400 pt_to_str(PT_LOWER), pt_to_str(PT_UPPER));
1402 if (need_to_close)
1403 (void) pager_close(fp);
1406 static void
1407 zone_perror(char *prefix, int err, boolean_t set_saw)
1409 zerr("%s: %s", prefix, zonecfg_strerror(err));
1410 if (set_saw)
1411 saw_error = B_TRUE;
1415 * zone_perror() expects a single string, but for remove and select
1416 * we have both the command and the resource type, so this wrapper
1417 * function serves the same purpose in a slightly different way.
1420 static void
1421 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1423 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
1424 zonecfg_strerror(err));
1425 if (set_saw)
1426 saw_error = B_TRUE;
1429 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
1430 static int
1431 initialize(boolean_t handle_expected)
1433 int err;
1434 char brandname[MAXNAMELEN];
1436 if (zonecfg_check_handle(handle) != Z_OK) {
1437 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
1438 got_handle = B_TRUE;
1439 if (zonecfg_get_brand(handle, brandname,
1440 sizeof (brandname)) != Z_OK) {
1441 zerr("Zone %s is inconsistent: missing "
1442 "brand attribute", zone);
1443 exit(Z_ERR);
1445 if ((brand = brand_open(brandname)) == NULL) {
1446 zerr("Zone %s uses non-existent brand \"%s\"."
1447 " Unable to continue", zone, brandname);
1448 exit(Z_ERR);
1451 * If the user_attr file is newer than
1452 * the zone config file, the admins
1453 * may need to be updated since the
1454 * RBAC files are authoritative for
1455 * authorization checks.
1457 err = zonecfg_update_userauths(handle, zone);
1458 if (err == Z_OK) {
1459 zerr(gettext("The administrative rights "
1460 "were updated to match "
1461 "the current RBAC configuration.\n"
1462 "Use \"info admin\" and \"revert\" to "
1463 "compare with the previous settings."));
1464 need_to_commit = B_TRUE;
1465 } else if (err != Z_NO_ENTRY) {
1466 zerr(gettext("failed to update "
1467 "admin rights."));
1468 exit(Z_ERR);
1469 } else if (need_to_commit) {
1470 zerr(gettext("admin rights were updated "
1471 "to match RBAC configuration."));
1474 } else if (global_zone && err == Z_NO_ZONE && !got_handle &&
1475 !read_only_mode) {
1477 * We implicitly create the global zone config if it
1478 * doesn't exist.
1480 zone_dochandle_t tmphandle;
1482 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1483 zone_perror(execname, Z_NOMEM, B_TRUE);
1484 exit(Z_ERR);
1487 err = zonecfg_get_template_handle("SUNWblank", zone,
1488 tmphandle);
1490 if (err != Z_OK) {
1491 zonecfg_fini_handle(tmphandle);
1492 zone_perror("SUNWblank", err, B_TRUE);
1493 return (err);
1496 need_to_commit = B_TRUE;
1497 zonecfg_fini_handle(handle);
1498 handle = tmphandle;
1499 got_handle = B_TRUE;
1501 } else {
1502 zone_perror(zone, err, handle_expected || got_handle);
1503 if (err == Z_NO_ZONE && !got_handle &&
1504 interactive_mode && !read_only_mode)
1505 (void) printf(gettext("Use '%s' to begin "
1506 "configuring a new zone.\n"),
1507 cmd_to_str(CMD_CREATE));
1508 return (err);
1511 return (Z_OK);
1514 static boolean_t
1515 state_atleast(zone_state_t state)
1517 zone_state_t state_num;
1518 int err;
1520 if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
1521 /* all states are greater than "non-existent" */
1522 if (err == Z_NO_ZONE)
1523 return (B_FALSE);
1524 zerr(gettext("Unexpectedly failed to determine state "
1525 "of zone %s: %s"), zone, zonecfg_strerror(err));
1526 exit(Z_ERR);
1528 return (state_num >= state);
1532 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
1535 void
1536 short_usage(int command)
1538 /* lex_lineno has already been incremented in the lexer; compensate */
1539 if (cmd_file_mode) {
1540 if (strcmp(cmd_file_name, "-") == 0)
1541 (void) fprintf(stderr,
1542 gettext("syntax error on line %d\n"),
1543 lex_lineno - 1);
1544 else
1545 (void) fprintf(stderr,
1546 gettext("syntax error on line %d of %s\n"),
1547 lex_lineno - 1, cmd_file_name);
1549 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
1550 helptab[command].short_usage);
1551 saw_error = B_TRUE;
1555 * long_usage() is for bad semantics: e.g., wrong property type for a given
1556 * resource type. It is also used by longer_usage() below.
1559 void
1560 long_usage(uint_t cmd_num, boolean_t set_saw)
1562 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
1563 helptab[cmd_num].short_usage);
1564 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
1565 if (set_saw)
1566 saw_error = B_TRUE;
1570 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
1571 * any extra usage() flags as appropriate for whatever command.
1574 void
1575 longer_usage(uint_t cmd_num)
1577 long_usage(cmd_num, B_FALSE);
1578 if (helptab[cmd_num].flags != 0) {
1579 (void) printf("\n");
1580 usage(B_TRUE, helptab[cmd_num].flags);
1585 * scope_usage() is simply used when a command is called from the wrong scope.
1588 static void
1589 scope_usage(uint_t cmd_num)
1591 zerr(gettext("The %s command only makes sense in the %s scope."),
1592 cmd_to_str(cmd_num),
1593 global_scope ? gettext("resource") : gettext("global"));
1594 saw_error = B_TRUE;
1598 * On input, B_TRUE => yes, B_FALSE => no.
1599 * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
1602 static int
1603 ask_yesno(boolean_t default_answer, const char *question)
1605 char line[64]; /* should be enough to answer yes or no */
1607 if (!ok_to_prompt) {
1608 saw_error = B_TRUE;
1609 return (-1);
1611 for (;;) {
1612 if (printf("%s (%s)? ", question,
1613 default_answer ? "[y]/n" : "y/[n]") < 0)
1614 return (-1);
1615 if (fgets(line, sizeof (line), stdin) == NULL)
1616 return (-1);
1618 if (line[0] == '\n')
1619 return (default_answer ? 1 : 0);
1620 if (tolower(line[0]) == 'y')
1621 return (1);
1622 if (tolower(line[0]) == 'n')
1623 return (0);
1628 * Prints warning if zone already exists.
1629 * In interactive mode, prompts if we should continue anyway and returns Z_OK
1630 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR.
1632 * Note that if a zone exists and its state is >= INSTALLED, an error message
1633 * will be printed and this function will return Z_ERR regardless of mode.
1636 static int
1637 check_if_zone_already_exists(boolean_t force)
1639 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
1640 zone_dochandle_t tmphandle;
1641 int res, answer;
1643 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1644 zone_perror(execname, Z_NOMEM, B_TRUE);
1645 exit(Z_ERR);
1647 res = zonecfg_get_handle(zone, tmphandle);
1648 zonecfg_fini_handle(tmphandle);
1649 if (res != Z_OK)
1650 return (Z_OK);
1652 if (state_atleast(ZONE_STATE_INSTALLED)) {
1653 zerr(gettext("Zone %s already installed; %s not allowed."),
1654 zone, cmd_to_str(CMD_CREATE));
1655 return (Z_ERR);
1658 if (force) {
1659 (void) printf(gettext("Zone %s already exists; overwriting.\n"),
1660 zone);
1661 return (Z_OK);
1663 (void) snprintf(line, sizeof (line),
1664 gettext("Zone %s already exists; %s anyway"), zone,
1665 cmd_to_str(CMD_CREATE));
1666 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
1667 zerr(gettext("Zone exists, input not from terminal and -F not "
1668 "specified:\n%s command ignored, exiting."),
1669 cmd_to_str(CMD_CREATE));
1670 exit(Z_ERR);
1672 return (answer == 1 ? Z_OK : Z_ERR);
1675 static boolean_t
1676 zone_is_read_only(int cmd_num)
1678 if (strncmp(zone, "SUNW", 4) == 0) {
1679 zerr(gettext("%s: zones beginning with SUNW are read-only."),
1680 zone);
1681 saw_error = B_TRUE;
1682 return (B_TRUE);
1684 if (read_only_mode) {
1685 zerr(gettext("%s: cannot %s in read-only mode."), zone,
1686 cmd_to_str(cmd_num));
1687 saw_error = B_TRUE;
1688 return (B_TRUE);
1690 return (B_FALSE);
1694 * Create a new configuration.
1696 void
1697 create_func(cmd_t *cmd)
1699 int err, arg;
1700 char zone_template[ZONENAME_MAX];
1701 char attach_path[MAXPATHLEN];
1702 zone_dochandle_t tmphandle;
1703 boolean_t force = B_FALSE;
1704 boolean_t attach = B_FALSE;
1705 boolean_t arg_err = B_FALSE;
1707 assert(cmd != NULL);
1709 /* This is the default if no arguments are given. */
1710 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
1712 optind = 0;
1713 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
1714 != EOF) {
1715 switch (arg) {
1716 case '?':
1717 if (optopt == '?')
1718 longer_usage(CMD_CREATE);
1719 else
1720 short_usage(CMD_CREATE);
1721 arg_err = B_TRUE;
1722 break;
1723 case 'a':
1724 (void) strlcpy(attach_path, optarg,
1725 sizeof (attach_path));
1726 attach = B_TRUE;
1727 break;
1728 case 'b':
1729 (void) strlcpy(zone_template, "SUNWblank",
1730 sizeof (zone_template));
1731 break;
1732 case 'F':
1733 force = B_TRUE;
1734 break;
1735 case 't':
1736 (void) strlcpy(zone_template, optarg,
1737 sizeof (zone_template));
1738 break;
1739 default:
1740 short_usage(CMD_CREATE);
1741 arg_err = B_TRUE;
1742 break;
1745 if (arg_err)
1746 return;
1748 if (optind != cmd->cmd_argc) {
1749 short_usage(CMD_CREATE);
1750 return;
1753 if (zone_is_read_only(CMD_CREATE))
1754 return;
1756 if (check_if_zone_already_exists(force) != Z_OK)
1757 return;
1760 * Get a temporary handle first. If that fails, the old handle
1761 * will not be lost. Then finish whichever one we don't need,
1762 * to avoid leaks. Then get the handle for zone_template, and
1763 * set the name to zone: this "copy, rename" method is how
1764 * create -[b|t] works.
1766 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1767 zone_perror(execname, Z_NOMEM, B_TRUE);
1768 exit(Z_ERR);
1771 if (attach)
1772 err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
1773 zone, B_FALSE, tmphandle);
1774 else
1775 err = zonecfg_get_template_handle(zone_template, zone,
1776 tmphandle);
1778 if (err != Z_OK) {
1779 zonecfg_fini_handle(tmphandle);
1780 if (attach && err == Z_NO_ZONE)
1781 (void) fprintf(stderr, gettext("invalid path to "
1782 "detached zone\n"));
1783 else if (attach && err == Z_INVALID_DOCUMENT)
1784 (void) fprintf(stderr, gettext("Cannot attach to an "
1785 "earlier release of the operating system\n"));
1786 else
1787 zone_perror(zone_template, err, B_TRUE);
1788 return;
1791 need_to_commit = B_TRUE;
1792 zonecfg_fini_handle(handle);
1793 handle = tmphandle;
1794 got_handle = B_TRUE;
1798 * This malloc()'s memory, which must be freed by the caller.
1800 static char *
1801 quoteit(char *instr)
1803 char *outstr;
1804 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */
1806 if ((outstr = malloc(outstrsize)) == NULL) {
1807 zone_perror(zone, Z_NOMEM, B_FALSE);
1808 exit(Z_ERR);
1810 if (strchr(instr, ' ') == NULL) {
1811 (void) strlcpy(outstr, instr, outstrsize);
1812 return (outstr);
1814 (void) snprintf(outstr, outstrsize, "\"%s\"", instr);
1815 return (outstr);
1818 static void
1819 export_prop(FILE *of, int prop_num, char *prop_id)
1821 char *quote_str;
1823 if (strlen(prop_id) == 0)
1824 return;
1825 quote_str = quoteit(prop_id);
1826 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1827 pt_to_str(prop_num), quote_str);
1828 free(quote_str);
1831 void
1832 export_func(cmd_t *cmd)
1834 struct zone_nwiftab nwiftab;
1835 struct zone_fstab fstab;
1836 struct zone_devtab devtab;
1837 struct zone_attrtab attrtab;
1838 struct zone_rctltab rctltab;
1839 struct zone_dstab dstab;
1840 struct zone_psettab psettab;
1841 struct zone_mcaptab mcaptab;
1842 struct zone_rctlvaltab *valptr;
1843 struct zone_admintab admintab;
1844 struct zone_secflagstab secflagstab;
1845 int err, arg;
1846 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
1847 char bootargs[BOOTARGS_MAX];
1848 char sched[MAXNAMELEN];
1849 char brand[MAXNAMELEN];
1850 char hostidp[HW_HOSTID_LEN];
1851 char fsallowedp[ZONE_FS_ALLOWED_MAX];
1852 char *limitpriv;
1853 FILE *of;
1854 boolean_t autoboot;
1855 zone_iptype_t iptype;
1856 boolean_t need_to_close = B_FALSE;
1857 boolean_t arg_err = B_FALSE;
1859 assert(cmd != NULL);
1861 outfile[0] = '\0';
1862 optind = 0;
1863 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
1864 switch (arg) {
1865 case '?':
1866 if (optopt == '?')
1867 longer_usage(CMD_EXPORT);
1868 else
1869 short_usage(CMD_EXPORT);
1870 arg_err = B_TRUE;
1871 break;
1872 case 'f':
1873 (void) strlcpy(outfile, optarg, sizeof (outfile));
1874 break;
1875 default:
1876 short_usage(CMD_EXPORT);
1877 arg_err = B_TRUE;
1878 break;
1881 if (arg_err)
1882 return;
1884 if (optind != cmd->cmd_argc) {
1885 short_usage(CMD_EXPORT);
1886 return;
1888 if (strlen(outfile) == 0) {
1889 of = stdout;
1890 } else {
1891 if ((of = fopen(outfile, "w")) == NULL) {
1892 zerr(gettext("opening file %s: %s"),
1893 outfile, strerror(errno));
1894 goto done;
1896 setbuf(of, NULL);
1897 need_to_close = B_TRUE;
1900 if ((err = initialize(B_TRUE)) != Z_OK)
1901 goto done;
1903 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
1905 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
1906 strlen(zonepath) > 0)
1907 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1908 pt_to_str(PT_ZONEPATH), zonepath);
1910 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
1911 (strcmp(brand, NATIVE_BRAND_NAME) != 0))
1912 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1913 pt_to_str(PT_BRAND), brand);
1915 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
1916 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1917 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
1919 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
1920 strlen(bootargs) > 0) {
1921 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1922 pt_to_str(PT_BOOTARGS), bootargs);
1925 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
1926 strlen(pool) > 0)
1927 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1928 pt_to_str(PT_POOL), pool);
1930 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
1931 strlen(limitpriv) > 0) {
1932 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1933 pt_to_str(PT_LIMITPRIV), limitpriv);
1934 free(limitpriv);
1937 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
1938 strlen(sched) > 0)
1939 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1940 pt_to_str(PT_SCHED), sched);
1942 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
1943 switch (iptype) {
1944 case ZS_SHARED:
1945 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1946 pt_to_str(PT_IPTYPE), "shared");
1947 break;
1948 case ZS_EXCLUSIVE:
1949 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1950 pt_to_str(PT_IPTYPE), "exclusive");
1951 break;
1955 if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
1956 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1957 pt_to_str(PT_HOSTID), hostidp);
1960 if (zonecfg_get_fs_allowed(handle, fsallowedp,
1961 sizeof (fsallowedp)) == Z_OK) {
1962 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1963 pt_to_str(PT_FS_ALLOWED), fsallowedp);
1966 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
1967 zone_perror(zone, err, B_FALSE);
1968 goto done;
1970 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1971 zone_fsopt_t *optptr;
1973 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1974 rt_to_str(RT_FS));
1975 export_prop(of, PT_DIR, fstab.zone_fs_dir);
1976 export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
1977 export_prop(of, PT_RAW, fstab.zone_fs_raw);
1978 export_prop(of, PT_TYPE, fstab.zone_fs_type);
1979 for (optptr = fstab.zone_fs_options; optptr != NULL;
1980 optptr = optptr->zone_fsopt_next) {
1982 * Simple property values with embedded equal signs
1983 * need to be quoted to prevent the lexer from
1984 * mis-parsing them as complex name=value pairs.
1986 if (strchr(optptr->zone_fsopt_opt, '='))
1987 (void) fprintf(of, "%s %s \"%s\"\n",
1988 cmd_to_str(CMD_ADD),
1989 pt_to_str(PT_OPTIONS),
1990 optptr->zone_fsopt_opt);
1991 else
1992 (void) fprintf(of, "%s %s %s\n",
1993 cmd_to_str(CMD_ADD),
1994 pt_to_str(PT_OPTIONS),
1995 optptr->zone_fsopt_opt);
1997 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
1998 zonecfg_free_fs_option_list(fstab.zone_fs_options);
2000 (void) zonecfg_endfsent(handle);
2002 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2003 zone_perror(zone, err, B_FALSE);
2004 goto done;
2006 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2007 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2008 rt_to_str(RT_NET));
2009 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
2010 export_prop(of, PT_ALLOWED_ADDRESS,
2011 nwiftab.zone_nwif_allowed_address);
2012 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
2013 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
2014 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2016 (void) zonecfg_endnwifent(handle);
2018 if ((err = zonecfg_setdevent(handle)) != Z_OK) {
2019 zone_perror(zone, err, B_FALSE);
2020 goto done;
2022 while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
2023 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2024 rt_to_str(RT_DEVICE));
2025 export_prop(of, PT_MATCH, devtab.zone_dev_match);
2026 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2028 (void) zonecfg_enddevent(handle);
2030 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
2031 char buf[128];
2033 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2034 rt_to_str(RT_MCAP));
2035 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
2036 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2037 pt_to_str(PT_PHYSICAL), buf);
2038 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2041 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
2042 zone_perror(zone, err, B_FALSE);
2043 goto done;
2045 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
2046 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
2047 export_prop(of, PT_NAME, rctltab.zone_rctl_name);
2048 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
2049 valptr = valptr->zone_rctlval_next) {
2050 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
2051 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
2052 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
2053 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
2054 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
2056 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2057 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2059 (void) zonecfg_endrctlent(handle);
2061 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
2062 zone_perror(zone, err, B_FALSE);
2063 goto done;
2065 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
2066 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2067 rt_to_str(RT_ATTR));
2068 export_prop(of, PT_NAME, attrtab.zone_attr_name);
2069 export_prop(of, PT_TYPE, attrtab.zone_attr_type);
2070 export_prop(of, PT_VALUE, attrtab.zone_attr_value);
2071 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2073 (void) zonecfg_endattrent(handle);
2075 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
2076 zone_perror(zone, err, B_FALSE);
2077 goto done;
2079 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
2080 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2081 rt_to_str(RT_DATASET));
2082 export_prop(of, PT_NAME, dstab.zone_dataset_name);
2083 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2085 (void) zonecfg_enddsent(handle);
2087 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
2088 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2089 rt_to_str(RT_DCPU));
2090 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
2091 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2092 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
2093 else
2094 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
2095 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
2096 psettab.zone_ncpu_max);
2097 if (psettab.zone_importance[0] != '\0')
2098 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2099 pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
2100 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2103 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
2104 zone_perror(zone, err, B_FALSE);
2105 goto done;
2107 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
2108 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2109 rt_to_str(RT_ADMIN));
2110 export_prop(of, PT_USER, admintab.zone_admin_user);
2111 export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
2112 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2115 (void) zonecfg_endadminent(handle);
2117 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
2118 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2119 rt_to_str(RT_SECFLAGS));
2120 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
2121 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
2122 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
2123 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2127 * There is nothing to export for pcap since this resource is just
2128 * a container for an rctl alias.
2131 done:
2132 if (need_to_close)
2133 (void) fclose(of);
2136 void
2137 exit_func(cmd_t *cmd)
2139 int arg, answer;
2140 boolean_t arg_err = B_FALSE;
2142 optind = 0;
2143 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2144 switch (arg) {
2145 case '?':
2146 longer_usage(CMD_EXIT);
2147 arg_err = B_TRUE;
2148 break;
2149 case 'F':
2150 force_exit = B_TRUE;
2151 break;
2152 default:
2153 short_usage(CMD_EXIT);
2154 arg_err = B_TRUE;
2155 break;
2158 if (arg_err)
2159 return;
2161 if (optind < cmd->cmd_argc) {
2162 short_usage(CMD_EXIT);
2163 return;
2166 if (global_scope || force_exit) {
2167 time_to_exit = B_TRUE;
2168 return;
2171 answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2172 if (answer == -1) {
2173 zerr(gettext("Resource incomplete, input "
2174 "not from terminal and -F not specified:\n%s command "
2175 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2176 exit(Z_ERR);
2177 } else if (answer == 1) {
2178 time_to_exit = B_TRUE;
2180 /* (answer == 0) => just return */
2183 static int
2184 validate_zonepath_syntax(char *path)
2186 if (path[0] != '/') {
2187 zerr(gettext("%s is not an absolute path."), path);
2188 return (Z_ERR);
2190 /* If path is all slashes, then fail */
2191 if (strspn(path, "/") == strlen(path)) {
2192 zerr(gettext("/ is not allowed as a %s."),
2193 pt_to_str(PT_ZONEPATH));
2194 return (Z_ERR);
2196 return (Z_OK);
2199 static void
2200 add_resource(cmd_t *cmd)
2202 int type;
2203 struct zone_psettab tmp_psettab;
2204 struct zone_mcaptab tmp_mcaptab;
2205 struct zone_secflagstab tmp_secflagstab;
2206 uint64_t tmp;
2207 uint64_t tmp_mcap;
2208 char pool[MAXNAMELEN];
2210 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2211 long_usage(CMD_ADD, B_TRUE);
2212 goto bad;
2215 switch (type) {
2216 case RT_FS:
2217 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2218 return;
2219 case RT_NET:
2220 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2221 return;
2222 case RT_DEVICE:
2223 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2224 return;
2225 case RT_RCTL:
2226 if (global_zone)
2227 zerr(gettext("WARNING: Setting a global zone resource "
2228 "control too low could deny\nservice "
2229 "to even the root user; "
2230 "this could render the system impossible\n"
2231 "to administer. Please use caution."));
2232 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2233 return;
2234 case RT_ATTR:
2235 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2236 return;
2237 case RT_DATASET:
2238 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2239 return;
2240 case RT_DCPU:
2241 /* Make sure there isn't already a cpu-set or cpu-cap entry. */
2242 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2243 zerr(gettext("The %s resource already exists."),
2244 rt_to_str(RT_DCPU));
2245 goto bad;
2247 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2248 Z_NO_ENTRY) {
2249 zerr(gettext("The %s resource already exists."),
2250 rt_to_str(RT_PCAP));
2251 goto bad;
2254 /* Make sure the pool property isn't set. */
2255 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2256 strlen(pool) > 0) {
2257 zerr(gettext("The %s property is already set. "
2258 "A persistent pool is incompatible with\nthe %s "
2259 "resource."),
2260 pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2261 goto bad;
2264 bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2265 return;
2266 case RT_PCAP:
2268 * Make sure there isn't already a cpu-set or incompatible
2269 * cpu-cap rctls.
2271 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2272 zerr(gettext("The %s resource already exists."),
2273 rt_to_str(RT_DCPU));
2274 goto bad;
2277 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2278 case Z_ALIAS_DISALLOW:
2279 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2280 B_FALSE);
2281 goto bad;
2283 case Z_OK:
2284 zerr(gettext("The %s resource already exists."),
2285 rt_to_str(RT_PCAP));
2286 goto bad;
2288 default:
2289 break;
2291 return;
2292 case RT_MCAP:
2294 * Make sure there isn't already a mem-cap entry or max-swap
2295 * or max-locked rctl.
2297 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2298 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2299 == Z_OK ||
2300 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2301 &tmp_mcap) == Z_OK) {
2302 zerr(gettext("The %s resource or a related resource "
2303 "control already exists."), rt_to_str(RT_MCAP));
2304 goto bad;
2306 if (global_zone)
2307 zerr(gettext("WARNING: Setting a global zone memory "
2308 "cap too low could deny\nservice "
2309 "to even the root user; "
2310 "this could render the system impossible\n"
2311 "to administer. Please use caution."));
2312 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2313 return;
2314 case RT_ADMIN:
2315 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2316 return;
2317 case RT_SECFLAGS:
2318 /* Make sure we haven't already set this */
2319 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
2320 zerr(gettext("The %s resource already exists."),
2321 rt_to_str(RT_SECFLAGS));
2322 bzero(&in_progress_secflagstab,
2323 sizeof (in_progress_secflagstab));
2324 return;
2325 default:
2326 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2327 long_usage(CMD_ADD, B_TRUE);
2328 usage(B_FALSE, HELP_RESOURCES);
2330 bad:
2331 global_scope = B_TRUE;
2332 end_op = -1;
2335 static void
2336 do_complex_rctl_val(complex_property_ptr_t cp)
2338 struct zone_rctlvaltab *rctlvaltab;
2339 complex_property_ptr_t cx;
2340 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2341 seen_action = B_FALSE;
2342 rctlblk_t *rctlblk;
2343 int err;
2345 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2346 zone_perror(zone, Z_NOMEM, B_TRUE);
2347 exit(Z_ERR);
2349 for (cx = cp; cx != NULL; cx = cx->cp_next) {
2350 switch (cx->cp_type) {
2351 case PT_PRIV:
2352 if (seen_priv) {
2353 zerr(gettext("%s already specified"),
2354 pt_to_str(PT_PRIV));
2355 goto bad;
2357 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
2358 cx->cp_value,
2359 sizeof (rctlvaltab->zone_rctlval_priv));
2360 seen_priv = B_TRUE;
2361 break;
2362 case PT_LIMIT:
2363 if (seen_limit) {
2364 zerr(gettext("%s already specified"),
2365 pt_to_str(PT_LIMIT));
2366 goto bad;
2368 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
2369 cx->cp_value,
2370 sizeof (rctlvaltab->zone_rctlval_limit));
2371 seen_limit = B_TRUE;
2372 break;
2373 case PT_ACTION:
2374 if (seen_action) {
2375 zerr(gettext("%s already specified"),
2376 pt_to_str(PT_ACTION));
2377 goto bad;
2379 (void) strlcpy(rctlvaltab->zone_rctlval_action,
2380 cx->cp_value,
2381 sizeof (rctlvaltab->zone_rctlval_action));
2382 seen_action = B_TRUE;
2383 break;
2384 default:
2385 zone_perror(pt_to_str(PT_VALUE),
2386 Z_NO_PROPERTY_TYPE, B_TRUE);
2387 long_usage(CMD_ADD, B_TRUE);
2388 usage(B_FALSE, HELP_PROPS);
2389 zonecfg_free_rctl_value_list(rctlvaltab);
2390 return;
2393 if (!seen_priv)
2394 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2395 if (!seen_limit)
2396 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2397 if (!seen_action)
2398 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2399 if (!seen_priv || !seen_limit || !seen_action)
2400 goto bad;
2401 rctlvaltab->zone_rctlval_next = NULL;
2402 rctlblk = alloca(rctlblk_size());
2404 * Make sure the rctl value looks roughly correct; we won't know if
2405 * it's truly OK until we verify the configuration on the target
2406 * system.
2408 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2409 !zonecfg_valid_rctlblk(rctlblk)) {
2410 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2411 pt_to_str(PT_VALUE));
2412 goto bad;
2414 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2415 if (err != Z_OK)
2416 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2417 return;
2419 bad:
2420 zonecfg_free_rctl_value_list(rctlvaltab);
2423 static void
2424 add_property(cmd_t *cmd)
2426 char *prop_id;
2427 int err, res_type, prop_type;
2428 property_value_ptr_t pp;
2429 list_property_ptr_t l;
2431 res_type = resource_scope;
2432 prop_type = cmd->cmd_prop_name[0];
2433 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2434 long_usage(CMD_ADD, B_TRUE);
2435 return;
2438 if (cmd->cmd_prop_nv_pairs != 1) {
2439 long_usage(CMD_ADD, B_TRUE);
2440 return;
2443 if (initialize(B_TRUE) != Z_OK)
2444 return;
2446 switch (res_type) {
2447 case RT_FS:
2448 if (prop_type != PT_OPTIONS) {
2449 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2450 B_TRUE);
2451 long_usage(CMD_ADD, B_TRUE);
2452 usage(B_FALSE, HELP_PROPS);
2453 return;
2455 pp = cmd->cmd_property_ptr[0];
2456 if (pp->pv_type != PROP_VAL_SIMPLE &&
2457 pp->pv_type != PROP_VAL_LIST) {
2458 zerr(gettext("A %s or %s value was expected here."),
2459 pvt_to_str(PROP_VAL_SIMPLE),
2460 pvt_to_str(PROP_VAL_LIST));
2461 saw_error = B_TRUE;
2462 return;
2464 if (pp->pv_type == PROP_VAL_SIMPLE) {
2465 if (pp->pv_simple == NULL) {
2466 long_usage(CMD_ADD, B_TRUE);
2467 return;
2469 prop_id = pp->pv_simple;
2470 err = zonecfg_add_fs_option(&in_progress_fstab,
2471 prop_id);
2472 if (err != Z_OK)
2473 zone_perror(pt_to_str(prop_type), err, B_TRUE);
2474 } else {
2475 list_property_ptr_t list;
2477 for (list = pp->pv_list; list != NULL;
2478 list = list->lp_next) {
2479 prop_id = list->lp_simple;
2480 if (prop_id == NULL)
2481 break;
2482 err = zonecfg_add_fs_option(
2483 &in_progress_fstab, prop_id);
2484 if (err != Z_OK)
2485 zone_perror(pt_to_str(prop_type), err,
2486 B_TRUE);
2489 return;
2490 case RT_RCTL:
2491 if (prop_type != PT_VALUE) {
2492 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2493 B_TRUE);
2494 long_usage(CMD_ADD, B_TRUE);
2495 usage(B_FALSE, HELP_PROPS);
2496 return;
2498 pp = cmd->cmd_property_ptr[0];
2499 if (pp->pv_type != PROP_VAL_COMPLEX &&
2500 pp->pv_type != PROP_VAL_LIST) {
2501 zerr(gettext("A %s or %s value was expected here."),
2502 pvt_to_str(PROP_VAL_COMPLEX),
2503 pvt_to_str(PROP_VAL_LIST));
2504 saw_error = B_TRUE;
2505 return;
2507 if (pp->pv_type == PROP_VAL_COMPLEX) {
2508 do_complex_rctl_val(pp->pv_complex);
2509 return;
2511 for (l = pp->pv_list; l != NULL; l = l->lp_next)
2512 do_complex_rctl_val(l->lp_complex);
2513 return;
2514 default:
2515 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2516 long_usage(CMD_ADD, B_TRUE);
2517 usage(B_FALSE, HELP_RESOURCES);
2518 return;
2522 static boolean_t
2523 gz_invalid_resource(int type)
2525 return (global_zone && (type == RT_FS ||
2526 type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2527 type == RT_DATASET));
2530 static boolean_t
2531 gz_invalid_rt_property(int type)
2533 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2534 type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2535 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2536 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2539 static boolean_t
2540 gz_invalid_property(int type)
2542 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2543 type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2544 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2545 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2548 void
2549 add_func(cmd_t *cmd)
2551 int arg;
2552 boolean_t arg_err = B_FALSE;
2554 assert(cmd != NULL);
2556 optind = 0;
2557 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2558 switch (arg) {
2559 case '?':
2560 longer_usage(CMD_ADD);
2561 arg_err = B_TRUE;
2562 break;
2563 default:
2564 short_usage(CMD_ADD);
2565 arg_err = B_TRUE;
2566 break;
2569 if (arg_err)
2570 return;
2572 if (optind != cmd->cmd_argc) {
2573 short_usage(CMD_ADD);
2574 return;
2577 if (zone_is_read_only(CMD_ADD))
2578 return;
2580 if (initialize(B_TRUE) != Z_OK)
2581 return;
2582 if (global_scope) {
2583 if (gz_invalid_resource(cmd->cmd_res_type)) {
2584 zerr(gettext("Cannot add a %s resource to the "
2585 "global zone."), rt_to_str(cmd->cmd_res_type));
2586 saw_error = B_TRUE;
2587 return;
2590 global_scope = B_FALSE;
2591 resource_scope = cmd->cmd_res_type;
2592 end_op = CMD_ADD;
2593 add_resource(cmd);
2594 } else
2595 add_property(cmd);
2599 * This routine has an unusual implementation, because it tries very
2600 * hard to succeed in the face of a variety of failure modes.
2601 * The most common and most vexing occurs when the index file and
2602 * the /etc/zones/<zonename.xml> file are not both present. In
2603 * this case, delete must eradicate as much of the zone state as is left
2604 * so that the user can later create a new zone with the same name.
2606 void
2607 delete_func(cmd_t *cmd)
2609 int err, arg, answer;
2610 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
2611 boolean_t force = B_FALSE;
2612 boolean_t arg_err = B_FALSE;
2614 optind = 0;
2615 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2616 switch (arg) {
2617 case '?':
2618 longer_usage(CMD_DELETE);
2619 arg_err = B_TRUE;
2620 break;
2621 case 'F':
2622 force = B_TRUE;
2623 break;
2624 default:
2625 short_usage(CMD_DELETE);
2626 arg_err = B_TRUE;
2627 break;
2630 if (arg_err)
2631 return;
2633 if (optind != cmd->cmd_argc) {
2634 short_usage(CMD_DELETE);
2635 return;
2638 if (zone_is_read_only(CMD_DELETE))
2639 return;
2641 if (!force) {
2643 * Initialize sets up the global called "handle" and warns the
2644 * user if the zone is not configured. In force mode, we don't
2645 * trust that evaluation, and hence skip it. (We don't need the
2646 * handle to be loaded anyway, since zonecfg_destroy is done by
2647 * zonename). However, we also have to take care to emulate the
2648 * messages spit out by initialize; see below.
2650 if (initialize(B_TRUE) != Z_OK)
2651 return;
2653 (void) snprintf(line, sizeof (line),
2654 gettext("Are you sure you want to delete zone %s"), zone);
2655 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2656 zerr(gettext("Input not from terminal and -F not "
2657 "specified:\n%s command ignored, exiting."),
2658 cmd_to_str(CMD_DELETE));
2659 exit(Z_ERR);
2661 if (answer != 1)
2662 return;
2666 * This function removes the authorizations from user_attr
2667 * that correspond to those specified in the configuration
2669 if (initialize(B_TRUE) == Z_OK) {
2670 (void) zonecfg_deauthorize_users(handle, zone);
2672 if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2673 if ((err == Z_BAD_ZONE_STATE) && !force) {
2674 zerr(gettext("Zone %s not in %s state; %s not "
2675 "allowed. Use -F to force %s."),
2676 zone, zone_state_str(ZONE_STATE_CONFIGURED),
2677 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2678 } else {
2679 zone_perror(zone, err, B_TRUE);
2682 need_to_commit = B_FALSE;
2685 * Emulate initialize's messaging; if there wasn't a valid handle to
2686 * begin with, then user had typed delete (or delete -F) multiple
2687 * times. So we emit a message.
2689 * We only do this in the 'force' case because normally, initialize()
2690 * takes care of this for us.
2692 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2693 (void) printf(gettext("Use '%s' to begin "
2694 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2697 * Time for a new handle: finish the old one off first
2698 * then get a new one properly to avoid leaks.
2700 if (got_handle) {
2701 zonecfg_fini_handle(handle);
2702 if ((handle = zonecfg_init_handle()) == NULL) {
2703 zone_perror(execname, Z_NOMEM, B_TRUE);
2704 exit(Z_ERR);
2706 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2707 /* If there was no zone before, that's OK */
2708 if (err != Z_NO_ZONE)
2709 zone_perror(zone, err, B_TRUE);
2710 got_handle = B_FALSE;
2715 static int
2716 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2718 int err, i;
2719 property_value_ptr_t pp;
2721 if ((err = initialize(B_TRUE)) != Z_OK)
2722 return (err);
2724 bzero(fstab, sizeof (*fstab));
2725 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2726 pp = cmd->cmd_property_ptr[i];
2727 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2728 zerr(gettext("A simple value was expected here."));
2729 saw_error = B_TRUE;
2730 return (Z_INSUFFICIENT_SPEC);
2732 switch (cmd->cmd_prop_name[i]) {
2733 case PT_DIR:
2734 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2735 sizeof (fstab->zone_fs_dir));
2736 break;
2737 case PT_SPECIAL:
2738 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2739 sizeof (fstab->zone_fs_special));
2740 break;
2741 case PT_RAW:
2742 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2743 sizeof (fstab->zone_fs_raw));
2744 break;
2745 case PT_TYPE:
2746 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2747 sizeof (fstab->zone_fs_type));
2748 break;
2749 default:
2750 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2751 Z_NO_PROPERTY_TYPE, B_TRUE);
2752 return (Z_INSUFFICIENT_SPEC);
2755 if (fill_in_only)
2756 return (Z_OK);
2757 return (zonecfg_lookup_filesystem(handle, fstab));
2760 static int
2761 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2762 boolean_t fill_in_only)
2764 int err, i;
2765 property_value_ptr_t pp;
2767 if ((err = initialize(B_TRUE)) != Z_OK)
2768 return (err);
2770 bzero(nwiftab, sizeof (*nwiftab));
2771 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2772 pp = cmd->cmd_property_ptr[i];
2773 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2774 zerr(gettext("A simple value was expected here."));
2775 saw_error = B_TRUE;
2776 return (Z_INSUFFICIENT_SPEC);
2778 switch (cmd->cmd_prop_name[i]) {
2779 case PT_ADDRESS:
2780 (void) strlcpy(nwiftab->zone_nwif_address,
2781 pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2782 break;
2783 case PT_ALLOWED_ADDRESS:
2784 (void) strlcpy(nwiftab->zone_nwif_allowed_address,
2785 pp->pv_simple,
2786 sizeof (nwiftab->zone_nwif_allowed_address));
2787 break;
2788 case PT_PHYSICAL:
2789 (void) strlcpy(nwiftab->zone_nwif_physical,
2790 pp->pv_simple,
2791 sizeof (nwiftab->zone_nwif_physical));
2792 break;
2793 case PT_DEFROUTER:
2794 (void) strlcpy(nwiftab->zone_nwif_defrouter,
2795 pp->pv_simple,
2796 sizeof (nwiftab->zone_nwif_defrouter));
2797 break;
2798 default:
2799 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2800 Z_NO_PROPERTY_TYPE, B_TRUE);
2801 return (Z_INSUFFICIENT_SPEC);
2804 if (fill_in_only)
2805 return (Z_OK);
2806 err = zonecfg_lookup_nwif(handle, nwiftab);
2807 return (err);
2810 static int
2811 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2813 int err, i;
2814 property_value_ptr_t pp;
2816 if ((err = initialize(B_TRUE)) != Z_OK)
2817 return (err);
2819 bzero(devtab, sizeof (*devtab));
2820 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2821 pp = cmd->cmd_property_ptr[i];
2822 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2823 zerr(gettext("A simple value was expected here."));
2824 saw_error = B_TRUE;
2825 return (Z_INSUFFICIENT_SPEC);
2827 switch (cmd->cmd_prop_name[i]) {
2828 case PT_MATCH:
2829 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2830 sizeof (devtab->zone_dev_match));
2831 break;
2832 default:
2833 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2834 Z_NO_PROPERTY_TYPE, B_TRUE);
2835 return (Z_INSUFFICIENT_SPEC);
2838 if (fill_in_only)
2839 return (Z_OK);
2840 err = zonecfg_lookup_dev(handle, devtab);
2841 return (err);
2844 static int
2845 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2846 boolean_t fill_in_only)
2848 int err, i;
2849 property_value_ptr_t pp;
2851 if ((err = initialize(B_TRUE)) != Z_OK)
2852 return (err);
2854 bzero(rctltab, sizeof (*rctltab));
2855 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2856 pp = cmd->cmd_property_ptr[i];
2857 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2858 zerr(gettext("A simple value was expected here."));
2859 saw_error = B_TRUE;
2860 return (Z_INSUFFICIENT_SPEC);
2862 switch (cmd->cmd_prop_name[i]) {
2863 case PT_NAME:
2864 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2865 sizeof (rctltab->zone_rctl_name));
2866 break;
2867 default:
2868 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2869 Z_NO_PROPERTY_TYPE, B_TRUE);
2870 return (Z_INSUFFICIENT_SPEC);
2873 if (fill_in_only)
2874 return (Z_OK);
2875 err = zonecfg_lookup_rctl(handle, rctltab);
2876 return (err);
2879 static int
2880 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2881 boolean_t fill_in_only)
2883 int err, i;
2884 property_value_ptr_t pp;
2886 if ((err = initialize(B_TRUE)) != Z_OK)
2887 return (err);
2889 bzero(attrtab, sizeof (*attrtab));
2890 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2891 pp = cmd->cmd_property_ptr[i];
2892 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2893 zerr(gettext("A simple value was expected here."));
2894 saw_error = B_TRUE;
2895 return (Z_INSUFFICIENT_SPEC);
2897 switch (cmd->cmd_prop_name[i]) {
2898 case PT_NAME:
2899 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2900 sizeof (attrtab->zone_attr_name));
2901 break;
2902 case PT_TYPE:
2903 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2904 sizeof (attrtab->zone_attr_type));
2905 break;
2906 case PT_VALUE:
2907 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2908 sizeof (attrtab->zone_attr_value));
2909 break;
2910 default:
2911 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2912 Z_NO_PROPERTY_TYPE, B_TRUE);
2913 return (Z_INSUFFICIENT_SPEC);
2916 if (fill_in_only)
2917 return (Z_OK);
2918 err = zonecfg_lookup_attr(handle, attrtab);
2919 return (err);
2922 static int
2923 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2925 int err, i;
2926 property_value_ptr_t pp;
2928 if ((err = initialize(B_TRUE)) != Z_OK)
2929 return (err);
2931 dstab->zone_dataset_name[0] = '\0';
2932 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2933 pp = cmd->cmd_property_ptr[i];
2934 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2935 zerr(gettext("A simple value was expected here."));
2936 saw_error = B_TRUE;
2937 return (Z_INSUFFICIENT_SPEC);
2939 switch (cmd->cmd_prop_name[i]) {
2940 case PT_NAME:
2941 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2942 sizeof (dstab->zone_dataset_name));
2943 break;
2944 default:
2945 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2946 Z_NO_PROPERTY_TYPE, B_TRUE);
2947 return (Z_INSUFFICIENT_SPEC);
2950 if (fill_in_only)
2951 return (Z_OK);
2952 return (zonecfg_lookup_ds(handle, dstab));
2955 static int
2956 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2957 boolean_t fill_in_only)
2959 int err, i;
2960 property_value_ptr_t pp;
2962 if ((err = initialize(B_TRUE)) != Z_OK)
2963 return (err);
2965 bzero(admintab, sizeof (*admintab));
2966 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2967 pp = cmd->cmd_property_ptr[i];
2968 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2969 zerr(gettext("A simple value was expected here."));
2970 saw_error = B_TRUE;
2971 return (Z_INSUFFICIENT_SPEC);
2973 switch (cmd->cmd_prop_name[i]) {
2974 case PT_USER:
2975 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2976 sizeof (admintab->zone_admin_user));
2977 break;
2978 case PT_AUTHS:
2979 (void) strlcpy(admintab->zone_admin_auths,
2980 pp->pv_simple, sizeof (admintab->zone_admin_auths));
2981 break;
2982 default:
2983 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2984 Z_NO_PROPERTY_TYPE, B_TRUE);
2985 return (Z_INSUFFICIENT_SPEC);
2988 if (fill_in_only)
2989 return (Z_OK);
2990 err = zonecfg_lookup_admin(handle, admintab);
2991 return (err);
2994 static int
2995 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
2996 boolean_t fill_in_only)
2998 int err, i;
2999 property_value_ptr_t pp;
3001 if ((err = initialize(B_TRUE)) != Z_OK)
3002 return (err);
3004 bzero(secflagstab, sizeof (*secflagstab));
3005 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
3006 pp = cmd->cmd_property_ptr[i];
3007 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
3008 zerr(gettext("A simple value was expected here."));
3009 saw_error = B_TRUE;
3010 return (Z_INSUFFICIENT_SPEC);
3012 switch (cmd->cmd_prop_name[i]) {
3013 case PT_DEFAULT:
3014 (void) strlcpy(secflagstab->zone_secflags_default,
3015 pp->pv_simple,
3016 sizeof (secflagstab->zone_secflags_default));
3017 break;
3018 case PT_LOWER:
3019 (void) strlcpy(secflagstab->zone_secflags_lower,
3020 pp->pv_simple,
3021 sizeof (secflagstab->zone_secflags_lower));
3022 break;
3023 case PT_UPPER:
3024 (void) strlcpy(secflagstab->zone_secflags_upper,
3025 pp->pv_simple,
3026 sizeof (secflagstab->zone_secflags_upper));
3027 break;
3028 default:
3029 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
3030 Z_NO_PROPERTY_TYPE, B_TRUE);
3031 return (Z_INSUFFICIENT_SPEC);
3034 if (fill_in_only)
3035 return (Z_OK);
3037 err = zonecfg_lookup_secflags(handle, secflagstab);
3039 return (err);
3042 static void
3043 remove_aliased_rctl(int type, char *name)
3045 int err;
3046 uint64_t tmp;
3048 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
3049 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3050 zonecfg_strerror(err));
3051 saw_error = B_TRUE;
3052 return;
3054 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
3055 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3056 zonecfg_strerror(err));
3057 saw_error = B_TRUE;
3058 } else {
3059 need_to_commit = B_TRUE;
3063 static boolean_t
3064 prompt_remove_resource(cmd_t *cmd, char *rsrc)
3066 int num;
3067 int answer;
3068 int arg;
3069 boolean_t force = B_FALSE;
3070 char prompt[128];
3071 boolean_t arg_err = B_FALSE;
3073 optind = 0;
3074 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3075 switch (arg) {
3076 case 'F':
3077 force = B_TRUE;
3078 break;
3079 default:
3080 arg_err = B_TRUE;
3081 break;
3084 if (arg_err)
3085 return (B_FALSE);
3088 num = zonecfg_num_resources(handle, rsrc);
3090 if (num == 0) {
3091 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
3092 B_TRUE);
3093 return (B_FALSE);
3095 if (num > 1 && !force) {
3096 if (!interactive_mode) {
3097 zerr(gettext("There are multiple instances of this "
3098 "resource. Either qualify the resource to\n"
3099 "remove a single instance or use the -F option to "
3100 "remove all instances."));
3101 saw_error = B_TRUE;
3102 return (B_FALSE);
3104 (void) snprintf(prompt, sizeof (prompt), gettext(
3105 "Are you sure you want to remove ALL '%s' resources"),
3106 rsrc);
3107 answer = ask_yesno(B_FALSE, prompt);
3108 if (answer == -1) {
3109 zerr(gettext("Resource incomplete."));
3110 return (B_FALSE);
3112 if (answer != 1)
3113 return (B_FALSE);
3115 return (B_TRUE);
3118 static void
3119 remove_fs(cmd_t *cmd)
3121 int err;
3123 /* traditional, qualified fs removal */
3124 if (cmd->cmd_prop_nv_pairs > 0) {
3125 struct zone_fstab fstab;
3127 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
3128 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3129 return;
3131 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
3132 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3133 else
3134 need_to_commit = B_TRUE;
3135 zonecfg_free_fs_option_list(fstab.zone_fs_options);
3136 return;
3140 * unqualified fs removal. remove all fs's but prompt if more
3141 * than one.
3143 if (!prompt_remove_resource(cmd, "fs"))
3144 return;
3146 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
3147 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3148 else
3149 need_to_commit = B_TRUE;
3152 static void
3153 remove_net(cmd_t *cmd)
3155 int err;
3157 /* traditional, qualified net removal */
3158 if (cmd->cmd_prop_nv_pairs > 0) {
3159 struct zone_nwiftab nwiftab;
3161 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3162 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3163 return;
3165 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3166 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3167 else
3168 need_to_commit = B_TRUE;
3169 return;
3173 * unqualified net removal. remove all nets but prompt if more
3174 * than one.
3176 if (!prompt_remove_resource(cmd, "net"))
3177 return;
3179 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3180 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3181 else
3182 need_to_commit = B_TRUE;
3185 static void
3186 remove_device(cmd_t *cmd)
3188 int err;
3190 /* traditional, qualified device removal */
3191 if (cmd->cmd_prop_nv_pairs > 0) {
3192 struct zone_devtab devtab;
3194 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3195 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3196 return;
3198 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3199 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3200 else
3201 need_to_commit = B_TRUE;
3202 return;
3206 * unqualified device removal. remove all devices but prompt if more
3207 * than one.
3209 if (!prompt_remove_resource(cmd, "device"))
3210 return;
3212 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3213 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3214 else
3215 need_to_commit = B_TRUE;
3218 static void
3219 remove_attr(cmd_t *cmd)
3221 int err;
3223 /* traditional, qualified attr removal */
3224 if (cmd->cmd_prop_nv_pairs > 0) {
3225 struct zone_attrtab attrtab;
3227 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3228 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3229 return;
3231 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3232 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3233 else
3234 need_to_commit = B_TRUE;
3235 return;
3239 * unqualified attr removal. remove all attrs but prompt if more
3240 * than one.
3242 if (!prompt_remove_resource(cmd, "attr"))
3243 return;
3245 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3246 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3247 else
3248 need_to_commit = B_TRUE;
3251 static void
3252 remove_dataset(cmd_t *cmd)
3254 int err;
3256 /* traditional, qualified dataset removal */
3257 if (cmd->cmd_prop_nv_pairs > 0) {
3258 struct zone_dstab dstab;
3260 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3261 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3262 return;
3264 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3265 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3266 else
3267 need_to_commit = B_TRUE;
3268 return;
3272 * unqualified dataset removal. remove all datasets but prompt if more
3273 * than one.
3275 if (!prompt_remove_resource(cmd, "dataset"))
3276 return;
3278 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3279 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3280 else
3281 need_to_commit = B_TRUE;
3284 static void
3285 remove_rctl(cmd_t *cmd)
3287 int err;
3289 /* traditional, qualified rctl removal */
3290 if (cmd->cmd_prop_nv_pairs > 0) {
3291 struct zone_rctltab rctltab;
3293 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3294 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3295 return;
3297 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3298 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3299 else
3300 need_to_commit = B_TRUE;
3301 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3302 return;
3306 * unqualified rctl removal. remove all rctls but prompt if more
3307 * than one.
3309 if (!prompt_remove_resource(cmd, "rctl"))
3310 return;
3312 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3313 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3314 else
3315 need_to_commit = B_TRUE;
3318 static void
3319 remove_pset()
3321 int err;
3322 struct zone_psettab psettab;
3324 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3325 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3326 return;
3328 if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3329 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3330 else
3331 need_to_commit = B_TRUE;
3334 static void
3335 remove_pcap()
3337 int err;
3338 uint64_t tmp;
3340 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3341 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3342 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3343 saw_error = B_TRUE;
3344 return;
3347 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3348 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3349 else
3350 need_to_commit = B_TRUE;
3353 static void
3354 remove_mcap()
3356 int err, res1, res2, res3;
3357 uint64_t tmp;
3358 struct zone_mcaptab mcaptab;
3359 boolean_t revert = B_FALSE;
3361 res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3362 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3363 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3365 /* if none of these exist, there is no resource to remove */
3366 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3367 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3368 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3369 saw_error = B_TRUE;
3370 return;
3372 if (res1 == Z_OK) {
3373 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3374 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3375 revert = B_TRUE;
3376 } else {
3377 need_to_commit = B_TRUE;
3380 if (res2 == Z_OK) {
3381 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3382 != Z_OK) {
3383 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3384 revert = B_TRUE;
3385 } else {
3386 need_to_commit = B_TRUE;
3389 if (res3 == Z_OK) {
3390 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3391 != Z_OK) {
3392 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3393 revert = B_TRUE;
3394 } else {
3395 need_to_commit = B_TRUE;
3399 if (revert)
3400 need_to_commit = B_FALSE;
3403 static void
3404 remove_admin(cmd_t *cmd)
3406 int err;
3408 /* traditional, qualified attr removal */
3409 if (cmd->cmd_prop_nv_pairs > 0) {
3410 struct zone_admintab admintab;
3412 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3413 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3414 err, B_TRUE);
3415 return;
3417 if ((err = zonecfg_delete_admin(handle, &admintab,
3418 zone))
3419 != Z_OK)
3420 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3421 err, B_TRUE);
3422 else
3423 need_to_commit = B_TRUE;
3424 return;
3425 } else {
3427 * unqualified admin removal.
3428 * remove all admins but prompt if more
3429 * than one.
3431 if (!prompt_remove_resource(cmd, "admin"))
3432 return;
3434 if ((err = zonecfg_delete_admins(handle, zone))
3435 != Z_OK)
3436 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3437 err, B_TRUE);
3438 else
3439 need_to_commit = B_TRUE;
3443 static void
3444 remove_secflags()
3446 int err;
3447 struct zone_secflagstab sectab = { 0 };
3449 if (zonecfg_lookup_secflags(handle, &sectab) != Z_OK) {
3450 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
3451 rt_to_str(RT_SECFLAGS),
3452 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3453 return;
3456 if ((err = zonecfg_delete_secflags(handle, &sectab)) != Z_OK) {
3457 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
3458 return;
3461 need_to_commit = B_TRUE;
3464 static void
3465 remove_resource(cmd_t *cmd)
3467 int type;
3468 int arg;
3469 boolean_t arg_err = B_FALSE;
3471 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3472 long_usage(CMD_REMOVE, B_TRUE);
3473 return;
3476 optind = 0;
3477 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3478 switch (arg) {
3479 case '?':
3480 longer_usage(CMD_REMOVE);
3481 arg_err = B_TRUE;
3482 break;
3483 case 'F':
3484 break;
3485 default:
3486 short_usage(CMD_REMOVE);
3487 arg_err = B_TRUE;
3488 break;
3491 if (arg_err)
3492 return;
3494 if (initialize(B_TRUE) != Z_OK)
3495 return;
3497 switch (type) {
3498 case RT_FS:
3499 remove_fs(cmd);
3500 return;
3501 case RT_NET:
3502 remove_net(cmd);
3503 return;
3504 case RT_DEVICE:
3505 remove_device(cmd);
3506 return;
3507 case RT_RCTL:
3508 remove_rctl(cmd);
3509 return;
3510 case RT_ATTR:
3511 remove_attr(cmd);
3512 return;
3513 case RT_DATASET:
3514 remove_dataset(cmd);
3515 return;
3516 case RT_DCPU:
3517 remove_pset();
3518 return;
3519 case RT_PCAP:
3520 remove_pcap();
3521 return;
3522 case RT_MCAP:
3523 remove_mcap();
3524 return;
3525 case RT_ADMIN:
3526 remove_admin(cmd);
3527 return;
3528 case RT_SECFLAGS:
3529 remove_secflags();
3530 return;
3531 default:
3532 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3533 long_usage(CMD_REMOVE, B_TRUE);
3534 usage(B_FALSE, HELP_RESOURCES);
3535 return;
3539 static void
3540 remove_property(cmd_t *cmd)
3542 char *prop_id;
3543 int err, res_type, prop_type;
3544 property_value_ptr_t pp;
3545 struct zone_rctlvaltab *rctlvaltab;
3546 complex_property_ptr_t cx;
3548 res_type = resource_scope;
3549 prop_type = cmd->cmd_prop_name[0];
3550 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3551 long_usage(CMD_REMOVE, B_TRUE);
3552 return;
3555 if (cmd->cmd_prop_nv_pairs != 1) {
3556 long_usage(CMD_ADD, B_TRUE);
3557 return;
3560 if (initialize(B_TRUE) != Z_OK)
3561 return;
3563 switch (res_type) {
3564 case RT_FS:
3565 if (prop_type != PT_OPTIONS) {
3566 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3567 B_TRUE);
3568 long_usage(CMD_REMOVE, B_TRUE);
3569 usage(B_FALSE, HELP_PROPS);
3570 return;
3572 pp = cmd->cmd_property_ptr[0];
3573 if (pp->pv_type == PROP_VAL_COMPLEX) {
3574 zerr(gettext("A %s or %s value was expected here."),
3575 pvt_to_str(PROP_VAL_SIMPLE),
3576 pvt_to_str(PROP_VAL_LIST));
3577 saw_error = B_TRUE;
3578 return;
3580 if (pp->pv_type == PROP_VAL_SIMPLE) {
3581 if (pp->pv_simple == NULL) {
3582 long_usage(CMD_ADD, B_TRUE);
3583 return;
3585 prop_id = pp->pv_simple;
3586 err = zonecfg_remove_fs_option(&in_progress_fstab,
3587 prop_id);
3588 if (err != Z_OK)
3589 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3590 } else {
3591 list_property_ptr_t list;
3593 for (list = pp->pv_list; list != NULL;
3594 list = list->lp_next) {
3595 prop_id = list->lp_simple;
3596 if (prop_id == NULL)
3597 break;
3598 err = zonecfg_remove_fs_option(
3599 &in_progress_fstab, prop_id);
3600 if (err != Z_OK)
3601 zone_perror(pt_to_str(prop_type), err,
3602 B_TRUE);
3605 return;
3606 case RT_RCTL:
3607 if (prop_type != PT_VALUE) {
3608 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3609 B_TRUE);
3610 long_usage(CMD_REMOVE, B_TRUE);
3611 usage(B_FALSE, HELP_PROPS);
3612 return;
3614 pp = cmd->cmd_property_ptr[0];
3615 if (pp->pv_type != PROP_VAL_COMPLEX) {
3616 zerr(gettext("A %s value was expected here."),
3617 pvt_to_str(PROP_VAL_COMPLEX));
3618 saw_error = B_TRUE;
3619 return;
3621 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3622 zone_perror(zone, Z_NOMEM, B_TRUE);
3623 exit(Z_ERR);
3625 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3626 switch (cx->cp_type) {
3627 case PT_PRIV:
3628 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
3629 cx->cp_value,
3630 sizeof (rctlvaltab->zone_rctlval_priv));
3631 break;
3632 case PT_LIMIT:
3633 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
3634 cx->cp_value,
3635 sizeof (rctlvaltab->zone_rctlval_limit));
3636 break;
3637 case PT_ACTION:
3638 (void) strlcpy(rctlvaltab->zone_rctlval_action,
3639 cx->cp_value,
3640 sizeof (rctlvaltab->zone_rctlval_action));
3641 break;
3642 default:
3643 zone_perror(pt_to_str(prop_type),
3644 Z_NO_PROPERTY_TYPE, B_TRUE);
3645 long_usage(CMD_ADD, B_TRUE);
3646 usage(B_FALSE, HELP_PROPS);
3647 zonecfg_free_rctl_value_list(rctlvaltab);
3648 return;
3651 rctlvaltab->zone_rctlval_next = NULL;
3652 err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3653 rctlvaltab);
3654 if (err != Z_OK)
3655 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3656 zonecfg_free_rctl_value_list(rctlvaltab);
3657 return;
3658 case RT_NET:
3659 if (prop_type != PT_DEFROUTER) {
3660 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3661 B_TRUE);
3662 long_usage(CMD_REMOVE, B_TRUE);
3663 usage(B_FALSE, HELP_PROPS);
3664 return;
3665 } else {
3666 bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3667 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3668 return;
3670 default:
3671 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3672 long_usage(CMD_REMOVE, B_TRUE);
3673 usage(B_FALSE, HELP_RESOURCES);
3674 return;
3678 void
3679 remove_func(cmd_t *cmd)
3681 if (zone_is_read_only(CMD_REMOVE))
3682 return;
3684 assert(cmd != NULL);
3686 if (global_scope) {
3687 if (gz_invalid_resource(cmd->cmd_res_type)) {
3688 zerr(gettext("%s is not a valid resource for the "
3689 "global zone."), rt_to_str(cmd->cmd_res_type));
3690 saw_error = B_TRUE;
3691 return;
3693 remove_resource(cmd);
3694 } else {
3695 remove_property(cmd);
3699 static void
3700 clear_property(cmd_t *cmd)
3702 int res_type, prop_type;
3704 res_type = resource_scope;
3705 prop_type = cmd->cmd_res_type;
3706 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3707 long_usage(CMD_CLEAR, B_TRUE);
3708 return;
3711 if (initialize(B_TRUE) != Z_OK)
3712 return;
3714 switch (res_type) {
3715 case RT_FS:
3716 if (prop_type == PT_RAW) {
3717 in_progress_fstab.zone_fs_raw[0] = '\0';
3718 need_to_commit = B_TRUE;
3719 return;
3721 break;
3722 case RT_DCPU:
3723 if (prop_type == PT_IMPORTANCE) {
3724 in_progress_psettab.zone_importance[0] = '\0';
3725 need_to_commit = B_TRUE;
3726 return;
3728 break;
3729 case RT_MCAP:
3730 switch (prop_type) {
3731 case PT_PHYSICAL:
3732 in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3733 need_to_commit = B_TRUE;
3734 return;
3735 case PT_SWAP:
3736 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3737 return;
3738 case PT_LOCKED:
3739 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3740 return;
3742 break;
3743 case RT_SECFLAGS:
3744 switch (prop_type) {
3745 case PT_LOWER:
3746 in_progress_secflagstab.zone_secflags_lower[0] = '\0';
3747 need_to_commit = B_TRUE;
3748 return;
3749 case PT_DEFAULT:
3750 in_progress_secflagstab.zone_secflags_default[0] = '\0';
3751 need_to_commit = B_TRUE;
3752 return;
3753 case PT_UPPER:
3754 in_progress_secflagstab.zone_secflags_upper[0] = '\0';
3755 need_to_commit = B_TRUE;
3756 return;
3758 break;
3759 default:
3760 break;
3763 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3766 static void
3767 clear_global(cmd_t *cmd)
3769 int err, type;
3771 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3772 long_usage(CMD_CLEAR, B_TRUE);
3773 return;
3776 if (initialize(B_TRUE) != Z_OK)
3777 return;
3779 switch (type) {
3780 case PT_ZONENAME:
3781 /* FALLTHRU */
3782 case PT_ZONEPATH:
3783 /* FALLTHRU */
3784 case PT_BRAND:
3785 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3786 return;
3787 case PT_AUTOBOOT:
3788 /* false is default; we'll treat as equivalent to clearing */
3789 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3790 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3791 else
3792 need_to_commit = B_TRUE;
3793 return;
3794 case PT_POOL:
3795 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3796 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3797 else
3798 need_to_commit = B_TRUE;
3799 return;
3800 case PT_LIMITPRIV:
3801 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3802 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3803 else
3804 need_to_commit = B_TRUE;
3805 return;
3806 case PT_BOOTARGS:
3807 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3808 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3809 else
3810 need_to_commit = B_TRUE;
3811 return;
3812 case PT_SCHED:
3813 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3814 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3815 else
3816 need_to_commit = B_TRUE;
3817 return;
3818 case PT_IPTYPE:
3819 /* shared is default; we'll treat as equivalent to clearing */
3820 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3821 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3822 else
3823 need_to_commit = B_TRUE;
3824 return;
3825 case PT_MAXLWPS:
3826 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3827 return;
3828 case PT_MAXPROCS:
3829 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS);
3830 return;
3831 case PT_MAXSHMMEM:
3832 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3833 return;
3834 case PT_MAXSHMIDS:
3835 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3836 return;
3837 case PT_MAXMSGIDS:
3838 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3839 return;
3840 case PT_MAXSEMIDS:
3841 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3842 return;
3843 case PT_SHARES:
3844 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3845 return;
3846 case PT_HOSTID:
3847 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3848 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3849 else
3850 need_to_commit = B_TRUE;
3851 return;
3852 case PT_FS_ALLOWED:
3853 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3854 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3855 else
3856 need_to_commit = B_TRUE;
3857 return;
3858 default:
3859 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3860 long_usage(CMD_CLEAR, B_TRUE);
3861 usage(B_FALSE, HELP_PROPS);
3862 return;
3866 void
3867 clear_func(cmd_t *cmd)
3869 if (zone_is_read_only(CMD_CLEAR))
3870 return;
3872 assert(cmd != NULL);
3874 if (global_scope) {
3875 if (gz_invalid_property(cmd->cmd_res_type)) {
3876 zerr(gettext("%s is not a valid property for the "
3877 "global zone."), pt_to_str(cmd->cmd_res_type));
3878 saw_error = B_TRUE;
3879 return;
3882 clear_global(cmd);
3883 } else {
3884 clear_property(cmd);
3888 void
3889 select_func(cmd_t *cmd)
3891 int type, err, res;
3892 uint64_t limit;
3893 uint64_t tmp;
3895 if (zone_is_read_only(CMD_SELECT))
3896 return;
3898 assert(cmd != NULL);
3900 if (global_scope) {
3901 global_scope = B_FALSE;
3902 resource_scope = cmd->cmd_res_type;
3903 end_op = CMD_SELECT;
3904 } else {
3905 scope_usage(CMD_SELECT);
3906 return;
3909 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3910 long_usage(CMD_SELECT, B_TRUE);
3911 return;
3914 if (initialize(B_TRUE) != Z_OK)
3915 return;
3917 switch (type) {
3918 case RT_FS:
3919 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3920 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3921 global_scope = B_TRUE;
3923 bcopy(&old_fstab, &in_progress_fstab,
3924 sizeof (struct zone_fstab));
3925 return;
3926 case RT_NET:
3927 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3928 != Z_OK) {
3929 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3930 global_scope = B_TRUE;
3932 bcopy(&old_nwiftab, &in_progress_nwiftab,
3933 sizeof (struct zone_nwiftab));
3934 return;
3935 case RT_DEVICE:
3936 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3937 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3938 global_scope = B_TRUE;
3940 bcopy(&old_devtab, &in_progress_devtab,
3941 sizeof (struct zone_devtab));
3942 return;
3943 case RT_RCTL:
3944 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3945 != Z_OK) {
3946 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3947 global_scope = B_TRUE;
3949 bcopy(&old_rctltab, &in_progress_rctltab,
3950 sizeof (struct zone_rctltab));
3951 return;
3952 case RT_ATTR:
3953 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3954 != Z_OK) {
3955 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3956 global_scope = B_TRUE;
3958 bcopy(&old_attrtab, &in_progress_attrtab,
3959 sizeof (struct zone_attrtab));
3960 return;
3961 case RT_DATASET:
3962 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3963 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3964 global_scope = B_TRUE;
3966 bcopy(&old_dstab, &in_progress_dstab,
3967 sizeof (struct zone_dstab));
3968 return;
3969 case RT_DCPU:
3970 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3971 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3972 global_scope = B_TRUE;
3974 bcopy(&old_psettab, &in_progress_psettab,
3975 sizeof (struct zone_psettab));
3976 return;
3977 case RT_PCAP:
3978 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3979 != Z_OK) {
3980 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3981 global_scope = B_TRUE;
3983 return;
3984 case RT_MCAP:
3985 /* if none of these exist, there is no resource to select */
3986 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3987 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3988 != Z_OK &&
3989 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3990 != Z_OK) {
3991 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3992 B_TRUE);
3993 global_scope = B_TRUE;
3995 if (res == Z_OK)
3996 bcopy(&old_mcaptab, &in_progress_mcaptab,
3997 sizeof (struct zone_mcaptab));
3998 else
3999 bzero(&in_progress_mcaptab,
4000 sizeof (in_progress_mcaptab));
4001 return;
4002 case RT_ADMIN:
4003 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
4004 != Z_OK) {
4005 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
4006 B_TRUE);
4007 global_scope = B_TRUE;
4009 bcopy(&old_admintab, &in_progress_admintab,
4010 sizeof (struct zone_admintab));
4011 return;
4012 case RT_SECFLAGS:
4013 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
4014 != Z_OK) {
4015 z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
4016 B_TRUE);
4017 global_scope = B_TRUE;
4019 bcopy(&old_secflagstab, &in_progress_secflagstab,
4020 sizeof (struct zone_secflagstab));
4021 return;
4022 default:
4023 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
4024 long_usage(CMD_SELECT, B_TRUE);
4025 usage(B_FALSE, HELP_RESOURCES);
4026 return;
4031 * Network "addresses" can be one of the following forms:
4032 * <IPv4 address>
4033 * <IPv4 address>/<prefix length>
4034 * <IPv6 address>/<prefix length>
4035 * <host name>
4036 * <host name>/<prefix length>
4037 * In other words, the "/" followed by a prefix length is allowed but not
4038 * required for IPv4 addresses and host names, and required for IPv6 addresses.
4039 * If a prefix length is given, it must be in the allowable range: 0 to 32 for
4040 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
4041 * Host names must start with an alpha-numeric character, and all subsequent
4042 * characters must be either alpha-numeric or "-".
4044 * In some cases, e.g., the nexthop for the defrouter, the context indicates
4045 * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
4046 * require the /<prefix length> (and should ignore it if provided).
4049 static int
4050 validate_net_address_syntax(char *address, boolean_t ishost)
4052 char *slashp, part1[MAXHOSTNAMELEN];
4053 struct in6_addr in6;
4054 struct in_addr in4;
4055 int prefixlen, i;
4058 * Copy the part before any '/' into part1 or copy the whole
4059 * thing if there is no '/'.
4061 if ((slashp = strchr(address, '/')) != NULL) {
4062 *slashp = '\0';
4063 (void) strlcpy(part1, address, sizeof (part1));
4064 *slashp = '/';
4065 prefixlen = atoi(++slashp);
4066 } else {
4067 (void) strlcpy(part1, address, sizeof (part1));
4070 if (ishost && slashp != NULL) {
4071 zerr(gettext("Warning: prefix length in %s is not required and "
4072 "will be ignored. The default host-prefix length "
4073 "will be used"), address);
4077 if (inet_pton(AF_INET6, part1, &in6) == 1) {
4078 if (ishost) {
4079 prefixlen = IPV6_ABITS;
4080 } else if (slashp == NULL) {
4081 zerr(gettext("%s: IPv6 addresses "
4082 "require /prefix-length suffix."), address);
4083 return (Z_ERR);
4085 if (prefixlen < 0 || prefixlen > 128) {
4086 zerr(gettext("%s: IPv6 address "
4087 "prefix lengths must be 0 - 128."), address);
4088 return (Z_ERR);
4090 return (Z_OK);
4093 /* At this point, any /prefix must be for IPv4. */
4094 if (ishost)
4095 prefixlen = IPV4_ABITS;
4096 else if (slashp != NULL) {
4097 if (prefixlen < 0 || prefixlen > 32) {
4098 zerr(gettext("%s: IPv4 address "
4099 "prefix lengths must be 0 - 32."), address);
4100 return (Z_ERR);
4104 if (inet_pton(AF_INET, part1, &in4) == 1)
4105 return (Z_OK);
4107 /* address may also be a host name */
4108 if (!isalnum(part1[0])) {
4109 zerr(gettext("%s: bogus host name or network address syntax"),
4110 part1);
4111 saw_error = B_TRUE;
4112 usage(B_FALSE, HELP_NETADDR);
4113 return (Z_ERR);
4115 for (i = 1; part1[i]; i++)
4116 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
4117 zerr(gettext("%s: bogus host name or "
4118 "network address syntax"), part1);
4119 saw_error = B_TRUE;
4120 usage(B_FALSE, HELP_NETADDR);
4121 return (Z_ERR);
4123 return (Z_OK);
4126 static int
4127 validate_net_physical_syntax(const char *ifname)
4129 ifspec_t ifnameprop;
4130 zone_iptype_t iptype;
4132 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
4133 zerr(gettext("zone configuration has an invalid or nonexistent "
4134 "ip-type property"));
4135 return (Z_ERR);
4137 switch (iptype) {
4138 case ZS_SHARED:
4139 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
4140 zerr(gettext("%s: invalid physical interface name"),
4141 ifname);
4142 return (Z_ERR);
4144 if (ifnameprop.ifsp_lunvalid) {
4145 zerr(gettext("%s: LUNs not allowed in physical "
4146 "interface names"), ifname);
4147 return (Z_ERR);
4149 break;
4150 case ZS_EXCLUSIVE:
4151 if (dladm_valid_linkname(ifname) == B_FALSE) {
4152 if (strchr(ifname, ':') != NULL)
4153 zerr(gettext("%s: physical interface name "
4154 "required; logical interface name not "
4155 "allowed"), ifname);
4156 else
4157 zerr(gettext("%s: invalid physical interface "
4158 "name"), ifname);
4159 return (Z_ERR);
4161 break;
4163 return (Z_OK);
4166 static boolean_t
4167 valid_fs_type(const char *type)
4170 * Is this a valid path component?
4172 if (strlen(type) + 1 > MAXNAMELEN)
4173 return (B_FALSE);
4175 * Make sure a bad value for "type" doesn't make
4176 * /usr/lib/fs/<type>/mount turn into something else.
4178 if (strchr(type, '/') != NULL || type[0] == '\0' ||
4179 strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4180 return (B_FALSE);
4182 * More detailed verification happens later by zoneadm(1m).
4184 return (B_TRUE);
4187 static boolean_t
4188 allow_exclusive()
4190 brand_handle_t bh;
4191 char brand[MAXNAMELEN];
4192 boolean_t ret;
4194 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4195 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4196 return (B_FALSE);
4198 if ((bh = brand_open(brand)) == NULL) {
4199 zerr("%s: %s\n", zone, gettext("unknown brand."));
4200 return (B_FALSE);
4202 ret = brand_allow_exclusive_ip(bh);
4203 brand_close(bh);
4204 if (!ret)
4205 zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4206 pt_to_str(PT_IPTYPE), "exclusive",
4207 pt_to_str(PT_BRAND), brand);
4208 return (ret);
4211 static void
4212 set_aliased_rctl(char *alias, int prop_type, char *s)
4214 uint64_t limit;
4215 int err;
4216 char tmp[128];
4218 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4219 zerr(gettext("WARNING: Setting a global zone resource "
4220 "control too low could deny\nservice "
4221 "to even the root user; "
4222 "this could render the system impossible\n"
4223 "to administer. Please use caution."));
4225 /* convert memory based properties */
4226 if (prop_type == PT_MAXSHMMEM) {
4227 if (!zonecfg_valid_memlimit(s, &limit)) {
4228 zerr(gettext("A non-negative number with a required "
4229 "scale suffix (K, M, G or T) was expected\nhere."));
4230 saw_error = B_TRUE;
4231 return;
4234 (void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4235 s = tmp;
4238 if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4239 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4240 saw_error = B_TRUE;
4241 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4242 zerr(gettext("%s property is out of range."),
4243 pt_to_str(prop_type));
4244 saw_error = B_TRUE;
4245 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4246 != Z_OK) {
4247 zone_perror(zone, err, B_TRUE);
4248 saw_error = B_TRUE;
4249 } else {
4250 need_to_commit = B_TRUE;
4254 static void
4255 set_in_progress_nwiftab_address(char *prop_id, int prop_type)
4257 if (prop_type == PT_ADDRESS) {
4258 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
4259 sizeof (in_progress_nwiftab.zone_nwif_address));
4260 } else {
4261 assert(prop_type == PT_ALLOWED_ADDRESS);
4262 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
4263 prop_id,
4264 sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
4268 void
4269 set_func(cmd_t *cmd)
4271 char *prop_id;
4272 int arg, err, res_type, prop_type;
4273 property_value_ptr_t pp;
4274 boolean_t autoboot;
4275 zone_iptype_t iptype;
4276 boolean_t force_set = B_FALSE;
4277 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4278 uint64_t mem_cap, mem_limit;
4279 float cap;
4280 char *unitp;
4281 struct zone_psettab tmp_psettab;
4282 boolean_t arg_err = B_FALSE;
4284 if (zone_is_read_only(CMD_SET))
4285 return;
4287 assert(cmd != NULL);
4289 optind = opterr = 0;
4290 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4291 switch (arg) {
4292 case 'F':
4293 force_set = B_TRUE;
4294 break;
4295 default:
4296 if (optopt == '?')
4297 longer_usage(CMD_SET);
4298 else
4299 short_usage(CMD_SET);
4300 arg_err = B_TRUE;
4301 break;
4304 if (arg_err)
4305 return;
4307 prop_type = cmd->cmd_prop_name[0];
4308 if (global_scope) {
4309 if (gz_invalid_property(prop_type)) {
4310 zerr(gettext("%s is not a valid property for the "
4311 "global zone."), pt_to_str(prop_type));
4312 saw_error = B_TRUE;
4313 return;
4316 if (prop_type == PT_ZONENAME) {
4317 res_type = RT_ZONENAME;
4318 } else if (prop_type == PT_ZONEPATH) {
4319 res_type = RT_ZONEPATH;
4320 } else if (prop_type == PT_AUTOBOOT) {
4321 res_type = RT_AUTOBOOT;
4322 } else if (prop_type == PT_BRAND) {
4323 res_type = RT_BRAND;
4324 } else if (prop_type == PT_POOL) {
4325 res_type = RT_POOL;
4326 } else if (prop_type == PT_LIMITPRIV) {
4327 res_type = RT_LIMITPRIV;
4328 } else if (prop_type == PT_BOOTARGS) {
4329 res_type = RT_BOOTARGS;
4330 } else if (prop_type == PT_SCHED) {
4331 res_type = RT_SCHED;
4332 } else if (prop_type == PT_IPTYPE) {
4333 res_type = RT_IPTYPE;
4334 } else if (prop_type == PT_MAXLWPS) {
4335 res_type = RT_MAXLWPS;
4336 } else if (prop_type == PT_MAXPROCS) {
4337 res_type = RT_MAXPROCS;
4338 } else if (prop_type == PT_MAXSHMMEM) {
4339 res_type = RT_MAXSHMMEM;
4340 } else if (prop_type == PT_MAXSHMIDS) {
4341 res_type = RT_MAXSHMIDS;
4342 } else if (prop_type == PT_MAXMSGIDS) {
4343 res_type = RT_MAXMSGIDS;
4344 } else if (prop_type == PT_MAXSEMIDS) {
4345 res_type = RT_MAXSEMIDS;
4346 } else if (prop_type == PT_SHARES) {
4347 res_type = RT_SHARES;
4348 } else if (prop_type == PT_HOSTID) {
4349 res_type = RT_HOSTID;
4350 } else if (prop_type == PT_FS_ALLOWED) {
4351 res_type = RT_FS_ALLOWED;
4352 } else {
4353 zerr(gettext("Cannot set a resource-specific property "
4354 "from the global scope."));
4355 saw_error = B_TRUE;
4356 return;
4358 } else {
4359 res_type = resource_scope;
4362 if (force_set) {
4363 if (res_type != RT_ZONEPATH) {
4364 zerr(gettext("Only zonepath setting can be forced."));
4365 saw_error = B_TRUE;
4366 return;
4368 if (!zonecfg_in_alt_root()) {
4369 zerr(gettext("Zonepath is changeable only in an "
4370 "alternate root."));
4371 saw_error = B_TRUE;
4372 return;
4376 pp = cmd->cmd_property_ptr[0];
4378 * A nasty expression but not that complicated:
4379 * 1. fs options are simple or list (tested below)
4380 * 2. rctl value's are complex or list (tested below)
4381 * Anything else should be simple.
4383 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4384 !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4385 (pp->pv_type != PROP_VAL_SIMPLE ||
4386 (prop_id = pp->pv_simple) == NULL)) {
4387 zerr(gettext("A %s value was expected here."),
4388 pvt_to_str(PROP_VAL_SIMPLE));
4389 saw_error = B_TRUE;
4390 return;
4392 if (prop_type == PT_UNKNOWN) {
4393 long_usage(CMD_SET, B_TRUE);
4394 return;
4398 * Special case: the user can change the zone name prior to 'create';
4399 * if the zone already exists, we fall through letting initialize()
4400 * and the rest of the logic run.
4402 if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4403 !state_atleast(ZONE_STATE_CONFIGURED)) {
4404 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4405 zone_perror(prop_id, err, B_TRUE);
4406 usage(B_FALSE, HELP_SYNTAX);
4407 return;
4409 (void) strlcpy(zone, prop_id, sizeof (zone));
4410 return;
4413 if (initialize(B_TRUE) != Z_OK)
4414 return;
4416 switch (res_type) {
4417 case RT_ZONENAME:
4418 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4420 * Use prop_id instead of 'zone' here, since we're
4421 * reporting a problem about the *new* zonename.
4423 zone_perror(prop_id, err, B_TRUE);
4424 usage(B_FALSE, HELP_SYNTAX);
4425 } else {
4426 need_to_commit = B_TRUE;
4427 (void) strlcpy(zone, prop_id, sizeof (zone));
4429 return;
4430 case RT_ZONEPATH:
4431 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4432 zerr(gettext("Zone %s already installed; %s %s not "
4433 "allowed."), zone, cmd_to_str(CMD_SET),
4434 rt_to_str(RT_ZONEPATH));
4435 return;
4437 if (validate_zonepath_syntax(prop_id) != Z_OK) {
4438 saw_error = B_TRUE;
4439 return;
4441 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4442 zone_perror(zone, err, B_TRUE);
4443 else
4444 need_to_commit = B_TRUE;
4445 return;
4446 case RT_BRAND:
4447 if (state_atleast(ZONE_STATE_INSTALLED)) {
4448 zerr(gettext("Zone %s already installed; %s %s not "
4449 "allowed."), zone, cmd_to_str(CMD_SET),
4450 rt_to_str(RT_BRAND));
4451 return;
4453 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4454 zone_perror(zone, err, B_TRUE);
4455 else
4456 need_to_commit = B_TRUE;
4457 return;
4458 case RT_AUTOBOOT:
4459 if (strcmp(prop_id, "true") == 0) {
4460 autoboot = B_TRUE;
4461 } else if (strcmp(prop_id, "false") == 0) {
4462 autoboot = B_FALSE;
4463 } else {
4464 zerr(gettext("%s value must be '%s' or '%s'."),
4465 pt_to_str(PT_AUTOBOOT), "true", "false");
4466 saw_error = B_TRUE;
4467 return;
4469 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4470 zone_perror(zone, err, B_TRUE);
4471 else
4472 need_to_commit = B_TRUE;
4473 return;
4474 case RT_POOL:
4475 /* don't allow use of the reserved temporary pool names */
4476 if (strncmp("SUNW", prop_id, 4) == 0) {
4477 zerr(gettext("pool names starting with SUNW are "
4478 "reserved."));
4479 saw_error = B_TRUE;
4480 return;
4483 /* can't set pool if dedicated-cpu exists */
4484 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4485 zerr(gettext("The %s resource already exists. "
4486 "A persistent pool is incompatible\nwith the %s "
4487 "resource."), rt_to_str(RT_DCPU),
4488 rt_to_str(RT_DCPU));
4489 saw_error = B_TRUE;
4490 return;
4493 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4494 zone_perror(zone, err, B_TRUE);
4495 else
4496 need_to_commit = B_TRUE;
4497 return;
4498 case RT_LIMITPRIV:
4499 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4500 zone_perror(zone, err, B_TRUE);
4501 else
4502 need_to_commit = B_TRUE;
4503 return;
4504 case RT_BOOTARGS:
4505 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4506 zone_perror(zone, err, B_TRUE);
4507 else
4508 need_to_commit = B_TRUE;
4509 return;
4510 case RT_SCHED:
4511 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4512 zone_perror(zone, err, B_TRUE);
4513 else
4514 need_to_commit = B_TRUE;
4515 return;
4516 case RT_IPTYPE:
4517 if (strcmp(prop_id, "shared") == 0) {
4518 iptype = ZS_SHARED;
4519 } else if (strcmp(prop_id, "exclusive") == 0) {
4520 iptype = ZS_EXCLUSIVE;
4521 } else {
4522 zerr(gettext("%s value must be '%s' or '%s'."),
4523 pt_to_str(PT_IPTYPE), "shared", "exclusive");
4524 saw_error = B_TRUE;
4525 return;
4527 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4528 saw_error = B_TRUE;
4529 return;
4531 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4532 zone_perror(zone, err, B_TRUE);
4533 else
4534 need_to_commit = B_TRUE;
4535 return;
4536 case RT_MAXLWPS:
4537 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4538 return;
4539 case RT_MAXPROCS:
4540 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id);
4541 return;
4542 case RT_MAXSHMMEM:
4543 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4544 return;
4545 case RT_MAXSHMIDS:
4546 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4547 return;
4548 case RT_MAXMSGIDS:
4549 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4550 return;
4551 case RT_MAXSEMIDS:
4552 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4553 return;
4554 case RT_SHARES:
4555 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4556 return;
4557 case RT_HOSTID:
4558 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4559 if (err == Z_TOO_BIG) {
4560 zerr(gettext("hostid string is too large: %s"),
4561 prop_id);
4562 saw_error = B_TRUE;
4563 } else {
4564 zone_perror(pt_to_str(prop_type), err, B_TRUE);
4566 return;
4568 need_to_commit = B_TRUE;
4569 return;
4570 case RT_FS_ALLOWED:
4571 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4572 zone_perror(zone, err, B_TRUE);
4573 else
4574 need_to_commit = B_TRUE;
4575 return;
4576 case RT_FS:
4577 switch (prop_type) {
4578 case PT_DIR:
4579 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4580 sizeof (in_progress_fstab.zone_fs_dir));
4581 return;
4582 case PT_SPECIAL:
4583 (void) strlcpy(in_progress_fstab.zone_fs_special,
4584 prop_id,
4585 sizeof (in_progress_fstab.zone_fs_special));
4586 return;
4587 case PT_RAW:
4588 (void) strlcpy(in_progress_fstab.zone_fs_raw,
4589 prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4590 return;
4591 case PT_TYPE:
4592 if (!valid_fs_type(prop_id)) {
4593 zerr(gettext("\"%s\" is not a valid %s."),
4594 prop_id, pt_to_str(PT_TYPE));
4595 saw_error = B_TRUE;
4596 return;
4598 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4599 sizeof (in_progress_fstab.zone_fs_type));
4600 return;
4601 case PT_OPTIONS:
4602 if (pp->pv_type != PROP_VAL_SIMPLE &&
4603 pp->pv_type != PROP_VAL_LIST) {
4604 zerr(gettext("A %s or %s value was expected "
4605 "here."), pvt_to_str(PROP_VAL_SIMPLE),
4606 pvt_to_str(PROP_VAL_LIST));
4607 saw_error = B_TRUE;
4608 return;
4610 zonecfg_free_fs_option_list(
4611 in_progress_fstab.zone_fs_options);
4612 in_progress_fstab.zone_fs_options = NULL;
4613 if (!(pp->pv_type == PROP_VAL_LIST &&
4614 pp->pv_list == NULL))
4615 add_property(cmd);
4616 return;
4617 default:
4618 break;
4620 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4621 long_usage(CMD_SET, B_TRUE);
4622 usage(B_FALSE, HELP_PROPS);
4623 return;
4624 case RT_NET:
4625 switch (prop_type) {
4626 case PT_ADDRESS:
4627 case PT_ALLOWED_ADDRESS:
4628 if (validate_net_address_syntax(prop_id, B_FALSE)
4629 != Z_OK) {
4630 saw_error = B_TRUE;
4631 return;
4633 set_in_progress_nwiftab_address(prop_id, prop_type);
4634 break;
4635 case PT_PHYSICAL:
4636 if (validate_net_physical_syntax(prop_id) != Z_OK) {
4637 saw_error = B_TRUE;
4638 return;
4640 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4641 prop_id,
4642 sizeof (in_progress_nwiftab.zone_nwif_physical));
4643 break;
4644 case PT_DEFROUTER:
4645 if (validate_net_address_syntax(prop_id, B_TRUE)
4646 != Z_OK) {
4647 saw_error = B_TRUE;
4648 return;
4650 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4651 prop_id,
4652 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4653 break;
4654 default:
4655 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4656 B_TRUE);
4657 long_usage(CMD_SET, B_TRUE);
4658 usage(B_FALSE, HELP_PROPS);
4659 return;
4661 return;
4662 case RT_DEVICE:
4663 switch (prop_type) {
4664 case PT_MATCH:
4665 (void) strlcpy(in_progress_devtab.zone_dev_match,
4666 prop_id,
4667 sizeof (in_progress_devtab.zone_dev_match));
4668 break;
4669 default:
4670 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4671 B_TRUE);
4672 long_usage(CMD_SET, B_TRUE);
4673 usage(B_FALSE, HELP_PROPS);
4674 return;
4676 return;
4677 case RT_RCTL:
4678 switch (prop_type) {
4679 case PT_NAME:
4680 if (!zonecfg_valid_rctlname(prop_id)) {
4681 zerr(gettext("'%s' is not a valid zone %s "
4682 "name."), prop_id, rt_to_str(RT_RCTL));
4683 return;
4685 (void) strlcpy(in_progress_rctltab.zone_rctl_name,
4686 prop_id,
4687 sizeof (in_progress_rctltab.zone_rctl_name));
4688 break;
4689 case PT_VALUE:
4690 if (pp->pv_type != PROP_VAL_COMPLEX &&
4691 pp->pv_type != PROP_VAL_LIST) {
4692 zerr(gettext("A %s or %s value was expected "
4693 "here."), pvt_to_str(PROP_VAL_COMPLEX),
4694 pvt_to_str(PROP_VAL_LIST));
4695 saw_error = B_TRUE;
4696 return;
4698 zonecfg_free_rctl_value_list(
4699 in_progress_rctltab.zone_rctl_valptr);
4700 in_progress_rctltab.zone_rctl_valptr = NULL;
4701 if (!(pp->pv_type == PROP_VAL_LIST &&
4702 pp->pv_list == NULL))
4703 add_property(cmd);
4704 break;
4705 default:
4706 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4707 B_TRUE);
4708 long_usage(CMD_SET, B_TRUE);
4709 usage(B_FALSE, HELP_PROPS);
4710 return;
4712 return;
4713 case RT_ATTR:
4714 switch (prop_type) {
4715 case PT_NAME:
4716 (void) strlcpy(in_progress_attrtab.zone_attr_name,
4717 prop_id,
4718 sizeof (in_progress_attrtab.zone_attr_name));
4719 break;
4720 case PT_TYPE:
4721 (void) strlcpy(in_progress_attrtab.zone_attr_type,
4722 prop_id,
4723 sizeof (in_progress_attrtab.zone_attr_type));
4724 break;
4725 case PT_VALUE:
4726 (void) strlcpy(in_progress_attrtab.zone_attr_value,
4727 prop_id,
4728 sizeof (in_progress_attrtab.zone_attr_value));
4729 break;
4730 default:
4731 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4732 B_TRUE);
4733 long_usage(CMD_SET, B_TRUE);
4734 usage(B_FALSE, HELP_PROPS);
4735 return;
4737 return;
4738 case RT_DATASET:
4739 switch (prop_type) {
4740 case PT_NAME:
4741 (void) strlcpy(in_progress_dstab.zone_dataset_name,
4742 prop_id,
4743 sizeof (in_progress_dstab.zone_dataset_name));
4744 return;
4745 default:
4746 break;
4748 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4749 long_usage(CMD_SET, B_TRUE);
4750 usage(B_FALSE, HELP_PROPS);
4751 return;
4752 case RT_DCPU:
4753 switch (prop_type) {
4754 char *lowp, *highp;
4756 case PT_NCPUS:
4757 lowp = prop_id;
4758 if ((highp = strchr(prop_id, '-')) != NULL)
4759 *highp++ = '\0';
4760 else
4761 highp = lowp;
4763 /* Make sure the input makes sense. */
4764 if (!zonecfg_valid_ncpus(lowp, highp)) {
4765 zerr(gettext("%s property is out of range."),
4766 pt_to_str(PT_NCPUS));
4767 saw_error = B_TRUE;
4768 return;
4771 (void) strlcpy(
4772 in_progress_psettab.zone_ncpu_min, lowp,
4773 sizeof (in_progress_psettab.zone_ncpu_min));
4774 (void) strlcpy(
4775 in_progress_psettab.zone_ncpu_max, highp,
4776 sizeof (in_progress_psettab.zone_ncpu_max));
4777 return;
4778 case PT_IMPORTANCE:
4779 /* Make sure the value makes sense. */
4780 if (!zonecfg_valid_importance(prop_id)) {
4781 zerr(gettext("%s property is out of range."),
4782 pt_to_str(PT_IMPORTANCE));
4783 saw_error = B_TRUE;
4784 return;
4787 (void) strlcpy(in_progress_psettab.zone_importance,
4788 prop_id,
4789 sizeof (in_progress_psettab.zone_importance));
4790 return;
4791 default:
4792 break;
4794 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4795 long_usage(CMD_SET, B_TRUE);
4796 usage(B_FALSE, HELP_PROPS);
4797 return;
4798 case RT_PCAP:
4799 if (prop_type != PT_NCPUS) {
4800 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4801 B_TRUE);
4802 long_usage(CMD_SET, B_TRUE);
4803 usage(B_FALSE, HELP_PROPS);
4804 return;
4808 * We already checked that an rctl alias is allowed in
4809 * the add_resource() function.
4812 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4813 (int)(cap * 100) < 1) {
4814 zerr(gettext("%s property is out of range."),
4815 pt_to_str(PT_NCPUS));
4816 saw_error = B_TRUE;
4817 return;
4820 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4821 (int)(cap * 100))) != Z_OK)
4822 zone_perror(zone, err, B_TRUE);
4823 else
4824 need_to_commit = B_TRUE;
4825 return;
4826 case RT_MCAP:
4827 switch (prop_type) {
4828 case PT_PHYSICAL:
4829 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4830 zerr(gettext("A positive number with a "
4831 "required scale suffix (K, M, G or T) was "
4832 "expected here."));
4833 saw_error = B_TRUE;
4834 } else if (mem_cap < ONE_MB) {
4835 zerr(gettext("%s value is too small. It must "
4836 "be at least 1M."), pt_to_str(PT_PHYSICAL));
4837 saw_error = B_TRUE;
4838 } else {
4839 snprintf(in_progress_mcaptab.zone_physmem_cap,
4840 physmem_size, "%llu", mem_cap);
4842 break;
4843 case PT_SWAP:
4845 * We have to check if an rctl is allowed here since
4846 * there might already be a rctl defined that blocks
4847 * the alias.
4849 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4850 zone_perror(pt_to_str(PT_MAXSWAP),
4851 Z_ALIAS_DISALLOW, B_FALSE);
4852 saw_error = B_TRUE;
4853 return;
4856 if (global_zone)
4857 mem_limit = ONE_MB * 100;
4858 else
4859 mem_limit = ONE_MB * 50;
4861 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4862 zerr(gettext("A positive number with a "
4863 "required scale suffix (K, M, G or T) was "
4864 "expected here."));
4865 saw_error = B_TRUE;
4866 } else if (mem_cap < mem_limit) {
4867 char buf[128];
4869 (void) snprintf(buf, sizeof (buf), "%llu",
4870 mem_limit);
4871 bytes_to_units(buf, buf, sizeof (buf));
4872 zerr(gettext("%s value is too small. It must "
4873 "be at least %s."), pt_to_str(PT_SWAP),
4874 buf);
4875 saw_error = B_TRUE;
4876 } else {
4877 if ((err = zonecfg_set_aliased_rctl(handle,
4878 ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4879 zone_perror(zone, err, B_TRUE);
4880 else
4881 need_to_commit = B_TRUE;
4883 break;
4884 case PT_LOCKED:
4886 * We have to check if an rctl is allowed here since
4887 * there might already be a rctl defined that blocks
4888 * the alias.
4890 if (!zonecfg_aliased_rctl_ok(handle,
4891 ALIAS_MAXLOCKEDMEM)) {
4892 zone_perror(pt_to_str(PT_LOCKED),
4893 Z_ALIAS_DISALLOW, B_FALSE);
4894 saw_error = B_TRUE;
4895 return;
4898 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4899 zerr(gettext("A non-negative number with a "
4900 "required scale suffix (K, M, G or T) was "
4901 "expected\nhere."));
4902 saw_error = B_TRUE;
4903 } else {
4904 if ((err = zonecfg_set_aliased_rctl(handle,
4905 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4906 zone_perror(zone, err, B_TRUE);
4907 else
4908 need_to_commit = B_TRUE;
4910 break;
4911 default:
4912 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4913 B_TRUE);
4914 long_usage(CMD_SET, B_TRUE);
4915 usage(B_FALSE, HELP_PROPS);
4916 return;
4918 return;
4919 case RT_ADMIN:
4920 switch (prop_type) {
4921 case PT_USER:
4922 (void) strlcpy(in_progress_admintab.zone_admin_user,
4923 prop_id,
4924 sizeof (in_progress_admintab.zone_admin_user));
4925 return;
4926 case PT_AUTHS:
4927 (void) strlcpy(in_progress_admintab.zone_admin_auths,
4928 prop_id,
4929 sizeof (in_progress_admintab.zone_admin_auths));
4930 return;
4931 default:
4932 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4933 B_TRUE);
4934 long_usage(CMD_SET, B_TRUE);
4935 usage(B_FALSE, HELP_PROPS);
4936 return;
4938 case RT_SECFLAGS: {
4939 char *propstr;
4941 switch (prop_type) {
4942 case PT_DEFAULT:
4943 propstr = in_progress_secflagstab.zone_secflags_default;
4944 break;
4945 case PT_UPPER:
4946 propstr = in_progress_secflagstab.zone_secflags_upper;
4947 break;
4948 case PT_LOWER:
4949 propstr = in_progress_secflagstab.zone_secflags_lower;
4950 break;
4951 default:
4952 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4953 B_TRUE);
4954 long_usage(CMD_SET, B_TRUE);
4955 usage(B_FALSE, HELP_PROPS);
4956 return;
4958 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
4959 return;
4961 default:
4962 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4963 long_usage(CMD_SET, B_TRUE);
4964 usage(B_FALSE, HELP_RESOURCES);
4965 return;
4969 static void
4970 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4972 char *qstr;
4974 if (*pval != '\0') {
4975 qstr = quoteit(pval);
4976 if (pnum == PT_SWAP || pnum == PT_LOCKED)
4977 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4978 qstr);
4979 else
4980 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4981 free(qstr);
4982 } else if (print_notspec)
4983 (void) fprintf(fp, gettext("\t%s not specified\n"),
4984 pt_to_str(pnum));
4987 static void
4988 info_zonename(zone_dochandle_t handle, FILE *fp)
4990 char zonename[ZONENAME_MAX];
4992 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4993 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4994 zonename);
4995 else
4996 (void) fprintf(fp, gettext("%s not specified\n"),
4997 pt_to_str(PT_ZONENAME));
5000 static void
5001 info_zonepath(zone_dochandle_t handle, FILE *fp)
5003 char zonepath[MAXPATHLEN];
5005 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
5006 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
5007 zonepath);
5008 else {
5009 (void) fprintf(fp, gettext("%s not specified\n"),
5010 pt_to_str(PT_ZONEPATH));
5014 static void
5015 info_brand(zone_dochandle_t handle, FILE *fp)
5017 char brand[MAXNAMELEN];
5019 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
5020 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
5021 brand);
5022 else
5023 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
5024 gettext("not specified"));
5027 static void
5028 info_autoboot(zone_dochandle_t handle, FILE *fp)
5030 boolean_t autoboot;
5031 int err;
5033 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
5034 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
5035 autoboot ? "true" : "false");
5036 else
5037 zone_perror(zone, err, B_TRUE);
5040 static void
5041 info_pool(zone_dochandle_t handle, FILE *fp)
5043 char pool[MAXNAMELEN];
5044 int err;
5046 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
5047 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
5048 else
5049 zone_perror(zone, err, B_TRUE);
5052 static void
5053 info_limitpriv(zone_dochandle_t handle, FILE *fp)
5055 char *limitpriv;
5056 int err;
5058 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
5059 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
5060 limitpriv);
5061 free(limitpriv);
5062 } else {
5063 zone_perror(zone, err, B_TRUE);
5067 static void
5068 info_bootargs(zone_dochandle_t handle, FILE *fp)
5070 char bootargs[BOOTARGS_MAX];
5071 int err;
5073 if ((err = zonecfg_get_bootargs(handle, bootargs,
5074 sizeof (bootargs))) == Z_OK) {
5075 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
5076 bootargs);
5077 } else {
5078 zone_perror(zone, err, B_TRUE);
5082 static void
5083 info_sched(zone_dochandle_t handle, FILE *fp)
5085 char sched[MAXNAMELEN];
5086 int err;
5088 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
5089 == Z_OK) {
5090 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
5091 } else {
5092 zone_perror(zone, err, B_TRUE);
5096 static void
5097 info_iptype(zone_dochandle_t handle, FILE *fp)
5099 zone_iptype_t iptype;
5100 int err;
5102 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
5103 switch (iptype) {
5104 case ZS_SHARED:
5105 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5106 "shared");
5107 break;
5108 case ZS_EXCLUSIVE:
5109 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5110 "exclusive");
5111 break;
5113 } else {
5114 zone_perror(zone, err, B_TRUE);
5118 static void
5119 info_hostid(zone_dochandle_t handle, FILE *fp)
5121 char hostidp[HW_HOSTID_LEN];
5122 int err;
5124 if ((err = zonecfg_get_hostid(handle, hostidp,
5125 sizeof (hostidp))) == Z_OK) {
5126 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
5127 } else if (err == Z_BAD_PROPERTY) {
5128 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
5129 } else {
5130 zone_perror(zone, err, B_TRUE);
5134 static void
5135 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
5137 char fsallowedp[ZONE_FS_ALLOWED_MAX];
5138 int err;
5140 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
5141 sizeof (fsallowedp))) == Z_OK) {
5142 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
5143 fsallowedp);
5144 } else if (err == Z_BAD_PROPERTY) {
5145 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
5146 } else {
5147 zone_perror(zone, err, B_TRUE);
5151 static void
5152 output_fs(FILE *fp, struct zone_fstab *fstab)
5154 zone_fsopt_t *this;
5156 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
5157 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
5158 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
5159 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
5160 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
5161 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
5162 for (this = fstab->zone_fs_options; this != NULL;
5163 this = this->zone_fsopt_next) {
5164 if (strchr(this->zone_fsopt_opt, '='))
5165 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
5166 else
5167 (void) fprintf(fp, "%s", this->zone_fsopt_opt);
5168 if (this->zone_fsopt_next != NULL)
5169 (void) fprintf(fp, ",");
5171 (void) fprintf(fp, "]\n");
5174 static void
5175 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5177 struct zone_fstab lookup, user;
5178 boolean_t output = B_FALSE;
5180 if (zonecfg_setfsent(handle) != Z_OK)
5181 return;
5182 while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
5183 if (cmd->cmd_prop_nv_pairs == 0) {
5184 output_fs(fp, &lookup);
5185 goto loopend;
5187 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
5188 goto loopend;
5189 if (strlen(user.zone_fs_dir) > 0 &&
5190 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5191 goto loopend; /* no match */
5192 if (strlen(user.zone_fs_special) > 0 &&
5193 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5194 goto loopend; /* no match */
5195 if (strlen(user.zone_fs_type) > 0 &&
5196 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5197 goto loopend; /* no match */
5198 output_fs(fp, &lookup);
5199 output = B_TRUE;
5200 loopend:
5201 zonecfg_free_fs_option_list(lookup.zone_fs_options);
5203 (void) zonecfg_endfsent(handle);
5205 * If a property n/v pair was specified, warn the user if there was
5206 * nothing to output.
5208 if (!output && cmd->cmd_prop_nv_pairs > 0)
5209 (void) printf(gettext("No such %s resource.\n"),
5210 rt_to_str(RT_FS));
5213 static void
5214 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5216 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5217 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5218 output_prop(fp, PT_ALLOWED_ADDRESS,
5219 nwiftab->zone_nwif_allowed_address, B_TRUE);
5220 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5221 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5224 static void
5225 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5227 struct zone_nwiftab lookup, user;
5228 boolean_t output = B_FALSE;
5230 if (zonecfg_setnwifent(handle) != Z_OK)
5231 return;
5232 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5233 if (cmd->cmd_prop_nv_pairs == 0) {
5234 output_net(fp, &lookup);
5235 continue;
5237 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5238 continue;
5239 if (strlen(user.zone_nwif_physical) > 0 &&
5240 strcmp(user.zone_nwif_physical,
5241 lookup.zone_nwif_physical) != 0)
5242 continue; /* no match */
5243 /* If present make sure it matches */
5244 if (strlen(user.zone_nwif_address) > 0 &&
5245 !zonecfg_same_net_address(user.zone_nwif_address,
5246 lookup.zone_nwif_address))
5247 continue; /* no match */
5248 output_net(fp, &lookup);
5249 output = B_TRUE;
5251 (void) zonecfg_endnwifent(handle);
5253 * If a property n/v pair was specified, warn the user if there was
5254 * nothing to output.
5256 if (!output && cmd->cmd_prop_nv_pairs > 0)
5257 (void) printf(gettext("No such %s resource.\n"),
5258 rt_to_str(RT_NET));
5261 static void
5262 output_dev(FILE *fp, struct zone_devtab *devtab)
5264 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5265 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5268 static void
5269 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5271 struct zone_devtab lookup, user;
5272 boolean_t output = B_FALSE;
5274 if (zonecfg_setdevent(handle) != Z_OK)
5275 return;
5276 while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5277 if (cmd->cmd_prop_nv_pairs == 0) {
5278 output_dev(fp, &lookup);
5279 continue;
5281 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5282 continue;
5283 if (strlen(user.zone_dev_match) > 0 &&
5284 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5285 continue; /* no match */
5286 output_dev(fp, &lookup);
5287 output = B_TRUE;
5289 (void) zonecfg_enddevent(handle);
5291 * If a property n/v pair was specified, warn the user if there was
5292 * nothing to output.
5294 if (!output && cmd->cmd_prop_nv_pairs > 0)
5295 (void) printf(gettext("No such %s resource.\n"),
5296 rt_to_str(RT_DEVICE));
5299 static void
5300 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5302 struct zone_rctlvaltab *valptr;
5304 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5305 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5306 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5307 valptr = valptr->zone_rctlval_next) {
5308 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5309 pt_to_str(PT_VALUE),
5310 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5311 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5312 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5316 static void
5317 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5319 struct zone_rctltab lookup, user;
5320 boolean_t output = B_FALSE;
5322 if (zonecfg_setrctlent(handle) != Z_OK)
5323 return;
5324 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5325 if (cmd->cmd_prop_nv_pairs == 0) {
5326 output_rctl(fp, &lookup);
5327 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5328 (strlen(user.zone_rctl_name) == 0 ||
5329 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5330 output_rctl(fp, &lookup);
5331 output = B_TRUE;
5333 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5335 (void) zonecfg_endrctlent(handle);
5337 * If a property n/v pair was specified, warn the user if there was
5338 * nothing to output.
5340 if (!output && cmd->cmd_prop_nv_pairs > 0)
5341 (void) printf(gettext("No such %s resource.\n"),
5342 rt_to_str(RT_RCTL));
5345 static void
5346 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5348 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5349 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5350 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5351 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5354 static void
5355 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5357 struct zone_attrtab lookup, user;
5358 boolean_t output = B_FALSE;
5360 if (zonecfg_setattrent(handle) != Z_OK)
5361 return;
5362 while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5363 if (cmd->cmd_prop_nv_pairs == 0) {
5364 output_attr(fp, &lookup);
5365 continue;
5367 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5368 continue;
5369 if (strlen(user.zone_attr_name) > 0 &&
5370 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5371 continue; /* no match */
5372 if (strlen(user.zone_attr_type) > 0 &&
5373 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5374 continue; /* no match */
5375 if (strlen(user.zone_attr_value) > 0 &&
5376 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5377 continue; /* no match */
5378 output_attr(fp, &lookup);
5379 output = B_TRUE;
5381 (void) zonecfg_endattrent(handle);
5383 * If a property n/v pair was specified, warn the user if there was
5384 * nothing to output.
5386 if (!output && cmd->cmd_prop_nv_pairs > 0)
5387 (void) printf(gettext("No such %s resource.\n"),
5388 rt_to_str(RT_ATTR));
5391 static void
5392 output_ds(FILE *fp, struct zone_dstab *dstab)
5394 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5395 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5398 static void
5399 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5401 struct zone_dstab lookup, user;
5402 boolean_t output = B_FALSE;
5404 if (zonecfg_setdsent(handle) != Z_OK)
5405 return;
5406 while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5407 if (cmd->cmd_prop_nv_pairs == 0) {
5408 output_ds(fp, &lookup);
5409 continue;
5411 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5412 continue;
5413 if (strlen(user.zone_dataset_name) > 0 &&
5414 strcmp(user.zone_dataset_name,
5415 lookup.zone_dataset_name) != 0)
5416 continue; /* no match */
5417 output_ds(fp, &lookup);
5418 output = B_TRUE;
5420 (void) zonecfg_enddsent(handle);
5422 * If a property n/v pair was specified, warn the user if there was
5423 * nothing to output.
5425 if (!output && cmd->cmd_prop_nv_pairs > 0)
5426 (void) printf(gettext("No such %s resource.\n"),
5427 rt_to_str(RT_DATASET));
5430 static void
5431 output_pset(FILE *fp, struct zone_psettab *psettab)
5433 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5434 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5435 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5436 psettab->zone_ncpu_max);
5437 else
5438 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5439 psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5440 if (psettab->zone_importance[0] != '\0')
5441 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5442 psettab->zone_importance);
5445 static void
5446 info_pset(zone_dochandle_t handle, FILE *fp)
5448 struct zone_psettab lookup;
5450 if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5451 output_pset(fp, &lookup);
5454 static void
5455 output_pcap(FILE *fp)
5457 uint64_t cap;
5459 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5460 float scaled = (float)cap / 100;
5461 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5462 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5463 scaled);
5467 static void
5468 info_pcap(FILE *fp)
5470 output_pcap(fp);
5474 static void
5475 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5477 uint64_t limit;
5479 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5480 /* convert memory based properties */
5481 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5482 char buf[128];
5484 (void) snprintf(buf, sizeof (buf), "%llu", limit);
5485 bytes_to_units(buf, buf, sizeof (buf));
5486 (void) fprintf(fp, "[%s: %s]\n", alias, buf);
5487 return;
5490 (void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5494 static void
5495 bytes_to_units(char *str, char *buf, int bufsize)
5497 unsigned long long num;
5498 unsigned long long save = 0;
5499 char *units = "BKMGT";
5500 char *up = units;
5502 num = strtoll(str, NULL, 10);
5504 if (num < 1024) {
5505 (void) snprintf(buf, bufsize, "%llu", num);
5506 return;
5509 while ((num >= 1024) && (*up != 'T')) {
5510 up++; /* next unit of measurement */
5511 save = num;
5512 num = (num + 512) >> 10;
5515 /* check if we should output a fraction. snprintf will round for us */
5516 if (save % 1024 != 0 && ((save >> 10) < 10))
5517 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5518 *up);
5519 else
5520 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
5523 static void
5524 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5525 uint64_t maxswap, int showlocked, uint64_t maxlocked)
5527 char buf[128];
5529 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5530 if (mcaptab->zone_physmem_cap[0] != '\0') {
5531 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5532 output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5535 if (showswap == Z_OK) {
5536 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5537 bytes_to_units(buf, buf, sizeof (buf));
5538 output_prop(fp, PT_SWAP, buf, B_TRUE);
5541 if (showlocked == Z_OK) {
5542 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5543 bytes_to_units(buf, buf, sizeof (buf));
5544 output_prop(fp, PT_LOCKED, buf, B_TRUE);
5548 static void
5549 info_mcap(zone_dochandle_t handle, FILE *fp)
5551 int res1, res2, res3;
5552 uint64_t swap_limit;
5553 uint64_t locked_limit;
5554 struct zone_mcaptab lookup;
5556 bzero(&lookup, sizeof (lookup));
5557 res1 = zonecfg_getmcapent(handle, &lookup);
5558 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5559 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5560 &locked_limit);
5562 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5563 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5566 static void
5567 output_auth(FILE *fp, struct zone_admintab *admintab)
5569 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5570 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5571 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5574 static void
5575 output_secflags(FILE *fp, struct zone_secflagstab *sftab)
5577 (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
5578 output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
5579 output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
5580 output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
5583 static void
5584 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5586 struct zone_admintab lookup, user;
5587 boolean_t output = B_FALSE;
5588 int err;
5590 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5591 zone_perror(zone, err, B_TRUE);
5592 return;
5594 while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5595 if (cmd->cmd_prop_nv_pairs == 0) {
5596 output_auth(fp, &lookup);
5597 continue;
5599 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5600 continue;
5601 if (strlen(user.zone_admin_user) > 0 &&
5602 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5603 continue; /* no match */
5604 output_auth(fp, &lookup);
5605 output = B_TRUE;
5607 (void) zonecfg_endadminent(handle);
5609 * If a property n/v pair was specified, warn the user if there was
5610 * nothing to output.
5612 if (!output && cmd->cmd_prop_nv_pairs > 0)
5613 (void) printf(gettext("No such %s resource.\n"),
5614 rt_to_str(RT_ADMIN));
5617 static void
5618 info_secflags(zone_dochandle_t handle, FILE *fp)
5620 struct zone_secflagstab sftab;
5622 if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) {
5623 output_secflags(fp, &sftab);
5627 void
5628 info_func(cmd_t *cmd)
5630 FILE *fp = stdout;
5631 boolean_t need_to_close = B_FALSE;
5632 int type;
5633 int res1, res2;
5634 uint64_t swap_limit;
5635 uint64_t locked_limit;
5637 assert(cmd != NULL);
5639 if (initialize(B_TRUE) != Z_OK)
5640 return;
5642 /* don't page error output */
5643 if (interactive_mode) {
5644 if ((fp = pager_open()) != NULL)
5645 need_to_close = B_TRUE;
5646 else
5647 fp = stdout;
5649 setbuf(fp, NULL);
5652 if (!global_scope) {
5653 switch (resource_scope) {
5654 case RT_FS:
5655 output_fs(fp, &in_progress_fstab);
5656 break;
5657 case RT_NET:
5658 output_net(fp, &in_progress_nwiftab);
5659 break;
5660 case RT_DEVICE:
5661 output_dev(fp, &in_progress_devtab);
5662 break;
5663 case RT_RCTL:
5664 output_rctl(fp, &in_progress_rctltab);
5665 break;
5666 case RT_ATTR:
5667 output_attr(fp, &in_progress_attrtab);
5668 break;
5669 case RT_DATASET:
5670 output_ds(fp, &in_progress_dstab);
5671 break;
5672 case RT_DCPU:
5673 output_pset(fp, &in_progress_psettab);
5674 break;
5675 case RT_PCAP:
5676 output_pcap(fp);
5677 break;
5678 case RT_MCAP:
5679 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5680 &swap_limit);
5681 res2 = zonecfg_get_aliased_rctl(handle,
5682 ALIAS_MAXLOCKEDMEM, &locked_limit);
5683 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5684 res2, locked_limit);
5685 break;
5686 case RT_ADMIN:
5687 output_auth(fp, &in_progress_admintab);
5688 break;
5689 case RT_SECFLAGS:
5690 output_secflags(fp, &in_progress_secflagstab);
5691 break;
5693 goto cleanup;
5696 type = cmd->cmd_res_type;
5698 if (gz_invalid_rt_property(type)) {
5699 zerr(gettext("%s is not a valid property for the global zone."),
5700 rt_to_str(type));
5701 goto cleanup;
5704 if (gz_invalid_resource(type)) {
5705 zerr(gettext("%s is not a valid resource for the global zone."),
5706 rt_to_str(type));
5707 goto cleanup;
5710 switch (cmd->cmd_res_type) {
5711 case RT_UNKNOWN:
5712 info_zonename(handle, fp);
5713 if (!global_zone) {
5714 info_zonepath(handle, fp);
5715 info_brand(handle, fp);
5716 info_autoboot(handle, fp);
5717 info_bootargs(handle, fp);
5719 info_pool(handle, fp);
5720 if (!global_zone) {
5721 info_limitpriv(handle, fp);
5722 info_sched(handle, fp);
5723 info_iptype(handle, fp);
5724 info_hostid(handle, fp);
5725 info_fs_allowed(handle, fp);
5727 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5728 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5729 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5730 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5731 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5732 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5733 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5734 if (!global_zone) {
5735 info_fs(handle, fp, cmd);
5736 info_net(handle, fp, cmd);
5737 info_dev(handle, fp, cmd);
5739 info_pset(handle, fp);
5740 info_pcap(fp);
5741 info_mcap(handle, fp);
5742 if (!global_zone) {
5743 info_attr(handle, fp, cmd);
5744 info_ds(handle, fp, cmd);
5745 info_auth(handle, fp, cmd);
5747 info_rctl(handle, fp, cmd);
5748 info_secflags(handle, fp);
5749 break;
5750 case RT_ZONENAME:
5751 info_zonename(handle, fp);
5752 break;
5753 case RT_ZONEPATH:
5754 info_zonepath(handle, fp);
5755 break;
5756 case RT_BRAND:
5757 info_brand(handle, fp);
5758 break;
5759 case RT_AUTOBOOT:
5760 info_autoboot(handle, fp);
5761 break;
5762 case RT_POOL:
5763 info_pool(handle, fp);
5764 break;
5765 case RT_LIMITPRIV:
5766 info_limitpriv(handle, fp);
5767 break;
5768 case RT_BOOTARGS:
5769 info_bootargs(handle, fp);
5770 break;
5771 case RT_SCHED:
5772 info_sched(handle, fp);
5773 break;
5774 case RT_IPTYPE:
5775 info_iptype(handle, fp);
5776 break;
5777 case RT_MAXLWPS:
5778 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5779 break;
5780 case RT_MAXPROCS:
5781 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5782 break;
5783 case RT_MAXSHMMEM:
5784 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5785 break;
5786 case RT_MAXSHMIDS:
5787 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5788 break;
5789 case RT_MAXMSGIDS:
5790 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5791 break;
5792 case RT_MAXSEMIDS:
5793 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5794 break;
5795 case RT_SHARES:
5796 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5797 break;
5798 case RT_FS:
5799 info_fs(handle, fp, cmd);
5800 break;
5801 case RT_NET:
5802 info_net(handle, fp, cmd);
5803 break;
5804 case RT_DEVICE:
5805 info_dev(handle, fp, cmd);
5806 break;
5807 case RT_RCTL:
5808 info_rctl(handle, fp, cmd);
5809 break;
5810 case RT_ATTR:
5811 info_attr(handle, fp, cmd);
5812 break;
5813 case RT_DATASET:
5814 info_ds(handle, fp, cmd);
5815 break;
5816 case RT_DCPU:
5817 info_pset(handle, fp);
5818 break;
5819 case RT_PCAP:
5820 info_pcap(fp);
5821 break;
5822 case RT_MCAP:
5823 info_mcap(handle, fp);
5824 break;
5825 case RT_HOSTID:
5826 info_hostid(handle, fp);
5827 break;
5828 case RT_ADMIN:
5829 info_auth(handle, fp, cmd);
5830 break;
5831 case RT_FS_ALLOWED:
5832 info_fs_allowed(handle, fp);
5833 break;
5834 case RT_SECFLAGS:
5835 info_secflags(handle, fp);
5836 break;
5837 default:
5838 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5839 B_TRUE);
5842 cleanup:
5843 if (need_to_close)
5844 (void) pager_close(fp);
5848 * Helper function for verify-- checks that a required string property
5849 * exists.
5851 static void
5852 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5854 if (strlen(attr) == 0) {
5855 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5856 pt_to_str(pt));
5857 saw_error = B_TRUE;
5858 if (*ret_val == Z_OK)
5859 *ret_val = Z_REQD_PROPERTY_MISSING;
5863 static int
5864 do_subproc(char *cmdbuf)
5866 char inbuf[MAX_CMD_LEN];
5867 FILE *file;
5868 int status;
5870 file = popen(cmdbuf, "r");
5871 if (file == NULL) {
5872 zerr(gettext("Could not launch: %s"), cmdbuf);
5873 return (-1);
5876 while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5877 fprintf(stderr, "%s", inbuf);
5878 status = pclose(file);
5880 if (WIFSIGNALED(status)) {
5881 zerr(gettext("%s unexpectedly terminated due to signal %d"),
5882 cmdbuf, WTERMSIG(status));
5883 return (-1);
5885 assert(WIFEXITED(status));
5886 return (WEXITSTATUS(status));
5889 static int
5890 brand_verify(zone_dochandle_t handle)
5892 char xml_file[32];
5893 char cmdbuf[MAX_CMD_LEN];
5894 brand_handle_t bh;
5895 char brand[MAXNAMELEN];
5896 int err;
5898 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5899 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5900 return (Z_INVALID_DOCUMENT);
5902 if ((bh = brand_open(brand)) == NULL) {
5903 zerr("%s: %s\n", zone, gettext("unknown brand."));
5904 return (Z_INVALID_DOCUMENT);
5908 * Fetch the verify command, if any, from the brand configuration
5909 * and build the command line to execute it.
5911 strcpy(cmdbuf, EXEC_PREFIX);
5912 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5913 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5914 brand_close(bh);
5915 if (err != Z_OK) {
5916 zerr("%s: %s\n", zone,
5917 gettext("could not get brand verification command"));
5918 return (Z_INVALID_DOCUMENT);
5922 * If the brand doesn't provide a verification routine, we just
5923 * return success.
5925 if (strlen(cmdbuf) == EXEC_LEN)
5926 return (Z_OK);
5929 * Dump the current config information for this zone to a file.
5931 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5932 if (mkstemp(xml_file) == 0)
5933 return (Z_TEMP_FILE);
5934 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5935 (void) unlink(xml_file);
5936 return (err);
5940 * Execute the verification command.
5942 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5943 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5944 err = Z_BRAND_ERROR;
5945 } else {
5946 err = do_subproc(cmdbuf);
5949 (void) unlink(xml_file);
5950 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5954 * Track the network interfaces listed in zonecfg(1m) in a linked list
5955 * so that we can later check that defrouter is specified for an exclusive IP
5956 * zone if and only if at least one allowed-address has been specified.
5958 static boolean_t
5959 add_nwif(struct zone_nwiftab *nwif)
5961 struct xif *tmp;
5963 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5964 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
5965 if (strlen(nwif->zone_nwif_allowed_address) > 0)
5966 tmp->xif_has_address = B_TRUE;
5967 if (strlen(nwif->zone_nwif_defrouter) > 0)
5968 tmp->xif_has_defrouter = B_TRUE;
5969 return (B_TRUE);
5973 tmp = malloc(sizeof (*tmp));
5974 if (tmp == NULL) {
5975 zerr(gettext("memory allocation failed for %s"),
5976 nwif->zone_nwif_physical);
5977 return (B_FALSE);
5979 strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
5980 sizeof (tmp->xif_name));
5981 tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
5982 tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
5983 tmp->xif_next = xif;
5984 xif = tmp;
5985 return (B_TRUE);
5988 boolean_t
5989 verify_secflags(struct zone_secflagstab *tab)
5991 secflagdelta_t def = {0};
5992 secflagdelta_t upper = {0};
5993 secflagdelta_t lower = {0};
5994 boolean_t def_set = B_FALSE;
5995 boolean_t upper_set = B_FALSE;
5996 boolean_t lower_set = B_FALSE;
5997 boolean_t ret = B_TRUE;
5999 if (strlen(tab->zone_secflags_default) > 0) {
6000 def_set = B_TRUE;
6001 if (secflags_parse(NULL, tab->zone_secflags_default,
6002 &def) == -1) {
6003 zerr(gettext("default security flags '%s' are invalid"),
6004 tab->zone_secflags_default);
6005 ret = B_FALSE;
6007 } else {
6008 secflags_zero(&def.psd_assign);
6009 def.psd_ass_active = B_TRUE;
6012 if (strlen(tab->zone_secflags_upper) > 0) {
6013 upper_set = B_TRUE;
6014 if (secflags_parse(NULL, tab->zone_secflags_upper,
6015 &upper) == -1) {
6016 zerr(gettext("upper security flags '%s' are invalid"),
6017 tab->zone_secflags_upper);
6018 ret = B_FALSE;
6020 } else {
6021 secflags_fullset(&upper.psd_assign);
6022 upper.psd_ass_active = B_TRUE;
6025 if (strlen(tab->zone_secflags_lower) > 0) {
6026 lower_set = B_TRUE;
6027 if (secflags_parse(NULL, tab->zone_secflags_lower,
6028 &lower) == -1) {
6029 zerr(gettext("lower security flags '%s' are invalid"),
6030 tab->zone_secflags_lower);
6031 ret = B_FALSE;
6033 } else {
6034 secflags_zero(&lower.psd_assign);
6035 lower.psd_ass_active = B_TRUE;
6038 if (def_set && !def.psd_ass_active) {
6039 zerr(gettext("only assignment of security flags is "
6040 "allowed (default: %s)"), tab->zone_secflags_default);
6043 if (lower_set && !lower.psd_ass_active) {
6044 zerr(gettext("only assignment of security flags is "
6045 "allowed (lower: %s)"), tab->zone_secflags_lower);
6048 if (upper_set && !upper.psd_ass_active) {
6049 zerr(gettext("only assignment of security flags is "
6050 "allowed (upper: %s)"), tab->zone_secflags_upper);
6053 if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */
6054 zerr(gettext("default secflags must be within the "
6055 "upper limit"));
6056 ret = B_FALSE;
6058 if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
6059 zerr(gettext("default secflags must be above the lower limit"));
6060 ret = B_FALSE;
6062 if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
6063 zerr(gettext("lower secflags must be within the upper limit"));
6064 ret = B_FALSE;
6067 return (ret);
6071 * See the DTD for which attributes are required for which resources.
6073 * This function can be called by commit_func(), which needs to save things,
6074 * in addition to the general call from parse_and_run(), which doesn't need
6075 * things saved. Since the parameters are standardized, we distinguish by
6076 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
6077 * that a save is needed.
6079 void
6080 verify_func(cmd_t *cmd)
6082 struct zone_nwiftab nwiftab;
6083 struct zone_fstab fstab;
6084 struct zone_attrtab attrtab;
6085 struct zone_rctltab rctltab;
6086 struct zone_dstab dstab;
6087 struct zone_psettab psettab;
6088 struct zone_admintab admintab;
6089 struct zone_secflagstab secflagstab;
6090 char zonepath[MAXPATHLEN];
6091 char sched[MAXNAMELEN];
6092 char brand[MAXNAMELEN];
6093 char hostidp[HW_HOSTID_LEN];
6094 char fsallowedp[ZONE_FS_ALLOWED_MAX];
6095 priv_set_t *privs;
6096 char *privname = NULL;
6097 int err, ret_val = Z_OK, arg;
6098 int pset_res;
6099 boolean_t save = B_FALSE;
6100 boolean_t arg_err = B_FALSE;
6101 zone_iptype_t iptype;
6102 boolean_t has_cpu_shares = B_FALSE;
6103 boolean_t has_cpu_cap = B_FALSE;
6104 struct xif *tmp;
6106 optind = 0;
6107 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6108 switch (arg) {
6109 case '?':
6110 longer_usage(CMD_VERIFY);
6111 arg_err = B_TRUE;
6112 break;
6113 default:
6114 short_usage(CMD_VERIFY);
6115 arg_err = B_TRUE;
6116 break;
6119 if (arg_err)
6120 return;
6122 if (optind > cmd->cmd_argc) {
6123 short_usage(CMD_VERIFY);
6124 return;
6127 if (zone_is_read_only(CMD_VERIFY))
6128 return;
6130 assert(cmd != NULL);
6132 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
6133 save = B_TRUE;
6134 if (initialize(B_TRUE) != Z_OK)
6135 return;
6137 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
6138 !global_zone) {
6139 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
6140 ret_val = Z_REQD_RESOURCE_MISSING;
6141 saw_error = B_TRUE;
6143 if (strlen(zonepath) == 0 && !global_zone) {
6144 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
6145 ret_val = Z_REQD_RESOURCE_MISSING;
6146 saw_error = B_TRUE;
6149 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
6150 zone_perror(zone, err, B_TRUE);
6151 return;
6153 if ((err = brand_verify(handle)) != Z_OK) {
6154 zone_perror(zone, err, B_TRUE);
6155 return;
6158 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
6159 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
6160 ret_val = Z_REQD_RESOURCE_MISSING;
6161 saw_error = B_TRUE;
6164 if ((privs = priv_allocset()) == NULL) {
6165 zerr(gettext("%s: priv_allocset failed"), zone);
6166 return;
6168 if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) {
6169 zerr(gettext("%s: invalid privilege: %s"), zone, privname);
6170 priv_freeset(privs);
6171 free(privname);
6172 return;
6174 priv_freeset(privs);
6176 if (zonecfg_get_hostid(handle, hostidp,
6177 sizeof (hostidp)) == Z_INVALID_PROPERTY) {
6178 zerr(gettext("%s: invalid hostid: %s"),
6179 zone, hostidp);
6180 return;
6183 if (zonecfg_get_fs_allowed(handle, fsallowedp,
6184 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
6185 zerr(gettext("%s: invalid fs-allowed: %s"),
6186 zone, fsallowedp);
6187 return;
6190 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
6191 zone_perror(zone, err, B_TRUE);
6192 return;
6194 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
6195 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
6196 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
6197 &ret_val);
6198 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
6200 zonecfg_free_fs_option_list(fstab.zone_fs_options);
6202 (void) zonecfg_endfsent(handle);
6204 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
6205 zone_perror(zone, err, B_TRUE);
6206 return;
6208 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
6210 * physical is required in all cases.
6211 * A shared IP requires an address,
6212 * and may include a default router, while
6213 * an exclusive IP must have neither an address
6214 * nor a default router.
6215 * The physical interface name must be valid in all cases.
6217 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
6218 PT_PHYSICAL, &ret_val);
6219 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
6220 Z_OK) {
6221 saw_error = B_TRUE;
6222 if (ret_val == Z_OK)
6223 ret_val = Z_INVAL;
6226 switch (iptype) {
6227 case ZS_SHARED:
6228 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
6229 PT_ADDRESS, &ret_val);
6230 if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
6231 zerr(gettext("%s: %s cannot be specified "
6232 "for a shared IP type"),
6233 rt_to_str(RT_NET),
6234 pt_to_str(PT_ALLOWED_ADDRESS));
6235 saw_error = B_TRUE;
6236 if (ret_val == Z_OK)
6237 ret_val = Z_INVAL;
6239 break;
6240 case ZS_EXCLUSIVE:
6241 if (strlen(nwiftab.zone_nwif_address) > 0) {
6242 zerr(gettext("%s: %s cannot be specified "
6243 "for an exclusive IP type"),
6244 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
6245 saw_error = B_TRUE;
6246 if (ret_val == Z_OK)
6247 ret_val = Z_INVAL;
6248 } else {
6249 if (!add_nwif(&nwiftab)) {
6250 saw_error = B_TRUE;
6251 if (ret_val == Z_OK)
6252 ret_val = Z_INVAL;
6255 break;
6258 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
6259 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
6260 zerr(gettext("%s: %s for %s cannot be specified "
6261 "without %s for an exclusive IP type"),
6262 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
6263 tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
6264 saw_error = B_TRUE;
6265 ret_val = Z_INVAL;
6268 free(xif);
6269 xif = NULL;
6270 (void) zonecfg_endnwifent(handle);
6272 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
6273 zone_perror(zone, err, B_TRUE);
6274 return;
6276 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
6277 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
6278 &ret_val);
6280 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
6281 has_cpu_shares = B_TRUE;
6283 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
6284 has_cpu_cap = B_TRUE;
6286 if (rctltab.zone_rctl_valptr == NULL) {
6287 zerr(gettext("%s: no %s specified"),
6288 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
6289 saw_error = B_TRUE;
6290 if (ret_val == Z_OK)
6291 ret_val = Z_REQD_PROPERTY_MISSING;
6292 } else {
6293 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
6296 (void) zonecfg_endrctlent(handle);
6298 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
6299 has_cpu_shares) {
6300 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
6301 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6302 saw_error = B_TRUE;
6303 if (ret_val == Z_OK)
6304 ret_val = Z_INCOMPATIBLE;
6307 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
6308 sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
6309 strcmp(sched, "FSS") != 0) {
6310 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
6311 "incompatible"),
6312 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
6313 saw_error = B_TRUE;
6314 if (ret_val == Z_OK)
6315 ret_val = Z_INCOMPATIBLE;
6318 if (pset_res == Z_OK && has_cpu_cap) {
6319 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6320 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6321 saw_error = B_TRUE;
6322 if (ret_val == Z_OK)
6323 ret_val = Z_INCOMPATIBLE;
6326 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6327 zone_perror(zone, err, B_TRUE);
6328 return;
6330 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6331 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6332 &ret_val);
6333 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6334 &ret_val);
6335 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6336 &ret_val);
6338 (void) zonecfg_endattrent(handle);
6340 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6341 zone_perror(zone, err, B_TRUE);
6342 return;
6344 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6345 if (strlen(dstab.zone_dataset_name) == 0) {
6346 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6347 pt_to_str(PT_NAME), gettext("not specified"));
6348 saw_error = B_TRUE;
6349 if (ret_val == Z_OK)
6350 ret_val = Z_REQD_PROPERTY_MISSING;
6351 } else if (!zfs_name_valid(dstab.zone_dataset_name,
6352 ZFS_TYPE_FILESYSTEM)) {
6353 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6354 pt_to_str(PT_NAME), gettext("invalid"));
6355 saw_error = B_TRUE;
6356 if (ret_val == Z_OK)
6357 ret_val = Z_BAD_PROPERTY;
6361 (void) zonecfg_enddsent(handle);
6363 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6364 zone_perror(zone, err, B_TRUE);
6365 return;
6367 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6368 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6369 PT_USER, &ret_val);
6370 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6371 PT_AUTHS, &ret_val);
6372 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6373 == NULL)) {
6374 zerr(gettext("%s %s is not a valid username"),
6375 pt_to_str(PT_USER),
6376 admintab.zone_admin_user);
6377 ret_val = Z_BAD_PROPERTY;
6379 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6380 admintab.zone_admin_auths, zone))) {
6381 ret_val = Z_BAD_PROPERTY;
6384 (void) zonecfg_endadminent(handle);
6386 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
6388 * No properties are required, but any specified should be
6389 * valid
6391 if (verify_secflags(&secflagstab) != B_TRUE) {
6392 /* Error is reported from verify_secflags */
6393 ret_val = Z_BAD_PROPERTY;
6397 if (!global_scope) {
6398 zerr(gettext("resource specification incomplete"));
6399 saw_error = B_TRUE;
6400 if (ret_val == Z_OK)
6401 ret_val = Z_INSUFFICIENT_SPEC;
6404 if (save) {
6405 if (ret_val == Z_OK) {
6406 if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6407 need_to_commit = B_FALSE;
6408 (void) strlcpy(revert_zone, zone,
6409 sizeof (revert_zone));
6411 } else {
6412 zerr(gettext("Zone %s failed to verify"), zone);
6415 if (ret_val != Z_OK)
6416 zone_perror(zone, ret_val, B_TRUE);
6419 void
6420 cancel_func(cmd_t *cmd)
6422 int arg;
6423 boolean_t arg_err = B_FALSE;
6425 assert(cmd != NULL);
6427 optind = 0;
6428 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6429 switch (arg) {
6430 case '?':
6431 longer_usage(CMD_CANCEL);
6432 arg_err = B_TRUE;
6433 break;
6434 default:
6435 short_usage(CMD_CANCEL);
6436 arg_err = B_TRUE;
6437 break;
6440 if (arg_err)
6441 return;
6443 if (optind != cmd->cmd_argc) {
6444 short_usage(CMD_CANCEL);
6445 return;
6448 if (global_scope)
6449 scope_usage(CMD_CANCEL);
6450 global_scope = B_TRUE;
6451 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6452 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6453 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6454 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6455 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6456 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6457 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6458 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6461 static int
6462 validate_attr_name(char *name)
6464 int i;
6466 if (!isalnum(name[0])) {
6467 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6468 "numeric character."), rt_to_str(RT_ATTR),
6469 pt_to_str(PT_NAME), name);
6470 return (Z_INVAL);
6472 for (i = 1; name[i]; i++)
6473 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6474 zerr(gettext("Invalid %s %s %s: can only contain "
6475 "alpha-numeric characters, plus '-' and '.'."),
6476 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6477 return (Z_INVAL);
6479 return (Z_OK);
6482 static int
6483 validate_attr_type_val(struct zone_attrtab *attrtab)
6485 boolean_t boolval;
6486 int64_t intval;
6487 char strval[MAXNAMELEN];
6488 uint64_t uintval;
6490 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6491 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6492 return (Z_OK);
6493 zerr(gettext("invalid %s value for %s=%s"),
6494 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6495 return (Z_ERR);
6498 if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6499 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6500 return (Z_OK);
6501 zerr(gettext("invalid %s value for %s=%s"),
6502 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6503 return (Z_ERR);
6506 if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6507 if (zonecfg_get_attr_string(attrtab, strval,
6508 sizeof (strval)) == Z_OK)
6509 return (Z_OK);
6510 zerr(gettext("invalid %s value for %s=%s"),
6511 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6512 return (Z_ERR);
6515 if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6516 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6517 return (Z_OK);
6518 zerr(gettext("invalid %s value for %s=%s"),
6519 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6520 return (Z_ERR);
6523 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6524 pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6525 return (Z_ERR);
6529 * Helper function for end_func-- checks the existence of a given property
6530 * and emits a message if not specified.
6532 static int
6533 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6535 if (strlen(attr) == 0) {
6536 *validation_failed = B_TRUE;
6537 zerr(gettext("%s not specified"), pt_to_str(pt));
6538 return (Z_ERR);
6540 return (Z_OK);
6543 static void
6544 net_exists_error(struct zone_nwiftab nwif)
6546 if (strlen(nwif.zone_nwif_address) > 0) {
6547 zerr(gettext("A %s resource with the %s '%s', "
6548 "and %s '%s' already exists."),
6549 rt_to_str(RT_NET),
6550 pt_to_str(PT_PHYSICAL),
6551 nwif.zone_nwif_physical,
6552 pt_to_str(PT_ADDRESS),
6553 in_progress_nwiftab.zone_nwif_address);
6554 } else {
6555 zerr(gettext("A %s resource with the %s '%s', "
6556 "and %s '%s' already exists."),
6557 rt_to_str(RT_NET),
6558 pt_to_str(PT_PHYSICAL),
6559 nwif.zone_nwif_physical,
6560 pt_to_str(PT_ALLOWED_ADDRESS),
6561 nwif.zone_nwif_allowed_address);
6565 void
6566 end_func(cmd_t *cmd)
6568 boolean_t validation_failed = B_FALSE;
6569 boolean_t arg_err = B_FALSE;
6570 struct zone_fstab tmp_fstab;
6571 struct zone_nwiftab tmp_nwiftab;
6572 struct zone_devtab tmp_devtab;
6573 struct zone_rctltab tmp_rctltab;
6574 struct zone_attrtab tmp_attrtab;
6575 struct zone_dstab tmp_dstab;
6576 struct zone_admintab tmp_admintab;
6577 int err, arg, res1, res2, res3;
6578 uint64_t swap_limit;
6579 uint64_t locked_limit;
6580 uint64_t proc_cap;
6582 assert(cmd != NULL);
6584 optind = 0;
6585 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6586 switch (arg) {
6587 case '?':
6588 longer_usage(CMD_END);
6589 arg_err = B_TRUE;
6590 break;
6591 default:
6592 short_usage(CMD_END);
6593 arg_err = B_TRUE;
6594 break;
6597 if (arg_err)
6598 return;
6600 if (optind != cmd->cmd_argc) {
6601 short_usage(CMD_END);
6602 return;
6605 if (global_scope) {
6606 scope_usage(CMD_END);
6607 return;
6610 assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6612 switch (resource_scope) {
6613 case RT_FS:
6614 /* First make sure everything was filled in. */
6615 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6616 PT_DIR, &validation_failed) == Z_OK) {
6617 if (in_progress_fstab.zone_fs_dir[0] != '/') {
6618 zerr(gettext("%s %s is not an absolute path."),
6619 pt_to_str(PT_DIR),
6620 in_progress_fstab.zone_fs_dir);
6621 validation_failed = B_TRUE;
6625 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6626 PT_SPECIAL, &validation_failed);
6628 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6629 in_progress_fstab.zone_fs_raw[0] != '/') {
6630 zerr(gettext("%s %s is not an absolute path."),
6631 pt_to_str(PT_RAW),
6632 in_progress_fstab.zone_fs_raw);
6633 validation_failed = B_TRUE;
6636 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6637 &validation_failed);
6639 if (validation_failed) {
6640 saw_error = B_TRUE;
6641 return;
6644 if (end_op == CMD_ADD) {
6645 /* Make sure there isn't already one like this. */
6646 bzero(&tmp_fstab, sizeof (tmp_fstab));
6647 (void) strlcpy(tmp_fstab.zone_fs_dir,
6648 in_progress_fstab.zone_fs_dir,
6649 sizeof (tmp_fstab.zone_fs_dir));
6650 err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6651 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6652 if (err == Z_OK) {
6653 zerr(gettext("A %s resource "
6654 "with the %s '%s' already exists."),
6655 rt_to_str(RT_FS), pt_to_str(PT_DIR),
6656 in_progress_fstab.zone_fs_dir);
6657 saw_error = B_TRUE;
6658 return;
6660 err = zonecfg_add_filesystem(handle,
6661 &in_progress_fstab);
6662 } else {
6663 err = zonecfg_modify_filesystem(handle, &old_fstab,
6664 &in_progress_fstab);
6666 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6667 in_progress_fstab.zone_fs_options = NULL;
6668 break;
6670 case RT_NET:
6672 * First make sure everything was filled in.
6673 * Since we don't know whether IP will be shared
6674 * or exclusive here, some checks are deferred until
6675 * the verify command.
6677 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6678 PT_PHYSICAL, &validation_failed);
6680 if (validation_failed) {
6681 saw_error = B_TRUE;
6682 return;
6684 if (end_op == CMD_ADD) {
6685 /* Make sure there isn't already one like this. */
6686 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6687 (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6688 in_progress_nwiftab.zone_nwif_physical,
6689 sizeof (tmp_nwiftab.zone_nwif_physical));
6690 (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6691 in_progress_nwiftab.zone_nwif_address,
6692 sizeof (tmp_nwiftab.zone_nwif_address));
6693 (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6694 in_progress_nwiftab.zone_nwif_allowed_address,
6695 sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6696 (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6697 in_progress_nwiftab.zone_nwif_defrouter,
6698 sizeof (tmp_nwiftab.zone_nwif_defrouter));
6699 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6700 net_exists_error(in_progress_nwiftab);
6701 saw_error = B_TRUE;
6702 return;
6704 err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6705 } else {
6706 err = zonecfg_modify_nwif(handle, &old_nwiftab,
6707 &in_progress_nwiftab);
6709 break;
6711 case RT_DEVICE:
6712 /* First make sure everything was filled in. */
6713 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6714 PT_MATCH, &validation_failed);
6716 if (validation_failed) {
6717 saw_error = B_TRUE;
6718 return;
6721 if (end_op == CMD_ADD) {
6722 /* Make sure there isn't already one like this. */
6723 (void) strlcpy(tmp_devtab.zone_dev_match,
6724 in_progress_devtab.zone_dev_match,
6725 sizeof (tmp_devtab.zone_dev_match));
6726 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6727 zerr(gettext("A %s resource with the %s '%s' "
6728 "already exists."), rt_to_str(RT_DEVICE),
6729 pt_to_str(PT_MATCH),
6730 in_progress_devtab.zone_dev_match);
6731 saw_error = B_TRUE;
6732 return;
6734 err = zonecfg_add_dev(handle, &in_progress_devtab);
6735 } else {
6736 err = zonecfg_modify_dev(handle, &old_devtab,
6737 &in_progress_devtab);
6739 break;
6741 case RT_RCTL:
6742 /* First make sure everything was filled in. */
6743 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6744 PT_NAME, &validation_failed);
6746 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6747 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6748 validation_failed = B_TRUE;
6751 if (validation_failed) {
6752 saw_error = B_TRUE;
6753 return;
6756 if (end_op == CMD_ADD) {
6757 /* Make sure there isn't already one like this. */
6758 (void) strlcpy(tmp_rctltab.zone_rctl_name,
6759 in_progress_rctltab.zone_rctl_name,
6760 sizeof (tmp_rctltab.zone_rctl_name));
6761 tmp_rctltab.zone_rctl_valptr = NULL;
6762 err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6763 zonecfg_free_rctl_value_list(
6764 tmp_rctltab.zone_rctl_valptr);
6765 if (err == Z_OK) {
6766 zerr(gettext("A %s resource "
6767 "with the %s '%s' already exists."),
6768 rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6769 in_progress_rctltab.zone_rctl_name);
6770 saw_error = B_TRUE;
6771 return;
6773 err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6774 } else {
6775 err = zonecfg_modify_rctl(handle, &old_rctltab,
6776 &in_progress_rctltab);
6778 if (err == Z_OK) {
6779 zonecfg_free_rctl_value_list(
6780 in_progress_rctltab.zone_rctl_valptr);
6781 in_progress_rctltab.zone_rctl_valptr = NULL;
6783 break;
6785 case RT_ATTR:
6786 /* First make sure everything was filled in. */
6787 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6788 PT_NAME, &validation_failed);
6789 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6790 PT_TYPE, &validation_failed);
6791 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6792 PT_VALUE, &validation_failed);
6794 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6795 Z_OK)
6796 validation_failed = B_TRUE;
6798 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6799 validation_failed = B_TRUE;
6801 if (validation_failed) {
6802 saw_error = B_TRUE;
6803 return;
6805 if (end_op == CMD_ADD) {
6806 /* Make sure there isn't already one like this. */
6807 bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6808 (void) strlcpy(tmp_attrtab.zone_attr_name,
6809 in_progress_attrtab.zone_attr_name,
6810 sizeof (tmp_attrtab.zone_attr_name));
6811 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6812 zerr(gettext("An %s resource "
6813 "with the %s '%s' already exists."),
6814 rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6815 in_progress_attrtab.zone_attr_name);
6816 saw_error = B_TRUE;
6817 return;
6819 err = zonecfg_add_attr(handle, &in_progress_attrtab);
6820 } else {
6821 err = zonecfg_modify_attr(handle, &old_attrtab,
6822 &in_progress_attrtab);
6824 break;
6825 case RT_DATASET:
6826 /* First make sure everything was filled in. */
6827 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6828 zerr("%s %s", pt_to_str(PT_NAME),
6829 gettext("not specified"));
6830 saw_error = B_TRUE;
6831 validation_failed = B_TRUE;
6833 if (validation_failed)
6834 return;
6835 if (end_op == CMD_ADD) {
6836 /* Make sure there isn't already one like this. */
6837 bzero(&tmp_dstab, sizeof (tmp_dstab));
6838 (void) strlcpy(tmp_dstab.zone_dataset_name,
6839 in_progress_dstab.zone_dataset_name,
6840 sizeof (tmp_dstab.zone_dataset_name));
6841 err = zonecfg_lookup_ds(handle, &tmp_dstab);
6842 if (err == Z_OK) {
6843 zerr(gettext("A %s resource "
6844 "with the %s '%s' already exists."),
6845 rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6846 in_progress_dstab.zone_dataset_name);
6847 saw_error = B_TRUE;
6848 return;
6850 err = zonecfg_add_ds(handle, &in_progress_dstab);
6851 } else {
6852 err = zonecfg_modify_ds(handle, &old_dstab,
6853 &in_progress_dstab);
6855 break;
6856 case RT_DCPU:
6857 /* Make sure everything was filled in. */
6858 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6859 PT_NCPUS, &validation_failed) != Z_OK) {
6860 saw_error = B_TRUE;
6861 return;
6864 if (end_op == CMD_ADD) {
6865 err = zonecfg_add_pset(handle, &in_progress_psettab);
6866 } else {
6867 err = zonecfg_modify_pset(handle, &in_progress_psettab);
6869 break;
6870 case RT_PCAP:
6871 /* Make sure everything was filled in. */
6872 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6873 != Z_OK) {
6874 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6875 saw_error = B_TRUE;
6876 validation_failed = B_TRUE;
6877 return;
6879 err = Z_OK;
6880 break;
6881 case RT_MCAP:
6882 /* Make sure everything was filled in. */
6883 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6884 Z_ERR : Z_OK;
6885 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6886 &swap_limit);
6887 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6888 &locked_limit);
6890 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6891 zerr(gettext("No property was specified. One of %s, "
6892 "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6893 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6894 saw_error = B_TRUE;
6895 return;
6898 /* if phys & locked are both set, verify locked <= phys */
6899 if (res1 == Z_OK && res3 == Z_OK) {
6900 uint64_t phys_limit;
6901 char *endp;
6903 phys_limit = strtoull(
6904 in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6905 if (phys_limit < locked_limit) {
6906 zerr(gettext("The %s cap must be less than or "
6907 "equal to the %s cap."),
6908 pt_to_str(PT_LOCKED),
6909 pt_to_str(PT_PHYSICAL));
6910 saw_error = B_TRUE;
6911 return;
6915 err = Z_OK;
6916 if (res1 == Z_OK) {
6918 * We could be ending from either an add operation
6919 * or a select operation. Since all of the properties
6920 * within this resource are optional, we always use
6921 * modify on the mcap entry. zonecfg_modify_mcap()
6922 * will handle both adding and modifying a memory cap.
6924 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6925 } else if (end_op == CMD_SELECT) {
6927 * If we're ending from a select and the physical
6928 * memory cap is empty then the user could have cleared
6929 * the physical cap value, so try to delete the entry.
6931 (void) zonecfg_delete_mcap(handle);
6933 break;
6934 case RT_ADMIN:
6935 /* First make sure everything was filled in. */
6936 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6937 PT_USER, &validation_failed) == Z_OK) {
6938 if (getpwnam(in_progress_admintab.zone_admin_user)
6939 == NULL) {
6940 zerr(gettext("%s %s is not a valid username"),
6941 pt_to_str(PT_USER),
6942 in_progress_admintab.zone_admin_user);
6943 validation_failed = B_TRUE;
6947 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6948 PT_AUTHS, &validation_failed) == Z_OK) {
6949 if (!zonecfg_valid_auths(
6950 in_progress_admintab.zone_admin_auths,
6951 zone)) {
6952 validation_failed = B_TRUE;
6956 if (validation_failed) {
6957 saw_error = B_TRUE;
6958 return;
6961 if (end_op == CMD_ADD) {
6962 /* Make sure there isn't already one like this. */
6963 bzero(&tmp_admintab, sizeof (tmp_admintab));
6964 (void) strlcpy(tmp_admintab.zone_admin_user,
6965 in_progress_admintab.zone_admin_user,
6966 sizeof (tmp_admintab.zone_admin_user));
6967 err = zonecfg_lookup_admin(
6968 handle, &tmp_admintab);
6969 if (err == Z_OK) {
6970 zerr(gettext("A %s resource "
6971 "with the %s '%s' already exists."),
6972 rt_to_str(RT_ADMIN),
6973 pt_to_str(PT_USER),
6974 in_progress_admintab.zone_admin_user);
6975 saw_error = B_TRUE;
6976 return;
6978 err = zonecfg_add_admin(handle,
6979 &in_progress_admintab, zone);
6980 } else {
6981 err = zonecfg_modify_admin(handle,
6982 &old_admintab, &in_progress_admintab,
6983 zone);
6985 break;
6986 case RT_SECFLAGS:
6987 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
6988 saw_error = B_TRUE;
6989 return;
6992 if (end_op == CMD_ADD) {
6993 err = zonecfg_add_secflags(handle,
6994 &in_progress_secflagstab);
6995 } else {
6996 err = zonecfg_modify_secflags(handle,
6997 &old_secflagstab, &in_progress_secflagstab);
6999 break;
7000 default:
7001 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
7002 B_TRUE);
7003 saw_error = B_TRUE;
7004 return;
7007 if (err != Z_OK) {
7008 zone_perror(zone, err, B_TRUE);
7009 } else {
7010 need_to_commit = B_TRUE;
7011 global_scope = B_TRUE;
7012 end_op = -1;
7016 void
7017 commit_func(cmd_t *cmd)
7019 int arg;
7020 boolean_t arg_err = B_FALSE;
7022 optind = 0;
7023 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
7024 switch (arg) {
7025 case '?':
7026 longer_usage(CMD_COMMIT);
7027 arg_err = B_TRUE;
7028 break;
7029 default:
7030 short_usage(CMD_COMMIT);
7031 arg_err = B_TRUE;
7032 break;
7035 if (arg_err)
7036 return;
7038 if (optind != cmd->cmd_argc) {
7039 short_usage(CMD_COMMIT);
7040 return;
7043 if (zone_is_read_only(CMD_COMMIT))
7044 return;
7046 assert(cmd != NULL);
7048 cmd->cmd_argc = 1;
7050 * cmd_arg normally comes from a strdup() in the lexer, and the
7051 * whole cmd structure and its (char *) attributes are freed at
7052 * the completion of each command, so the strdup() below is needed
7053 * to match this and prevent a core dump from trying to free()
7054 * something that can't be.
7056 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
7057 zone_perror(zone, Z_NOMEM, B_TRUE);
7058 exit(Z_ERR);
7060 cmd->cmd_argv[1] = NULL;
7061 verify_func(cmd);
7064 void
7065 revert_func(cmd_t *cmd)
7067 char line[128]; /* enough to ask a question */
7068 boolean_t force = B_FALSE;
7069 boolean_t arg_err = B_FALSE;
7070 int err, arg, answer;
7072 optind = 0;
7073 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
7074 switch (arg) {
7075 case '?':
7076 longer_usage(CMD_REVERT);
7077 arg_err = B_TRUE;
7078 break;
7079 case 'F':
7080 force = B_TRUE;
7081 break;
7082 default:
7083 short_usage(CMD_REVERT);
7084 arg_err = B_TRUE;
7085 break;
7088 if (arg_err)
7089 return;
7091 if (optind != cmd->cmd_argc) {
7092 short_usage(CMD_REVERT);
7093 return;
7096 if (zone_is_read_only(CMD_REVERT))
7097 return;
7099 if (!global_scope) {
7100 zerr(gettext("You can only use %s in the global scope.\nUse"
7101 " '%s' to cancel changes to a resource specification."),
7102 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
7103 saw_error = B_TRUE;
7104 return;
7107 if (zonecfg_check_handle(handle) != Z_OK) {
7108 zerr(gettext("No changes to revert."));
7109 saw_error = B_TRUE;
7110 return;
7113 if (!force) {
7114 (void) snprintf(line, sizeof (line),
7115 gettext("Are you sure you want to revert"));
7116 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
7117 zerr(gettext("Input not from terminal and -F not "
7118 "specified:\n%s command ignored, exiting."),
7119 cmd_to_str(CMD_REVERT));
7120 exit(Z_ERR);
7122 if (answer != 1)
7123 return;
7127 * Reset any pending admins that were
7128 * removed from the previous zone
7130 zonecfg_remove_userauths(handle, "", zone, B_FALSE);
7133 * Time for a new handle: finish the old one off first
7134 * then get a new one properly to avoid leaks.
7136 zonecfg_fini_handle(handle);
7137 if ((handle = zonecfg_init_handle()) == NULL) {
7138 zone_perror(execname, Z_NOMEM, B_TRUE);
7139 exit(Z_ERR);
7142 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
7143 saw_error = B_TRUE;
7144 got_handle = B_FALSE;
7145 if (err == Z_NO_ZONE)
7146 zerr(gettext("%s: no such saved zone to revert to."),
7147 revert_zone);
7148 else
7149 zone_perror(zone, err, B_TRUE);
7151 (void) strlcpy(zone, revert_zone, sizeof (zone));
7154 void
7155 help_func(cmd_t *cmd)
7157 int i;
7159 assert(cmd != NULL);
7161 if (cmd->cmd_argc == 0) {
7162 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
7163 return;
7165 if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
7166 usage(B_TRUE, HELP_USAGE);
7167 return;
7169 if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
7170 usage(B_TRUE, HELP_SUBCMDS);
7171 return;
7173 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
7174 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
7175 return;
7177 if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
7178 longer_usage(CMD_HELP);
7179 return;
7182 for (i = 0; i <= CMD_MAX; i++) {
7183 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
7184 longer_usage(i);
7185 return;
7188 /* We do not use zerr() here because we do not want its extra \n. */
7189 (void) fprintf(stderr, gettext("Unknown help subject %s. "),
7190 cmd->cmd_argv[0]);
7191 usage(B_FALSE, HELP_META);
7194 static int
7195 string_to_yyin(char *string)
7197 if ((yyin = tmpfile()) == NULL) {
7198 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7199 return (Z_ERR);
7201 if (fwrite(string, strlen(string), 1, yyin) != 1) {
7202 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7203 return (Z_ERR);
7205 if (fseek(yyin, 0, SEEK_SET) != 0) {
7206 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7207 return (Z_ERR);
7209 return (Z_OK);
7212 /* This is the back-end helper function for read_input() below. */
7214 static int
7215 cleanup()
7217 int answer;
7218 cmd_t *cmd;
7220 if (!interactive_mode && !cmd_file_mode) {
7222 * If we're not in interactive mode, and we're not in command
7223 * file mode, then we must be in commands-from-the-command-line
7224 * mode. As such, we can't loop back and ask for more input.
7225 * It was OK to prompt for such things as whether or not to
7226 * really delete a zone in the command handler called from
7227 * yyparse() above, but "really quit?" makes no sense in this
7228 * context. So disable prompting.
7230 ok_to_prompt = B_FALSE;
7232 if (!global_scope) {
7233 if (!time_to_exit) {
7235 * Just print a simple error message in the -1 case,
7236 * since exit_func() already handles that case, and
7237 * EOF means we are finished anyway.
7239 answer = ask_yesno(B_FALSE,
7240 gettext("Resource incomplete; really quit"));
7241 if (answer == -1) {
7242 zerr(gettext("Resource incomplete."));
7243 return (Z_ERR);
7245 if (answer != 1) {
7246 yyin = stdin;
7247 return (Z_REPEAT);
7249 } else {
7250 saw_error = B_TRUE;
7254 * Make sure we tried something and that the handle checks
7255 * out, or we would get a false error trying to commit.
7257 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
7258 if ((cmd = alloc_cmd()) == NULL) {
7259 zone_perror(zone, Z_NOMEM, B_TRUE);
7260 return (Z_ERR);
7262 cmd->cmd_argc = 0;
7263 cmd->cmd_argv[0] = NULL;
7264 commit_func(cmd);
7265 free_cmd(cmd);
7267 * need_to_commit will get set back to FALSE if the
7268 * configuration is saved successfully.
7270 if (need_to_commit) {
7271 if (force_exit) {
7272 zerr(gettext("Configuration not saved."));
7273 return (Z_ERR);
7275 answer = ask_yesno(B_FALSE,
7276 gettext("Configuration not saved; really quit"));
7277 if (answer == -1) {
7278 zerr(gettext("Configuration not saved."));
7279 return (Z_ERR);
7281 if (answer != 1) {
7282 time_to_exit = B_FALSE;
7283 yyin = stdin;
7284 return (Z_REPEAT);
7288 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
7292 * read_input() is the driver of this program. It is a wrapper around
7293 * yyparse(), printing appropriate prompts when needed, checking for
7294 * exit conditions and reacting appropriately [the latter in its cleanup()
7295 * helper function].
7297 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
7298 * so do_interactive() knows that we are not really done (i.e, we asked
7299 * the user if we should really quit and the user said no).
7301 static int
7302 read_input()
7304 boolean_t yyin_is_a_tty = isatty(fileno(yyin));
7306 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
7307 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
7309 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
7311 /* yyin should have been set to the appropriate (FILE *) if not stdin */
7312 newline_terminated = B_TRUE;
7313 for (;;) {
7314 if (yyin_is_a_tty) {
7315 if (newline_terminated) {
7316 if (global_scope)
7317 (void) snprintf(prompt, sizeof (prompt),
7318 "%s:%s> ", execname, zone);
7319 else
7320 (void) snprintf(prompt, sizeof (prompt),
7321 "%s:%s:%s> ", execname, zone,
7322 rt_to_str(resource_scope));
7325 * If the user hits ^C then we want to catch it and
7326 * start over. If the user hits EOF then we want to
7327 * bail out.
7329 line = gl_get_line(gl, prompt, NULL, -1);
7330 if (gl_return_status(gl) == GLR_SIGNAL) {
7331 gl_abandon_line(gl);
7332 continue;
7334 if (line == NULL)
7335 break;
7336 (void) string_to_yyin(line);
7337 while (!feof(yyin))
7338 yyparse();
7339 } else {
7340 yyparse();
7342 /* Bail out on an error in command file mode. */
7343 if (saw_error && cmd_file_mode && !interactive_mode)
7344 time_to_exit = B_TRUE;
7345 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7346 break;
7348 return (cleanup());
7352 * This function is used in the zonecfg-interactive-mode scenario: it just
7353 * calls read_input() until we are done.
7356 static int
7357 do_interactive(void)
7359 int err;
7361 interactive_mode = B_TRUE;
7362 if (!read_only_mode) {
7364 * Try to set things up proactively in interactive mode, so
7365 * that if the zone in question does not exist yet, we can
7366 * provide the user with a clue.
7368 (void) initialize(B_FALSE);
7370 do {
7371 err = read_input();
7372 } while (err == Z_REPEAT);
7373 return (err);
7377 * cmd_file is slightly more complicated, as it has to open the command file
7378 * and set yyin appropriately. Once that is done, though, it just calls
7379 * read_input(), and only once, since prompting is not possible.
7382 static int
7383 cmd_file(char *file)
7385 FILE *infile;
7386 int err;
7387 struct stat statbuf;
7388 boolean_t using_real_file = (strcmp(file, "-") != 0);
7390 if (using_real_file) {
7392 * zerr() prints a line number in cmd_file_mode, which we do
7393 * not want here, so temporarily unset it.
7395 cmd_file_mode = B_FALSE;
7396 if ((infile = fopen(file, "r")) == NULL) {
7397 zerr(gettext("could not open file %s: %s"),
7398 file, strerror(errno));
7399 return (Z_ERR);
7401 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7402 zerr(gettext("could not stat file %s: %s"),
7403 file, strerror(errno));
7404 err = Z_ERR;
7405 goto done;
7407 if (!S_ISREG(statbuf.st_mode)) {
7408 zerr(gettext("%s is not a regular file."), file);
7409 err = Z_ERR;
7410 goto done;
7412 yyin = infile;
7413 cmd_file_mode = B_TRUE;
7414 ok_to_prompt = B_FALSE;
7415 } else {
7417 * "-f -" is essentially the same as interactive mode,
7418 * so treat it that way.
7420 interactive_mode = B_TRUE;
7422 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7423 if ((err = read_input()) == Z_REPEAT)
7424 err = Z_ERR;
7425 done:
7426 if (using_real_file)
7427 (void) fclose(infile);
7428 return (err);
7432 * Since yacc is based on reading from a (FILE *) whereas what we get from
7433 * the command line is in argv format, we need to convert when the user
7434 * gives us commands directly from the command line. That is done here by
7435 * concatenating the argv list into a space-separated string, writing it
7436 * to a temp file, and rewinding the file so yyin can be set to it. Then
7437 * we call read_input(), and only once, since prompting about whether to
7438 * continue or quit would make no sense in this context.
7441 static int
7442 one_command_at_a_time(int argc, char *argv[])
7444 char *command;
7445 size_t len = 2; /* terminal \n\0 */
7446 int i, err;
7448 for (i = 0; i < argc; i++)
7449 len += strlen(argv[i]) + 1;
7450 if ((command = malloc(len)) == NULL) {
7451 zone_perror(execname, Z_NOMEM, B_TRUE);
7452 return (Z_ERR);
7454 (void) strlcpy(command, argv[0], len);
7455 for (i = 1; i < argc; i++) {
7456 (void) strlcat(command, " ", len);
7457 (void) strlcat(command, argv[i], len);
7459 (void) strlcat(command, "\n", len);
7460 err = string_to_yyin(command);
7461 free(command);
7462 if (err != Z_OK)
7463 return (err);
7464 while (!feof(yyin))
7465 yyparse();
7466 return (cleanup());
7469 static char *
7470 get_execbasename(char *execfullname)
7472 char *last_slash, *execbasename;
7474 /* guard against '/' at end of command invocation */
7475 for (;;) {
7476 last_slash = strrchr(execfullname, '/');
7477 if (last_slash == NULL) {
7478 execbasename = execfullname;
7479 break;
7480 } else {
7481 execbasename = last_slash + 1;
7482 if (*execbasename == '\0') {
7483 *last_slash = '\0';
7484 continue;
7486 break;
7489 return (execbasename);
7493 main(int argc, char *argv[])
7495 int err, arg;
7496 struct stat st;
7498 /* This must be before anything goes to stdout. */
7499 setbuf(stdout, NULL);
7501 saw_error = B_FALSE;
7502 cmd_file_mode = B_FALSE;
7503 execname = get_execbasename(argv[0]);
7505 (void) setlocale(LC_ALL, "");
7506 (void) textdomain(TEXT_DOMAIN);
7508 if (getzoneid() != GLOBAL_ZONEID) {
7509 zerr(gettext("%s can only be run from the global zone."),
7510 execname);
7511 exit(Z_ERR);
7514 if (argc < 2) {
7515 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7516 exit(Z_USAGE);
7518 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7519 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7520 exit(Z_OK);
7523 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7524 switch (arg) {
7525 case '?':
7526 if (optopt == '?')
7527 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7528 else
7529 usage(B_FALSE, HELP_USAGE);
7530 exit(Z_USAGE);
7531 /* NOTREACHED */
7532 case 'f':
7533 cmd_file_name = optarg;
7534 cmd_file_mode = B_TRUE;
7535 break;
7536 case 'R':
7537 if (*optarg != '/') {
7538 zerr(gettext("root path must be absolute: %s"),
7539 optarg);
7540 exit(Z_USAGE);
7542 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7543 zerr(gettext(
7544 "root path must be a directory: %s"),
7545 optarg);
7546 exit(Z_USAGE);
7548 zonecfg_set_root(optarg);
7549 break;
7550 case 'z':
7551 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7552 global_zone = B_TRUE;
7553 } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7554 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7555 usage(B_FALSE, HELP_SYNTAX);
7556 exit(Z_USAGE);
7558 (void) strlcpy(zone, optarg, sizeof (zone));
7559 (void) strlcpy(revert_zone, optarg, sizeof (zone));
7560 break;
7561 default:
7562 usage(B_FALSE, HELP_USAGE);
7563 exit(Z_USAGE);
7567 if (optind > argc || strcmp(zone, "") == 0) {
7568 usage(B_FALSE, HELP_USAGE);
7569 exit(Z_USAGE);
7572 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7573 read_only_mode = B_FALSE;
7574 } else if (err == Z_ACCES) {
7575 read_only_mode = B_TRUE;
7576 /* skip this message in one-off from command line mode */
7577 if (optind == argc)
7578 (void) fprintf(stderr, gettext("WARNING: you do not "
7579 "have write access to this zone's configuration "
7580 "file;\ngoing into read-only mode.\n"));
7581 } else {
7582 fprintf(stderr, "%s: Could not access zone configuration "
7583 "store: %s\n", execname, zonecfg_strerror(err));
7584 exit(Z_ERR);
7587 if ((handle = zonecfg_init_handle()) == NULL) {
7588 zone_perror(execname, Z_NOMEM, B_TRUE);
7589 exit(Z_ERR);
7593 * This may get set back to FALSE again in cmd_file() if cmd_file_name
7594 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7596 if (isatty(STDIN_FILENO))
7597 ok_to_prompt = B_TRUE;
7598 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7599 exit(Z_ERR);
7600 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7601 exit(Z_ERR);
7602 (void) sigset(SIGINT, SIG_IGN);
7603 if (optind == argc) {
7604 if (!cmd_file_mode)
7605 err = do_interactive();
7606 else
7607 err = cmd_file(cmd_file_name);
7608 } else {
7609 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7611 zonecfg_fini_handle(handle);
7612 if (brand != NULL)
7613 brand_close(brand);
7614 (void) del_GetLine(gl);
7615 return (err);