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