7029 want per-process exploit mitigation features (secflags)
[unleashed.git] / usr / src / cmd / zonecfg / zonecfg.c
blobab35860691073a8a9de5aa11d68667f90ca3364f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2014 Gary Mills
29 * zonecfg is a lex/yacc based command interpreter used to manage zone
30 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
31 * the grammar (see zonecfg_grammar.y) builds up into commands, some of
32 * which takes resources and/or properties as arguments. See the block
33 * comments near the end of zonecfg_grammar.y for how the data structures
34 * which keep track of these resources and properties are built up.
36 * The resource/property data structures are inserted into a command
37 * structure (see zonecfg.h), which also keeps track of command names,
38 * miscellaneous arguments, and function handlers. The grammar selects
39 * the appropriate function handler, each of which takes a pointer to a
40 * command structure as its sole argument, and invokes it. The grammar
41 * itself is "entered" (a la the Matrix) by yyparse(), which is called
42 * from read_input(), our main driving function. That in turn is called
43 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
44 * of which is called from main() depending on how the program was invoked.
46 * The rest of this module consists of the various function handlers and
47 * their helper functions. Some of these functions, particularly the
48 * X_to_str() functions, which maps command, resource and property numbers
49 * to strings, are used quite liberally, as doing so results in a better
50 * program w/rt I18N, reducing the need for translation notes.
53 #include <sys/mntent.h>
54 #include <sys/varargs.h>
55 #include <sys/sysmacros.h>
56 #include <sys/secflags.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <strings.h>
61 #include <unistd.h>
62 #include <ctype.h>
63 #include <stdlib.h>
64 #include <assert.h>
65 #include <sys/stat.h>
66 #include <zone.h>
67 #include <arpa/inet.h>
68 #include <netdb.h>
69 #include <locale.h>
70 #include <libintl.h>
71 #include <alloca.h>
72 #include <signal.h>
73 #include <wait.h>
74 #include <libtecla.h>
75 #include <libzfs.h>
76 #include <sys/brand.h>
77 #include <libbrand.h>
78 #include <sys/systeminfo.h>
79 #include <libdladm.h>
80 #include <libinetutil.h>
81 #include <pwd.h>
82 #include <inet/ip.h>
84 #include <libzonecfg.h>
85 #include "zonecfg.h"
87 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
88 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
89 #endif
91 #define PAGER "/usr/bin/more"
92 #define EXEC_PREFIX "exec "
93 #define EXEC_LEN (strlen(EXEC_PREFIX))
95 struct help {
96 uint_t cmd_num;
97 char *cmd_name;
98 uint_t flags;
99 char *short_usage;
102 extern int yyparse(void);
103 extern int lex_lineno;
105 #define MAX_LINE_LEN 1024
106 #define MAX_CMD_HIST 1024
107 #define MAX_CMD_LEN 1024
109 #define ONE_MB 1048576
112 * Each SHELP_ should be a simple string.
115 #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \
116 "add <property-name> <property-value>\n\t(resource scope)"
117 #define SHELP_CANCEL "cancel"
118 #define SHELP_CLEAR "clear <property-name>"
119 #define SHELP_COMMIT "commit"
120 #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]"
121 #define SHELP_DELETE "delete [-F]"
122 #define SHELP_END "end"
123 #define SHELP_EXIT "exit [-F]"
124 #define SHELP_EXPORT "export [-f output-file]"
125 #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]"
126 #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]"
127 #define SHELP_REMOVE "remove [-F] <resource-type> " \
128 "[ <property-name>=<property-value> ]*\n" \
129 "\t(global scope)\n" \
130 "remove <property-name> <property-value>\n" \
131 "\t(resource scope)"
132 #define SHELP_REVERT "revert [-F]"
133 #define SHELP_SELECT "select <resource-type> { <property-name>=" \
134 "<property-value> }"
135 #define SHELP_SET "set <property-name>=<property-value>"
136 #define SHELP_VERIFY "verify"
138 static struct help helptab[] = {
139 { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, },
140 { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, },
141 { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, },
142 { CMD_COMMIT, "commit", 0, SHELP_COMMIT, },
143 { CMD_CREATE, "create", 0, SHELP_CREATE, },
144 { CMD_DELETE, "delete", 0, SHELP_DELETE, },
145 { CMD_END, "end", 0, SHELP_END, },
146 { CMD_EXIT, "exit", 0, SHELP_EXIT, },
147 { CMD_EXPORT, "export", 0, SHELP_EXPORT, },
148 { CMD_HELP, "help", 0, SHELP_HELP },
149 { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, },
150 { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, },
151 { CMD_REVERT, "revert", 0, SHELP_REVERT, },
152 { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, },
153 { CMD_SET, "set", HELP_PROPS, SHELP_SET, },
154 { CMD_VERIFY, "verify", 0, SHELP_VERIFY, },
155 { 0 },
158 #define MAX_RT_STRLEN 16
160 /* These *must* match the order of the RT_ define's from zonecfg.h */
161 char *res_types[] = {
162 "unknown",
163 "zonename",
164 "zonepath",
165 "autoboot",
166 "pool",
167 "fs",
168 "net",
169 "device",
170 "rctl",
171 "attr",
172 "dataset",
173 "limitpriv",
174 "bootargs",
175 "brand",
176 "dedicated-cpu",
177 "capped-memory",
178 ALIAS_MAXLWPS,
179 ALIAS_MAXSHMMEM,
180 ALIAS_MAXSHMIDS,
181 ALIAS_MAXMSGIDS,
182 ALIAS_MAXSEMIDS,
183 ALIAS_SHARES,
184 "scheduling-class",
185 "ip-type",
186 "capped-cpu",
187 "hostid",
188 "admin",
189 "fs-allowed",
190 ALIAS_MAXPROCS,
191 "security-flags",
192 NULL
195 /* These *must* match the order of the PT_ define's from zonecfg.h */
196 char *prop_types[] = {
197 "unknown",
198 "zonename",
199 "zonepath",
200 "autoboot",
201 "pool",
202 "dir",
203 "special",
204 "type",
205 "options",
206 "address",
207 "physical",
208 "name",
209 "value",
210 "match",
211 "priv",
212 "limit",
213 "action",
214 "raw",
215 "limitpriv",
216 "bootargs",
217 "brand",
218 "ncpus",
219 "importance",
220 "swap",
221 "locked",
222 ALIAS_SHARES,
223 ALIAS_MAXLWPS,
224 ALIAS_MAXSHMMEM,
225 ALIAS_MAXSHMIDS,
226 ALIAS_MAXMSGIDS,
227 ALIAS_MAXSEMIDS,
228 ALIAS_MAXLOCKEDMEM,
229 ALIAS_MAXSWAP,
230 "scheduling-class",
231 "ip-type",
232 "defrouter",
233 "hostid",
234 "user",
235 "auths",
236 "fs-allowed",
237 ALIAS_MAXPROCS,
238 "allowed-address",
239 "default",
240 "lower",
241 "upper",
242 NULL
245 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
246 static char *prop_val_types[] = {
247 "simple",
248 "complex",
249 "list",
253 * The various _cmds[] lists below are for command tab-completion.
257 * remove has a space afterwards because it has qualifiers; the other commands
258 * that have qualifiers (add, select, etc.) don't need a space here because
259 * they have their own _cmds[] lists below.
261 static const char *global_scope_cmds[] = {
262 "add",
263 "clear",
264 "commit",
265 "create",
266 "delete",
267 "exit",
268 "export",
269 "help",
270 "info",
271 "remove ",
272 "revert",
273 "select",
274 "set",
275 "verify",
276 NULL
279 static const char *add_cmds[] = {
280 "add fs",
281 "add net",
282 "add device",
283 "add rctl",
284 "add attr",
285 "add dataset",
286 "add dedicated-cpu",
287 "add capped-cpu",
288 "add capped-memory",
289 "add admin",
290 "add security-flags",
291 NULL
294 static const char *clear_cmds[] = {
295 "clear autoboot",
296 "clear pool",
297 "clear limitpriv",
298 "clear bootargs",
299 "clear scheduling-class",
300 "clear ip-type",
301 "clear " ALIAS_MAXLWPS,
302 "clear " ALIAS_MAXSHMMEM,
303 "clear " ALIAS_MAXSHMIDS,
304 "clear " ALIAS_MAXMSGIDS,
305 "clear " ALIAS_MAXSEMIDS,
306 "clear " ALIAS_SHARES,
307 "clear " ALIAS_MAXPROCS,
308 NULL
311 static const char *remove_cmds[] = {
312 "remove fs ",
313 "remove net ",
314 "remove device ",
315 "remove rctl ",
316 "remove attr ",
317 "remove dataset ",
318 "remove dedicated-cpu ",
319 "remove capped-cpu ",
320 "remove capped-memory ",
321 "remove admin ",
322 "remove security-flags",
323 NULL
326 static const char *select_cmds[] = {
327 "select fs ",
328 "select net ",
329 "select device ",
330 "select rctl ",
331 "select attr ",
332 "select dataset ",
333 "select dedicated-cpu",
334 "select capped-cpu",
335 "select capped-memory",
336 "select admin",
337 "select security-flags",
338 NULL
341 static const char *set_cmds[] = {
342 "set zonename=",
343 "set zonepath=",
344 "set brand=",
345 "set autoboot=",
346 "set pool=",
347 "set limitpriv=",
348 "set bootargs=",
349 "set scheduling-class=",
350 "set ip-type=",
351 "set " ALIAS_MAXLWPS "=",
352 "set " ALIAS_MAXSHMMEM "=",
353 "set " ALIAS_MAXSHMIDS "=",
354 "set " ALIAS_MAXMSGIDS "=",
355 "set " ALIAS_MAXSEMIDS "=",
356 "set " ALIAS_SHARES "=",
357 "set hostid=",
358 "set fs-allowed=",
359 "set " ALIAS_MAXPROCS "=",
360 NULL
363 static const char *info_cmds[] = {
364 "info fs ",
365 "info net ",
366 "info device ",
367 "info rctl ",
368 "info attr ",
369 "info dataset ",
370 "info capped-memory",
371 "info dedicated-cpu",
372 "info capped-cpu",
373 "info security-flags",
374 "info zonename",
375 "info zonepath",
376 "info autoboot",
377 "info pool",
378 "info limitpriv",
379 "info bootargs",
380 "info brand",
381 "info scheduling-class",
382 "info ip-type",
383 "info max-lwps",
384 "info max-shm-memory",
385 "info max-shm-ids",
386 "info max-msg-ids",
387 "info max-sem-ids",
388 "info cpu-shares",
389 "info hostid",
390 "info admin",
391 "info fs-allowed",
392 "info max-processes",
393 NULL
396 static const char *fs_res_scope_cmds[] = {
397 "add options ",
398 "cancel",
399 "end",
400 "exit",
401 "help",
402 "info",
403 "remove options ",
404 "set dir=",
405 "set raw=",
406 "set special=",
407 "set type=",
408 "clear raw",
409 NULL
412 static const char *net_res_scope_cmds[] = {
413 "cancel",
414 "end",
415 "exit",
416 "help",
417 "info",
418 "set address=",
419 "set physical=",
420 "set defrouter=",
421 NULL
424 static const char *device_res_scope_cmds[] = {
425 "cancel",
426 "end",
427 "exit",
428 "help",
429 "info",
430 "set match=",
431 NULL
434 static const char *attr_res_scope_cmds[] = {
435 "cancel",
436 "end",
437 "exit",
438 "help",
439 "info",
440 "set name=",
441 "set type=",
442 "set value=",
443 NULL
446 static const char *rctl_res_scope_cmds[] = {
447 "add value ",
448 "cancel",
449 "end",
450 "exit",
451 "help",
452 "info",
453 "remove value ",
454 "set name=",
455 NULL
458 static const char *dataset_res_scope_cmds[] = {
459 "cancel",
460 "end",
461 "exit",
462 "help",
463 "info",
464 "set name=",
465 NULL
468 static const char *pset_res_scope_cmds[] = {
469 "cancel",
470 "end",
471 "exit",
472 "help",
473 "info",
474 "set ncpus=",
475 "set importance=",
476 "clear importance",
477 NULL
480 static const char *pcap_res_scope_cmds[] = {
481 "cancel",
482 "end",
483 "exit",
484 "help",
485 "info",
486 "set ncpus=",
487 NULL
490 static const char *mcap_res_scope_cmds[] = {
491 "cancel",
492 "end",
493 "exit",
494 "help",
495 "info",
496 "set physical=",
497 "set swap=",
498 "set locked=",
499 "clear physical",
500 "clear swap",
501 "clear locked",
502 NULL
505 static const char *admin_res_scope_cmds[] = {
506 "cancel",
507 "end",
508 "exit",
509 "help",
510 "info",
511 "set user=",
512 "set auths=",
513 NULL
516 static const char *secflags_res_scope_cmds[] = {
517 "cancel",
518 "end",
519 "exit",
520 "set default=",
521 "set lower=",
522 "set upper=",
523 NULL
526 struct xif {
527 struct xif *xif_next;
528 char xif_name[LIFNAMSIZ];
529 boolean_t xif_has_address;
530 boolean_t xif_has_defrouter;
533 /* Global variables */
535 /* list of network interfaces specified for exclusive IP zone */
536 struct xif *xif;
538 /* set early in main(), never modified thereafter, used all over the place */
539 static char *execname;
541 /* set in main(), used all over the place */
542 static zone_dochandle_t handle;
544 /* used all over the place */
545 static char zone[ZONENAME_MAX];
546 static char revert_zone[ZONENAME_MAX];
548 /* global brand operations */
549 static brand_handle_t brand;
551 /* set in modifying functions, checked in read_input() */
552 static boolean_t need_to_commit = B_FALSE;
553 boolean_t saw_error;
555 /* set in yacc parser, checked in read_input() */
556 boolean_t newline_terminated;
558 /* set in main(), checked in lex error handler */
559 boolean_t cmd_file_mode;
561 /* set in exit_func(), checked in read_input() */
562 static boolean_t time_to_exit = B_FALSE, force_exit = B_FALSE;
564 /* used in short_usage() and zerr() */
565 static char *cmd_file_name = NULL;
567 /* checked in read_input() and other places */
568 static boolean_t ok_to_prompt = B_FALSE;
570 /* set and checked in initialize() */
571 static boolean_t got_handle = B_FALSE;
573 /* initialized in do_interactive(), checked in initialize() */
574 static boolean_t interactive_mode;
576 /* set if configuring the global zone */
577 static boolean_t global_zone = B_FALSE;
579 /* set in main(), checked in multiple places */
580 static boolean_t read_only_mode;
582 /* scope is outer/global or inner/resource */
583 static boolean_t global_scope = B_TRUE;
584 static int resource_scope; /* should be in the RT_ list from zonecfg.h */
585 static int end_op = -1; /* operation on end is either add or modify */
587 int num_prop_vals; /* for grammar */
590 * These are for keeping track of resources as they are specified as part of
591 * the multi-step process. They should be initialized by add_resource() or
592 * select_func() and filled in by add_property() or set_func().
594 static struct zone_fstab old_fstab, in_progress_fstab;
595 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab;
596 static struct zone_devtab old_devtab, in_progress_devtab;
597 static struct zone_rctltab old_rctltab, in_progress_rctltab;
598 static struct zone_attrtab old_attrtab, in_progress_attrtab;
599 static struct zone_dstab old_dstab, in_progress_dstab;
600 static struct zone_psettab old_psettab, in_progress_psettab;
601 static struct zone_mcaptab old_mcaptab, in_progress_mcaptab;
602 static struct zone_admintab old_admintab, in_progress_admintab;
603 static struct zone_secflagstab old_secflagstab, in_progress_secflagstab;
605 static GetLine *gl; /* The gl_get_line() resource object */
607 static void bytes_to_units(char *str, char *buf, int bufsize);
609 /* Functions begin here */
611 static boolean_t
612 initial_match(const char *line1, const char *line2, int word_end)
614 if (word_end <= 0)
615 return (B_TRUE);
616 return (strncmp(line1, line2, word_end) == 0);
619 static int
620 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
621 int word_end)
623 int i, err;
625 for (i = 0; list[i] != NULL; i++) {
626 if (initial_match(line1, list[i], word_end)) {
627 err = cpl_add_completion(cpl, line1, 0, word_end,
628 list[i] + word_end, "", "");
629 if (err != 0)
630 return (err);
633 return (0);
636 static
637 /* ARGSUSED */
638 CPL_MATCH_FN(cmd_cpl_fn)
640 if (global_scope) {
642 * The MAX/MIN tests below are to make sure we have at least
643 * enough characters to distinguish from other prefixes (MAX)
644 * but only check MIN(what we have, what we're checking).
646 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0)
647 return (add_stuff(cpl, line, add_cmds, word_end));
648 if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0)
649 return (add_stuff(cpl, line, clear_cmds, word_end));
650 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0)
651 return (add_stuff(cpl, line, select_cmds, word_end));
652 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0)
653 return (add_stuff(cpl, line, set_cmds, word_end));
654 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0)
655 return (add_stuff(cpl, line, remove_cmds, word_end));
656 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0)
657 return (add_stuff(cpl, line, info_cmds, word_end));
658 return (add_stuff(cpl, line, global_scope_cmds, word_end));
660 switch (resource_scope) {
661 case RT_FS:
662 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end));
663 case RT_NET:
664 return (add_stuff(cpl, line, net_res_scope_cmds, word_end));
665 case RT_DEVICE:
666 return (add_stuff(cpl, line, device_res_scope_cmds, word_end));
667 case RT_RCTL:
668 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end));
669 case RT_ATTR:
670 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end));
671 case RT_DATASET:
672 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end));
673 case RT_DCPU:
674 return (add_stuff(cpl, line, pset_res_scope_cmds, word_end));
675 case RT_PCAP:
676 return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
677 case RT_MCAP:
678 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
679 case RT_ADMIN:
680 return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
681 case RT_SECFLAGS:
682 return (add_stuff(cpl, line, secflags_res_scope_cmds,
683 word_end));
686 return (0);
690 * For the main CMD_func() functions below, several of them call getopt()
691 * then check optind against argc to make sure an extra parameter was not
692 * passed in. The reason this is not caught in the grammar is that the
693 * grammar just checks for a miscellaneous TOKEN, which is *expected* to
694 * be "-F" (for example), but could be anything. So (for example) this
695 * check will prevent "create bogus".
698 cmd_t *
699 alloc_cmd(void)
701 return (calloc(1, sizeof (cmd_t)));
704 void
705 free_cmd(cmd_t *cmd)
707 int i;
709 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
710 if (cmd->cmd_property_ptr[i] != NULL) {
711 property_value_ptr_t pp = cmd->cmd_property_ptr[i];
713 switch (pp->pv_type) {
714 case PROP_VAL_SIMPLE:
715 free(pp->pv_simple);
716 break;
717 case PROP_VAL_COMPLEX:
718 free_complex(pp->pv_complex);
719 break;
720 case PROP_VAL_LIST:
721 free_list(pp->pv_list);
722 break;
725 for (i = 0; i < cmd->cmd_argc; i++)
726 free(cmd->cmd_argv[i]);
727 free(cmd);
730 complex_property_ptr_t
731 alloc_complex(void)
733 return (calloc(1, sizeof (complex_property_t)));
736 void
737 free_complex(complex_property_ptr_t complex)
739 if (complex == NULL)
740 return;
741 free_complex(complex->cp_next);
742 if (complex->cp_value != NULL)
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 if (list->lp_simple != NULL)
759 free(list->lp_simple);
760 free_complex(list->lp_complex);
761 free_list(list->lp_next);
762 free(list);
765 void
766 free_outer_list(list_property_ptr_t list)
768 if (list == NULL)
769 return;
770 free_outer_list(list->lp_next);
771 free(list);
774 static struct zone_rctlvaltab *
775 alloc_rctlvaltab(void)
777 return (calloc(1, sizeof (struct zone_rctlvaltab)));
780 static char *
781 rt_to_str(int res_type)
783 assert(res_type >= RT_MIN && res_type <= RT_MAX);
784 return (res_types[res_type]);
787 static char *
788 pt_to_str(int prop_type)
790 assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
791 return (prop_types[prop_type]);
794 static char *
795 pvt_to_str(int pv_type)
797 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX);
798 return (prop_val_types[pv_type]);
801 static char *
802 cmd_to_str(int cmd_num)
804 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
805 return (helptab[cmd_num].cmd_name);
808 /* PRINTFLIKE1 */
809 static void
810 zerr(const char *fmt, ...)
812 va_list alist;
813 static int last_lineno;
815 /* lex_lineno has already been incremented in the lexer; compensate */
816 if (cmd_file_mode && lex_lineno > last_lineno) {
817 if (strcmp(cmd_file_name, "-") == 0)
818 (void) fprintf(stderr, gettext("On line %d:\n"),
819 lex_lineno - 1);
820 else
821 (void) fprintf(stderr, gettext("On line %d of %s:\n"),
822 lex_lineno - 1, cmd_file_name);
823 last_lineno = lex_lineno;
825 va_start(alist, fmt);
826 (void) vfprintf(stderr, fmt, alist);
827 (void) fprintf(stderr, "\n");
828 va_end(alist);
832 * This is a separate function rather than a set of define's because of the
833 * gettext() wrapping.
837 * TRANSLATION_NOTE
838 * Each string below should have \t follow \n whenever needed; the
839 * initial \t and the terminal \n will be provided by the calling function.
842 static char *
843 long_help(int cmd_num)
845 static char line[1024]; /* arbitrary large amount */
847 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
848 switch (cmd_num) {
849 case CMD_HELP:
850 return (gettext("Prints help message."));
851 case CMD_CREATE:
852 (void) snprintf(line, sizeof (line),
853 gettext("Creates a configuration for the "
854 "specified zone. %s should be\n\tused to "
855 "begin configuring a new zone. If overwriting an "
856 "existing\n\tconfiguration, the -F flag can be "
857 "used to force the action. If\n\t-t template is "
858 "given, creates a configuration identical to the\n"
859 "\tspecified template, except that the zone name "
860 "is changed from\n\ttemplate to zonename. '%s -a' "
861 "creates a configuration from a\n\tdetached "
862 "zonepath. '%s -b' results in a blank "
863 "configuration.\n\t'%s' with no arguments applies "
864 "the Sun default settings."),
865 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE),
866 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE));
867 return (line);
868 case CMD_EXIT:
869 return (gettext("Exits the program. The -F flag can "
870 "be used to force the action."));
871 case CMD_EXPORT:
872 return (gettext("Prints configuration to standard "
873 "output, or to output-file if\n\tspecified, in "
874 "a form suitable for use in a command-file."));
875 case CMD_ADD:
876 return (gettext("Add specified resource to "
877 "configuration."));
878 case CMD_DELETE:
879 return (gettext("Deletes the specified zone. The -F "
880 "flag can be used to force the\n\taction."));
881 case CMD_REMOVE:
882 return (gettext("Remove specified resource from "
883 "configuration. The -F flag can be used\n\tto "
884 "force the action."));
885 case CMD_SELECT:
886 (void) snprintf(line, sizeof (line),
887 gettext("Selects a resource to modify. "
888 "Resource modification is completed\n\twith the "
889 "command \"%s\". The property name/value pairs "
890 "must uniquely\n\tidentify a resource. Note that "
891 "the curly braces ('{', '}') mean one\n\tor more "
892 "of whatever is between them."),
893 cmd_to_str(CMD_END));
894 return (line);
895 case CMD_SET:
896 return (gettext("Sets property values."));
897 case CMD_CLEAR:
898 return (gettext("Clears property values."));
899 case CMD_INFO:
900 return (gettext("Displays information about the "
901 "current configuration. If resource\n\ttype is "
902 "specified, displays only information about "
903 "resources of\n\tthe relevant type. If resource "
904 "id is specified, displays only\n\tinformation "
905 "about that resource."));
906 case CMD_VERIFY:
907 return (gettext("Verifies current configuration "
908 "for correctness (some resource types\n\thave "
909 "required properties)."));
910 case CMD_COMMIT:
911 (void) snprintf(line, sizeof (line),
912 gettext("Commits current configuration. "
913 "Configuration must be committed to\n\tbe used by "
914 "%s. Until the configuration is committed, "
915 "changes \n\tcan be removed with the %s "
916 "command. This operation is\n\tattempted "
917 "automatically upon completion of a %s "
918 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
919 "zonecfg");
920 return (line);
921 case CMD_REVERT:
922 return (gettext("Reverts configuration back to the "
923 "last committed state. The -F flag\n\tcan be "
924 "used to force the action."));
925 case CMD_CANCEL:
926 return (gettext("Cancels resource/property "
927 "specification."));
928 case CMD_END:
929 return (gettext("Ends resource/property "
930 "specification."));
932 /* NOTREACHED */
933 return (NULL);
937 * Return the input filename appended to each component of the path
938 * or the filename itself if it is absolute.
939 * Parameters: path string, file name, output string.
941 /* Copied almost verbatim from libtnfctl/prb_findexec.c */
942 static const char *
943 exec_cat(const char *s1, const char *s2, char *si)
945 char *s;
946 /* Number of remaining characters in s */
947 int cnt = PATH_MAX + 1;
949 s = si;
950 while (*s1 && *s1 != ':') { /* Copy first component of path to si */
951 if (cnt > 0) {
952 *s++ = *s1++;
953 cnt--;
954 } else {
955 s1++;
958 if (si != s && cnt > 0) { /* Add slash if s2 is not absolute */
959 *s++ = '/';
960 cnt--;
962 while (*s2 && cnt > 0) { /* Copy s2 to si */
963 *s++ = *s2++;
964 cnt--;
966 *s = '\0'; /* Terminate the output string */
967 return (*s1 ? ++s1 : NULL); /* Return next path component or NULL */
970 /* Determine that a name exists in PATH */
971 /* Copied with changes from libtnfctl/prb_findexec.c */
972 static int
973 path_find(const char *name)
975 const char *pathstr;
976 char fname[PATH_MAX + 2];
977 const char *cp;
978 struct stat stat_buf;
980 if ((pathstr = getenv("PATH")) == NULL) {
981 if (geteuid() == 0 || getuid() == 0)
982 pathstr = "/usr/sbin:/usr/bin";
983 else
984 pathstr = "/usr/bin:";
986 cp = strchr(name, '/') ? (const char *) "" : pathstr;
988 do {
989 cp = exec_cat(cp, name, fname);
990 if (stat(fname, &stat_buf) != -1) {
991 /* successful find of the file */
992 return (0);
994 } while (cp != NULL);
996 return (-1);
999 static FILE *
1000 pager_open(void)
1002 FILE *newfp;
1003 char *pager, *space;
1005 pager = getenv("PAGER");
1006 if (pager == NULL || *pager == '\0')
1007 pager = PAGER;
1009 space = strchr(pager, ' ');
1010 if (space)
1011 *space = '\0';
1012 if (path_find(pager) == 0) {
1013 if (space)
1014 *space = ' ';
1015 if ((newfp = popen(pager, "w")) == NULL)
1016 zerr(gettext("PAGER open failed (%s)."),
1017 strerror(errno));
1018 return (newfp);
1019 } else {
1020 zerr(gettext("PAGER %s does not exist (%s)."),
1021 pager, strerror(errno));
1023 return (NULL);
1026 static void
1027 pager_close(FILE *fp)
1029 int status;
1031 status = pclose(fp);
1032 if (status == -1)
1033 zerr(gettext("PAGER close failed (%s)."),
1034 strerror(errno));
1038 * Called with verbose TRUE when help is explicitly requested, FALSE for
1039 * unexpected errors.
1042 void
1043 usage(boolean_t verbose, uint_t flags)
1045 FILE *fp = verbose ? stdout : stderr;
1046 FILE *newfp;
1047 boolean_t need_to_close = B_FALSE;
1048 int i;
1050 /* don't page error output */
1051 if (verbose && interactive_mode) {
1052 if ((newfp = pager_open()) != NULL) {
1053 need_to_close = B_TRUE;
1054 fp = newfp;
1058 if (flags & HELP_META) {
1059 (void) fprintf(fp, gettext("More help is available for the "
1060 "following:\n"));
1061 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1062 cmd_to_str(CMD_HELP));
1063 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1064 cmd_to_str(CMD_HELP));
1065 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1066 cmd_to_str(CMD_HELP));
1067 (void) fprintf(fp, gettext("You may also obtain help on any "
1068 "command by typing '%s <command-name>.'\n"),
1069 cmd_to_str(CMD_HELP));
1071 if (flags & HELP_RES_SCOPE) {
1072 switch (resource_scope) {
1073 case RT_FS:
1074 (void) fprintf(fp, gettext("The '%s' resource scope is "
1075 "used to configure a file-system.\n"),
1076 rt_to_str(resource_scope));
1077 (void) fprintf(fp, gettext("Valid commands:\n"));
1078 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1079 pt_to_str(PT_DIR), gettext("<path>"));
1080 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1081 pt_to_str(PT_SPECIAL), gettext("<path>"));
1082 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1083 pt_to_str(PT_RAW), gettext("<raw-device>"));
1084 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1085 pt_to_str(PT_TYPE), gettext("<file-system type>"));
1086 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD),
1087 pt_to_str(PT_OPTIONS),
1088 gettext("<file-system options>"));
1089 (void) fprintf(fp, "\t%s %s %s\n",
1090 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS),
1091 gettext("<file-system options>"));
1092 (void) fprintf(fp, gettext("Consult the file-system "
1093 "specific manual page, such as mount_ufs(1M), "
1094 "for\ndetails about file-system options. Note "
1095 "that any file-system options with an\nembedded "
1096 "'=' character must be enclosed in double quotes, "
1097 /*CSTYLED*/
1098 "such as \"%s=5\".\n"), MNTOPT_RETRY);
1099 break;
1100 case RT_NET:
1101 (void) fprintf(fp, gettext("The '%s' resource scope is "
1102 "used to configure a network interface.\n"),
1103 rt_to_str(resource_scope));
1104 (void) fprintf(fp, gettext("Valid commands:\n"));
1105 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1106 pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
1107 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1108 pt_to_str(PT_ALLOWED_ADDRESS),
1109 gettext("<IP-address>"));
1110 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1111 pt_to_str(PT_PHYSICAL), gettext("<interface>"));
1112 (void) fprintf(fp, gettext("See ifconfig(1M) for "
1113 "details of the <interface> string.\n"));
1114 (void) fprintf(fp, gettext("%s %s is valid "
1115 "if the %s property is set to %s, otherwise it "
1116 "must not be set.\n"),
1117 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
1118 pt_to_str(PT_IPTYPE), gettext("shared"));
1119 (void) fprintf(fp, gettext("%s %s is valid "
1120 "if the %s property is set to %s, otherwise it "
1121 "must not be set.\n"),
1122 cmd_to_str(CMD_SET), pt_to_str(PT_ALLOWED_ADDRESS),
1123 pt_to_str(PT_IPTYPE), gettext("exclusive"));
1124 (void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
1125 "is valid if the %s or %s property is set, "
1126 "otherwise it must not be set\n"),
1127 cmd_to_str(CMD_SET),
1128 pt_to_str(PT_DEFROUTER), gettext("<IP-address>"),
1129 cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
1130 gettext(pt_to_str(PT_ADDRESS)),
1131 gettext(pt_to_str(PT_ALLOWED_ADDRESS)));
1132 break;
1133 case RT_DEVICE:
1134 (void) fprintf(fp, gettext("The '%s' resource scope is "
1135 "used to configure a device node.\n"),
1136 rt_to_str(resource_scope));
1137 (void) fprintf(fp, gettext("Valid commands:\n"));
1138 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1139 pt_to_str(PT_MATCH), gettext("<device-path>"));
1140 break;
1141 case RT_RCTL:
1142 (void) fprintf(fp, gettext("The '%s' resource scope is "
1143 "used to configure a resource control.\n"),
1144 rt_to_str(resource_scope));
1145 (void) fprintf(fp, gettext("Valid commands:\n"));
1146 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1147 pt_to_str(PT_NAME), gettext("<string>"));
1148 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1149 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
1150 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1151 pt_to_str(PT_LIMIT), gettext("<number>"),
1152 pt_to_str(PT_ACTION), gettext("<action-value>"));
1153 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n",
1154 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE),
1155 pt_to_str(PT_PRIV), gettext("<priv-value>"),
1156 pt_to_str(PT_LIMIT), gettext("<number>"),
1157 pt_to_str(PT_ACTION), gettext("<action-value>"));
1158 (void) fprintf(fp, "%s\n\t%s := privileged\n"
1159 "\t%s := none | deny\n", gettext("Where"),
1160 gettext("<priv-value>"), gettext("<action-value>"));
1161 break;
1162 case RT_ATTR:
1163 (void) fprintf(fp, gettext("The '%s' resource scope is "
1164 "used to configure a generic attribute.\n"),
1165 rt_to_str(resource_scope));
1166 (void) fprintf(fp, gettext("Valid commands:\n"));
1167 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1168 pt_to_str(PT_NAME), gettext("<name>"));
1169 (void) fprintf(fp, "\t%s %s=boolean\n",
1170 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1171 (void) fprintf(fp, "\t%s %s=true | false\n",
1172 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE));
1173 (void) fprintf(fp, gettext("or\n"));
1174 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET),
1175 pt_to_str(PT_TYPE));
1176 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1177 pt_to_str(PT_VALUE), gettext("<integer>"));
1178 (void) fprintf(fp, gettext("or\n"));
1179 (void) fprintf(fp, "\t%s %s=string\n",
1180 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1181 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1182 pt_to_str(PT_VALUE), gettext("<string>"));
1183 (void) fprintf(fp, gettext("or\n"));
1184 (void) fprintf(fp, "\t%s %s=uint\n",
1185 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE));
1186 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1187 pt_to_str(PT_VALUE), gettext("<unsigned integer>"));
1188 break;
1189 case RT_DATASET:
1190 (void) fprintf(fp, gettext("The '%s' resource scope is "
1191 "used to export ZFS datasets.\n"),
1192 rt_to_str(resource_scope));
1193 (void) fprintf(fp, gettext("Valid commands:\n"));
1194 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1195 pt_to_str(PT_NAME), gettext("<name>"));
1196 break;
1197 case RT_DCPU:
1198 (void) fprintf(fp, gettext("The '%s' resource scope "
1199 "configures the 'pools' facility to dedicate\na "
1200 "subset of the system's processors to this zone "
1201 "while it is running.\n"),
1202 rt_to_str(resource_scope));
1203 (void) fprintf(fp, gettext("Valid commands:\n"));
1204 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1205 pt_to_str(PT_NCPUS),
1206 gettext("<unsigned integer | range>"));
1207 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1208 pt_to_str(PT_IMPORTANCE),
1209 gettext("<unsigned integer>"));
1210 break;
1211 case RT_PCAP:
1212 (void) fprintf(fp, gettext("The '%s' resource scope is "
1213 "used to set an upper limit (a cap) on the\n"
1214 "percentage of CPU that can be used by this zone. "
1215 "A '%s' value of 1\ncorresponds to one cpu. The "
1216 "value can be set higher than 1, up to the total\n"
1217 "number of CPUs on the system. The value can "
1218 "also be less than 1,\nrepresenting a fraction of "
1219 "a cpu.\n"),
1220 rt_to_str(resource_scope), pt_to_str(PT_NCPUS));
1221 (void) fprintf(fp, gettext("Valid commands:\n"));
1222 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1223 pt_to_str(PT_NCPUS), gettext("<unsigned decimal>"));
1224 break;
1225 case RT_MCAP:
1226 (void) fprintf(fp, gettext("The '%s' resource scope is "
1227 "used to set an upper limit (a cap) on the\n"
1228 "amount of physical memory, swap space and locked "
1229 "memory that can be used by\nthis zone.\n"),
1230 rt_to_str(resource_scope));
1231 (void) fprintf(fp, gettext("Valid commands:\n"));
1232 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1233 pt_to_str(PT_PHYSICAL),
1234 gettext("<qualified unsigned decimal>"));
1235 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1236 pt_to_str(PT_SWAP),
1237 gettext("<qualified unsigned decimal>"));
1238 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1239 pt_to_str(PT_LOCKED),
1240 gettext("<qualified unsigned decimal>"));
1241 break;
1242 case RT_ADMIN:
1243 (void) fprintf(fp, gettext("The '%s' resource scope is "
1244 "used to delegate specific zone management\n"
1245 "rights to users and roles. These rights are "
1246 "only applicable to this zone.\n"),
1247 rt_to_str(resource_scope));
1248 (void) fprintf(fp, gettext("Valid commands:\n"));
1249 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1250 pt_to_str(PT_USER),
1251 gettext("<single user or role name>"));
1252 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
1253 pt_to_str(PT_AUTHS),
1254 gettext("<comma separated list>"));
1255 break;
1256 case RT_SECFLAGS:
1257 (void) fprintf(fp, gettext("The '%s' resource scope is "
1258 "used to specify the default security-flags\n"
1259 "of this zone, and their upper and lower bound.\n"),
1260 rt_to_str(resource_scope));
1261 (void) fprintf(fp, "\t%s %s=%s\n",
1262 cmd_to_str(CMD_SET), pt_to_str(PT_DEFAULT),
1263 gettext("<security flags>"));
1264 (void) fprintf(fp, "\t%s %s=%s\n",
1265 cmd_to_str(CMD_SET), pt_to_str(PT_LOWER),
1266 gettext("<security flags>"));
1267 (void) fprintf(fp, "\t%s %s=%s\n",
1268 cmd_to_str(CMD_SET), pt_to_str(PT_UPPER),
1269 gettext("<security flags>"));
1270 break;
1272 (void) fprintf(fp, gettext("And from any resource scope, you "
1273 "can:\n"));
1274 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END),
1275 gettext("(to conclude this operation)"));
1276 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL),
1277 gettext("(to cancel this operation)"));
1278 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT),
1279 gettext("(to exit the zonecfg utility)"));
1281 if (flags & HELP_USAGE) {
1282 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
1283 execname, cmd_to_str(CMD_HELP));
1284 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
1285 execname, gettext("interactive"));
1286 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
1287 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
1288 execname);
1290 if (flags & HELP_SUBCMDS) {
1291 (void) fprintf(fp, "%s:\n\n", gettext("Commands"));
1292 for (i = 0; i <= CMD_MAX; i++) {
1293 (void) fprintf(fp, "%s\n", helptab[i].short_usage);
1294 if (verbose)
1295 (void) fprintf(fp, "\t%s\n\n", long_help(i));
1298 if (flags & HELP_SYNTAX) {
1299 if (!verbose)
1300 (void) fprintf(fp, "\n");
1301 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n");
1302 (void) fprintf(fp, gettext("\t(except the reserved words "
1303 "'%s' and anything starting with '%s')\n"), "global",
1304 "SUNW");
1305 (void) fprintf(fp,
1306 gettext("\tName must be less than %d characters.\n"),
1307 ZONENAME_MAX);
1308 if (verbose)
1309 (void) fprintf(fp, "\n");
1311 if (flags & HELP_NETADDR) {
1312 (void) fprintf(fp, gettext("\n<net-addr> :="));
1313 (void) fprintf(fp,
1314 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
1315 (void) fprintf(fp,
1316 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
1317 (void) fprintf(fp,
1318 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
1319 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and "
1320 "IPv6 address syntax.\n"));
1321 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n"));
1322 (void) fprintf(fp,
1323 gettext("<IPv6-prefix-length> := [0-128]\n"));
1324 (void) fprintf(fp,
1325 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
1327 if (flags & HELP_RESOURCES) {
1328 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s |\n\t"
1329 "%s | %s | %s | %s | %s\n\n",
1330 gettext("resource type"), rt_to_str(RT_FS),
1331 rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
1332 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
1333 rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
1334 rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
1335 rt_to_str(RT_ADMIN), rt_to_str(RT_SECFLAGS));
1337 if (flags & HELP_PROPS) {
1338 (void) fprintf(fp, gettext("For resource type ... there are "
1339 "property types ...:\n"));
1340 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1341 pt_to_str(PT_ZONENAME));
1342 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1343 pt_to_str(PT_ZONEPATH));
1344 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1345 pt_to_str(PT_BRAND));
1346 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1347 pt_to_str(PT_AUTOBOOT));
1348 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1349 pt_to_str(PT_BOOTARGS));
1350 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1351 pt_to_str(PT_POOL));
1352 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1353 pt_to_str(PT_LIMITPRIV));
1354 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1355 pt_to_str(PT_SCHED));
1356 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1357 pt_to_str(PT_IPTYPE));
1358 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1359 pt_to_str(PT_HOSTID));
1360 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1361 pt_to_str(PT_FS_ALLOWED));
1362 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1363 pt_to_str(PT_MAXLWPS));
1364 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1365 pt_to_str(PT_MAXPROCS));
1366 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1367 pt_to_str(PT_MAXSHMMEM));
1368 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1369 pt_to_str(PT_MAXSHMIDS));
1370 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1371 pt_to_str(PT_MAXMSGIDS));
1372 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1373 pt_to_str(PT_MAXSEMIDS));
1374 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
1375 pt_to_str(PT_SHARES));
1376 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
1377 rt_to_str(RT_FS), pt_to_str(PT_DIR),
1378 pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
1379 pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
1380 (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
1381 pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
1382 pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
1383 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1384 pt_to_str(PT_MATCH));
1385 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1386 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1387 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1388 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1389 pt_to_str(PT_VALUE));
1390 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1391 pt_to_str(PT_NAME));
1392 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1393 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1394 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1395 pt_to_str(PT_NCPUS));
1396 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1397 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1398 pt_to_str(PT_LOCKED));
1399 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1400 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1401 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n",
1402 rt_to_str(RT_SECFLAGS), pt_to_str(PT_DEFAULT),
1403 pt_to_str(PT_LOWER), pt_to_str(PT_UPPER));
1405 if (need_to_close)
1406 (void) pager_close(fp);
1409 static void
1410 zone_perror(char *prefix, int err, boolean_t set_saw)
1412 zerr("%s: %s", prefix, zonecfg_strerror(err));
1413 if (set_saw)
1414 saw_error = B_TRUE;
1418 * zone_perror() expects a single string, but for remove and select
1419 * we have both the command and the resource type, so this wrapper
1420 * function serves the same purpose in a slightly different way.
1423 static void
1424 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1426 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
1427 zonecfg_strerror(err));
1428 if (set_saw)
1429 saw_error = B_TRUE;
1432 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
1433 static int
1434 initialize(boolean_t handle_expected)
1436 int err;
1437 char brandname[MAXNAMELEN];
1439 if (zonecfg_check_handle(handle) != Z_OK) {
1440 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
1441 got_handle = B_TRUE;
1442 if (zonecfg_get_brand(handle, brandname,
1443 sizeof (brandname)) != Z_OK) {
1444 zerr("Zone %s is inconsistent: missing "
1445 "brand attribute", zone);
1446 exit(Z_ERR);
1448 if ((brand = brand_open(brandname)) == NULL) {
1449 zerr("Zone %s uses non-existent brand \"%s\"."
1450 " Unable to continue", zone, brandname);
1451 exit(Z_ERR);
1454 * If the user_attr file is newer than
1455 * the zone config file, the admins
1456 * may need to be updated since the
1457 * RBAC files are authoritative for
1458 * authorization checks.
1460 err = zonecfg_update_userauths(handle, zone);
1461 if (err == Z_OK) {
1462 zerr(gettext("The administrative rights "
1463 "were updated to match "
1464 "the current RBAC configuration.\n"
1465 "Use \"info admin\" and \"revert\" to "
1466 "compare with the previous settings."));
1467 need_to_commit = B_TRUE;
1468 } else if (err != Z_NO_ENTRY) {
1469 zerr(gettext("failed to update "
1470 "admin rights."));
1471 exit(Z_ERR);
1472 } else if (need_to_commit) {
1473 zerr(gettext("admin rights were updated "
1474 "to match RBAC configuration."));
1477 } else if (global_zone && err == Z_NO_ZONE && !got_handle &&
1478 !read_only_mode) {
1480 * We implicitly create the global zone config if it
1481 * doesn't exist.
1483 zone_dochandle_t tmphandle;
1485 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1486 zone_perror(execname, Z_NOMEM, B_TRUE);
1487 exit(Z_ERR);
1490 err = zonecfg_get_template_handle("SUNWblank", zone,
1491 tmphandle);
1493 if (err != Z_OK) {
1494 zonecfg_fini_handle(tmphandle);
1495 zone_perror("SUNWblank", err, B_TRUE);
1496 return (err);
1499 need_to_commit = B_TRUE;
1500 zonecfg_fini_handle(handle);
1501 handle = tmphandle;
1502 got_handle = B_TRUE;
1504 } else {
1505 zone_perror(zone, err, handle_expected || got_handle);
1506 if (err == Z_NO_ZONE && !got_handle &&
1507 interactive_mode && !read_only_mode)
1508 (void) printf(gettext("Use '%s' to begin "
1509 "configuring a new zone.\n"),
1510 cmd_to_str(CMD_CREATE));
1511 return (err);
1514 return (Z_OK);
1517 static boolean_t
1518 state_atleast(zone_state_t state)
1520 zone_state_t state_num;
1521 int err;
1523 if ((err = zone_get_state(zone, &state_num)) != Z_OK) {
1524 /* all states are greater than "non-existent" */
1525 if (err == Z_NO_ZONE)
1526 return (B_FALSE);
1527 zerr(gettext("Unexpectedly failed to determine state "
1528 "of zone %s: %s"), zone, zonecfg_strerror(err));
1529 exit(Z_ERR);
1531 return (state_num >= state);
1535 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
1538 void
1539 short_usage(int command)
1541 /* lex_lineno has already been incremented in the lexer; compensate */
1542 if (cmd_file_mode) {
1543 if (strcmp(cmd_file_name, "-") == 0)
1544 (void) fprintf(stderr,
1545 gettext("syntax error on line %d\n"),
1546 lex_lineno - 1);
1547 else
1548 (void) fprintf(stderr,
1549 gettext("syntax error on line %d of %s\n"),
1550 lex_lineno - 1, cmd_file_name);
1552 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"),
1553 helptab[command].short_usage);
1554 saw_error = B_TRUE;
1558 * long_usage() is for bad semantics: e.g., wrong property type for a given
1559 * resource type. It is also used by longer_usage() below.
1562 void
1563 long_usage(uint_t cmd_num, boolean_t set_saw)
1565 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"),
1566 helptab[cmd_num].short_usage);
1567 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num));
1568 if (set_saw)
1569 saw_error = B_TRUE;
1573 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
1574 * any extra usage() flags as appropriate for whatever command.
1577 void
1578 longer_usage(uint_t cmd_num)
1580 long_usage(cmd_num, B_FALSE);
1581 if (helptab[cmd_num].flags != 0) {
1582 (void) printf("\n");
1583 usage(B_TRUE, helptab[cmd_num].flags);
1588 * scope_usage() is simply used when a command is called from the wrong scope.
1591 static void
1592 scope_usage(uint_t cmd_num)
1594 zerr(gettext("The %s command only makes sense in the %s scope."),
1595 cmd_to_str(cmd_num),
1596 global_scope ? gettext("resource") : gettext("global"));
1597 saw_error = B_TRUE;
1601 * On input, B_TRUE => yes, B_FALSE => no.
1602 * On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
1605 static int
1606 ask_yesno(boolean_t default_answer, const char *question)
1608 char line[64]; /* should be enough to answer yes or no */
1610 if (!ok_to_prompt) {
1611 saw_error = B_TRUE;
1612 return (-1);
1614 for (;;) {
1615 if (printf("%s (%s)? ", question,
1616 default_answer ? "[y]/n" : "y/[n]") < 0)
1617 return (-1);
1618 if (fgets(line, sizeof (line), stdin) == NULL)
1619 return (-1);
1621 if (line[0] == '\n')
1622 return (default_answer ? 1 : 0);
1623 if (tolower(line[0]) == 'y')
1624 return (1);
1625 if (tolower(line[0]) == 'n')
1626 return (0);
1631 * Prints warning if zone already exists.
1632 * In interactive mode, prompts if we should continue anyway and returns Z_OK
1633 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR.
1635 * Note that if a zone exists and its state is >= INSTALLED, an error message
1636 * will be printed and this function will return Z_ERR regardless of mode.
1639 static int
1640 check_if_zone_already_exists(boolean_t force)
1642 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
1643 zone_dochandle_t tmphandle;
1644 int res, answer;
1646 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1647 zone_perror(execname, Z_NOMEM, B_TRUE);
1648 exit(Z_ERR);
1650 res = zonecfg_get_handle(zone, tmphandle);
1651 zonecfg_fini_handle(tmphandle);
1652 if (res != Z_OK)
1653 return (Z_OK);
1655 if (state_atleast(ZONE_STATE_INSTALLED)) {
1656 zerr(gettext("Zone %s already installed; %s not allowed."),
1657 zone, cmd_to_str(CMD_CREATE));
1658 return (Z_ERR);
1661 if (force) {
1662 (void) printf(gettext("Zone %s already exists; overwriting.\n"),
1663 zone);
1664 return (Z_OK);
1666 (void) snprintf(line, sizeof (line),
1667 gettext("Zone %s already exists; %s anyway"), zone,
1668 cmd_to_str(CMD_CREATE));
1669 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
1670 zerr(gettext("Zone exists, input not from terminal and -F not "
1671 "specified:\n%s command ignored, exiting."),
1672 cmd_to_str(CMD_CREATE));
1673 exit(Z_ERR);
1675 return (answer == 1 ? Z_OK : Z_ERR);
1678 static boolean_t
1679 zone_is_read_only(int cmd_num)
1681 if (strncmp(zone, "SUNW", 4) == 0) {
1682 zerr(gettext("%s: zones beginning with SUNW are read-only."),
1683 zone);
1684 saw_error = B_TRUE;
1685 return (B_TRUE);
1687 if (read_only_mode) {
1688 zerr(gettext("%s: cannot %s in read-only mode."), zone,
1689 cmd_to_str(cmd_num));
1690 saw_error = B_TRUE;
1691 return (B_TRUE);
1693 return (B_FALSE);
1697 * Create a new configuration.
1699 void
1700 create_func(cmd_t *cmd)
1702 int err, arg;
1703 char zone_template[ZONENAME_MAX];
1704 char attach_path[MAXPATHLEN];
1705 zone_dochandle_t tmphandle;
1706 boolean_t force = B_FALSE;
1707 boolean_t attach = B_FALSE;
1708 boolean_t arg_err = B_FALSE;
1710 assert(cmd != NULL);
1712 /* This is the default if no arguments are given. */
1713 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
1715 optind = 0;
1716 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
1717 != EOF) {
1718 switch (arg) {
1719 case '?':
1720 if (optopt == '?')
1721 longer_usage(CMD_CREATE);
1722 else
1723 short_usage(CMD_CREATE);
1724 arg_err = B_TRUE;
1725 break;
1726 case 'a':
1727 (void) strlcpy(attach_path, optarg,
1728 sizeof (attach_path));
1729 attach = B_TRUE;
1730 break;
1731 case 'b':
1732 (void) strlcpy(zone_template, "SUNWblank",
1733 sizeof (zone_template));
1734 break;
1735 case 'F':
1736 force = B_TRUE;
1737 break;
1738 case 't':
1739 (void) strlcpy(zone_template, optarg,
1740 sizeof (zone_template));
1741 break;
1742 default:
1743 short_usage(CMD_CREATE);
1744 arg_err = B_TRUE;
1745 break;
1748 if (arg_err)
1749 return;
1751 if (optind != cmd->cmd_argc) {
1752 short_usage(CMD_CREATE);
1753 return;
1756 if (zone_is_read_only(CMD_CREATE))
1757 return;
1759 if (check_if_zone_already_exists(force) != Z_OK)
1760 return;
1763 * Get a temporary handle first. If that fails, the old handle
1764 * will not be lost. Then finish whichever one we don't need,
1765 * to avoid leaks. Then get the handle for zone_template, and
1766 * set the name to zone: this "copy, rename" method is how
1767 * create -[b|t] works.
1769 if ((tmphandle = zonecfg_init_handle()) == NULL) {
1770 zone_perror(execname, Z_NOMEM, B_TRUE);
1771 exit(Z_ERR);
1774 if (attach)
1775 err = zonecfg_get_attach_handle(attach_path, ZONE_DETACHED,
1776 zone, B_FALSE, tmphandle);
1777 else
1778 err = zonecfg_get_template_handle(zone_template, zone,
1779 tmphandle);
1781 if (err != Z_OK) {
1782 zonecfg_fini_handle(tmphandle);
1783 if (attach && err == Z_NO_ZONE)
1784 (void) fprintf(stderr, gettext("invalid path to "
1785 "detached zone\n"));
1786 else if (attach && err == Z_INVALID_DOCUMENT)
1787 (void) fprintf(stderr, gettext("Cannot attach to an "
1788 "earlier release of the operating system\n"));
1789 else
1790 zone_perror(zone_template, err, B_TRUE);
1791 return;
1794 need_to_commit = B_TRUE;
1795 zonecfg_fini_handle(handle);
1796 handle = tmphandle;
1797 got_handle = B_TRUE;
1801 * This malloc()'s memory, which must be freed by the caller.
1803 static char *
1804 quoteit(char *instr)
1806 char *outstr;
1807 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */
1809 if ((outstr = malloc(outstrsize)) == NULL) {
1810 zone_perror(zone, Z_NOMEM, B_FALSE);
1811 exit(Z_ERR);
1813 if (strchr(instr, ' ') == NULL) {
1814 (void) strlcpy(outstr, instr, outstrsize);
1815 return (outstr);
1817 (void) snprintf(outstr, outstrsize, "\"%s\"", instr);
1818 return (outstr);
1821 static void
1822 export_prop(FILE *of, int prop_num, char *prop_id)
1824 char *quote_str;
1826 if (strlen(prop_id) == 0)
1827 return;
1828 quote_str = quoteit(prop_id);
1829 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1830 pt_to_str(prop_num), quote_str);
1831 free(quote_str);
1834 void
1835 export_func(cmd_t *cmd)
1837 struct zone_nwiftab nwiftab;
1838 struct zone_fstab fstab;
1839 struct zone_devtab devtab;
1840 struct zone_attrtab attrtab;
1841 struct zone_rctltab rctltab;
1842 struct zone_dstab dstab;
1843 struct zone_psettab psettab;
1844 struct zone_mcaptab mcaptab;
1845 struct zone_rctlvaltab *valptr;
1846 struct zone_admintab admintab;
1847 struct zone_secflagstab secflagstab;
1848 int err, arg;
1849 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
1850 char bootargs[BOOTARGS_MAX];
1851 char sched[MAXNAMELEN];
1852 char brand[MAXNAMELEN];
1853 char hostidp[HW_HOSTID_LEN];
1854 char fsallowedp[ZONE_FS_ALLOWED_MAX];
1855 char *limitpriv;
1856 FILE *of;
1857 boolean_t autoboot;
1858 zone_iptype_t iptype;
1859 boolean_t need_to_close = B_FALSE;
1860 boolean_t arg_err = B_FALSE;
1862 assert(cmd != NULL);
1864 outfile[0] = '\0';
1865 optind = 0;
1866 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) {
1867 switch (arg) {
1868 case '?':
1869 if (optopt == '?')
1870 longer_usage(CMD_EXPORT);
1871 else
1872 short_usage(CMD_EXPORT);
1873 arg_err = B_TRUE;
1874 break;
1875 case 'f':
1876 (void) strlcpy(outfile, optarg, sizeof (outfile));
1877 break;
1878 default:
1879 short_usage(CMD_EXPORT);
1880 arg_err = B_TRUE;
1881 break;
1884 if (arg_err)
1885 return;
1887 if (optind != cmd->cmd_argc) {
1888 short_usage(CMD_EXPORT);
1889 return;
1891 if (strlen(outfile) == 0) {
1892 of = stdout;
1893 } else {
1894 if ((of = fopen(outfile, "w")) == NULL) {
1895 zerr(gettext("opening file %s: %s"),
1896 outfile, strerror(errno));
1897 goto done;
1899 setbuf(of, NULL);
1900 need_to_close = B_TRUE;
1903 if ((err = initialize(B_TRUE)) != Z_OK)
1904 goto done;
1906 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE));
1908 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK &&
1909 strlen(zonepath) > 0)
1910 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1911 pt_to_str(PT_ZONEPATH), zonepath);
1913 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) &&
1914 (strcmp(brand, NATIVE_BRAND_NAME) != 0))
1915 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1916 pt_to_str(PT_BRAND), brand);
1918 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK)
1919 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1920 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false");
1922 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK &&
1923 strlen(bootargs) > 0) {
1924 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1925 pt_to_str(PT_BOOTARGS), bootargs);
1928 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
1929 strlen(pool) > 0)
1930 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1931 pt_to_str(PT_POOL), pool);
1933 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK &&
1934 strlen(limitpriv) > 0) {
1935 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1936 pt_to_str(PT_LIMITPRIV), limitpriv);
1937 free(limitpriv);
1940 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
1941 strlen(sched) > 0)
1942 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1943 pt_to_str(PT_SCHED), sched);
1945 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
1946 switch (iptype) {
1947 case ZS_SHARED:
1948 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1949 pt_to_str(PT_IPTYPE), "shared");
1950 break;
1951 case ZS_EXCLUSIVE:
1952 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1953 pt_to_str(PT_IPTYPE), "exclusive");
1954 break;
1958 if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
1959 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1960 pt_to_str(PT_HOSTID), hostidp);
1963 if (zonecfg_get_fs_allowed(handle, fsallowedp,
1964 sizeof (fsallowedp)) == Z_OK) {
1965 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
1966 pt_to_str(PT_FS_ALLOWED), fsallowedp);
1969 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
1970 zone_perror(zone, err, B_FALSE);
1971 goto done;
1973 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
1974 zone_fsopt_t *optptr;
1976 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
1977 rt_to_str(RT_FS));
1978 export_prop(of, PT_DIR, fstab.zone_fs_dir);
1979 export_prop(of, PT_SPECIAL, fstab.zone_fs_special);
1980 export_prop(of, PT_RAW, fstab.zone_fs_raw);
1981 export_prop(of, PT_TYPE, fstab.zone_fs_type);
1982 for (optptr = fstab.zone_fs_options; optptr != NULL;
1983 optptr = optptr->zone_fsopt_next) {
1985 * Simple property values with embedded equal signs
1986 * need to be quoted to prevent the lexer from
1987 * mis-parsing them as complex name=value pairs.
1989 if (strchr(optptr->zone_fsopt_opt, '='))
1990 (void) fprintf(of, "%s %s \"%s\"\n",
1991 cmd_to_str(CMD_ADD),
1992 pt_to_str(PT_OPTIONS),
1993 optptr->zone_fsopt_opt);
1994 else
1995 (void) fprintf(of, "%s %s %s\n",
1996 cmd_to_str(CMD_ADD),
1997 pt_to_str(PT_OPTIONS),
1998 optptr->zone_fsopt_opt);
2000 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2001 zonecfg_free_fs_option_list(fstab.zone_fs_options);
2003 (void) zonecfg_endfsent(handle);
2005 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2006 zone_perror(zone, err, B_FALSE);
2007 goto done;
2009 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2010 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2011 rt_to_str(RT_NET));
2012 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
2013 export_prop(of, PT_ALLOWED_ADDRESS,
2014 nwiftab.zone_nwif_allowed_address);
2015 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
2016 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
2017 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2019 (void) zonecfg_endnwifent(handle);
2021 if ((err = zonecfg_setdevent(handle)) != Z_OK) {
2022 zone_perror(zone, err, B_FALSE);
2023 goto done;
2025 while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
2026 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2027 rt_to_str(RT_DEVICE));
2028 export_prop(of, PT_MATCH, devtab.zone_dev_match);
2029 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2031 (void) zonecfg_enddevent(handle);
2033 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
2034 char buf[128];
2036 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2037 rt_to_str(RT_MCAP));
2038 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
2039 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2040 pt_to_str(PT_PHYSICAL), buf);
2041 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2044 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
2045 zone_perror(zone, err, B_FALSE);
2046 goto done;
2048 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
2049 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD));
2050 export_prop(of, PT_NAME, rctltab.zone_rctl_name);
2051 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL;
2052 valptr = valptr->zone_rctlval_next) {
2053 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n",
2054 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE),
2055 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
2056 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
2057 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
2059 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2060 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2062 (void) zonecfg_endrctlent(handle);
2064 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
2065 zone_perror(zone, err, B_FALSE);
2066 goto done;
2068 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
2069 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2070 rt_to_str(RT_ATTR));
2071 export_prop(of, PT_NAME, attrtab.zone_attr_name);
2072 export_prop(of, PT_TYPE, attrtab.zone_attr_type);
2073 export_prop(of, PT_VALUE, attrtab.zone_attr_value);
2074 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2076 (void) zonecfg_endattrent(handle);
2078 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
2079 zone_perror(zone, err, B_FALSE);
2080 goto done;
2082 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
2083 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2084 rt_to_str(RT_DATASET));
2085 export_prop(of, PT_NAME, dstab.zone_dataset_name);
2086 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2088 (void) zonecfg_enddsent(handle);
2090 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) {
2091 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2092 rt_to_str(RT_DCPU));
2093 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0)
2094 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2095 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max);
2096 else
2097 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET),
2098 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min,
2099 psettab.zone_ncpu_max);
2100 if (psettab.zone_importance[0] != '\0')
2101 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
2102 pt_to_str(PT_IMPORTANCE), psettab.zone_importance);
2103 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2106 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
2107 zone_perror(zone, err, B_FALSE);
2108 goto done;
2110 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
2111 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2112 rt_to_str(RT_ADMIN));
2113 export_prop(of, PT_USER, admintab.zone_admin_user);
2114 export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
2115 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2118 (void) zonecfg_endadminent(handle);
2120 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
2121 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2122 rt_to_str(RT_SECFLAGS));
2123 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
2124 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
2125 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
2126 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2130 * There is nothing to export for pcap since this resource is just
2131 * a container for an rctl alias.
2134 done:
2135 if (need_to_close)
2136 (void) fclose(of);
2139 void
2140 exit_func(cmd_t *cmd)
2142 int arg, answer;
2143 boolean_t arg_err = B_FALSE;
2145 optind = 0;
2146 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2147 switch (arg) {
2148 case '?':
2149 longer_usage(CMD_EXIT);
2150 arg_err = B_TRUE;
2151 break;
2152 case 'F':
2153 force_exit = B_TRUE;
2154 break;
2155 default:
2156 short_usage(CMD_EXIT);
2157 arg_err = B_TRUE;
2158 break;
2161 if (arg_err)
2162 return;
2164 if (optind < cmd->cmd_argc) {
2165 short_usage(CMD_EXIT);
2166 return;
2169 if (global_scope || force_exit) {
2170 time_to_exit = B_TRUE;
2171 return;
2174 answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2175 if (answer == -1) {
2176 zerr(gettext("Resource incomplete, input "
2177 "not from terminal and -F not specified:\n%s command "
2178 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2179 exit(Z_ERR);
2180 } else if (answer == 1) {
2181 time_to_exit = B_TRUE;
2183 /* (answer == 0) => just return */
2186 static int
2187 validate_zonepath_syntax(char *path)
2189 if (path[0] != '/') {
2190 zerr(gettext("%s is not an absolute path."), path);
2191 return (Z_ERR);
2193 /* If path is all slashes, then fail */
2194 if (strspn(path, "/") == strlen(path)) {
2195 zerr(gettext("/ is not allowed as a %s."),
2196 pt_to_str(PT_ZONEPATH));
2197 return (Z_ERR);
2199 return (Z_OK);
2202 static void
2203 add_resource(cmd_t *cmd)
2205 int type;
2206 struct zone_psettab tmp_psettab;
2207 struct zone_mcaptab tmp_mcaptab;
2208 struct zone_secflagstab tmp_secflagstab;
2209 uint64_t tmp;
2210 uint64_t tmp_mcap;
2211 char pool[MAXNAMELEN];
2213 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2214 long_usage(CMD_ADD, B_TRUE);
2215 goto bad;
2218 switch (type) {
2219 case RT_FS:
2220 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2221 return;
2222 case RT_NET:
2223 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2224 return;
2225 case RT_DEVICE:
2226 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2227 return;
2228 case RT_RCTL:
2229 if (global_zone)
2230 zerr(gettext("WARNING: Setting a global zone resource "
2231 "control too low could deny\nservice "
2232 "to even the root user; "
2233 "this could render the system impossible\n"
2234 "to administer. Please use caution."));
2235 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2236 return;
2237 case RT_ATTR:
2238 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2239 return;
2240 case RT_DATASET:
2241 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2242 return;
2243 case RT_DCPU:
2244 /* Make sure there isn't already a cpu-set or cpu-cap entry. */
2245 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2246 zerr(gettext("The %s resource already exists."),
2247 rt_to_str(RT_DCPU));
2248 goto bad;
2250 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2251 Z_NO_ENTRY) {
2252 zerr(gettext("The %s resource already exists."),
2253 rt_to_str(RT_PCAP));
2254 goto bad;
2257 /* Make sure the pool property isn't set. */
2258 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2259 strlen(pool) > 0) {
2260 zerr(gettext("The %s property is already set. "
2261 "A persistent pool is incompatible with\nthe %s "
2262 "resource."),
2263 pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2264 goto bad;
2267 bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2268 return;
2269 case RT_PCAP:
2271 * Make sure there isn't already a cpu-set or incompatible
2272 * cpu-cap rctls.
2274 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2275 zerr(gettext("The %s resource already exists."),
2276 rt_to_str(RT_DCPU));
2277 goto bad;
2280 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2281 case Z_ALIAS_DISALLOW:
2282 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2283 B_FALSE);
2284 goto bad;
2286 case Z_OK:
2287 zerr(gettext("The %s resource already exists."),
2288 rt_to_str(RT_PCAP));
2289 goto bad;
2291 default:
2292 break;
2294 return;
2295 case RT_MCAP:
2297 * Make sure there isn't already a mem-cap entry or max-swap
2298 * or max-locked rctl.
2300 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2301 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2302 == Z_OK ||
2303 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2304 &tmp_mcap) == Z_OK) {
2305 zerr(gettext("The %s resource or a related resource "
2306 "control already exists."), rt_to_str(RT_MCAP));
2307 goto bad;
2309 if (global_zone)
2310 zerr(gettext("WARNING: Setting a global zone memory "
2311 "cap too low could deny\nservice "
2312 "to even the root user; "
2313 "this could render the system impossible\n"
2314 "to administer. Please use caution."));
2315 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2316 return;
2317 case RT_ADMIN:
2318 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2319 return;
2320 case RT_SECFLAGS:
2321 /* Make sure we haven't already set this */
2322 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
2323 zerr(gettext("The %s resource already exists."),
2324 rt_to_str(RT_SECFLAGS));
2325 bzero(&in_progress_secflagstab,
2326 sizeof (in_progress_secflagstab));
2327 return;
2328 default:
2329 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2330 long_usage(CMD_ADD, B_TRUE);
2331 usage(B_FALSE, HELP_RESOURCES);
2333 bad:
2334 global_scope = B_TRUE;
2335 end_op = -1;
2338 static void
2339 do_complex_rctl_val(complex_property_ptr_t cp)
2341 struct zone_rctlvaltab *rctlvaltab;
2342 complex_property_ptr_t cx;
2343 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2344 seen_action = B_FALSE;
2345 rctlblk_t *rctlblk;
2346 int err;
2348 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2349 zone_perror(zone, Z_NOMEM, B_TRUE);
2350 exit(Z_ERR);
2352 for (cx = cp; cx != NULL; cx = cx->cp_next) {
2353 switch (cx->cp_type) {
2354 case PT_PRIV:
2355 if (seen_priv) {
2356 zerr(gettext("%s already specified"),
2357 pt_to_str(PT_PRIV));
2358 goto bad;
2360 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
2361 cx->cp_value,
2362 sizeof (rctlvaltab->zone_rctlval_priv));
2363 seen_priv = B_TRUE;
2364 break;
2365 case PT_LIMIT:
2366 if (seen_limit) {
2367 zerr(gettext("%s already specified"),
2368 pt_to_str(PT_LIMIT));
2369 goto bad;
2371 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
2372 cx->cp_value,
2373 sizeof (rctlvaltab->zone_rctlval_limit));
2374 seen_limit = B_TRUE;
2375 break;
2376 case PT_ACTION:
2377 if (seen_action) {
2378 zerr(gettext("%s already specified"),
2379 pt_to_str(PT_ACTION));
2380 goto bad;
2382 (void) strlcpy(rctlvaltab->zone_rctlval_action,
2383 cx->cp_value,
2384 sizeof (rctlvaltab->zone_rctlval_action));
2385 seen_action = B_TRUE;
2386 break;
2387 default:
2388 zone_perror(pt_to_str(PT_VALUE),
2389 Z_NO_PROPERTY_TYPE, B_TRUE);
2390 long_usage(CMD_ADD, B_TRUE);
2391 usage(B_FALSE, HELP_PROPS);
2392 zonecfg_free_rctl_value_list(rctlvaltab);
2393 return;
2396 if (!seen_priv)
2397 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2398 if (!seen_limit)
2399 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2400 if (!seen_action)
2401 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2402 if (!seen_priv || !seen_limit || !seen_action)
2403 goto bad;
2404 rctlvaltab->zone_rctlval_next = NULL;
2405 rctlblk = alloca(rctlblk_size());
2407 * Make sure the rctl value looks roughly correct; we won't know if
2408 * it's truly OK until we verify the configuration on the target
2409 * system.
2411 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2412 !zonecfg_valid_rctlblk(rctlblk)) {
2413 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2414 pt_to_str(PT_VALUE));
2415 goto bad;
2417 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2418 if (err != Z_OK)
2419 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2420 return;
2422 bad:
2423 zonecfg_free_rctl_value_list(rctlvaltab);
2426 static void
2427 add_property(cmd_t *cmd)
2429 char *prop_id;
2430 int err, res_type, prop_type;
2431 property_value_ptr_t pp;
2432 list_property_ptr_t l;
2434 res_type = resource_scope;
2435 prop_type = cmd->cmd_prop_name[0];
2436 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2437 long_usage(CMD_ADD, B_TRUE);
2438 return;
2441 if (cmd->cmd_prop_nv_pairs != 1) {
2442 long_usage(CMD_ADD, B_TRUE);
2443 return;
2446 if (initialize(B_TRUE) != Z_OK)
2447 return;
2449 switch (res_type) {
2450 case RT_FS:
2451 if (prop_type != PT_OPTIONS) {
2452 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2453 B_TRUE);
2454 long_usage(CMD_ADD, B_TRUE);
2455 usage(B_FALSE, HELP_PROPS);
2456 return;
2458 pp = cmd->cmd_property_ptr[0];
2459 if (pp->pv_type != PROP_VAL_SIMPLE &&
2460 pp->pv_type != PROP_VAL_LIST) {
2461 zerr(gettext("A %s or %s value was expected here."),
2462 pvt_to_str(PROP_VAL_SIMPLE),
2463 pvt_to_str(PROP_VAL_LIST));
2464 saw_error = B_TRUE;
2465 return;
2467 if (pp->pv_type == PROP_VAL_SIMPLE) {
2468 if (pp->pv_simple == NULL) {
2469 long_usage(CMD_ADD, B_TRUE);
2470 return;
2472 prop_id = pp->pv_simple;
2473 err = zonecfg_add_fs_option(&in_progress_fstab,
2474 prop_id);
2475 if (err != Z_OK)
2476 zone_perror(pt_to_str(prop_type), err, B_TRUE);
2477 } else {
2478 list_property_ptr_t list;
2480 for (list = pp->pv_list; list != NULL;
2481 list = list->lp_next) {
2482 prop_id = list->lp_simple;
2483 if (prop_id == NULL)
2484 break;
2485 err = zonecfg_add_fs_option(
2486 &in_progress_fstab, prop_id);
2487 if (err != Z_OK)
2488 zone_perror(pt_to_str(prop_type), err,
2489 B_TRUE);
2492 return;
2493 case RT_RCTL:
2494 if (prop_type != PT_VALUE) {
2495 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2496 B_TRUE);
2497 long_usage(CMD_ADD, B_TRUE);
2498 usage(B_FALSE, HELP_PROPS);
2499 return;
2501 pp = cmd->cmd_property_ptr[0];
2502 if (pp->pv_type != PROP_VAL_COMPLEX &&
2503 pp->pv_type != PROP_VAL_LIST) {
2504 zerr(gettext("A %s or %s value was expected here."),
2505 pvt_to_str(PROP_VAL_COMPLEX),
2506 pvt_to_str(PROP_VAL_LIST));
2507 saw_error = B_TRUE;
2508 return;
2510 if (pp->pv_type == PROP_VAL_COMPLEX) {
2511 do_complex_rctl_val(pp->pv_complex);
2512 return;
2514 for (l = pp->pv_list; l != NULL; l = l->lp_next)
2515 do_complex_rctl_val(l->lp_complex);
2516 return;
2517 default:
2518 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2519 long_usage(CMD_ADD, B_TRUE);
2520 usage(B_FALSE, HELP_RESOURCES);
2521 return;
2525 static boolean_t
2526 gz_invalid_resource(int type)
2528 return (global_zone && (type == RT_FS ||
2529 type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2530 type == RT_DATASET));
2533 static boolean_t
2534 gz_invalid_rt_property(int type)
2536 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2537 type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2538 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2539 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2542 static boolean_t
2543 gz_invalid_property(int type)
2545 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2546 type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2547 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2548 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2551 void
2552 add_func(cmd_t *cmd)
2554 int arg;
2555 boolean_t arg_err = B_FALSE;
2557 assert(cmd != NULL);
2559 optind = 0;
2560 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2561 switch (arg) {
2562 case '?':
2563 longer_usage(CMD_ADD);
2564 arg_err = B_TRUE;
2565 break;
2566 default:
2567 short_usage(CMD_ADD);
2568 arg_err = B_TRUE;
2569 break;
2572 if (arg_err)
2573 return;
2575 if (optind != cmd->cmd_argc) {
2576 short_usage(CMD_ADD);
2577 return;
2580 if (zone_is_read_only(CMD_ADD))
2581 return;
2583 if (initialize(B_TRUE) != Z_OK)
2584 return;
2585 if (global_scope) {
2586 if (gz_invalid_resource(cmd->cmd_res_type)) {
2587 zerr(gettext("Cannot add a %s resource to the "
2588 "global zone."), rt_to_str(cmd->cmd_res_type));
2589 saw_error = B_TRUE;
2590 return;
2593 global_scope = B_FALSE;
2594 resource_scope = cmd->cmd_res_type;
2595 end_op = CMD_ADD;
2596 add_resource(cmd);
2597 } else
2598 add_property(cmd);
2602 * This routine has an unusual implementation, because it tries very
2603 * hard to succeed in the face of a variety of failure modes.
2604 * The most common and most vexing occurs when the index file and
2605 * the /etc/zones/<zonename.xml> file are not both present. In
2606 * this case, delete must eradicate as much of the zone state as is left
2607 * so that the user can later create a new zone with the same name.
2609 void
2610 delete_func(cmd_t *cmd)
2612 int err, arg, answer;
2613 char line[ZONENAME_MAX + 128]; /* enough to ask a question */
2614 boolean_t force = B_FALSE;
2615 boolean_t arg_err = B_FALSE;
2617 optind = 0;
2618 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2619 switch (arg) {
2620 case '?':
2621 longer_usage(CMD_DELETE);
2622 arg_err = B_TRUE;
2623 break;
2624 case 'F':
2625 force = B_TRUE;
2626 break;
2627 default:
2628 short_usage(CMD_DELETE);
2629 arg_err = B_TRUE;
2630 break;
2633 if (arg_err)
2634 return;
2636 if (optind != cmd->cmd_argc) {
2637 short_usage(CMD_DELETE);
2638 return;
2641 if (zone_is_read_only(CMD_DELETE))
2642 return;
2644 if (!force) {
2646 * Initialize sets up the global called "handle" and warns the
2647 * user if the zone is not configured. In force mode, we don't
2648 * trust that evaluation, and hence skip it. (We don't need the
2649 * handle to be loaded anyway, since zonecfg_destroy is done by
2650 * zonename). However, we also have to take care to emulate the
2651 * messages spit out by initialize; see below.
2653 if (initialize(B_TRUE) != Z_OK)
2654 return;
2656 (void) snprintf(line, sizeof (line),
2657 gettext("Are you sure you want to delete zone %s"), zone);
2658 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2659 zerr(gettext("Input not from terminal and -F not "
2660 "specified:\n%s command ignored, exiting."),
2661 cmd_to_str(CMD_DELETE));
2662 exit(Z_ERR);
2664 if (answer != 1)
2665 return;
2669 * This function removes the authorizations from user_attr
2670 * that correspond to those specified in the configuration
2672 if (initialize(B_TRUE) == Z_OK) {
2673 (void) zonecfg_deauthorize_users(handle, zone);
2675 if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2676 if ((err == Z_BAD_ZONE_STATE) && !force) {
2677 zerr(gettext("Zone %s not in %s state; %s not "
2678 "allowed. Use -F to force %s."),
2679 zone, zone_state_str(ZONE_STATE_CONFIGURED),
2680 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2681 } else {
2682 zone_perror(zone, err, B_TRUE);
2685 need_to_commit = B_FALSE;
2688 * Emulate initialize's messaging; if there wasn't a valid handle to
2689 * begin with, then user had typed delete (or delete -F) multiple
2690 * times. So we emit a message.
2692 * We only do this in the 'force' case because normally, initialize()
2693 * takes care of this for us.
2695 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2696 (void) printf(gettext("Use '%s' to begin "
2697 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2700 * Time for a new handle: finish the old one off first
2701 * then get a new one properly to avoid leaks.
2703 if (got_handle) {
2704 zonecfg_fini_handle(handle);
2705 if ((handle = zonecfg_init_handle()) == NULL) {
2706 zone_perror(execname, Z_NOMEM, B_TRUE);
2707 exit(Z_ERR);
2709 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2710 /* If there was no zone before, that's OK */
2711 if (err != Z_NO_ZONE)
2712 zone_perror(zone, err, B_TRUE);
2713 got_handle = B_FALSE;
2718 static int
2719 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2721 int err, i;
2722 property_value_ptr_t pp;
2724 if ((err = initialize(B_TRUE)) != Z_OK)
2725 return (err);
2727 bzero(fstab, sizeof (*fstab));
2728 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2729 pp = cmd->cmd_property_ptr[i];
2730 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2731 zerr(gettext("A simple value was expected here."));
2732 saw_error = B_TRUE;
2733 return (Z_INSUFFICIENT_SPEC);
2735 switch (cmd->cmd_prop_name[i]) {
2736 case PT_DIR:
2737 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2738 sizeof (fstab->zone_fs_dir));
2739 break;
2740 case PT_SPECIAL:
2741 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2742 sizeof (fstab->zone_fs_special));
2743 break;
2744 case PT_RAW:
2745 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2746 sizeof (fstab->zone_fs_raw));
2747 break;
2748 case PT_TYPE:
2749 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2750 sizeof (fstab->zone_fs_type));
2751 break;
2752 default:
2753 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2754 Z_NO_PROPERTY_TYPE, B_TRUE);
2755 return (Z_INSUFFICIENT_SPEC);
2758 if (fill_in_only)
2759 return (Z_OK);
2760 return (zonecfg_lookup_filesystem(handle, fstab));
2763 static int
2764 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2765 boolean_t fill_in_only)
2767 int err, i;
2768 property_value_ptr_t pp;
2770 if ((err = initialize(B_TRUE)) != Z_OK)
2771 return (err);
2773 bzero(nwiftab, sizeof (*nwiftab));
2774 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2775 pp = cmd->cmd_property_ptr[i];
2776 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2777 zerr(gettext("A simple value was expected here."));
2778 saw_error = B_TRUE;
2779 return (Z_INSUFFICIENT_SPEC);
2781 switch (cmd->cmd_prop_name[i]) {
2782 case PT_ADDRESS:
2783 (void) strlcpy(nwiftab->zone_nwif_address,
2784 pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2785 break;
2786 case PT_ALLOWED_ADDRESS:
2787 (void) strlcpy(nwiftab->zone_nwif_allowed_address,
2788 pp->pv_simple,
2789 sizeof (nwiftab->zone_nwif_allowed_address));
2790 break;
2791 case PT_PHYSICAL:
2792 (void) strlcpy(nwiftab->zone_nwif_physical,
2793 pp->pv_simple,
2794 sizeof (nwiftab->zone_nwif_physical));
2795 break;
2796 case PT_DEFROUTER:
2797 (void) strlcpy(nwiftab->zone_nwif_defrouter,
2798 pp->pv_simple,
2799 sizeof (nwiftab->zone_nwif_defrouter));
2800 break;
2801 default:
2802 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2803 Z_NO_PROPERTY_TYPE, B_TRUE);
2804 return (Z_INSUFFICIENT_SPEC);
2807 if (fill_in_only)
2808 return (Z_OK);
2809 err = zonecfg_lookup_nwif(handle, nwiftab);
2810 return (err);
2813 static int
2814 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2816 int err, i;
2817 property_value_ptr_t pp;
2819 if ((err = initialize(B_TRUE)) != Z_OK)
2820 return (err);
2822 bzero(devtab, sizeof (*devtab));
2823 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2824 pp = cmd->cmd_property_ptr[i];
2825 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2826 zerr(gettext("A simple value was expected here."));
2827 saw_error = B_TRUE;
2828 return (Z_INSUFFICIENT_SPEC);
2830 switch (cmd->cmd_prop_name[i]) {
2831 case PT_MATCH:
2832 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2833 sizeof (devtab->zone_dev_match));
2834 break;
2835 default:
2836 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2837 Z_NO_PROPERTY_TYPE, B_TRUE);
2838 return (Z_INSUFFICIENT_SPEC);
2841 if (fill_in_only)
2842 return (Z_OK);
2843 err = zonecfg_lookup_dev(handle, devtab);
2844 return (err);
2847 static int
2848 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2849 boolean_t fill_in_only)
2851 int err, i;
2852 property_value_ptr_t pp;
2854 if ((err = initialize(B_TRUE)) != Z_OK)
2855 return (err);
2857 bzero(rctltab, sizeof (*rctltab));
2858 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2859 pp = cmd->cmd_property_ptr[i];
2860 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2861 zerr(gettext("A simple value was expected here."));
2862 saw_error = B_TRUE;
2863 return (Z_INSUFFICIENT_SPEC);
2865 switch (cmd->cmd_prop_name[i]) {
2866 case PT_NAME:
2867 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2868 sizeof (rctltab->zone_rctl_name));
2869 break;
2870 default:
2871 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2872 Z_NO_PROPERTY_TYPE, B_TRUE);
2873 return (Z_INSUFFICIENT_SPEC);
2876 if (fill_in_only)
2877 return (Z_OK);
2878 err = zonecfg_lookup_rctl(handle, rctltab);
2879 return (err);
2882 static int
2883 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2884 boolean_t fill_in_only)
2886 int err, i;
2887 property_value_ptr_t pp;
2889 if ((err = initialize(B_TRUE)) != Z_OK)
2890 return (err);
2892 bzero(attrtab, sizeof (*attrtab));
2893 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2894 pp = cmd->cmd_property_ptr[i];
2895 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2896 zerr(gettext("A simple value was expected here."));
2897 saw_error = B_TRUE;
2898 return (Z_INSUFFICIENT_SPEC);
2900 switch (cmd->cmd_prop_name[i]) {
2901 case PT_NAME:
2902 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2903 sizeof (attrtab->zone_attr_name));
2904 break;
2905 case PT_TYPE:
2906 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2907 sizeof (attrtab->zone_attr_type));
2908 break;
2909 case PT_VALUE:
2910 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2911 sizeof (attrtab->zone_attr_value));
2912 break;
2913 default:
2914 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2915 Z_NO_PROPERTY_TYPE, B_TRUE);
2916 return (Z_INSUFFICIENT_SPEC);
2919 if (fill_in_only)
2920 return (Z_OK);
2921 err = zonecfg_lookup_attr(handle, attrtab);
2922 return (err);
2925 static int
2926 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2928 int err, i;
2929 property_value_ptr_t pp;
2931 if ((err = initialize(B_TRUE)) != Z_OK)
2932 return (err);
2934 dstab->zone_dataset_name[0] = '\0';
2935 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2936 pp = cmd->cmd_property_ptr[i];
2937 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2938 zerr(gettext("A simple value was expected here."));
2939 saw_error = B_TRUE;
2940 return (Z_INSUFFICIENT_SPEC);
2942 switch (cmd->cmd_prop_name[i]) {
2943 case PT_NAME:
2944 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2945 sizeof (dstab->zone_dataset_name));
2946 break;
2947 default:
2948 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2949 Z_NO_PROPERTY_TYPE, B_TRUE);
2950 return (Z_INSUFFICIENT_SPEC);
2953 if (fill_in_only)
2954 return (Z_OK);
2955 return (zonecfg_lookup_ds(handle, dstab));
2958 static int
2959 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2960 boolean_t fill_in_only)
2962 int err, i;
2963 property_value_ptr_t pp;
2965 if ((err = initialize(B_TRUE)) != Z_OK)
2966 return (err);
2968 bzero(admintab, sizeof (*admintab));
2969 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2970 pp = cmd->cmd_property_ptr[i];
2971 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2972 zerr(gettext("A simple value was expected here."));
2973 saw_error = B_TRUE;
2974 return (Z_INSUFFICIENT_SPEC);
2976 switch (cmd->cmd_prop_name[i]) {
2977 case PT_USER:
2978 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2979 sizeof (admintab->zone_admin_user));
2980 break;
2981 case PT_AUTHS:
2982 (void) strlcpy(admintab->zone_admin_auths,
2983 pp->pv_simple, sizeof (admintab->zone_admin_auths));
2984 break;
2985 default:
2986 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2987 Z_NO_PROPERTY_TYPE, B_TRUE);
2988 return (Z_INSUFFICIENT_SPEC);
2991 if (fill_in_only)
2992 return (Z_OK);
2993 err = zonecfg_lookup_admin(handle, admintab);
2994 return (err);
2997 static int
2998 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
2999 boolean_t fill_in_only)
3001 int err, i;
3002 property_value_ptr_t pp;
3004 if ((err = initialize(B_TRUE)) != Z_OK)
3005 return (err);
3007 bzero(secflagstab, sizeof (*secflagstab));
3008 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
3009 pp = cmd->cmd_property_ptr[i];
3010 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
3011 zerr(gettext("A simple value was expected here."));
3012 saw_error = B_TRUE;
3013 return (Z_INSUFFICIENT_SPEC);
3015 switch (cmd->cmd_prop_name[i]) {
3016 case PT_DEFAULT:
3017 (void) strlcpy(secflagstab->zone_secflags_default,
3018 pp->pv_simple,
3019 sizeof (secflagstab->zone_secflags_default));
3020 break;
3021 case PT_LOWER:
3022 (void) strlcpy(secflagstab->zone_secflags_lower,
3023 pp->pv_simple,
3024 sizeof (secflagstab->zone_secflags_lower));
3025 break;
3026 case PT_UPPER:
3027 (void) strlcpy(secflagstab->zone_secflags_upper,
3028 pp->pv_simple,
3029 sizeof (secflagstab->zone_secflags_upper));
3030 break;
3031 default:
3032 zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
3033 Z_NO_PROPERTY_TYPE, B_TRUE);
3034 return (Z_INSUFFICIENT_SPEC);
3037 if (fill_in_only)
3038 return (Z_OK);
3040 err = zonecfg_lookup_secflags(handle, secflagstab);
3042 return (err);
3045 static void
3046 remove_aliased_rctl(int type, char *name)
3048 int err;
3049 uint64_t tmp;
3051 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
3052 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3053 zonecfg_strerror(err));
3054 saw_error = B_TRUE;
3055 return;
3057 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
3058 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3059 zonecfg_strerror(err));
3060 saw_error = B_TRUE;
3061 } else {
3062 need_to_commit = B_TRUE;
3066 static boolean_t
3067 prompt_remove_resource(cmd_t *cmd, char *rsrc)
3069 int num;
3070 int answer;
3071 int arg;
3072 boolean_t force = B_FALSE;
3073 char prompt[128];
3074 boolean_t arg_err = B_FALSE;
3076 optind = 0;
3077 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3078 switch (arg) {
3079 case 'F':
3080 force = B_TRUE;
3081 break;
3082 default:
3083 arg_err = B_TRUE;
3084 break;
3087 if (arg_err)
3088 return (B_FALSE);
3091 num = zonecfg_num_resources(handle, rsrc);
3093 if (num == 0) {
3094 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
3095 B_TRUE);
3096 return (B_FALSE);
3098 if (num > 1 && !force) {
3099 if (!interactive_mode) {
3100 zerr(gettext("There are multiple instances of this "
3101 "resource. Either qualify the resource to\n"
3102 "remove a single instance or use the -F option to "
3103 "remove all instances."));
3104 saw_error = B_TRUE;
3105 return (B_FALSE);
3107 (void) snprintf(prompt, sizeof (prompt), gettext(
3108 "Are you sure you want to remove ALL '%s' resources"),
3109 rsrc);
3110 answer = ask_yesno(B_FALSE, prompt);
3111 if (answer == -1) {
3112 zerr(gettext("Resource incomplete."));
3113 return (B_FALSE);
3115 if (answer != 1)
3116 return (B_FALSE);
3118 return (B_TRUE);
3121 static void
3122 remove_fs(cmd_t *cmd)
3124 int err;
3126 /* traditional, qualified fs removal */
3127 if (cmd->cmd_prop_nv_pairs > 0) {
3128 struct zone_fstab fstab;
3130 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
3131 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3132 return;
3134 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
3135 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3136 else
3137 need_to_commit = B_TRUE;
3138 zonecfg_free_fs_option_list(fstab.zone_fs_options);
3139 return;
3143 * unqualified fs removal. remove all fs's but prompt if more
3144 * than one.
3146 if (!prompt_remove_resource(cmd, "fs"))
3147 return;
3149 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
3150 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3151 else
3152 need_to_commit = B_TRUE;
3155 static void
3156 remove_net(cmd_t *cmd)
3158 int err;
3160 /* traditional, qualified net removal */
3161 if (cmd->cmd_prop_nv_pairs > 0) {
3162 struct zone_nwiftab nwiftab;
3164 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3165 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3166 return;
3168 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3169 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3170 else
3171 need_to_commit = B_TRUE;
3172 return;
3176 * unqualified net removal. remove all nets but prompt if more
3177 * than one.
3179 if (!prompt_remove_resource(cmd, "net"))
3180 return;
3182 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3183 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3184 else
3185 need_to_commit = B_TRUE;
3188 static void
3189 remove_device(cmd_t *cmd)
3191 int err;
3193 /* traditional, qualified device removal */
3194 if (cmd->cmd_prop_nv_pairs > 0) {
3195 struct zone_devtab devtab;
3197 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3198 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3199 return;
3201 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3202 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3203 else
3204 need_to_commit = B_TRUE;
3205 return;
3209 * unqualified device removal. remove all devices but prompt if more
3210 * than one.
3212 if (!prompt_remove_resource(cmd, "device"))
3213 return;
3215 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3216 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3217 else
3218 need_to_commit = B_TRUE;
3221 static void
3222 remove_attr(cmd_t *cmd)
3224 int err;
3226 /* traditional, qualified attr removal */
3227 if (cmd->cmd_prop_nv_pairs > 0) {
3228 struct zone_attrtab attrtab;
3230 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3231 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3232 return;
3234 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3235 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3236 else
3237 need_to_commit = B_TRUE;
3238 return;
3242 * unqualified attr removal. remove all attrs but prompt if more
3243 * than one.
3245 if (!prompt_remove_resource(cmd, "attr"))
3246 return;
3248 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3249 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3250 else
3251 need_to_commit = B_TRUE;
3254 static void
3255 remove_dataset(cmd_t *cmd)
3257 int err;
3259 /* traditional, qualified dataset removal */
3260 if (cmd->cmd_prop_nv_pairs > 0) {
3261 struct zone_dstab dstab;
3263 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3264 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3265 return;
3267 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3268 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3269 else
3270 need_to_commit = B_TRUE;
3271 return;
3275 * unqualified dataset removal. remove all datasets but prompt if more
3276 * than one.
3278 if (!prompt_remove_resource(cmd, "dataset"))
3279 return;
3281 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3282 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3283 else
3284 need_to_commit = B_TRUE;
3287 static void
3288 remove_rctl(cmd_t *cmd)
3290 int err;
3292 /* traditional, qualified rctl removal */
3293 if (cmd->cmd_prop_nv_pairs > 0) {
3294 struct zone_rctltab rctltab;
3296 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3297 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3298 return;
3300 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3301 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3302 else
3303 need_to_commit = B_TRUE;
3304 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3305 return;
3309 * unqualified rctl removal. remove all rctls but prompt if more
3310 * than one.
3312 if (!prompt_remove_resource(cmd, "rctl"))
3313 return;
3315 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3316 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3317 else
3318 need_to_commit = B_TRUE;
3321 static void
3322 remove_pset()
3324 int err;
3325 struct zone_psettab psettab;
3327 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3328 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3329 return;
3331 if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3332 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3333 else
3334 need_to_commit = B_TRUE;
3337 static void
3338 remove_pcap()
3340 int err;
3341 uint64_t tmp;
3343 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3344 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3345 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3346 saw_error = B_TRUE;
3347 return;
3350 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3351 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3352 else
3353 need_to_commit = B_TRUE;
3356 static void
3357 remove_mcap()
3359 int err, res1, res2, res3;
3360 uint64_t tmp;
3361 struct zone_mcaptab mcaptab;
3362 boolean_t revert = B_FALSE;
3364 res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3365 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3366 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3368 /* if none of these exist, there is no resource to remove */
3369 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3370 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3371 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3372 saw_error = B_TRUE;
3373 return;
3375 if (res1 == Z_OK) {
3376 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3377 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3378 revert = B_TRUE;
3379 } else {
3380 need_to_commit = B_TRUE;
3383 if (res2 == Z_OK) {
3384 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3385 != Z_OK) {
3386 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3387 revert = B_TRUE;
3388 } else {
3389 need_to_commit = B_TRUE;
3392 if (res3 == Z_OK) {
3393 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3394 != Z_OK) {
3395 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3396 revert = B_TRUE;
3397 } else {
3398 need_to_commit = B_TRUE;
3402 if (revert)
3403 need_to_commit = B_FALSE;
3406 static void
3407 remove_admin(cmd_t *cmd)
3409 int err;
3411 /* traditional, qualified attr removal */
3412 if (cmd->cmd_prop_nv_pairs > 0) {
3413 struct zone_admintab admintab;
3415 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3416 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3417 err, B_TRUE);
3418 return;
3420 if ((err = zonecfg_delete_admin(handle, &admintab,
3421 zone))
3422 != Z_OK)
3423 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3424 err, B_TRUE);
3425 else
3426 need_to_commit = B_TRUE;
3427 return;
3428 } else {
3430 * unqualified admin removal.
3431 * remove all admins but prompt if more
3432 * than one.
3434 if (!prompt_remove_resource(cmd, "admin"))
3435 return;
3437 if ((err = zonecfg_delete_admins(handle, zone))
3438 != Z_OK)
3439 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3440 err, B_TRUE);
3441 else
3442 need_to_commit = B_TRUE;
3446 static void
3447 remove_secflags()
3449 int err;
3450 struct zone_secflagstab sectab = { 0 };
3452 if (zonecfg_lookup_secflags(handle, &sectab) != Z_OK) {
3453 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
3454 rt_to_str(RT_SECFLAGS),
3455 zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3456 return;
3459 if ((err = zonecfg_delete_secflags(handle, &sectab)) != Z_OK) {
3460 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
3461 return;
3464 need_to_commit = B_TRUE;
3467 static void
3468 remove_resource(cmd_t *cmd)
3470 int type;
3471 int arg;
3472 boolean_t arg_err = B_FALSE;
3474 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3475 long_usage(CMD_REMOVE, B_TRUE);
3476 return;
3479 optind = 0;
3480 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3481 switch (arg) {
3482 case '?':
3483 longer_usage(CMD_REMOVE);
3484 arg_err = B_TRUE;
3485 break;
3486 case 'F':
3487 break;
3488 default:
3489 short_usage(CMD_REMOVE);
3490 arg_err = B_TRUE;
3491 break;
3494 if (arg_err)
3495 return;
3497 if (initialize(B_TRUE) != Z_OK)
3498 return;
3500 switch (type) {
3501 case RT_FS:
3502 remove_fs(cmd);
3503 return;
3504 case RT_NET:
3505 remove_net(cmd);
3506 return;
3507 case RT_DEVICE:
3508 remove_device(cmd);
3509 return;
3510 case RT_RCTL:
3511 remove_rctl(cmd);
3512 return;
3513 case RT_ATTR:
3514 remove_attr(cmd);
3515 return;
3516 case RT_DATASET:
3517 remove_dataset(cmd);
3518 return;
3519 case RT_DCPU:
3520 remove_pset();
3521 return;
3522 case RT_PCAP:
3523 remove_pcap();
3524 return;
3525 case RT_MCAP:
3526 remove_mcap();
3527 return;
3528 case RT_ADMIN:
3529 remove_admin(cmd);
3530 return;
3531 case RT_SECFLAGS:
3532 remove_secflags();
3533 return;
3534 default:
3535 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3536 long_usage(CMD_REMOVE, B_TRUE);
3537 usage(B_FALSE, HELP_RESOURCES);
3538 return;
3542 static void
3543 remove_property(cmd_t *cmd)
3545 char *prop_id;
3546 int err, res_type, prop_type;
3547 property_value_ptr_t pp;
3548 struct zone_rctlvaltab *rctlvaltab;
3549 complex_property_ptr_t cx;
3551 res_type = resource_scope;
3552 prop_type = cmd->cmd_prop_name[0];
3553 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3554 long_usage(CMD_REMOVE, B_TRUE);
3555 return;
3558 if (cmd->cmd_prop_nv_pairs != 1) {
3559 long_usage(CMD_ADD, B_TRUE);
3560 return;
3563 if (initialize(B_TRUE) != Z_OK)
3564 return;
3566 switch (res_type) {
3567 case RT_FS:
3568 if (prop_type != PT_OPTIONS) {
3569 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3570 B_TRUE);
3571 long_usage(CMD_REMOVE, B_TRUE);
3572 usage(B_FALSE, HELP_PROPS);
3573 return;
3575 pp = cmd->cmd_property_ptr[0];
3576 if (pp->pv_type == PROP_VAL_COMPLEX) {
3577 zerr(gettext("A %s or %s value was expected here."),
3578 pvt_to_str(PROP_VAL_SIMPLE),
3579 pvt_to_str(PROP_VAL_LIST));
3580 saw_error = B_TRUE;
3581 return;
3583 if (pp->pv_type == PROP_VAL_SIMPLE) {
3584 if (pp->pv_simple == NULL) {
3585 long_usage(CMD_ADD, B_TRUE);
3586 return;
3588 prop_id = pp->pv_simple;
3589 err = zonecfg_remove_fs_option(&in_progress_fstab,
3590 prop_id);
3591 if (err != Z_OK)
3592 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3593 } else {
3594 list_property_ptr_t list;
3596 for (list = pp->pv_list; list != NULL;
3597 list = list->lp_next) {
3598 prop_id = list->lp_simple;
3599 if (prop_id == NULL)
3600 break;
3601 err = zonecfg_remove_fs_option(
3602 &in_progress_fstab, prop_id);
3603 if (err != Z_OK)
3604 zone_perror(pt_to_str(prop_type), err,
3605 B_TRUE);
3608 return;
3609 case RT_RCTL:
3610 if (prop_type != PT_VALUE) {
3611 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3612 B_TRUE);
3613 long_usage(CMD_REMOVE, B_TRUE);
3614 usage(B_FALSE, HELP_PROPS);
3615 return;
3617 pp = cmd->cmd_property_ptr[0];
3618 if (pp->pv_type != PROP_VAL_COMPLEX) {
3619 zerr(gettext("A %s value was expected here."),
3620 pvt_to_str(PROP_VAL_COMPLEX));
3621 saw_error = B_TRUE;
3622 return;
3624 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3625 zone_perror(zone, Z_NOMEM, B_TRUE);
3626 exit(Z_ERR);
3628 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3629 switch (cx->cp_type) {
3630 case PT_PRIV:
3631 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
3632 cx->cp_value,
3633 sizeof (rctlvaltab->zone_rctlval_priv));
3634 break;
3635 case PT_LIMIT:
3636 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
3637 cx->cp_value,
3638 sizeof (rctlvaltab->zone_rctlval_limit));
3639 break;
3640 case PT_ACTION:
3641 (void) strlcpy(rctlvaltab->zone_rctlval_action,
3642 cx->cp_value,
3643 sizeof (rctlvaltab->zone_rctlval_action));
3644 break;
3645 default:
3646 zone_perror(pt_to_str(prop_type),
3647 Z_NO_PROPERTY_TYPE, B_TRUE);
3648 long_usage(CMD_ADD, B_TRUE);
3649 usage(B_FALSE, HELP_PROPS);
3650 zonecfg_free_rctl_value_list(rctlvaltab);
3651 return;
3654 rctlvaltab->zone_rctlval_next = NULL;
3655 err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3656 rctlvaltab);
3657 if (err != Z_OK)
3658 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3659 zonecfg_free_rctl_value_list(rctlvaltab);
3660 return;
3661 case RT_NET:
3662 if (prop_type != PT_DEFROUTER) {
3663 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3664 B_TRUE);
3665 long_usage(CMD_REMOVE, B_TRUE);
3666 usage(B_FALSE, HELP_PROPS);
3667 return;
3668 } else {
3669 bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3670 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3671 return;
3673 default:
3674 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3675 long_usage(CMD_REMOVE, B_TRUE);
3676 usage(B_FALSE, HELP_RESOURCES);
3677 return;
3681 void
3682 remove_func(cmd_t *cmd)
3684 if (zone_is_read_only(CMD_REMOVE))
3685 return;
3687 assert(cmd != NULL);
3689 if (global_scope) {
3690 if (gz_invalid_resource(cmd->cmd_res_type)) {
3691 zerr(gettext("%s is not a valid resource for the "
3692 "global zone."), rt_to_str(cmd->cmd_res_type));
3693 saw_error = B_TRUE;
3694 return;
3696 remove_resource(cmd);
3697 } else {
3698 remove_property(cmd);
3702 static void
3703 clear_property(cmd_t *cmd)
3705 int res_type, prop_type;
3707 res_type = resource_scope;
3708 prop_type = cmd->cmd_res_type;
3709 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3710 long_usage(CMD_CLEAR, B_TRUE);
3711 return;
3714 if (initialize(B_TRUE) != Z_OK)
3715 return;
3717 switch (res_type) {
3718 case RT_FS:
3719 if (prop_type == PT_RAW) {
3720 in_progress_fstab.zone_fs_raw[0] = '\0';
3721 need_to_commit = B_TRUE;
3722 return;
3724 break;
3725 case RT_DCPU:
3726 if (prop_type == PT_IMPORTANCE) {
3727 in_progress_psettab.zone_importance[0] = '\0';
3728 need_to_commit = B_TRUE;
3729 return;
3731 break;
3732 case RT_MCAP:
3733 switch (prop_type) {
3734 case PT_PHYSICAL:
3735 in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3736 need_to_commit = B_TRUE;
3737 return;
3738 case PT_SWAP:
3739 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3740 return;
3741 case PT_LOCKED:
3742 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3743 return;
3745 break;
3746 case RT_SECFLAGS:
3747 switch (prop_type) {
3748 case PT_LOWER:
3749 in_progress_secflagstab.zone_secflags_lower[0] = '\0';
3750 need_to_commit = B_TRUE;
3751 return;
3752 case PT_DEFAULT:
3753 in_progress_secflagstab.zone_secflags_default[0] = '\0';
3754 need_to_commit = B_TRUE;
3755 return;
3756 case PT_UPPER:
3757 in_progress_secflagstab.zone_secflags_upper[0] = '\0';
3758 need_to_commit = B_TRUE;
3759 return;
3761 break;
3762 default:
3763 break;
3766 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3769 static void
3770 clear_global(cmd_t *cmd)
3772 int err, type;
3774 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3775 long_usage(CMD_CLEAR, B_TRUE);
3776 return;
3779 if (initialize(B_TRUE) != Z_OK)
3780 return;
3782 switch (type) {
3783 case PT_ZONENAME:
3784 /* FALLTHRU */
3785 case PT_ZONEPATH:
3786 /* FALLTHRU */
3787 case PT_BRAND:
3788 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3789 return;
3790 case PT_AUTOBOOT:
3791 /* false is default; we'll treat as equivalent to clearing */
3792 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3793 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3794 else
3795 need_to_commit = B_TRUE;
3796 return;
3797 case PT_POOL:
3798 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3799 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3800 else
3801 need_to_commit = B_TRUE;
3802 return;
3803 case PT_LIMITPRIV:
3804 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3805 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3806 else
3807 need_to_commit = B_TRUE;
3808 return;
3809 case PT_BOOTARGS:
3810 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3811 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3812 else
3813 need_to_commit = B_TRUE;
3814 return;
3815 case PT_SCHED:
3816 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3817 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3818 else
3819 need_to_commit = B_TRUE;
3820 return;
3821 case PT_IPTYPE:
3822 /* shared is default; we'll treat as equivalent to clearing */
3823 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3824 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3825 else
3826 need_to_commit = B_TRUE;
3827 return;
3828 case PT_MAXLWPS:
3829 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3830 return;
3831 case PT_MAXPROCS:
3832 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS);
3833 return;
3834 case PT_MAXSHMMEM:
3835 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3836 return;
3837 case PT_MAXSHMIDS:
3838 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3839 return;
3840 case PT_MAXMSGIDS:
3841 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3842 return;
3843 case PT_MAXSEMIDS:
3844 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3845 return;
3846 case PT_SHARES:
3847 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3848 return;
3849 case PT_HOSTID:
3850 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3851 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3852 else
3853 need_to_commit = B_TRUE;
3854 return;
3855 case PT_FS_ALLOWED:
3856 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3857 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3858 else
3859 need_to_commit = B_TRUE;
3860 return;
3861 default:
3862 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3863 long_usage(CMD_CLEAR, B_TRUE);
3864 usage(B_FALSE, HELP_PROPS);
3865 return;
3869 void
3870 clear_func(cmd_t *cmd)
3872 if (zone_is_read_only(CMD_CLEAR))
3873 return;
3875 assert(cmd != NULL);
3877 if (global_scope) {
3878 if (gz_invalid_property(cmd->cmd_res_type)) {
3879 zerr(gettext("%s is not a valid property for the "
3880 "global zone."), pt_to_str(cmd->cmd_res_type));
3881 saw_error = B_TRUE;
3882 return;
3885 clear_global(cmd);
3886 } else {
3887 clear_property(cmd);
3891 void
3892 select_func(cmd_t *cmd)
3894 int type, err, res;
3895 uint64_t limit;
3896 uint64_t tmp;
3898 if (zone_is_read_only(CMD_SELECT))
3899 return;
3901 assert(cmd != NULL);
3903 if (global_scope) {
3904 global_scope = B_FALSE;
3905 resource_scope = cmd->cmd_res_type;
3906 end_op = CMD_SELECT;
3907 } else {
3908 scope_usage(CMD_SELECT);
3909 return;
3912 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3913 long_usage(CMD_SELECT, B_TRUE);
3914 return;
3917 if (initialize(B_TRUE) != Z_OK)
3918 return;
3920 switch (type) {
3921 case RT_FS:
3922 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3923 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3924 global_scope = B_TRUE;
3926 bcopy(&old_fstab, &in_progress_fstab,
3927 sizeof (struct zone_fstab));
3928 return;
3929 case RT_NET:
3930 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3931 != Z_OK) {
3932 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3933 global_scope = B_TRUE;
3935 bcopy(&old_nwiftab, &in_progress_nwiftab,
3936 sizeof (struct zone_nwiftab));
3937 return;
3938 case RT_DEVICE:
3939 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3940 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3941 global_scope = B_TRUE;
3943 bcopy(&old_devtab, &in_progress_devtab,
3944 sizeof (struct zone_devtab));
3945 return;
3946 case RT_RCTL:
3947 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3948 != Z_OK) {
3949 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3950 global_scope = B_TRUE;
3952 bcopy(&old_rctltab, &in_progress_rctltab,
3953 sizeof (struct zone_rctltab));
3954 return;
3955 case RT_ATTR:
3956 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3957 != Z_OK) {
3958 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3959 global_scope = B_TRUE;
3961 bcopy(&old_attrtab, &in_progress_attrtab,
3962 sizeof (struct zone_attrtab));
3963 return;
3964 case RT_DATASET:
3965 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3966 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3967 global_scope = B_TRUE;
3969 bcopy(&old_dstab, &in_progress_dstab,
3970 sizeof (struct zone_dstab));
3971 return;
3972 case RT_DCPU:
3973 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3974 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3975 global_scope = B_TRUE;
3977 bcopy(&old_psettab, &in_progress_psettab,
3978 sizeof (struct zone_psettab));
3979 return;
3980 case RT_PCAP:
3981 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3982 != Z_OK) {
3983 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3984 global_scope = B_TRUE;
3986 return;
3987 case RT_MCAP:
3988 /* if none of these exist, there is no resource to select */
3989 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3990 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3991 != Z_OK &&
3992 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3993 != Z_OK) {
3994 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3995 B_TRUE);
3996 global_scope = B_TRUE;
3998 if (res == Z_OK)
3999 bcopy(&old_mcaptab, &in_progress_mcaptab,
4000 sizeof (struct zone_mcaptab));
4001 else
4002 bzero(&in_progress_mcaptab,
4003 sizeof (in_progress_mcaptab));
4004 return;
4005 case RT_ADMIN:
4006 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
4007 != Z_OK) {
4008 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
4009 B_TRUE);
4010 global_scope = B_TRUE;
4012 bcopy(&old_admintab, &in_progress_admintab,
4013 sizeof (struct zone_admintab));
4014 return;
4015 case RT_SECFLAGS:
4016 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
4017 != Z_OK) {
4018 z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
4019 B_TRUE);
4020 global_scope = B_TRUE;
4022 bcopy(&old_secflagstab, &in_progress_secflagstab,
4023 sizeof (struct zone_secflagstab));
4024 return;
4025 default:
4026 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
4027 long_usage(CMD_SELECT, B_TRUE);
4028 usage(B_FALSE, HELP_RESOURCES);
4029 return;
4034 * Network "addresses" can be one of the following forms:
4035 * <IPv4 address>
4036 * <IPv4 address>/<prefix length>
4037 * <IPv6 address>/<prefix length>
4038 * <host name>
4039 * <host name>/<prefix length>
4040 * In other words, the "/" followed by a prefix length is allowed but not
4041 * required for IPv4 addresses and host names, and required for IPv6 addresses.
4042 * If a prefix length is given, it must be in the allowable range: 0 to 32 for
4043 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
4044 * Host names must start with an alpha-numeric character, and all subsequent
4045 * characters must be either alpha-numeric or "-".
4047 * In some cases, e.g., the nexthop for the defrouter, the context indicates
4048 * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
4049 * require the /<prefix length> (and should ignore it if provided).
4052 static int
4053 validate_net_address_syntax(char *address, boolean_t ishost)
4055 char *slashp, part1[MAXHOSTNAMELEN];
4056 struct in6_addr in6;
4057 struct in_addr in4;
4058 int prefixlen, i;
4061 * Copy the part before any '/' into part1 or copy the whole
4062 * thing if there is no '/'.
4064 if ((slashp = strchr(address, '/')) != NULL) {
4065 *slashp = '\0';
4066 (void) strlcpy(part1, address, sizeof (part1));
4067 *slashp = '/';
4068 prefixlen = atoi(++slashp);
4069 } else {
4070 (void) strlcpy(part1, address, sizeof (part1));
4073 if (ishost && slashp != NULL) {
4074 zerr(gettext("Warning: prefix length in %s is not required and "
4075 "will be ignored. The default host-prefix length "
4076 "will be used"), address);
4080 if (inet_pton(AF_INET6, part1, &in6) == 1) {
4081 if (ishost) {
4082 prefixlen = IPV6_ABITS;
4083 } else if (slashp == NULL) {
4084 zerr(gettext("%s: IPv6 addresses "
4085 "require /prefix-length suffix."), address);
4086 return (Z_ERR);
4088 if (prefixlen < 0 || prefixlen > 128) {
4089 zerr(gettext("%s: IPv6 address "
4090 "prefix lengths must be 0 - 128."), address);
4091 return (Z_ERR);
4093 return (Z_OK);
4096 /* At this point, any /prefix must be for IPv4. */
4097 if (ishost)
4098 prefixlen = IPV4_ABITS;
4099 else if (slashp != NULL) {
4100 if (prefixlen < 0 || prefixlen > 32) {
4101 zerr(gettext("%s: IPv4 address "
4102 "prefix lengths must be 0 - 32."), address);
4103 return (Z_ERR);
4107 if (inet_pton(AF_INET, part1, &in4) == 1)
4108 return (Z_OK);
4110 /* address may also be a host name */
4111 if (!isalnum(part1[0])) {
4112 zerr(gettext("%s: bogus host name or network address syntax"),
4113 part1);
4114 saw_error = B_TRUE;
4115 usage(B_FALSE, HELP_NETADDR);
4116 return (Z_ERR);
4118 for (i = 1; part1[i]; i++)
4119 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
4120 zerr(gettext("%s: bogus host name or "
4121 "network address syntax"), part1);
4122 saw_error = B_TRUE;
4123 usage(B_FALSE, HELP_NETADDR);
4124 return (Z_ERR);
4126 return (Z_OK);
4129 static int
4130 validate_net_physical_syntax(const char *ifname)
4132 ifspec_t ifnameprop;
4133 zone_iptype_t iptype;
4135 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
4136 zerr(gettext("zone configuration has an invalid or nonexistent "
4137 "ip-type property"));
4138 return (Z_ERR);
4140 switch (iptype) {
4141 case ZS_SHARED:
4142 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
4143 zerr(gettext("%s: invalid physical interface name"),
4144 ifname);
4145 return (Z_ERR);
4147 if (ifnameprop.ifsp_lunvalid) {
4148 zerr(gettext("%s: LUNs not allowed in physical "
4149 "interface names"), ifname);
4150 return (Z_ERR);
4152 break;
4153 case ZS_EXCLUSIVE:
4154 if (dladm_valid_linkname(ifname) == B_FALSE) {
4155 if (strchr(ifname, ':') != NULL)
4156 zerr(gettext("%s: physical interface name "
4157 "required; logical interface name not "
4158 "allowed"), ifname);
4159 else
4160 zerr(gettext("%s: invalid physical interface "
4161 "name"), ifname);
4162 return (Z_ERR);
4164 break;
4166 return (Z_OK);
4169 static boolean_t
4170 valid_fs_type(const char *type)
4173 * Is this a valid path component?
4175 if (strlen(type) + 1 > MAXNAMELEN)
4176 return (B_FALSE);
4178 * Make sure a bad value for "type" doesn't make
4179 * /usr/lib/fs/<type>/mount turn into something else.
4181 if (strchr(type, '/') != NULL || type[0] == '\0' ||
4182 strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4183 return (B_FALSE);
4185 * More detailed verification happens later by zoneadm(1m).
4187 return (B_TRUE);
4190 static boolean_t
4191 allow_exclusive()
4193 brand_handle_t bh;
4194 char brand[MAXNAMELEN];
4195 boolean_t ret;
4197 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4198 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4199 return (B_FALSE);
4201 if ((bh = brand_open(brand)) == NULL) {
4202 zerr("%s: %s\n", zone, gettext("unknown brand."));
4203 return (B_FALSE);
4205 ret = brand_allow_exclusive_ip(bh);
4206 brand_close(bh);
4207 if (!ret)
4208 zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4209 pt_to_str(PT_IPTYPE), "exclusive",
4210 pt_to_str(PT_BRAND), brand);
4211 return (ret);
4214 static void
4215 set_aliased_rctl(char *alias, int prop_type, char *s)
4217 uint64_t limit;
4218 int err;
4219 char tmp[128];
4221 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4222 zerr(gettext("WARNING: Setting a global zone resource "
4223 "control too low could deny\nservice "
4224 "to even the root user; "
4225 "this could render the system impossible\n"
4226 "to administer. Please use caution."));
4228 /* convert memory based properties */
4229 if (prop_type == PT_MAXSHMMEM) {
4230 if (!zonecfg_valid_memlimit(s, &limit)) {
4231 zerr(gettext("A non-negative number with a required "
4232 "scale suffix (K, M, G or T) was expected\nhere."));
4233 saw_error = B_TRUE;
4234 return;
4237 (void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4238 s = tmp;
4241 if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4242 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4243 saw_error = B_TRUE;
4244 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4245 zerr(gettext("%s property is out of range."),
4246 pt_to_str(prop_type));
4247 saw_error = B_TRUE;
4248 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4249 != Z_OK) {
4250 zone_perror(zone, err, B_TRUE);
4251 saw_error = B_TRUE;
4252 } else {
4253 need_to_commit = B_TRUE;
4257 static void
4258 set_in_progress_nwiftab_address(char *prop_id, int prop_type)
4260 if (prop_type == PT_ADDRESS) {
4261 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
4262 sizeof (in_progress_nwiftab.zone_nwif_address));
4263 } else {
4264 assert(prop_type == PT_ALLOWED_ADDRESS);
4265 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
4266 prop_id,
4267 sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
4271 void
4272 set_func(cmd_t *cmd)
4274 char *prop_id;
4275 int arg, err, res_type, prop_type;
4276 property_value_ptr_t pp;
4277 boolean_t autoboot;
4278 zone_iptype_t iptype;
4279 boolean_t force_set = B_FALSE;
4280 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4281 uint64_t mem_cap, mem_limit;
4282 float cap;
4283 char *unitp;
4284 struct zone_psettab tmp_psettab;
4285 boolean_t arg_err = B_FALSE;
4287 if (zone_is_read_only(CMD_SET))
4288 return;
4290 assert(cmd != NULL);
4292 optind = opterr = 0;
4293 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4294 switch (arg) {
4295 case 'F':
4296 force_set = B_TRUE;
4297 break;
4298 default:
4299 if (optopt == '?')
4300 longer_usage(CMD_SET);
4301 else
4302 short_usage(CMD_SET);
4303 arg_err = B_TRUE;
4304 break;
4307 if (arg_err)
4308 return;
4310 prop_type = cmd->cmd_prop_name[0];
4311 if (global_scope) {
4312 if (gz_invalid_property(prop_type)) {
4313 zerr(gettext("%s is not a valid property for the "
4314 "global zone."), pt_to_str(prop_type));
4315 saw_error = B_TRUE;
4316 return;
4319 if (prop_type == PT_ZONENAME) {
4320 res_type = RT_ZONENAME;
4321 } else if (prop_type == PT_ZONEPATH) {
4322 res_type = RT_ZONEPATH;
4323 } else if (prop_type == PT_AUTOBOOT) {
4324 res_type = RT_AUTOBOOT;
4325 } else if (prop_type == PT_BRAND) {
4326 res_type = RT_BRAND;
4327 } else if (prop_type == PT_POOL) {
4328 res_type = RT_POOL;
4329 } else if (prop_type == PT_LIMITPRIV) {
4330 res_type = RT_LIMITPRIV;
4331 } else if (prop_type == PT_BOOTARGS) {
4332 res_type = RT_BOOTARGS;
4333 } else if (prop_type == PT_SCHED) {
4334 res_type = RT_SCHED;
4335 } else if (prop_type == PT_IPTYPE) {
4336 res_type = RT_IPTYPE;
4337 } else if (prop_type == PT_MAXLWPS) {
4338 res_type = RT_MAXLWPS;
4339 } else if (prop_type == PT_MAXPROCS) {
4340 res_type = RT_MAXPROCS;
4341 } else if (prop_type == PT_MAXSHMMEM) {
4342 res_type = RT_MAXSHMMEM;
4343 } else if (prop_type == PT_MAXSHMIDS) {
4344 res_type = RT_MAXSHMIDS;
4345 } else if (prop_type == PT_MAXMSGIDS) {
4346 res_type = RT_MAXMSGIDS;
4347 } else if (prop_type == PT_MAXSEMIDS) {
4348 res_type = RT_MAXSEMIDS;
4349 } else if (prop_type == PT_SHARES) {
4350 res_type = RT_SHARES;
4351 } else if (prop_type == PT_HOSTID) {
4352 res_type = RT_HOSTID;
4353 } else if (prop_type == PT_FS_ALLOWED) {
4354 res_type = RT_FS_ALLOWED;
4355 } else {
4356 zerr(gettext("Cannot set a resource-specific property "
4357 "from the global scope."));
4358 saw_error = B_TRUE;
4359 return;
4361 } else {
4362 res_type = resource_scope;
4365 if (force_set) {
4366 if (res_type != RT_ZONEPATH) {
4367 zerr(gettext("Only zonepath setting can be forced."));
4368 saw_error = B_TRUE;
4369 return;
4371 if (!zonecfg_in_alt_root()) {
4372 zerr(gettext("Zonepath is changeable only in an "
4373 "alternate root."));
4374 saw_error = B_TRUE;
4375 return;
4379 pp = cmd->cmd_property_ptr[0];
4381 * A nasty expression but not that complicated:
4382 * 1. fs options are simple or list (tested below)
4383 * 2. rctl value's are complex or list (tested below)
4384 * Anything else should be simple.
4386 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4387 !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4388 (pp->pv_type != PROP_VAL_SIMPLE ||
4389 (prop_id = pp->pv_simple) == NULL)) {
4390 zerr(gettext("A %s value was expected here."),
4391 pvt_to_str(PROP_VAL_SIMPLE));
4392 saw_error = B_TRUE;
4393 return;
4395 if (prop_type == PT_UNKNOWN) {
4396 long_usage(CMD_SET, B_TRUE);
4397 return;
4401 * Special case: the user can change the zone name prior to 'create';
4402 * if the zone already exists, we fall through letting initialize()
4403 * and the rest of the logic run.
4405 if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4406 !state_atleast(ZONE_STATE_CONFIGURED)) {
4407 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4408 zone_perror(prop_id, err, B_TRUE);
4409 usage(B_FALSE, HELP_SYNTAX);
4410 return;
4412 (void) strlcpy(zone, prop_id, sizeof (zone));
4413 return;
4416 if (initialize(B_TRUE) != Z_OK)
4417 return;
4419 switch (res_type) {
4420 case RT_ZONENAME:
4421 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4423 * Use prop_id instead of 'zone' here, since we're
4424 * reporting a problem about the *new* zonename.
4426 zone_perror(prop_id, err, B_TRUE);
4427 usage(B_FALSE, HELP_SYNTAX);
4428 } else {
4429 need_to_commit = B_TRUE;
4430 (void) strlcpy(zone, prop_id, sizeof (zone));
4432 return;
4433 case RT_ZONEPATH:
4434 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4435 zerr(gettext("Zone %s already installed; %s %s not "
4436 "allowed."), zone, cmd_to_str(CMD_SET),
4437 rt_to_str(RT_ZONEPATH));
4438 return;
4440 if (validate_zonepath_syntax(prop_id) != Z_OK) {
4441 saw_error = B_TRUE;
4442 return;
4444 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4445 zone_perror(zone, err, B_TRUE);
4446 else
4447 need_to_commit = B_TRUE;
4448 return;
4449 case RT_BRAND:
4450 if (state_atleast(ZONE_STATE_INSTALLED)) {
4451 zerr(gettext("Zone %s already installed; %s %s not "
4452 "allowed."), zone, cmd_to_str(CMD_SET),
4453 rt_to_str(RT_BRAND));
4454 return;
4456 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4457 zone_perror(zone, err, B_TRUE);
4458 else
4459 need_to_commit = B_TRUE;
4460 return;
4461 case RT_AUTOBOOT:
4462 if (strcmp(prop_id, "true") == 0) {
4463 autoboot = B_TRUE;
4464 } else if (strcmp(prop_id, "false") == 0) {
4465 autoboot = B_FALSE;
4466 } else {
4467 zerr(gettext("%s value must be '%s' or '%s'."),
4468 pt_to_str(PT_AUTOBOOT), "true", "false");
4469 saw_error = B_TRUE;
4470 return;
4472 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4473 zone_perror(zone, err, B_TRUE);
4474 else
4475 need_to_commit = B_TRUE;
4476 return;
4477 case RT_POOL:
4478 /* don't allow use of the reserved temporary pool names */
4479 if (strncmp("SUNW", prop_id, 4) == 0) {
4480 zerr(gettext("pool names starting with SUNW are "
4481 "reserved."));
4482 saw_error = B_TRUE;
4483 return;
4486 /* can't set pool if dedicated-cpu exists */
4487 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4488 zerr(gettext("The %s resource already exists. "
4489 "A persistent pool is incompatible\nwith the %s "
4490 "resource."), rt_to_str(RT_DCPU),
4491 rt_to_str(RT_DCPU));
4492 saw_error = B_TRUE;
4493 return;
4496 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4497 zone_perror(zone, err, B_TRUE);
4498 else
4499 need_to_commit = B_TRUE;
4500 return;
4501 case RT_LIMITPRIV:
4502 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4503 zone_perror(zone, err, B_TRUE);
4504 else
4505 need_to_commit = B_TRUE;
4506 return;
4507 case RT_BOOTARGS:
4508 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4509 zone_perror(zone, err, B_TRUE);
4510 else
4511 need_to_commit = B_TRUE;
4512 return;
4513 case RT_SCHED:
4514 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4515 zone_perror(zone, err, B_TRUE);
4516 else
4517 need_to_commit = B_TRUE;
4518 return;
4519 case RT_IPTYPE:
4520 if (strcmp(prop_id, "shared") == 0) {
4521 iptype = ZS_SHARED;
4522 } else if (strcmp(prop_id, "exclusive") == 0) {
4523 iptype = ZS_EXCLUSIVE;
4524 } else {
4525 zerr(gettext("%s value must be '%s' or '%s'."),
4526 pt_to_str(PT_IPTYPE), "shared", "exclusive");
4527 saw_error = B_TRUE;
4528 return;
4530 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4531 saw_error = B_TRUE;
4532 return;
4534 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4535 zone_perror(zone, err, B_TRUE);
4536 else
4537 need_to_commit = B_TRUE;
4538 return;
4539 case RT_MAXLWPS:
4540 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4541 return;
4542 case RT_MAXPROCS:
4543 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id);
4544 return;
4545 case RT_MAXSHMMEM:
4546 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4547 return;
4548 case RT_MAXSHMIDS:
4549 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4550 return;
4551 case RT_MAXMSGIDS:
4552 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4553 return;
4554 case RT_MAXSEMIDS:
4555 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4556 return;
4557 case RT_SHARES:
4558 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4559 return;
4560 case RT_HOSTID:
4561 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4562 if (err == Z_TOO_BIG) {
4563 zerr(gettext("hostid string is too large: %s"),
4564 prop_id);
4565 saw_error = B_TRUE;
4566 } else {
4567 zone_perror(pt_to_str(prop_type), err, B_TRUE);
4569 return;
4571 need_to_commit = B_TRUE;
4572 return;
4573 case RT_FS_ALLOWED:
4574 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4575 zone_perror(zone, err, B_TRUE);
4576 else
4577 need_to_commit = B_TRUE;
4578 return;
4579 case RT_FS:
4580 switch (prop_type) {
4581 case PT_DIR:
4582 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4583 sizeof (in_progress_fstab.zone_fs_dir));
4584 return;
4585 case PT_SPECIAL:
4586 (void) strlcpy(in_progress_fstab.zone_fs_special,
4587 prop_id,
4588 sizeof (in_progress_fstab.zone_fs_special));
4589 return;
4590 case PT_RAW:
4591 (void) strlcpy(in_progress_fstab.zone_fs_raw,
4592 prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4593 return;
4594 case PT_TYPE:
4595 if (!valid_fs_type(prop_id)) {
4596 zerr(gettext("\"%s\" is not a valid %s."),
4597 prop_id, pt_to_str(PT_TYPE));
4598 saw_error = B_TRUE;
4599 return;
4601 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4602 sizeof (in_progress_fstab.zone_fs_type));
4603 return;
4604 case PT_OPTIONS:
4605 if (pp->pv_type != PROP_VAL_SIMPLE &&
4606 pp->pv_type != PROP_VAL_LIST) {
4607 zerr(gettext("A %s or %s value was expected "
4608 "here."), pvt_to_str(PROP_VAL_SIMPLE),
4609 pvt_to_str(PROP_VAL_LIST));
4610 saw_error = B_TRUE;
4611 return;
4613 zonecfg_free_fs_option_list(
4614 in_progress_fstab.zone_fs_options);
4615 in_progress_fstab.zone_fs_options = NULL;
4616 if (!(pp->pv_type == PROP_VAL_LIST &&
4617 pp->pv_list == NULL))
4618 add_property(cmd);
4619 return;
4620 default:
4621 break;
4623 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4624 long_usage(CMD_SET, B_TRUE);
4625 usage(B_FALSE, HELP_PROPS);
4626 return;
4627 case RT_NET:
4628 switch (prop_type) {
4629 case PT_ADDRESS:
4630 case PT_ALLOWED_ADDRESS:
4631 if (validate_net_address_syntax(prop_id, B_FALSE)
4632 != Z_OK) {
4633 saw_error = B_TRUE;
4634 return;
4636 set_in_progress_nwiftab_address(prop_id, prop_type);
4637 break;
4638 case PT_PHYSICAL:
4639 if (validate_net_physical_syntax(prop_id) != Z_OK) {
4640 saw_error = B_TRUE;
4641 return;
4643 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4644 prop_id,
4645 sizeof (in_progress_nwiftab.zone_nwif_physical));
4646 break;
4647 case PT_DEFROUTER:
4648 if (validate_net_address_syntax(prop_id, B_TRUE)
4649 != Z_OK) {
4650 saw_error = B_TRUE;
4651 return;
4653 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4654 prop_id,
4655 sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4656 break;
4657 default:
4658 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4659 B_TRUE);
4660 long_usage(CMD_SET, B_TRUE);
4661 usage(B_FALSE, HELP_PROPS);
4662 return;
4664 return;
4665 case RT_DEVICE:
4666 switch (prop_type) {
4667 case PT_MATCH:
4668 (void) strlcpy(in_progress_devtab.zone_dev_match,
4669 prop_id,
4670 sizeof (in_progress_devtab.zone_dev_match));
4671 break;
4672 default:
4673 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4674 B_TRUE);
4675 long_usage(CMD_SET, B_TRUE);
4676 usage(B_FALSE, HELP_PROPS);
4677 return;
4679 return;
4680 case RT_RCTL:
4681 switch (prop_type) {
4682 case PT_NAME:
4683 if (!zonecfg_valid_rctlname(prop_id)) {
4684 zerr(gettext("'%s' is not a valid zone %s "
4685 "name."), prop_id, rt_to_str(RT_RCTL));
4686 return;
4688 (void) strlcpy(in_progress_rctltab.zone_rctl_name,
4689 prop_id,
4690 sizeof (in_progress_rctltab.zone_rctl_name));
4691 break;
4692 case PT_VALUE:
4693 if (pp->pv_type != PROP_VAL_COMPLEX &&
4694 pp->pv_type != PROP_VAL_LIST) {
4695 zerr(gettext("A %s or %s value was expected "
4696 "here."), pvt_to_str(PROP_VAL_COMPLEX),
4697 pvt_to_str(PROP_VAL_LIST));
4698 saw_error = B_TRUE;
4699 return;
4701 zonecfg_free_rctl_value_list(
4702 in_progress_rctltab.zone_rctl_valptr);
4703 in_progress_rctltab.zone_rctl_valptr = NULL;
4704 if (!(pp->pv_type == PROP_VAL_LIST &&
4705 pp->pv_list == NULL))
4706 add_property(cmd);
4707 break;
4708 default:
4709 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4710 B_TRUE);
4711 long_usage(CMD_SET, B_TRUE);
4712 usage(B_FALSE, HELP_PROPS);
4713 return;
4715 return;
4716 case RT_ATTR:
4717 switch (prop_type) {
4718 case PT_NAME:
4719 (void) strlcpy(in_progress_attrtab.zone_attr_name,
4720 prop_id,
4721 sizeof (in_progress_attrtab.zone_attr_name));
4722 break;
4723 case PT_TYPE:
4724 (void) strlcpy(in_progress_attrtab.zone_attr_type,
4725 prop_id,
4726 sizeof (in_progress_attrtab.zone_attr_type));
4727 break;
4728 case PT_VALUE:
4729 (void) strlcpy(in_progress_attrtab.zone_attr_value,
4730 prop_id,
4731 sizeof (in_progress_attrtab.zone_attr_value));
4732 break;
4733 default:
4734 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4735 B_TRUE);
4736 long_usage(CMD_SET, B_TRUE);
4737 usage(B_FALSE, HELP_PROPS);
4738 return;
4740 return;
4741 case RT_DATASET:
4742 switch (prop_type) {
4743 case PT_NAME:
4744 (void) strlcpy(in_progress_dstab.zone_dataset_name,
4745 prop_id,
4746 sizeof (in_progress_dstab.zone_dataset_name));
4747 return;
4748 default:
4749 break;
4751 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4752 long_usage(CMD_SET, B_TRUE);
4753 usage(B_FALSE, HELP_PROPS);
4754 return;
4755 case RT_DCPU:
4756 switch (prop_type) {
4757 char *lowp, *highp;
4759 case PT_NCPUS:
4760 lowp = prop_id;
4761 if ((highp = strchr(prop_id, '-')) != NULL)
4762 *highp++ = '\0';
4763 else
4764 highp = lowp;
4766 /* Make sure the input makes sense. */
4767 if (!zonecfg_valid_ncpus(lowp, highp)) {
4768 zerr(gettext("%s property is out of range."),
4769 pt_to_str(PT_NCPUS));
4770 saw_error = B_TRUE;
4771 return;
4774 (void) strlcpy(
4775 in_progress_psettab.zone_ncpu_min, lowp,
4776 sizeof (in_progress_psettab.zone_ncpu_min));
4777 (void) strlcpy(
4778 in_progress_psettab.zone_ncpu_max, highp,
4779 sizeof (in_progress_psettab.zone_ncpu_max));
4780 return;
4781 case PT_IMPORTANCE:
4782 /* Make sure the value makes sense. */
4783 if (!zonecfg_valid_importance(prop_id)) {
4784 zerr(gettext("%s property is out of range."),
4785 pt_to_str(PT_IMPORTANCE));
4786 saw_error = B_TRUE;
4787 return;
4790 (void) strlcpy(in_progress_psettab.zone_importance,
4791 prop_id,
4792 sizeof (in_progress_psettab.zone_importance));
4793 return;
4794 default:
4795 break;
4797 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4798 long_usage(CMD_SET, B_TRUE);
4799 usage(B_FALSE, HELP_PROPS);
4800 return;
4801 case RT_PCAP:
4802 if (prop_type != PT_NCPUS) {
4803 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4804 B_TRUE);
4805 long_usage(CMD_SET, B_TRUE);
4806 usage(B_FALSE, HELP_PROPS);
4807 return;
4811 * We already checked that an rctl alias is allowed in
4812 * the add_resource() function.
4815 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4816 (int)(cap * 100) < 1) {
4817 zerr(gettext("%s property is out of range."),
4818 pt_to_str(PT_NCPUS));
4819 saw_error = B_TRUE;
4820 return;
4823 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4824 (int)(cap * 100))) != Z_OK)
4825 zone_perror(zone, err, B_TRUE);
4826 else
4827 need_to_commit = B_TRUE;
4828 return;
4829 case RT_MCAP:
4830 switch (prop_type) {
4831 case PT_PHYSICAL:
4832 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4833 zerr(gettext("A positive number with a "
4834 "required scale suffix (K, M, G or T) was "
4835 "expected here."));
4836 saw_error = B_TRUE;
4837 } else if (mem_cap < ONE_MB) {
4838 zerr(gettext("%s value is too small. It must "
4839 "be at least 1M."), pt_to_str(PT_PHYSICAL));
4840 saw_error = B_TRUE;
4841 } else {
4842 snprintf(in_progress_mcaptab.zone_physmem_cap,
4843 physmem_size, "%llu", mem_cap);
4845 break;
4846 case PT_SWAP:
4848 * We have to check if an rctl is allowed here since
4849 * there might already be a rctl defined that blocks
4850 * the alias.
4852 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4853 zone_perror(pt_to_str(PT_MAXSWAP),
4854 Z_ALIAS_DISALLOW, B_FALSE);
4855 saw_error = B_TRUE;
4856 return;
4859 if (global_zone)
4860 mem_limit = ONE_MB * 100;
4861 else
4862 mem_limit = ONE_MB * 50;
4864 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4865 zerr(gettext("A positive number with a "
4866 "required scale suffix (K, M, G or T) was "
4867 "expected here."));
4868 saw_error = B_TRUE;
4869 } else if (mem_cap < mem_limit) {
4870 char buf[128];
4872 (void) snprintf(buf, sizeof (buf), "%llu",
4873 mem_limit);
4874 bytes_to_units(buf, buf, sizeof (buf));
4875 zerr(gettext("%s value is too small. It must "
4876 "be at least %s."), pt_to_str(PT_SWAP),
4877 buf);
4878 saw_error = B_TRUE;
4879 } else {
4880 if ((err = zonecfg_set_aliased_rctl(handle,
4881 ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4882 zone_perror(zone, err, B_TRUE);
4883 else
4884 need_to_commit = B_TRUE;
4886 break;
4887 case PT_LOCKED:
4889 * We have to check if an rctl is allowed here since
4890 * there might already be a rctl defined that blocks
4891 * the alias.
4893 if (!zonecfg_aliased_rctl_ok(handle,
4894 ALIAS_MAXLOCKEDMEM)) {
4895 zone_perror(pt_to_str(PT_LOCKED),
4896 Z_ALIAS_DISALLOW, B_FALSE);
4897 saw_error = B_TRUE;
4898 return;
4901 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4902 zerr(gettext("A non-negative number with a "
4903 "required scale suffix (K, M, G or T) was "
4904 "expected\nhere."));
4905 saw_error = B_TRUE;
4906 } else {
4907 if ((err = zonecfg_set_aliased_rctl(handle,
4908 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4909 zone_perror(zone, err, B_TRUE);
4910 else
4911 need_to_commit = B_TRUE;
4913 break;
4914 default:
4915 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4916 B_TRUE);
4917 long_usage(CMD_SET, B_TRUE);
4918 usage(B_FALSE, HELP_PROPS);
4919 return;
4921 return;
4922 case RT_ADMIN:
4923 switch (prop_type) {
4924 case PT_USER:
4925 (void) strlcpy(in_progress_admintab.zone_admin_user,
4926 prop_id,
4927 sizeof (in_progress_admintab.zone_admin_user));
4928 return;
4929 case PT_AUTHS:
4930 (void) strlcpy(in_progress_admintab.zone_admin_auths,
4931 prop_id,
4932 sizeof (in_progress_admintab.zone_admin_auths));
4933 return;
4934 default:
4935 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4936 B_TRUE);
4937 long_usage(CMD_SET, B_TRUE);
4938 usage(B_FALSE, HELP_PROPS);
4939 return;
4941 case RT_SECFLAGS: {
4942 char *propstr;
4944 switch (prop_type) {
4945 case PT_DEFAULT:
4946 propstr = in_progress_secflagstab.zone_secflags_default;
4947 break;
4948 case PT_UPPER:
4949 propstr = in_progress_secflagstab.zone_secflags_upper;
4950 break;
4951 case PT_LOWER:
4952 propstr = in_progress_secflagstab.zone_secflags_lower;
4953 break;
4954 default:
4955 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4956 B_TRUE);
4957 long_usage(CMD_SET, B_TRUE);
4958 usage(B_FALSE, HELP_PROPS);
4959 return;
4961 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
4962 return;
4964 default:
4965 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4966 long_usage(CMD_SET, B_TRUE);
4967 usage(B_FALSE, HELP_RESOURCES);
4968 return;
4972 static void
4973 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4975 char *qstr;
4977 if (*pval != '\0') {
4978 qstr = quoteit(pval);
4979 if (pnum == PT_SWAP || pnum == PT_LOCKED)
4980 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4981 qstr);
4982 else
4983 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4984 free(qstr);
4985 } else if (print_notspec)
4986 (void) fprintf(fp, gettext("\t%s not specified\n"),
4987 pt_to_str(pnum));
4990 static void
4991 info_zonename(zone_dochandle_t handle, FILE *fp)
4993 char zonename[ZONENAME_MAX];
4995 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4996 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4997 zonename);
4998 else
4999 (void) fprintf(fp, gettext("%s not specified\n"),
5000 pt_to_str(PT_ZONENAME));
5003 static void
5004 info_zonepath(zone_dochandle_t handle, FILE *fp)
5006 char zonepath[MAXPATHLEN];
5008 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
5009 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
5010 zonepath);
5011 else {
5012 (void) fprintf(fp, gettext("%s not specified\n"),
5013 pt_to_str(PT_ZONEPATH));
5017 static void
5018 info_brand(zone_dochandle_t handle, FILE *fp)
5020 char brand[MAXNAMELEN];
5022 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
5023 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
5024 brand);
5025 else
5026 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
5027 gettext("not specified"));
5030 static void
5031 info_autoboot(zone_dochandle_t handle, FILE *fp)
5033 boolean_t autoboot;
5034 int err;
5036 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
5037 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
5038 autoboot ? "true" : "false");
5039 else
5040 zone_perror(zone, err, B_TRUE);
5043 static void
5044 info_pool(zone_dochandle_t handle, FILE *fp)
5046 char pool[MAXNAMELEN];
5047 int err;
5049 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
5050 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
5051 else
5052 zone_perror(zone, err, B_TRUE);
5055 static void
5056 info_limitpriv(zone_dochandle_t handle, FILE *fp)
5058 char *limitpriv;
5059 int err;
5061 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
5062 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
5063 limitpriv);
5064 free(limitpriv);
5065 } else {
5066 zone_perror(zone, err, B_TRUE);
5070 static void
5071 info_bootargs(zone_dochandle_t handle, FILE *fp)
5073 char bootargs[BOOTARGS_MAX];
5074 int err;
5076 if ((err = zonecfg_get_bootargs(handle, bootargs,
5077 sizeof (bootargs))) == Z_OK) {
5078 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
5079 bootargs);
5080 } else {
5081 zone_perror(zone, err, B_TRUE);
5085 static void
5086 info_sched(zone_dochandle_t handle, FILE *fp)
5088 char sched[MAXNAMELEN];
5089 int err;
5091 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
5092 == Z_OK) {
5093 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
5094 } else {
5095 zone_perror(zone, err, B_TRUE);
5099 static void
5100 info_iptype(zone_dochandle_t handle, FILE *fp)
5102 zone_iptype_t iptype;
5103 int err;
5105 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
5106 switch (iptype) {
5107 case ZS_SHARED:
5108 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5109 "shared");
5110 break;
5111 case ZS_EXCLUSIVE:
5112 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5113 "exclusive");
5114 break;
5116 } else {
5117 zone_perror(zone, err, B_TRUE);
5121 static void
5122 info_hostid(zone_dochandle_t handle, FILE *fp)
5124 char hostidp[HW_HOSTID_LEN];
5125 int err;
5127 if ((err = zonecfg_get_hostid(handle, hostidp,
5128 sizeof (hostidp))) == Z_OK) {
5129 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
5130 } else if (err == Z_BAD_PROPERTY) {
5131 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
5132 } else {
5133 zone_perror(zone, err, B_TRUE);
5137 static void
5138 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
5140 char fsallowedp[ZONE_FS_ALLOWED_MAX];
5141 int err;
5143 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
5144 sizeof (fsallowedp))) == Z_OK) {
5145 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
5146 fsallowedp);
5147 } else if (err == Z_BAD_PROPERTY) {
5148 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
5149 } else {
5150 zone_perror(zone, err, B_TRUE);
5154 static void
5155 output_fs(FILE *fp, struct zone_fstab *fstab)
5157 zone_fsopt_t *this;
5159 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
5160 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
5161 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
5162 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
5163 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
5164 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
5165 for (this = fstab->zone_fs_options; this != NULL;
5166 this = this->zone_fsopt_next) {
5167 if (strchr(this->zone_fsopt_opt, '='))
5168 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
5169 else
5170 (void) fprintf(fp, "%s", this->zone_fsopt_opt);
5171 if (this->zone_fsopt_next != NULL)
5172 (void) fprintf(fp, ",");
5174 (void) fprintf(fp, "]\n");
5177 static void
5178 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5180 struct zone_fstab lookup, user;
5181 boolean_t output = B_FALSE;
5183 if (zonecfg_setfsent(handle) != Z_OK)
5184 return;
5185 while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
5186 if (cmd->cmd_prop_nv_pairs == 0) {
5187 output_fs(fp, &lookup);
5188 goto loopend;
5190 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
5191 goto loopend;
5192 if (strlen(user.zone_fs_dir) > 0 &&
5193 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5194 goto loopend; /* no match */
5195 if (strlen(user.zone_fs_special) > 0 &&
5196 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5197 goto loopend; /* no match */
5198 if (strlen(user.zone_fs_type) > 0 &&
5199 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5200 goto loopend; /* no match */
5201 output_fs(fp, &lookup);
5202 output = B_TRUE;
5203 loopend:
5204 zonecfg_free_fs_option_list(lookup.zone_fs_options);
5206 (void) zonecfg_endfsent(handle);
5208 * If a property n/v pair was specified, warn the user if there was
5209 * nothing to output.
5211 if (!output && cmd->cmd_prop_nv_pairs > 0)
5212 (void) printf(gettext("No such %s resource.\n"),
5213 rt_to_str(RT_FS));
5216 static void
5217 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5219 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5220 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5221 output_prop(fp, PT_ALLOWED_ADDRESS,
5222 nwiftab->zone_nwif_allowed_address, B_TRUE);
5223 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5224 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5227 static void
5228 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5230 struct zone_nwiftab lookup, user;
5231 boolean_t output = B_FALSE;
5233 if (zonecfg_setnwifent(handle) != Z_OK)
5234 return;
5235 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5236 if (cmd->cmd_prop_nv_pairs == 0) {
5237 output_net(fp, &lookup);
5238 continue;
5240 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5241 continue;
5242 if (strlen(user.zone_nwif_physical) > 0 &&
5243 strcmp(user.zone_nwif_physical,
5244 lookup.zone_nwif_physical) != 0)
5245 continue; /* no match */
5246 /* If present make sure it matches */
5247 if (strlen(user.zone_nwif_address) > 0 &&
5248 !zonecfg_same_net_address(user.zone_nwif_address,
5249 lookup.zone_nwif_address))
5250 continue; /* no match */
5251 output_net(fp, &lookup);
5252 output = B_TRUE;
5254 (void) zonecfg_endnwifent(handle);
5256 * If a property n/v pair was specified, warn the user if there was
5257 * nothing to output.
5259 if (!output && cmd->cmd_prop_nv_pairs > 0)
5260 (void) printf(gettext("No such %s resource.\n"),
5261 rt_to_str(RT_NET));
5264 static void
5265 output_dev(FILE *fp, struct zone_devtab *devtab)
5267 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5268 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5271 static void
5272 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5274 struct zone_devtab lookup, user;
5275 boolean_t output = B_FALSE;
5277 if (zonecfg_setdevent(handle) != Z_OK)
5278 return;
5279 while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5280 if (cmd->cmd_prop_nv_pairs == 0) {
5281 output_dev(fp, &lookup);
5282 continue;
5284 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5285 continue;
5286 if (strlen(user.zone_dev_match) > 0 &&
5287 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5288 continue; /* no match */
5289 output_dev(fp, &lookup);
5290 output = B_TRUE;
5292 (void) zonecfg_enddevent(handle);
5294 * If a property n/v pair was specified, warn the user if there was
5295 * nothing to output.
5297 if (!output && cmd->cmd_prop_nv_pairs > 0)
5298 (void) printf(gettext("No such %s resource.\n"),
5299 rt_to_str(RT_DEVICE));
5302 static void
5303 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5305 struct zone_rctlvaltab *valptr;
5307 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5308 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5309 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5310 valptr = valptr->zone_rctlval_next) {
5311 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5312 pt_to_str(PT_VALUE),
5313 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5314 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5315 pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5319 static void
5320 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5322 struct zone_rctltab lookup, user;
5323 boolean_t output = B_FALSE;
5325 if (zonecfg_setrctlent(handle) != Z_OK)
5326 return;
5327 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5328 if (cmd->cmd_prop_nv_pairs == 0) {
5329 output_rctl(fp, &lookup);
5330 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5331 (strlen(user.zone_rctl_name) == 0 ||
5332 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5333 output_rctl(fp, &lookup);
5334 output = B_TRUE;
5336 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5338 (void) zonecfg_endrctlent(handle);
5340 * If a property n/v pair was specified, warn the user if there was
5341 * nothing to output.
5343 if (!output && cmd->cmd_prop_nv_pairs > 0)
5344 (void) printf(gettext("No such %s resource.\n"),
5345 rt_to_str(RT_RCTL));
5348 static void
5349 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5351 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5352 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5353 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5354 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5357 static void
5358 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5360 struct zone_attrtab lookup, user;
5361 boolean_t output = B_FALSE;
5363 if (zonecfg_setattrent(handle) != Z_OK)
5364 return;
5365 while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5366 if (cmd->cmd_prop_nv_pairs == 0) {
5367 output_attr(fp, &lookup);
5368 continue;
5370 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5371 continue;
5372 if (strlen(user.zone_attr_name) > 0 &&
5373 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5374 continue; /* no match */
5375 if (strlen(user.zone_attr_type) > 0 &&
5376 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5377 continue; /* no match */
5378 if (strlen(user.zone_attr_value) > 0 &&
5379 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5380 continue; /* no match */
5381 output_attr(fp, &lookup);
5382 output = B_TRUE;
5384 (void) zonecfg_endattrent(handle);
5386 * If a property n/v pair was specified, warn the user if there was
5387 * nothing to output.
5389 if (!output && cmd->cmd_prop_nv_pairs > 0)
5390 (void) printf(gettext("No such %s resource.\n"),
5391 rt_to_str(RT_ATTR));
5394 static void
5395 output_ds(FILE *fp, struct zone_dstab *dstab)
5397 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5398 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5401 static void
5402 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5404 struct zone_dstab lookup, user;
5405 boolean_t output = B_FALSE;
5407 if (zonecfg_setdsent(handle) != Z_OK)
5408 return;
5409 while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5410 if (cmd->cmd_prop_nv_pairs == 0) {
5411 output_ds(fp, &lookup);
5412 continue;
5414 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5415 continue;
5416 if (strlen(user.zone_dataset_name) > 0 &&
5417 strcmp(user.zone_dataset_name,
5418 lookup.zone_dataset_name) != 0)
5419 continue; /* no match */
5420 output_ds(fp, &lookup);
5421 output = B_TRUE;
5423 (void) zonecfg_enddsent(handle);
5425 * If a property n/v pair was specified, warn the user if there was
5426 * nothing to output.
5428 if (!output && cmd->cmd_prop_nv_pairs > 0)
5429 (void) printf(gettext("No such %s resource.\n"),
5430 rt_to_str(RT_DATASET));
5433 static void
5434 output_pset(FILE *fp, struct zone_psettab *psettab)
5436 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5437 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5438 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5439 psettab->zone_ncpu_max);
5440 else
5441 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5442 psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5443 if (psettab->zone_importance[0] != '\0')
5444 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5445 psettab->zone_importance);
5448 static void
5449 info_pset(zone_dochandle_t handle, FILE *fp)
5451 struct zone_psettab lookup;
5453 if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5454 output_pset(fp, &lookup);
5457 static void
5458 output_pcap(FILE *fp)
5460 uint64_t cap;
5462 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5463 float scaled = (float)cap / 100;
5464 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5465 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5466 scaled);
5470 static void
5471 info_pcap(FILE *fp)
5473 output_pcap(fp);
5477 static void
5478 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5480 uint64_t limit;
5482 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5483 /* convert memory based properties */
5484 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5485 char buf[128];
5487 (void) snprintf(buf, sizeof (buf), "%llu", limit);
5488 bytes_to_units(buf, buf, sizeof (buf));
5489 (void) fprintf(fp, "[%s: %s]\n", alias, buf);
5490 return;
5493 (void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5497 static void
5498 bytes_to_units(char *str, char *buf, int bufsize)
5500 unsigned long long num;
5501 unsigned long long save = 0;
5502 char *units = "BKMGT";
5503 char *up = units;
5505 num = strtoll(str, NULL, 10);
5507 if (num < 1024) {
5508 (void) snprintf(buf, bufsize, "%llu", num);
5509 return;
5512 while ((num >= 1024) && (*up != 'T')) {
5513 up++; /* next unit of measurement */
5514 save = num;
5515 num = (num + 512) >> 10;
5518 /* check if we should output a fraction. snprintf will round for us */
5519 if (save % 1024 != 0 && ((save >> 10) < 10))
5520 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5521 *up);
5522 else
5523 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
5526 static void
5527 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5528 uint64_t maxswap, int showlocked, uint64_t maxlocked)
5530 char buf[128];
5532 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5533 if (mcaptab->zone_physmem_cap[0] != '\0') {
5534 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5535 output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5538 if (showswap == Z_OK) {
5539 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5540 bytes_to_units(buf, buf, sizeof (buf));
5541 output_prop(fp, PT_SWAP, buf, B_TRUE);
5544 if (showlocked == Z_OK) {
5545 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5546 bytes_to_units(buf, buf, sizeof (buf));
5547 output_prop(fp, PT_LOCKED, buf, B_TRUE);
5551 static void
5552 info_mcap(zone_dochandle_t handle, FILE *fp)
5554 int res1, res2, res3;
5555 uint64_t swap_limit;
5556 uint64_t locked_limit;
5557 struct zone_mcaptab lookup;
5559 bzero(&lookup, sizeof (lookup));
5560 res1 = zonecfg_getmcapent(handle, &lookup);
5561 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5562 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5563 &locked_limit);
5565 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5566 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5569 static void
5570 output_auth(FILE *fp, struct zone_admintab *admintab)
5572 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5573 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5574 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5577 static void
5578 output_secflags(FILE *fp, struct zone_secflagstab *sftab)
5580 (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
5581 output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
5582 output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
5583 output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
5586 static void
5587 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5589 struct zone_admintab lookup, user;
5590 boolean_t output = B_FALSE;
5591 int err;
5593 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5594 zone_perror(zone, err, B_TRUE);
5595 return;
5597 while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5598 if (cmd->cmd_prop_nv_pairs == 0) {
5599 output_auth(fp, &lookup);
5600 continue;
5602 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5603 continue;
5604 if (strlen(user.zone_admin_user) > 0 &&
5605 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5606 continue; /* no match */
5607 output_auth(fp, &lookup);
5608 output = B_TRUE;
5610 (void) zonecfg_endadminent(handle);
5612 * If a property n/v pair was specified, warn the user if there was
5613 * nothing to output.
5615 if (!output && cmd->cmd_prop_nv_pairs > 0)
5616 (void) printf(gettext("No such %s resource.\n"),
5617 rt_to_str(RT_ADMIN));
5620 static void
5621 info_secflags(zone_dochandle_t handle, FILE *fp)
5623 struct zone_secflagstab sftab;
5625 if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) {
5626 output_secflags(fp, &sftab);
5630 void
5631 info_func(cmd_t *cmd)
5633 FILE *fp = stdout;
5634 boolean_t need_to_close = B_FALSE;
5635 int type;
5636 int res1, res2;
5637 uint64_t swap_limit;
5638 uint64_t locked_limit;
5640 assert(cmd != NULL);
5642 if (initialize(B_TRUE) != Z_OK)
5643 return;
5645 /* don't page error output */
5646 if (interactive_mode) {
5647 if ((fp = pager_open()) != NULL)
5648 need_to_close = B_TRUE;
5649 else
5650 fp = stdout;
5652 setbuf(fp, NULL);
5655 if (!global_scope) {
5656 switch (resource_scope) {
5657 case RT_FS:
5658 output_fs(fp, &in_progress_fstab);
5659 break;
5660 case RT_NET:
5661 output_net(fp, &in_progress_nwiftab);
5662 break;
5663 case RT_DEVICE:
5664 output_dev(fp, &in_progress_devtab);
5665 break;
5666 case RT_RCTL:
5667 output_rctl(fp, &in_progress_rctltab);
5668 break;
5669 case RT_ATTR:
5670 output_attr(fp, &in_progress_attrtab);
5671 break;
5672 case RT_DATASET:
5673 output_ds(fp, &in_progress_dstab);
5674 break;
5675 case RT_DCPU:
5676 output_pset(fp, &in_progress_psettab);
5677 break;
5678 case RT_PCAP:
5679 output_pcap(fp);
5680 break;
5681 case RT_MCAP:
5682 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5683 &swap_limit);
5684 res2 = zonecfg_get_aliased_rctl(handle,
5685 ALIAS_MAXLOCKEDMEM, &locked_limit);
5686 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5687 res2, locked_limit);
5688 break;
5689 case RT_ADMIN:
5690 output_auth(fp, &in_progress_admintab);
5691 break;
5692 case RT_SECFLAGS:
5693 output_secflags(fp, &in_progress_secflagstab);
5694 break;
5696 goto cleanup;
5699 type = cmd->cmd_res_type;
5701 if (gz_invalid_rt_property(type)) {
5702 zerr(gettext("%s is not a valid property for the global zone."),
5703 rt_to_str(type));
5704 goto cleanup;
5707 if (gz_invalid_resource(type)) {
5708 zerr(gettext("%s is not a valid resource for the global zone."),
5709 rt_to_str(type));
5710 goto cleanup;
5713 switch (cmd->cmd_res_type) {
5714 case RT_UNKNOWN:
5715 info_zonename(handle, fp);
5716 if (!global_zone) {
5717 info_zonepath(handle, fp);
5718 info_brand(handle, fp);
5719 info_autoboot(handle, fp);
5720 info_bootargs(handle, fp);
5722 info_pool(handle, fp);
5723 if (!global_zone) {
5724 info_limitpriv(handle, fp);
5725 info_sched(handle, fp);
5726 info_iptype(handle, fp);
5727 info_hostid(handle, fp);
5728 info_fs_allowed(handle, fp);
5730 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5731 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5732 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5733 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5734 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5735 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5736 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5737 if (!global_zone) {
5738 info_fs(handle, fp, cmd);
5739 info_net(handle, fp, cmd);
5740 info_dev(handle, fp, cmd);
5742 info_pset(handle, fp);
5743 info_pcap(fp);
5744 info_mcap(handle, fp);
5745 if (!global_zone) {
5746 info_attr(handle, fp, cmd);
5747 info_ds(handle, fp, cmd);
5748 info_auth(handle, fp, cmd);
5750 info_rctl(handle, fp, cmd);
5751 info_secflags(handle, fp);
5752 break;
5753 case RT_ZONENAME:
5754 info_zonename(handle, fp);
5755 break;
5756 case RT_ZONEPATH:
5757 info_zonepath(handle, fp);
5758 break;
5759 case RT_BRAND:
5760 info_brand(handle, fp);
5761 break;
5762 case RT_AUTOBOOT:
5763 info_autoboot(handle, fp);
5764 break;
5765 case RT_POOL:
5766 info_pool(handle, fp);
5767 break;
5768 case RT_LIMITPRIV:
5769 info_limitpriv(handle, fp);
5770 break;
5771 case RT_BOOTARGS:
5772 info_bootargs(handle, fp);
5773 break;
5774 case RT_SCHED:
5775 info_sched(handle, fp);
5776 break;
5777 case RT_IPTYPE:
5778 info_iptype(handle, fp);
5779 break;
5780 case RT_MAXLWPS:
5781 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5782 break;
5783 case RT_MAXPROCS:
5784 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5785 break;
5786 case RT_MAXSHMMEM:
5787 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5788 break;
5789 case RT_MAXSHMIDS:
5790 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5791 break;
5792 case RT_MAXMSGIDS:
5793 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5794 break;
5795 case RT_MAXSEMIDS:
5796 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5797 break;
5798 case RT_SHARES:
5799 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5800 break;
5801 case RT_FS:
5802 info_fs(handle, fp, cmd);
5803 break;
5804 case RT_NET:
5805 info_net(handle, fp, cmd);
5806 break;
5807 case RT_DEVICE:
5808 info_dev(handle, fp, cmd);
5809 break;
5810 case RT_RCTL:
5811 info_rctl(handle, fp, cmd);
5812 break;
5813 case RT_ATTR:
5814 info_attr(handle, fp, cmd);
5815 break;
5816 case RT_DATASET:
5817 info_ds(handle, fp, cmd);
5818 break;
5819 case RT_DCPU:
5820 info_pset(handle, fp);
5821 break;
5822 case RT_PCAP:
5823 info_pcap(fp);
5824 break;
5825 case RT_MCAP:
5826 info_mcap(handle, fp);
5827 break;
5828 case RT_HOSTID:
5829 info_hostid(handle, fp);
5830 break;
5831 case RT_ADMIN:
5832 info_auth(handle, fp, cmd);
5833 break;
5834 case RT_FS_ALLOWED:
5835 info_fs_allowed(handle, fp);
5836 break;
5837 case RT_SECFLAGS:
5838 info_secflags(handle, fp);
5839 break;
5840 default:
5841 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5842 B_TRUE);
5845 cleanup:
5846 if (need_to_close)
5847 (void) pager_close(fp);
5851 * Helper function for verify-- checks that a required string property
5852 * exists.
5854 static void
5855 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5857 if (strlen(attr) == 0) {
5858 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5859 pt_to_str(pt));
5860 saw_error = B_TRUE;
5861 if (*ret_val == Z_OK)
5862 *ret_val = Z_REQD_PROPERTY_MISSING;
5866 static int
5867 do_subproc(char *cmdbuf)
5869 char inbuf[MAX_CMD_LEN];
5870 FILE *file;
5871 int status;
5873 file = popen(cmdbuf, "r");
5874 if (file == NULL) {
5875 zerr(gettext("Could not launch: %s"), cmdbuf);
5876 return (-1);
5879 while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5880 fprintf(stderr, "%s", inbuf);
5881 status = pclose(file);
5883 if (WIFSIGNALED(status)) {
5884 zerr(gettext("%s unexpectedly terminated due to signal %d"),
5885 cmdbuf, WTERMSIG(status));
5886 return (-1);
5888 assert(WIFEXITED(status));
5889 return (WEXITSTATUS(status));
5892 static int
5893 brand_verify(zone_dochandle_t handle)
5895 char xml_file[32];
5896 char cmdbuf[MAX_CMD_LEN];
5897 brand_handle_t bh;
5898 char brand[MAXNAMELEN];
5899 int err;
5901 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5902 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5903 return (Z_INVALID_DOCUMENT);
5905 if ((bh = brand_open(brand)) == NULL) {
5906 zerr("%s: %s\n", zone, gettext("unknown brand."));
5907 return (Z_INVALID_DOCUMENT);
5911 * Fetch the verify command, if any, from the brand configuration
5912 * and build the command line to execute it.
5914 strcpy(cmdbuf, EXEC_PREFIX);
5915 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5916 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5917 brand_close(bh);
5918 if (err != Z_OK) {
5919 zerr("%s: %s\n", zone,
5920 gettext("could not get brand verification command"));
5921 return (Z_INVALID_DOCUMENT);
5925 * If the brand doesn't provide a verification routine, we just
5926 * return success.
5928 if (strlen(cmdbuf) == EXEC_LEN)
5929 return (Z_OK);
5932 * Dump the current config information for this zone to a file.
5934 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5935 if (mkstemp(xml_file) == NULL)
5936 return (Z_TEMP_FILE);
5937 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5938 (void) unlink(xml_file);
5939 return (err);
5943 * Execute the verification command.
5945 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5946 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5947 err = Z_BRAND_ERROR;
5948 } else {
5949 err = do_subproc(cmdbuf);
5952 (void) unlink(xml_file);
5953 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5957 * Track the network interfaces listed in zonecfg(1m) in a linked list
5958 * so that we can later check that defrouter is specified for an exclusive IP
5959 * zone if and only if at least one allowed-address has been specified.
5961 static boolean_t
5962 add_nwif(struct zone_nwiftab *nwif)
5964 struct xif *tmp;
5966 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5967 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
5968 if (strlen(nwif->zone_nwif_allowed_address) > 0)
5969 tmp->xif_has_address = B_TRUE;
5970 if (strlen(nwif->zone_nwif_defrouter) > 0)
5971 tmp->xif_has_defrouter = B_TRUE;
5972 return (B_TRUE);
5976 tmp = malloc(sizeof (*tmp));
5977 if (tmp == NULL) {
5978 zerr(gettext("memory allocation failed for %s"),
5979 nwif->zone_nwif_physical);
5980 return (B_FALSE);
5982 strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
5983 sizeof (tmp->xif_name));
5984 tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
5985 tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
5986 tmp->xif_next = xif;
5987 xif = tmp;
5988 return (B_TRUE);
5991 boolean_t
5992 verify_secflags(struct zone_secflagstab *tab)
5994 secflagdelta_t def = {0};
5995 secflagdelta_t upper = {0};
5996 secflagdelta_t lower = {0};
5997 boolean_t def_set = B_FALSE;
5998 boolean_t upper_set = B_FALSE;
5999 boolean_t lower_set = B_FALSE;
6000 boolean_t ret = B_TRUE;
6002 if (strlen(tab->zone_secflags_default) > 0) {
6003 def_set = B_TRUE;
6004 if (secflags_parse(NULL, tab->zone_secflags_default,
6005 &def) == -1) {
6006 zerr(gettext("default security flags '%s' are invalid"),
6007 tab->zone_secflags_default);
6008 ret = B_FALSE;
6010 } else {
6011 secflags_zero(&def.psd_assign);
6012 def.psd_ass_active = B_TRUE;
6015 if (strlen(tab->zone_secflags_upper) > 0) {
6016 upper_set = B_TRUE;
6017 if (secflags_parse(NULL, tab->zone_secflags_upper,
6018 &upper) == -1) {
6019 zerr(gettext("upper security flags '%s' are invalid"),
6020 tab->zone_secflags_upper);
6021 ret = B_FALSE;
6023 } else {
6024 secflags_fullset(&upper.psd_assign);
6025 upper.psd_ass_active = B_TRUE;
6028 if (strlen(tab->zone_secflags_lower) > 0) {
6029 lower_set = B_TRUE;
6030 if (secflags_parse(NULL, tab->zone_secflags_lower,
6031 &lower) == -1) {
6032 zerr(gettext("lower security flags '%s' are invalid"),
6033 tab->zone_secflags_lower);
6034 ret = B_FALSE;
6036 } else {
6037 secflags_zero(&lower.psd_assign);
6038 lower.psd_ass_active = B_TRUE;
6041 if (def_set && !def.psd_ass_active) {
6042 zerr(gettext("only assignment of security flags is "
6043 "allowed (default: %s)"), tab->zone_secflags_default);
6046 if (lower_set && !lower.psd_ass_active) {
6047 zerr(gettext("only assignment of security flags is "
6048 "allowed (lower: %s)"), tab->zone_secflags_lower);
6051 if (upper_set && !upper.psd_ass_active) {
6052 zerr(gettext("only assignment of security flags is "
6053 "allowed (upper: %s)"), tab->zone_secflags_upper);
6056 if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */
6057 zerr(gettext("default secflags must be within the "
6058 "upper limit"));
6059 ret = B_FALSE;
6061 if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
6062 zerr(gettext("default secflags must be above the lower limit"));
6063 ret = B_FALSE;
6065 if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
6066 zerr(gettext("lower secflags must be within the upper limit"));
6067 ret = B_FALSE;
6070 return (ret);
6074 * See the DTD for which attributes are required for which resources.
6076 * This function can be called by commit_func(), which needs to save things,
6077 * in addition to the general call from parse_and_run(), which doesn't need
6078 * things saved. Since the parameters are standardized, we distinguish by
6079 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
6080 * that a save is needed.
6082 void
6083 verify_func(cmd_t *cmd)
6085 struct zone_nwiftab nwiftab;
6086 struct zone_fstab fstab;
6087 struct zone_attrtab attrtab;
6088 struct zone_rctltab rctltab;
6089 struct zone_dstab dstab;
6090 struct zone_psettab psettab;
6091 struct zone_admintab admintab;
6092 struct zone_secflagstab secflagstab;
6093 char zonepath[MAXPATHLEN];
6094 char sched[MAXNAMELEN];
6095 char brand[MAXNAMELEN];
6096 char hostidp[HW_HOSTID_LEN];
6097 char fsallowedp[ZONE_FS_ALLOWED_MAX];
6098 priv_set_t *privs;
6099 char *privname = NULL;
6100 int err, ret_val = Z_OK, arg;
6101 int pset_res;
6102 boolean_t save = B_FALSE;
6103 boolean_t arg_err = B_FALSE;
6104 zone_iptype_t iptype;
6105 boolean_t has_cpu_shares = B_FALSE;
6106 boolean_t has_cpu_cap = B_FALSE;
6107 struct xif *tmp;
6109 optind = 0;
6110 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6111 switch (arg) {
6112 case '?':
6113 longer_usage(CMD_VERIFY);
6114 arg_err = B_TRUE;
6115 break;
6116 default:
6117 short_usage(CMD_VERIFY);
6118 arg_err = B_TRUE;
6119 break;
6122 if (arg_err)
6123 return;
6125 if (optind > cmd->cmd_argc) {
6126 short_usage(CMD_VERIFY);
6127 return;
6130 if (zone_is_read_only(CMD_VERIFY))
6131 return;
6133 assert(cmd != NULL);
6135 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
6136 save = B_TRUE;
6137 if (initialize(B_TRUE) != Z_OK)
6138 return;
6140 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
6141 !global_zone) {
6142 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
6143 ret_val = Z_REQD_RESOURCE_MISSING;
6144 saw_error = B_TRUE;
6146 if (strlen(zonepath) == 0 && !global_zone) {
6147 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
6148 ret_val = Z_REQD_RESOURCE_MISSING;
6149 saw_error = B_TRUE;
6152 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
6153 zone_perror(zone, err, B_TRUE);
6154 return;
6156 if ((err = brand_verify(handle)) != Z_OK) {
6157 zone_perror(zone, err, B_TRUE);
6158 return;
6161 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
6162 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
6163 ret_val = Z_REQD_RESOURCE_MISSING;
6164 saw_error = B_TRUE;
6167 if ((privs = priv_allocset()) == NULL) {
6168 zerr(gettext("%s: priv_allocset failed"), zone);
6169 return;
6171 if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) {
6172 zerr(gettext("%s: invalid privilege: %s"), zone, privname);
6173 priv_freeset(privs);
6174 free(privname);
6175 return;
6177 priv_freeset(privs);
6179 if (zonecfg_get_hostid(handle, hostidp,
6180 sizeof (hostidp)) == Z_INVALID_PROPERTY) {
6181 zerr(gettext("%s: invalid hostid: %s"),
6182 zone, hostidp);
6183 return;
6186 if (zonecfg_get_fs_allowed(handle, fsallowedp,
6187 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
6188 zerr(gettext("%s: invalid fs-allowed: %s"),
6189 zone, fsallowedp);
6190 return;
6193 if ((err = zonecfg_setfsent(handle)) != Z_OK) {
6194 zone_perror(zone, err, B_TRUE);
6195 return;
6197 while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
6198 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
6199 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
6200 &ret_val);
6201 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
6203 zonecfg_free_fs_option_list(fstab.zone_fs_options);
6205 (void) zonecfg_endfsent(handle);
6207 if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
6208 zone_perror(zone, err, B_TRUE);
6209 return;
6211 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
6213 * physical is required in all cases.
6214 * A shared IP requires an address,
6215 * and may include a default router, while
6216 * an exclusive IP must have neither an address
6217 * nor a default router.
6218 * The physical interface name must be valid in all cases.
6220 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
6221 PT_PHYSICAL, &ret_val);
6222 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
6223 Z_OK) {
6224 saw_error = B_TRUE;
6225 if (ret_val == Z_OK)
6226 ret_val = Z_INVAL;
6229 switch (iptype) {
6230 case ZS_SHARED:
6231 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
6232 PT_ADDRESS, &ret_val);
6233 if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
6234 zerr(gettext("%s: %s cannot be specified "
6235 "for a shared IP type"),
6236 rt_to_str(RT_NET),
6237 pt_to_str(PT_ALLOWED_ADDRESS));
6238 saw_error = B_TRUE;
6239 if (ret_val == Z_OK)
6240 ret_val = Z_INVAL;
6242 break;
6243 case ZS_EXCLUSIVE:
6244 if (strlen(nwiftab.zone_nwif_address) > 0) {
6245 zerr(gettext("%s: %s cannot be specified "
6246 "for an exclusive IP type"),
6247 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
6248 saw_error = B_TRUE;
6249 if (ret_val == Z_OK)
6250 ret_val = Z_INVAL;
6251 } else {
6252 if (!add_nwif(&nwiftab)) {
6253 saw_error = B_TRUE;
6254 if (ret_val == Z_OK)
6255 ret_val = Z_INVAL;
6258 break;
6261 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
6262 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
6263 zerr(gettext("%s: %s for %s cannot be specified "
6264 "without %s for an exclusive IP type"),
6265 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
6266 tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
6267 saw_error = B_TRUE;
6268 ret_val = Z_INVAL;
6271 free(xif);
6272 xif = NULL;
6273 (void) zonecfg_endnwifent(handle);
6275 if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
6276 zone_perror(zone, err, B_TRUE);
6277 return;
6279 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
6280 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
6281 &ret_val);
6283 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
6284 has_cpu_shares = B_TRUE;
6286 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
6287 has_cpu_cap = B_TRUE;
6289 if (rctltab.zone_rctl_valptr == NULL) {
6290 zerr(gettext("%s: no %s specified"),
6291 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
6292 saw_error = B_TRUE;
6293 if (ret_val == Z_OK)
6294 ret_val = Z_REQD_PROPERTY_MISSING;
6295 } else {
6296 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
6299 (void) zonecfg_endrctlent(handle);
6301 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
6302 has_cpu_shares) {
6303 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
6304 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6305 saw_error = B_TRUE;
6306 if (ret_val == Z_OK)
6307 ret_val = Z_INCOMPATIBLE;
6310 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
6311 sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
6312 strcmp(sched, "FSS") != 0) {
6313 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
6314 "incompatible"),
6315 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
6316 saw_error = B_TRUE;
6317 if (ret_val == Z_OK)
6318 ret_val = Z_INCOMPATIBLE;
6321 if (pset_res == Z_OK && has_cpu_cap) {
6322 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6323 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6324 saw_error = B_TRUE;
6325 if (ret_val == Z_OK)
6326 ret_val = Z_INCOMPATIBLE;
6329 if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6330 zone_perror(zone, err, B_TRUE);
6331 return;
6333 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6334 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6335 &ret_val);
6336 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6337 &ret_val);
6338 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6339 &ret_val);
6341 (void) zonecfg_endattrent(handle);
6343 if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6344 zone_perror(zone, err, B_TRUE);
6345 return;
6347 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6348 if (strlen(dstab.zone_dataset_name) == 0) {
6349 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6350 pt_to_str(PT_NAME), gettext("not specified"));
6351 saw_error = B_TRUE;
6352 if (ret_val == Z_OK)
6353 ret_val = Z_REQD_PROPERTY_MISSING;
6354 } else if (!zfs_name_valid(dstab.zone_dataset_name,
6355 ZFS_TYPE_FILESYSTEM)) {
6356 zerr("%s: %s %s", rt_to_str(RT_DATASET),
6357 pt_to_str(PT_NAME), gettext("invalid"));
6358 saw_error = B_TRUE;
6359 if (ret_val == Z_OK)
6360 ret_val = Z_BAD_PROPERTY;
6364 (void) zonecfg_enddsent(handle);
6366 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6367 zone_perror(zone, err, B_TRUE);
6368 return;
6370 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6371 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6372 PT_USER, &ret_val);
6373 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6374 PT_AUTHS, &ret_val);
6375 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6376 == NULL)) {
6377 zerr(gettext("%s %s is not a valid username"),
6378 pt_to_str(PT_USER),
6379 admintab.zone_admin_user);
6380 ret_val = Z_BAD_PROPERTY;
6382 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6383 admintab.zone_admin_auths, zone))) {
6384 ret_val = Z_BAD_PROPERTY;
6387 (void) zonecfg_endadminent(handle);
6389 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
6391 * No properties are required, but any specified should be
6392 * valid
6394 if (verify_secflags(&secflagstab) != B_TRUE) {
6395 /* Error is reported from verify_secflags */
6396 ret_val = Z_BAD_PROPERTY;
6400 if (!global_scope) {
6401 zerr(gettext("resource specification incomplete"));
6402 saw_error = B_TRUE;
6403 if (ret_val == Z_OK)
6404 ret_val = Z_INSUFFICIENT_SPEC;
6407 if (save) {
6408 if (ret_val == Z_OK) {
6409 if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6410 need_to_commit = B_FALSE;
6411 (void) strlcpy(revert_zone, zone,
6412 sizeof (revert_zone));
6414 } else {
6415 zerr(gettext("Zone %s failed to verify"), zone);
6418 if (ret_val != Z_OK)
6419 zone_perror(zone, ret_val, B_TRUE);
6422 void
6423 cancel_func(cmd_t *cmd)
6425 int arg;
6426 boolean_t arg_err = B_FALSE;
6428 assert(cmd != NULL);
6430 optind = 0;
6431 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6432 switch (arg) {
6433 case '?':
6434 longer_usage(CMD_CANCEL);
6435 arg_err = B_TRUE;
6436 break;
6437 default:
6438 short_usage(CMD_CANCEL);
6439 arg_err = B_TRUE;
6440 break;
6443 if (arg_err)
6444 return;
6446 if (optind != cmd->cmd_argc) {
6447 short_usage(CMD_CANCEL);
6448 return;
6451 if (global_scope)
6452 scope_usage(CMD_CANCEL);
6453 global_scope = B_TRUE;
6454 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6455 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6456 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6457 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6458 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6459 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6460 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6461 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6464 static int
6465 validate_attr_name(char *name)
6467 int i;
6469 if (!isalnum(name[0])) {
6470 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6471 "numeric character."), rt_to_str(RT_ATTR),
6472 pt_to_str(PT_NAME), name);
6473 return (Z_INVAL);
6475 for (i = 1; name[i]; i++)
6476 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6477 zerr(gettext("Invalid %s %s %s: can only contain "
6478 "alpha-numeric characters, plus '-' and '.'."),
6479 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6480 return (Z_INVAL);
6482 return (Z_OK);
6485 static int
6486 validate_attr_type_val(struct zone_attrtab *attrtab)
6488 boolean_t boolval;
6489 int64_t intval;
6490 char strval[MAXNAMELEN];
6491 uint64_t uintval;
6493 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6494 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6495 return (Z_OK);
6496 zerr(gettext("invalid %s value for %s=%s"),
6497 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6498 return (Z_ERR);
6501 if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6502 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6503 return (Z_OK);
6504 zerr(gettext("invalid %s value for %s=%s"),
6505 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6506 return (Z_ERR);
6509 if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6510 if (zonecfg_get_attr_string(attrtab, strval,
6511 sizeof (strval)) == Z_OK)
6512 return (Z_OK);
6513 zerr(gettext("invalid %s value for %s=%s"),
6514 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6515 return (Z_ERR);
6518 if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6519 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6520 return (Z_OK);
6521 zerr(gettext("invalid %s value for %s=%s"),
6522 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6523 return (Z_ERR);
6526 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6527 pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6528 return (Z_ERR);
6532 * Helper function for end_func-- checks the existence of a given property
6533 * and emits a message if not specified.
6535 static int
6536 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6538 if (strlen(attr) == 0) {
6539 *validation_failed = B_TRUE;
6540 zerr(gettext("%s not specified"), pt_to_str(pt));
6541 return (Z_ERR);
6543 return (Z_OK);
6546 static void
6547 net_exists_error(struct zone_nwiftab nwif)
6549 if (strlen(nwif.zone_nwif_address) > 0) {
6550 zerr(gettext("A %s resource with the %s '%s', "
6551 "and %s '%s' already exists."),
6552 rt_to_str(RT_NET),
6553 pt_to_str(PT_PHYSICAL),
6554 nwif.zone_nwif_physical,
6555 pt_to_str(PT_ADDRESS),
6556 in_progress_nwiftab.zone_nwif_address);
6557 } else {
6558 zerr(gettext("A %s resource with the %s '%s', "
6559 "and %s '%s' already exists."),
6560 rt_to_str(RT_NET),
6561 pt_to_str(PT_PHYSICAL),
6562 nwif.zone_nwif_physical,
6563 pt_to_str(PT_ALLOWED_ADDRESS),
6564 nwif.zone_nwif_allowed_address);
6568 void
6569 end_func(cmd_t *cmd)
6571 boolean_t validation_failed = B_FALSE;
6572 boolean_t arg_err = B_FALSE;
6573 struct zone_fstab tmp_fstab;
6574 struct zone_nwiftab tmp_nwiftab;
6575 struct zone_devtab tmp_devtab;
6576 struct zone_rctltab tmp_rctltab;
6577 struct zone_attrtab tmp_attrtab;
6578 struct zone_dstab tmp_dstab;
6579 struct zone_admintab tmp_admintab;
6580 int err, arg, res1, res2, res3;
6581 uint64_t swap_limit;
6582 uint64_t locked_limit;
6583 uint64_t proc_cap;
6585 assert(cmd != NULL);
6587 optind = 0;
6588 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6589 switch (arg) {
6590 case '?':
6591 longer_usage(CMD_END);
6592 arg_err = B_TRUE;
6593 break;
6594 default:
6595 short_usage(CMD_END);
6596 arg_err = B_TRUE;
6597 break;
6600 if (arg_err)
6601 return;
6603 if (optind != cmd->cmd_argc) {
6604 short_usage(CMD_END);
6605 return;
6608 if (global_scope) {
6609 scope_usage(CMD_END);
6610 return;
6613 assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6615 switch (resource_scope) {
6616 case RT_FS:
6617 /* First make sure everything was filled in. */
6618 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6619 PT_DIR, &validation_failed) == Z_OK) {
6620 if (in_progress_fstab.zone_fs_dir[0] != '/') {
6621 zerr(gettext("%s %s is not an absolute path."),
6622 pt_to_str(PT_DIR),
6623 in_progress_fstab.zone_fs_dir);
6624 validation_failed = B_TRUE;
6628 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6629 PT_SPECIAL, &validation_failed);
6631 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6632 in_progress_fstab.zone_fs_raw[0] != '/') {
6633 zerr(gettext("%s %s is not an absolute path."),
6634 pt_to_str(PT_RAW),
6635 in_progress_fstab.zone_fs_raw);
6636 validation_failed = B_TRUE;
6639 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6640 &validation_failed);
6642 if (validation_failed) {
6643 saw_error = B_TRUE;
6644 return;
6647 if (end_op == CMD_ADD) {
6648 /* Make sure there isn't already one like this. */
6649 bzero(&tmp_fstab, sizeof (tmp_fstab));
6650 (void) strlcpy(tmp_fstab.zone_fs_dir,
6651 in_progress_fstab.zone_fs_dir,
6652 sizeof (tmp_fstab.zone_fs_dir));
6653 err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6654 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6655 if (err == Z_OK) {
6656 zerr(gettext("A %s resource "
6657 "with the %s '%s' already exists."),
6658 rt_to_str(RT_FS), pt_to_str(PT_DIR),
6659 in_progress_fstab.zone_fs_dir);
6660 saw_error = B_TRUE;
6661 return;
6663 err = zonecfg_add_filesystem(handle,
6664 &in_progress_fstab);
6665 } else {
6666 err = zonecfg_modify_filesystem(handle, &old_fstab,
6667 &in_progress_fstab);
6669 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6670 in_progress_fstab.zone_fs_options = NULL;
6671 break;
6673 case RT_NET:
6675 * First make sure everything was filled in.
6676 * Since we don't know whether IP will be shared
6677 * or exclusive here, some checks are deferred until
6678 * the verify command.
6680 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6681 PT_PHYSICAL, &validation_failed);
6683 if (validation_failed) {
6684 saw_error = B_TRUE;
6685 return;
6687 if (end_op == CMD_ADD) {
6688 /* Make sure there isn't already one like this. */
6689 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6690 (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6691 in_progress_nwiftab.zone_nwif_physical,
6692 sizeof (tmp_nwiftab.zone_nwif_physical));
6693 (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6694 in_progress_nwiftab.zone_nwif_address,
6695 sizeof (tmp_nwiftab.zone_nwif_address));
6696 (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6697 in_progress_nwiftab.zone_nwif_allowed_address,
6698 sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6699 (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6700 in_progress_nwiftab.zone_nwif_defrouter,
6701 sizeof (tmp_nwiftab.zone_nwif_defrouter));
6702 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6703 net_exists_error(in_progress_nwiftab);
6704 saw_error = B_TRUE;
6705 return;
6707 err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6708 } else {
6709 err = zonecfg_modify_nwif(handle, &old_nwiftab,
6710 &in_progress_nwiftab);
6712 break;
6714 case RT_DEVICE:
6715 /* First make sure everything was filled in. */
6716 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6717 PT_MATCH, &validation_failed);
6719 if (validation_failed) {
6720 saw_error = B_TRUE;
6721 return;
6724 if (end_op == CMD_ADD) {
6725 /* Make sure there isn't already one like this. */
6726 (void) strlcpy(tmp_devtab.zone_dev_match,
6727 in_progress_devtab.zone_dev_match,
6728 sizeof (tmp_devtab.zone_dev_match));
6729 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6730 zerr(gettext("A %s resource with the %s '%s' "
6731 "already exists."), rt_to_str(RT_DEVICE),
6732 pt_to_str(PT_MATCH),
6733 in_progress_devtab.zone_dev_match);
6734 saw_error = B_TRUE;
6735 return;
6737 err = zonecfg_add_dev(handle, &in_progress_devtab);
6738 } else {
6739 err = zonecfg_modify_dev(handle, &old_devtab,
6740 &in_progress_devtab);
6742 break;
6744 case RT_RCTL:
6745 /* First make sure everything was filled in. */
6746 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6747 PT_NAME, &validation_failed);
6749 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6750 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6751 validation_failed = B_TRUE;
6754 if (validation_failed) {
6755 saw_error = B_TRUE;
6756 return;
6759 if (end_op == CMD_ADD) {
6760 /* Make sure there isn't already one like this. */
6761 (void) strlcpy(tmp_rctltab.zone_rctl_name,
6762 in_progress_rctltab.zone_rctl_name,
6763 sizeof (tmp_rctltab.zone_rctl_name));
6764 tmp_rctltab.zone_rctl_valptr = NULL;
6765 err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6766 zonecfg_free_rctl_value_list(
6767 tmp_rctltab.zone_rctl_valptr);
6768 if (err == Z_OK) {
6769 zerr(gettext("A %s resource "
6770 "with the %s '%s' already exists."),
6771 rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6772 in_progress_rctltab.zone_rctl_name);
6773 saw_error = B_TRUE;
6774 return;
6776 err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6777 } else {
6778 err = zonecfg_modify_rctl(handle, &old_rctltab,
6779 &in_progress_rctltab);
6781 if (err == Z_OK) {
6782 zonecfg_free_rctl_value_list(
6783 in_progress_rctltab.zone_rctl_valptr);
6784 in_progress_rctltab.zone_rctl_valptr = NULL;
6786 break;
6788 case RT_ATTR:
6789 /* First make sure everything was filled in. */
6790 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6791 PT_NAME, &validation_failed);
6792 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6793 PT_TYPE, &validation_failed);
6794 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6795 PT_VALUE, &validation_failed);
6797 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6798 Z_OK)
6799 validation_failed = B_TRUE;
6801 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6802 validation_failed = B_TRUE;
6804 if (validation_failed) {
6805 saw_error = B_TRUE;
6806 return;
6808 if (end_op == CMD_ADD) {
6809 /* Make sure there isn't already one like this. */
6810 bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6811 (void) strlcpy(tmp_attrtab.zone_attr_name,
6812 in_progress_attrtab.zone_attr_name,
6813 sizeof (tmp_attrtab.zone_attr_name));
6814 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6815 zerr(gettext("An %s resource "
6816 "with the %s '%s' already exists."),
6817 rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6818 in_progress_attrtab.zone_attr_name);
6819 saw_error = B_TRUE;
6820 return;
6822 err = zonecfg_add_attr(handle, &in_progress_attrtab);
6823 } else {
6824 err = zonecfg_modify_attr(handle, &old_attrtab,
6825 &in_progress_attrtab);
6827 break;
6828 case RT_DATASET:
6829 /* First make sure everything was filled in. */
6830 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6831 zerr("%s %s", pt_to_str(PT_NAME),
6832 gettext("not specified"));
6833 saw_error = B_TRUE;
6834 validation_failed = B_TRUE;
6836 if (validation_failed)
6837 return;
6838 if (end_op == CMD_ADD) {
6839 /* Make sure there isn't already one like this. */
6840 bzero(&tmp_dstab, sizeof (tmp_dstab));
6841 (void) strlcpy(tmp_dstab.zone_dataset_name,
6842 in_progress_dstab.zone_dataset_name,
6843 sizeof (tmp_dstab.zone_dataset_name));
6844 err = zonecfg_lookup_ds(handle, &tmp_dstab);
6845 if (err == Z_OK) {
6846 zerr(gettext("A %s resource "
6847 "with the %s '%s' already exists."),
6848 rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6849 in_progress_dstab.zone_dataset_name);
6850 saw_error = B_TRUE;
6851 return;
6853 err = zonecfg_add_ds(handle, &in_progress_dstab);
6854 } else {
6855 err = zonecfg_modify_ds(handle, &old_dstab,
6856 &in_progress_dstab);
6858 break;
6859 case RT_DCPU:
6860 /* Make sure everything was filled in. */
6861 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6862 PT_NCPUS, &validation_failed) != Z_OK) {
6863 saw_error = B_TRUE;
6864 return;
6867 if (end_op == CMD_ADD) {
6868 err = zonecfg_add_pset(handle, &in_progress_psettab);
6869 } else {
6870 err = zonecfg_modify_pset(handle, &in_progress_psettab);
6872 break;
6873 case RT_PCAP:
6874 /* Make sure everything was filled in. */
6875 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6876 != Z_OK) {
6877 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6878 saw_error = B_TRUE;
6879 validation_failed = B_TRUE;
6880 return;
6882 err = Z_OK;
6883 break;
6884 case RT_MCAP:
6885 /* Make sure everything was filled in. */
6886 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6887 Z_ERR : Z_OK;
6888 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6889 &swap_limit);
6890 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6891 &locked_limit);
6893 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6894 zerr(gettext("No property was specified. One of %s, "
6895 "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6896 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6897 saw_error = B_TRUE;
6898 return;
6901 /* if phys & locked are both set, verify locked <= phys */
6902 if (res1 == Z_OK && res3 == Z_OK) {
6903 uint64_t phys_limit;
6904 char *endp;
6906 phys_limit = strtoull(
6907 in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6908 if (phys_limit < locked_limit) {
6909 zerr(gettext("The %s cap must be less than or "
6910 "equal to the %s cap."),
6911 pt_to_str(PT_LOCKED),
6912 pt_to_str(PT_PHYSICAL));
6913 saw_error = B_TRUE;
6914 return;
6918 err = Z_OK;
6919 if (res1 == Z_OK) {
6921 * We could be ending from either an add operation
6922 * or a select operation. Since all of the properties
6923 * within this resource are optional, we always use
6924 * modify on the mcap entry. zonecfg_modify_mcap()
6925 * will handle both adding and modifying a memory cap.
6927 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6928 } else if (end_op == CMD_SELECT) {
6930 * If we're ending from a select and the physical
6931 * memory cap is empty then the user could have cleared
6932 * the physical cap value, so try to delete the entry.
6934 (void) zonecfg_delete_mcap(handle);
6936 break;
6937 case RT_ADMIN:
6938 /* First make sure everything was filled in. */
6939 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6940 PT_USER, &validation_failed) == Z_OK) {
6941 if (getpwnam(in_progress_admintab.zone_admin_user)
6942 == NULL) {
6943 zerr(gettext("%s %s is not a valid username"),
6944 pt_to_str(PT_USER),
6945 in_progress_admintab.zone_admin_user);
6946 validation_failed = B_TRUE;
6950 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6951 PT_AUTHS, &validation_failed) == Z_OK) {
6952 if (!zonecfg_valid_auths(
6953 in_progress_admintab.zone_admin_auths,
6954 zone)) {
6955 validation_failed = B_TRUE;
6959 if (validation_failed) {
6960 saw_error = B_TRUE;
6961 return;
6964 if (end_op == CMD_ADD) {
6965 /* Make sure there isn't already one like this. */
6966 bzero(&tmp_admintab, sizeof (tmp_admintab));
6967 (void) strlcpy(tmp_admintab.zone_admin_user,
6968 in_progress_admintab.zone_admin_user,
6969 sizeof (tmp_admintab.zone_admin_user));
6970 err = zonecfg_lookup_admin(
6971 handle, &tmp_admintab);
6972 if (err == Z_OK) {
6973 zerr(gettext("A %s resource "
6974 "with the %s '%s' already exists."),
6975 rt_to_str(RT_ADMIN),
6976 pt_to_str(PT_USER),
6977 in_progress_admintab.zone_admin_user);
6978 saw_error = B_TRUE;
6979 return;
6981 err = zonecfg_add_admin(handle,
6982 &in_progress_admintab, zone);
6983 } else {
6984 err = zonecfg_modify_admin(handle,
6985 &old_admintab, &in_progress_admintab,
6986 zone);
6988 break;
6989 case RT_SECFLAGS:
6990 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
6991 saw_error = B_TRUE;
6992 return;
6995 if (end_op == CMD_ADD) {
6996 err = zonecfg_add_secflags(handle,
6997 &in_progress_secflagstab);
6998 } else {
6999 err = zonecfg_modify_secflags(handle,
7000 &old_secflagstab, &in_progress_secflagstab);
7002 break;
7003 default:
7004 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
7005 B_TRUE);
7006 saw_error = B_TRUE;
7007 return;
7010 if (err != Z_OK) {
7011 zone_perror(zone, err, B_TRUE);
7012 } else {
7013 need_to_commit = B_TRUE;
7014 global_scope = B_TRUE;
7015 end_op = -1;
7019 void
7020 commit_func(cmd_t *cmd)
7022 int arg;
7023 boolean_t arg_err = B_FALSE;
7025 optind = 0;
7026 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
7027 switch (arg) {
7028 case '?':
7029 longer_usage(CMD_COMMIT);
7030 arg_err = B_TRUE;
7031 break;
7032 default:
7033 short_usage(CMD_COMMIT);
7034 arg_err = B_TRUE;
7035 break;
7038 if (arg_err)
7039 return;
7041 if (optind != cmd->cmd_argc) {
7042 short_usage(CMD_COMMIT);
7043 return;
7046 if (zone_is_read_only(CMD_COMMIT))
7047 return;
7049 assert(cmd != NULL);
7051 cmd->cmd_argc = 1;
7053 * cmd_arg normally comes from a strdup() in the lexer, and the
7054 * whole cmd structure and its (char *) attributes are freed at
7055 * the completion of each command, so the strdup() below is needed
7056 * to match this and prevent a core dump from trying to free()
7057 * something that can't be.
7059 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
7060 zone_perror(zone, Z_NOMEM, B_TRUE);
7061 exit(Z_ERR);
7063 cmd->cmd_argv[1] = NULL;
7064 verify_func(cmd);
7067 void
7068 revert_func(cmd_t *cmd)
7070 char line[128]; /* enough to ask a question */
7071 boolean_t force = B_FALSE;
7072 boolean_t arg_err = B_FALSE;
7073 int err, arg, answer;
7075 optind = 0;
7076 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
7077 switch (arg) {
7078 case '?':
7079 longer_usage(CMD_REVERT);
7080 arg_err = B_TRUE;
7081 break;
7082 case 'F':
7083 force = B_TRUE;
7084 break;
7085 default:
7086 short_usage(CMD_REVERT);
7087 arg_err = B_TRUE;
7088 break;
7091 if (arg_err)
7092 return;
7094 if (optind != cmd->cmd_argc) {
7095 short_usage(CMD_REVERT);
7096 return;
7099 if (zone_is_read_only(CMD_REVERT))
7100 return;
7102 if (!global_scope) {
7103 zerr(gettext("You can only use %s in the global scope.\nUse"
7104 " '%s' to cancel changes to a resource specification."),
7105 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
7106 saw_error = B_TRUE;
7107 return;
7110 if (zonecfg_check_handle(handle) != Z_OK) {
7111 zerr(gettext("No changes to revert."));
7112 saw_error = B_TRUE;
7113 return;
7116 if (!force) {
7117 (void) snprintf(line, sizeof (line),
7118 gettext("Are you sure you want to revert"));
7119 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
7120 zerr(gettext("Input not from terminal and -F not "
7121 "specified:\n%s command ignored, exiting."),
7122 cmd_to_str(CMD_REVERT));
7123 exit(Z_ERR);
7125 if (answer != 1)
7126 return;
7130 * Reset any pending admins that were
7131 * removed from the previous zone
7133 zonecfg_remove_userauths(handle, "", zone, B_FALSE);
7136 * Time for a new handle: finish the old one off first
7137 * then get a new one properly to avoid leaks.
7139 zonecfg_fini_handle(handle);
7140 if ((handle = zonecfg_init_handle()) == NULL) {
7141 zone_perror(execname, Z_NOMEM, B_TRUE);
7142 exit(Z_ERR);
7145 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
7146 saw_error = B_TRUE;
7147 got_handle = B_FALSE;
7148 if (err == Z_NO_ZONE)
7149 zerr(gettext("%s: no such saved zone to revert to."),
7150 revert_zone);
7151 else
7152 zone_perror(zone, err, B_TRUE);
7154 (void) strlcpy(zone, revert_zone, sizeof (zone));
7157 void
7158 help_func(cmd_t *cmd)
7160 int i;
7162 assert(cmd != NULL);
7164 if (cmd->cmd_argc == 0) {
7165 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
7166 return;
7168 if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
7169 usage(B_TRUE, HELP_USAGE);
7170 return;
7172 if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
7173 usage(B_TRUE, HELP_SUBCMDS);
7174 return;
7176 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
7177 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
7178 return;
7180 if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
7181 longer_usage(CMD_HELP);
7182 return;
7185 for (i = 0; i <= CMD_MAX; i++) {
7186 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
7187 longer_usage(i);
7188 return;
7191 /* We do not use zerr() here because we do not want its extra \n. */
7192 (void) fprintf(stderr, gettext("Unknown help subject %s. "),
7193 cmd->cmd_argv[0]);
7194 usage(B_FALSE, HELP_META);
7197 static int
7198 string_to_yyin(char *string)
7200 if ((yyin = tmpfile()) == NULL) {
7201 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7202 return (Z_ERR);
7204 if (fwrite(string, strlen(string), 1, yyin) != 1) {
7205 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7206 return (Z_ERR);
7208 if (fseek(yyin, 0, SEEK_SET) != 0) {
7209 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7210 return (Z_ERR);
7212 return (Z_OK);
7215 /* This is the back-end helper function for read_input() below. */
7217 static int
7218 cleanup()
7220 int answer;
7221 cmd_t *cmd;
7223 if (!interactive_mode && !cmd_file_mode) {
7225 * If we're not in interactive mode, and we're not in command
7226 * file mode, then we must be in commands-from-the-command-line
7227 * mode. As such, we can't loop back and ask for more input.
7228 * It was OK to prompt for such things as whether or not to
7229 * really delete a zone in the command handler called from
7230 * yyparse() above, but "really quit?" makes no sense in this
7231 * context. So disable prompting.
7233 ok_to_prompt = B_FALSE;
7235 if (!global_scope) {
7236 if (!time_to_exit) {
7238 * Just print a simple error message in the -1 case,
7239 * since exit_func() already handles that case, and
7240 * EOF means we are finished anyway.
7242 answer = ask_yesno(B_FALSE,
7243 gettext("Resource incomplete; really quit"));
7244 if (answer == -1) {
7245 zerr(gettext("Resource incomplete."));
7246 return (Z_ERR);
7248 if (answer != 1) {
7249 yyin = stdin;
7250 return (Z_REPEAT);
7252 } else {
7253 saw_error = B_TRUE;
7257 * Make sure we tried something and that the handle checks
7258 * out, or we would get a false error trying to commit.
7260 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
7261 if ((cmd = alloc_cmd()) == NULL) {
7262 zone_perror(zone, Z_NOMEM, B_TRUE);
7263 return (Z_ERR);
7265 cmd->cmd_argc = 0;
7266 cmd->cmd_argv[0] = NULL;
7267 commit_func(cmd);
7268 free_cmd(cmd);
7270 * need_to_commit will get set back to FALSE if the
7271 * configuration is saved successfully.
7273 if (need_to_commit) {
7274 if (force_exit) {
7275 zerr(gettext("Configuration not saved."));
7276 return (Z_ERR);
7278 answer = ask_yesno(B_FALSE,
7279 gettext("Configuration not saved; really quit"));
7280 if (answer == -1) {
7281 zerr(gettext("Configuration not saved."));
7282 return (Z_ERR);
7284 if (answer != 1) {
7285 time_to_exit = B_FALSE;
7286 yyin = stdin;
7287 return (Z_REPEAT);
7291 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
7295 * read_input() is the driver of this program. It is a wrapper around
7296 * yyparse(), printing appropriate prompts when needed, checking for
7297 * exit conditions and reacting appropriately [the latter in its cleanup()
7298 * helper function].
7300 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
7301 * so do_interactive() knows that we are not really done (i.e, we asked
7302 * the user if we should really quit and the user said no).
7304 static int
7305 read_input()
7307 boolean_t yyin_is_a_tty = isatty(fileno(yyin));
7309 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
7310 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
7312 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
7314 /* yyin should have been set to the appropriate (FILE *) if not stdin */
7315 newline_terminated = B_TRUE;
7316 for (;;) {
7317 if (yyin_is_a_tty) {
7318 if (newline_terminated) {
7319 if (global_scope)
7320 (void) snprintf(prompt, sizeof (prompt),
7321 "%s:%s> ", execname, zone);
7322 else
7323 (void) snprintf(prompt, sizeof (prompt),
7324 "%s:%s:%s> ", execname, zone,
7325 rt_to_str(resource_scope));
7328 * If the user hits ^C then we want to catch it and
7329 * start over. If the user hits EOF then we want to
7330 * bail out.
7332 line = gl_get_line(gl, prompt, NULL, -1);
7333 if (gl_return_status(gl) == GLR_SIGNAL) {
7334 gl_abandon_line(gl);
7335 continue;
7337 if (line == NULL)
7338 break;
7339 (void) string_to_yyin(line);
7340 while (!feof(yyin))
7341 yyparse();
7342 } else {
7343 yyparse();
7345 /* Bail out on an error in command file mode. */
7346 if (saw_error && cmd_file_mode && !interactive_mode)
7347 time_to_exit = B_TRUE;
7348 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7349 break;
7351 return (cleanup());
7355 * This function is used in the zonecfg-interactive-mode scenario: it just
7356 * calls read_input() until we are done.
7359 static int
7360 do_interactive(void)
7362 int err;
7364 interactive_mode = B_TRUE;
7365 if (!read_only_mode) {
7367 * Try to set things up proactively in interactive mode, so
7368 * that if the zone in question does not exist yet, we can
7369 * provide the user with a clue.
7371 (void) initialize(B_FALSE);
7373 do {
7374 err = read_input();
7375 } while (err == Z_REPEAT);
7376 return (err);
7380 * cmd_file is slightly more complicated, as it has to open the command file
7381 * and set yyin appropriately. Once that is done, though, it just calls
7382 * read_input(), and only once, since prompting is not possible.
7385 static int
7386 cmd_file(char *file)
7388 FILE *infile;
7389 int err;
7390 struct stat statbuf;
7391 boolean_t using_real_file = (strcmp(file, "-") != 0);
7393 if (using_real_file) {
7395 * zerr() prints a line number in cmd_file_mode, which we do
7396 * not want here, so temporarily unset it.
7398 cmd_file_mode = B_FALSE;
7399 if ((infile = fopen(file, "r")) == NULL) {
7400 zerr(gettext("could not open file %s: %s"),
7401 file, strerror(errno));
7402 return (Z_ERR);
7404 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7405 zerr(gettext("could not stat file %s: %s"),
7406 file, strerror(errno));
7407 err = Z_ERR;
7408 goto done;
7410 if (!S_ISREG(statbuf.st_mode)) {
7411 zerr(gettext("%s is not a regular file."), file);
7412 err = Z_ERR;
7413 goto done;
7415 yyin = infile;
7416 cmd_file_mode = B_TRUE;
7417 ok_to_prompt = B_FALSE;
7418 } else {
7420 * "-f -" is essentially the same as interactive mode,
7421 * so treat it that way.
7423 interactive_mode = B_TRUE;
7425 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7426 if ((err = read_input()) == Z_REPEAT)
7427 err = Z_ERR;
7428 done:
7429 if (using_real_file)
7430 (void) fclose(infile);
7431 return (err);
7435 * Since yacc is based on reading from a (FILE *) whereas what we get from
7436 * the command line is in argv format, we need to convert when the user
7437 * gives us commands directly from the command line. That is done here by
7438 * concatenating the argv list into a space-separated string, writing it
7439 * to a temp file, and rewinding the file so yyin can be set to it. Then
7440 * we call read_input(), and only once, since prompting about whether to
7441 * continue or quit would make no sense in this context.
7444 static int
7445 one_command_at_a_time(int argc, char *argv[])
7447 char *command;
7448 size_t len = 2; /* terminal \n\0 */
7449 int i, err;
7451 for (i = 0; i < argc; i++)
7452 len += strlen(argv[i]) + 1;
7453 if ((command = malloc(len)) == NULL) {
7454 zone_perror(execname, Z_NOMEM, B_TRUE);
7455 return (Z_ERR);
7457 (void) strlcpy(command, argv[0], len);
7458 for (i = 1; i < argc; i++) {
7459 (void) strlcat(command, " ", len);
7460 (void) strlcat(command, argv[i], len);
7462 (void) strlcat(command, "\n", len);
7463 err = string_to_yyin(command);
7464 free(command);
7465 if (err != Z_OK)
7466 return (err);
7467 while (!feof(yyin))
7468 yyparse();
7469 return (cleanup());
7472 static char *
7473 get_execbasename(char *execfullname)
7475 char *last_slash, *execbasename;
7477 /* guard against '/' at end of command invocation */
7478 for (;;) {
7479 last_slash = strrchr(execfullname, '/');
7480 if (last_slash == NULL) {
7481 execbasename = execfullname;
7482 break;
7483 } else {
7484 execbasename = last_slash + 1;
7485 if (*execbasename == '\0') {
7486 *last_slash = '\0';
7487 continue;
7489 break;
7492 return (execbasename);
7496 main(int argc, char *argv[])
7498 int err, arg;
7499 struct stat st;
7501 /* This must be before anything goes to stdout. */
7502 setbuf(stdout, NULL);
7504 saw_error = B_FALSE;
7505 cmd_file_mode = B_FALSE;
7506 execname = get_execbasename(argv[0]);
7508 (void) setlocale(LC_ALL, "");
7509 (void) textdomain(TEXT_DOMAIN);
7511 if (getzoneid() != GLOBAL_ZONEID) {
7512 zerr(gettext("%s can only be run from the global zone."),
7513 execname);
7514 exit(Z_ERR);
7517 if (argc < 2) {
7518 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7519 exit(Z_USAGE);
7521 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7522 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7523 exit(Z_OK);
7526 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7527 switch (arg) {
7528 case '?':
7529 if (optopt == '?')
7530 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7531 else
7532 usage(B_FALSE, HELP_USAGE);
7533 exit(Z_USAGE);
7534 /* NOTREACHED */
7535 case 'f':
7536 cmd_file_name = optarg;
7537 cmd_file_mode = B_TRUE;
7538 break;
7539 case 'R':
7540 if (*optarg != '/') {
7541 zerr(gettext("root path must be absolute: %s"),
7542 optarg);
7543 exit(Z_USAGE);
7545 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7546 zerr(gettext(
7547 "root path must be a directory: %s"),
7548 optarg);
7549 exit(Z_USAGE);
7551 zonecfg_set_root(optarg);
7552 break;
7553 case 'z':
7554 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7555 global_zone = B_TRUE;
7556 } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7557 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7558 usage(B_FALSE, HELP_SYNTAX);
7559 exit(Z_USAGE);
7561 (void) strlcpy(zone, optarg, sizeof (zone));
7562 (void) strlcpy(revert_zone, optarg, sizeof (zone));
7563 break;
7564 default:
7565 usage(B_FALSE, HELP_USAGE);
7566 exit(Z_USAGE);
7570 if (optind > argc || strcmp(zone, "") == 0) {
7571 usage(B_FALSE, HELP_USAGE);
7572 exit(Z_USAGE);
7575 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7576 read_only_mode = B_FALSE;
7577 } else if (err == Z_ACCES) {
7578 read_only_mode = B_TRUE;
7579 /* skip this message in one-off from command line mode */
7580 if (optind == argc)
7581 (void) fprintf(stderr, gettext("WARNING: you do not "
7582 "have write access to this zone's configuration "
7583 "file;\ngoing into read-only mode.\n"));
7584 } else {
7585 fprintf(stderr, "%s: Could not access zone configuration "
7586 "store: %s\n", execname, zonecfg_strerror(err));
7587 exit(Z_ERR);
7590 if ((handle = zonecfg_init_handle()) == NULL) {
7591 zone_perror(execname, Z_NOMEM, B_TRUE);
7592 exit(Z_ERR);
7596 * This may get set back to FALSE again in cmd_file() if cmd_file_name
7597 * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7599 if (isatty(STDIN_FILENO))
7600 ok_to_prompt = B_TRUE;
7601 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7602 exit(Z_ERR);
7603 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7604 exit(Z_ERR);
7605 (void) sigset(SIGINT, SIG_IGN);
7606 if (optind == argc) {
7607 if (!cmd_file_mode)
7608 err = do_interactive();
7609 else
7610 err = cmd_file(cmd_file_name);
7611 } else {
7612 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7614 zonecfg_fini_handle(handle);
7615 if (brand != NULL)
7616 brand_close(brand);
7617 (void) del_GetLine(gl);
7618 return (err);