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