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