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