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