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