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 int err; 3740 3741 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) { 3742 zerr(gettext("zone configuration has an invalid or nonexistent " 3743 "ip-type property")); 3744 return (Z_ERR); 3745 } 3746 switch (iptype) { 3747 case ZS_SHARED: 3748 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) { 3749 zerr(gettext("%s: invalid physical interface name"), 3750 ifname); 3751 return (Z_ERR); 3752 } 3753 if (ifnameprop.ifsp_lunvalid) { 3754 zerr(gettext("%s: LUNs not allowed in physical " 3755 "interface names"), ifname); 3756 return (Z_ERR); 3757 } 3758 break; 3759 case ZS_EXCLUSIVE: 3760 if (dladm_valid_linkname(ifname) == B_FALSE) { 3761 if (strchr(ifname, ':') != NULL) 3762 zerr(gettext("%s: physical interface name " 3763 "required; logical interface name not " 3764 "allowed"), ifname); 3765 else 3766 zerr(gettext("%s: invalid physical interface " 3767 "name"), ifname); 3768 return (Z_ERR); 3769 } 3770 break; 3771 } 3772 return (Z_OK); 3773 } 3774 3775 static boolean_t 3776 valid_fs_type(const char *type) 3777 { 3778 /* 3779 * Is this a valid path component? 3780 */ 3781 if (strlen(type) + 1 > MAXNAMELEN) 3782 return (B_FALSE); 3783 /* 3784 * Make sure a bad value for "type" doesn't make 3785 * /usr/lib/fs/<type>/mount turn into something else. 3786 */ 3787 if (strchr(type, '/') != NULL || type[0] == '\0' || 3788 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 3789 return (B_FALSE); 3790 /* 3791 * More detailed verification happens later by zoneadm(1m). 3792 */ 3793 return (B_TRUE); 3794 } 3795 3796 static boolean_t 3797 allow_exclusive() 3798 { 3799 brand_handle_t bh; 3800 char brand[MAXNAMELEN]; 3801 boolean_t ret; 3802 3803 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 3804 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 3805 return (B_FALSE); 3806 } 3807 if ((bh = brand_open(brand)) == NULL) { 3808 zerr("%s: %s\n", zone, gettext("unknown brand.")); 3809 return (B_FALSE); 3810 } 3811 ret = brand_allow_exclusive_ip(bh); 3812 brand_close(bh); 3813 if (!ret) 3814 zerr(gettext("%s cannot be '%s' when %s is '%s'."), 3815 pt_to_str(PT_IPTYPE), "exclusive", 3816 pt_to_str(PT_BRAND), brand); 3817 return (ret); 3818 } 3819 3820 static void 3821 set_aliased_rctl(char *alias, int prop_type, char *s) 3822 { 3823 uint64_t limit; 3824 int err; 3825 char tmp[128]; 3826 3827 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0) 3828 zerr(gettext("WARNING: Setting a global zone resource " 3829 "control too low could deny\nservice " 3830 "to even the root user; " 3831 "this could render the system impossible\n" 3832 "to administer. Please use caution.")); 3833 3834 /* convert memory based properties */ 3835 if (prop_type == PT_MAXSHMMEM) { 3836 if (!zonecfg_valid_memlimit(s, &limit)) { 3837 zerr(gettext("A non-negative number with a required " 3838 "scale suffix (K, M, G or T) was expected\nhere.")); 3839 saw_error = B_TRUE; 3840 return; 3841 } 3842 3843 (void) snprintf(tmp, sizeof (tmp), "%llu", limit); 3844 s = tmp; 3845 } 3846 3847 if (!zonecfg_aliased_rctl_ok(handle, alias)) { 3848 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE); 3849 saw_error = B_TRUE; 3850 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) { 3851 zerr(gettext("%s property is out of range."), 3852 pt_to_str(prop_type)); 3853 saw_error = B_TRUE; 3854 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit)) 3855 != Z_OK) { 3856 zone_perror(zone, err, B_TRUE); 3857 saw_error = B_TRUE; 3858 } else { 3859 need_to_commit = B_TRUE; 3860 } 3861 } 3862 3863 void 3864 set_func(cmd_t *cmd) 3865 { 3866 char *prop_id; 3867 int arg, err, res_type, prop_type; 3868 property_value_ptr_t pp; 3869 boolean_t autoboot; 3870 zone_iptype_t iptype; 3871 boolean_t force_set = B_FALSE; 3872 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap); 3873 uint64_t mem_cap, mem_limit; 3874 float cap; 3875 char *unitp; 3876 struct zone_psettab tmp_psettab; 3877 boolean_t arg_err = B_FALSE; 3878 3879 if (zone_is_read_only(CMD_SET)) 3880 return; 3881 3882 assert(cmd != NULL); 3883 3884 optind = opterr = 0; 3885 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 3886 switch (arg) { 3887 case 'F': 3888 force_set = B_TRUE; 3889 break; 3890 default: 3891 if (optopt == '?') 3892 longer_usage(CMD_SET); 3893 else 3894 short_usage(CMD_SET); 3895 arg_err = B_TRUE; 3896 break; 3897 } 3898 } 3899 if (arg_err) 3900 return; 3901 3902 prop_type = cmd->cmd_prop_name[0]; 3903 if (global_scope) { 3904 if (gz_invalid_property(prop_type)) { 3905 zerr(gettext("%s is not a valid property for the " 3906 "global zone."), pt_to_str(prop_type)); 3907 saw_error = B_TRUE; 3908 return; 3909 } 3910 3911 if (prop_type == PT_ZONENAME) { 3912 res_type = RT_ZONENAME; 3913 } else if (prop_type == PT_ZONEPATH) { 3914 res_type = RT_ZONEPATH; 3915 } else if (prop_type == PT_AUTOBOOT) { 3916 res_type = RT_AUTOBOOT; 3917 } else if (prop_type == PT_BRAND) { 3918 res_type = RT_BRAND; 3919 } else if (prop_type == PT_POOL) { 3920 res_type = RT_POOL; 3921 } else if (prop_type == PT_LIMITPRIV) { 3922 res_type = RT_LIMITPRIV; 3923 } else if (prop_type == PT_BOOTARGS) { 3924 res_type = RT_BOOTARGS; 3925 } else if (prop_type == PT_SCHED) { 3926 res_type = RT_SCHED; 3927 } else if (prop_type == PT_IPTYPE) { 3928 res_type = RT_IPTYPE; 3929 } else if (prop_type == PT_MAXLWPS) { 3930 res_type = RT_MAXLWPS; 3931 } else if (prop_type == PT_MAXSHMMEM) { 3932 res_type = RT_MAXSHMMEM; 3933 } else if (prop_type == PT_MAXSHMIDS) { 3934 res_type = RT_MAXSHMIDS; 3935 } else if (prop_type == PT_MAXMSGIDS) { 3936 res_type = RT_MAXMSGIDS; 3937 } else if (prop_type == PT_MAXSEMIDS) { 3938 res_type = RT_MAXSEMIDS; 3939 } else if (prop_type == PT_SHARES) { 3940 res_type = RT_SHARES; 3941 } else { 3942 zerr(gettext("Cannot set a resource-specific property " 3943 "from the global scope.")); 3944 saw_error = B_TRUE; 3945 return; 3946 } 3947 } else { 3948 res_type = resource_scope; 3949 } 3950 3951 if (force_set) { 3952 if (res_type != RT_ZONEPATH) { 3953 zerr(gettext("Only zonepath setting can be forced.")); 3954 saw_error = B_TRUE; 3955 return; 3956 } 3957 if (!zonecfg_in_alt_root()) { 3958 zerr(gettext("Zonepath is changeable only in an " 3959 "alternate root.")); 3960 saw_error = B_TRUE; 3961 return; 3962 } 3963 } 3964 3965 pp = cmd->cmd_property_ptr[0]; 3966 /* 3967 * A nasty expression but not that complicated: 3968 * 1. fs options are simple or list (tested below) 3969 * 2. rctl value's are complex or list (tested below) 3970 * Anything else should be simple. 3971 */ 3972 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 3973 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 3974 (pp->pv_type != PROP_VAL_SIMPLE || 3975 (prop_id = pp->pv_simple) == NULL)) { 3976 zerr(gettext("A %s value was expected here."), 3977 pvt_to_str(PROP_VAL_SIMPLE)); 3978 saw_error = B_TRUE; 3979 return; 3980 } 3981 if (prop_type == PT_UNKNOWN) { 3982 long_usage(CMD_SET, B_TRUE); 3983 return; 3984 } 3985 3986 /* 3987 * Special case: the user can change the zone name prior to 'create'; 3988 * if the zone already exists, we fall through letting initialize() 3989 * and the rest of the logic run. 3990 */ 3991 if (res_type == RT_ZONENAME && got_handle == B_FALSE && 3992 !state_atleast(ZONE_STATE_CONFIGURED)) { 3993 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) { 3994 zone_perror(prop_id, err, B_TRUE); 3995 usage(B_FALSE, HELP_SYNTAX); 3996 return; 3997 } 3998 (void) strlcpy(zone, prop_id, sizeof (zone)); 3999 return; 4000 } 4001 4002 if (initialize(B_TRUE) != Z_OK) 4003 return; 4004 4005 switch (res_type) { 4006 case RT_ZONENAME: 4007 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 4008 /* 4009 * Use prop_id instead of 'zone' here, since we're 4010 * reporting a problem about the *new* zonename. 4011 */ 4012 zone_perror(prop_id, err, B_TRUE); 4013 usage(B_FALSE, HELP_SYNTAX); 4014 } else { 4015 need_to_commit = B_TRUE; 4016 (void) strlcpy(zone, prop_id, sizeof (zone)); 4017 } 4018 return; 4019 case RT_ZONEPATH: 4020 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) { 4021 zerr(gettext("Zone %s already installed; %s %s not " 4022 "allowed."), zone, cmd_to_str(CMD_SET), 4023 rt_to_str(RT_ZONEPATH)); 4024 return; 4025 } 4026 if (validate_zonepath_syntax(prop_id) != Z_OK) { 4027 saw_error = B_TRUE; 4028 return; 4029 } 4030 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 4031 zone_perror(zone, err, B_TRUE); 4032 else 4033 need_to_commit = B_TRUE; 4034 return; 4035 case RT_BRAND: 4036 if (state_atleast(ZONE_STATE_INSTALLED)) { 4037 zerr(gettext("Zone %s already installed; %s %s not " 4038 "allowed."), zone, cmd_to_str(CMD_SET), 4039 rt_to_str(RT_BRAND)); 4040 return; 4041 } 4042 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK) 4043 zone_perror(zone, err, B_TRUE); 4044 else 4045 need_to_commit = B_TRUE; 4046 return; 4047 case RT_AUTOBOOT: 4048 if (strcmp(prop_id, "true") == 0) { 4049 autoboot = B_TRUE; 4050 } else if (strcmp(prop_id, "false") == 0) { 4051 autoboot = B_FALSE; 4052 } else { 4053 zerr(gettext("%s value must be '%s' or '%s'."), 4054 pt_to_str(PT_AUTOBOOT), "true", "false"); 4055 saw_error = B_TRUE; 4056 return; 4057 } 4058 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 4059 zone_perror(zone, err, B_TRUE); 4060 else 4061 need_to_commit = B_TRUE; 4062 return; 4063 case RT_POOL: 4064 /* don't allow use of the reserved temporary pool names */ 4065 if (strncmp("SUNW", prop_id, 4) == 0) { 4066 zerr(gettext("pool names starting with SUNW are " 4067 "reserved.")); 4068 saw_error = B_TRUE; 4069 return; 4070 } 4071 4072 /* can't set pool if dedicated-cpu exists */ 4073 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 4074 zerr(gettext("The %s resource already exists. " 4075 "A persistent pool is incompatible\nwith the %s " 4076 "resource."), rt_to_str(RT_DCPU), 4077 rt_to_str(RT_DCPU)); 4078 saw_error = B_TRUE; 4079 return; 4080 } 4081 4082 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 4083 zone_perror(zone, err, B_TRUE); 4084 else 4085 need_to_commit = B_TRUE; 4086 return; 4087 case RT_LIMITPRIV: 4088 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK) 4089 zone_perror(zone, err, B_TRUE); 4090 else 4091 need_to_commit = B_TRUE; 4092 return; 4093 case RT_BOOTARGS: 4094 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK) 4095 zone_perror(zone, err, B_TRUE); 4096 else 4097 need_to_commit = B_TRUE; 4098 return; 4099 case RT_SCHED: 4100 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK) 4101 zone_perror(zone, err, B_TRUE); 4102 else 4103 need_to_commit = B_TRUE; 4104 return; 4105 case RT_IPTYPE: 4106 if (strcmp(prop_id, "shared") == 0) { 4107 iptype = ZS_SHARED; 4108 } else if (strcmp(prop_id, "exclusive") == 0) { 4109 iptype = ZS_EXCLUSIVE; 4110 } else { 4111 zerr(gettext("%s value must be '%s' or '%s'."), 4112 pt_to_str(PT_IPTYPE), "shared", "exclusive"); 4113 saw_error = B_TRUE; 4114 return; 4115 } 4116 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) { 4117 saw_error = B_TRUE; 4118 return; 4119 } 4120 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK) 4121 zone_perror(zone, err, B_TRUE); 4122 else 4123 need_to_commit = B_TRUE; 4124 return; 4125 case RT_MAXLWPS: 4126 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id); 4127 return; 4128 case RT_MAXSHMMEM: 4129 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id); 4130 return; 4131 case RT_MAXSHMIDS: 4132 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id); 4133 return; 4134 case RT_MAXMSGIDS: 4135 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id); 4136 return; 4137 case RT_MAXSEMIDS: 4138 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id); 4139 return; 4140 case RT_SHARES: 4141 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id); 4142 return; 4143 case RT_FS: 4144 switch (prop_type) { 4145 case PT_DIR: 4146 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 4147 sizeof (in_progress_fstab.zone_fs_dir)); 4148 return; 4149 case PT_SPECIAL: 4150 (void) strlcpy(in_progress_fstab.zone_fs_special, 4151 prop_id, 4152 sizeof (in_progress_fstab.zone_fs_special)); 4153 return; 4154 case PT_RAW: 4155 (void) strlcpy(in_progress_fstab.zone_fs_raw, 4156 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 4157 return; 4158 case PT_TYPE: 4159 if (!valid_fs_type(prop_id)) { 4160 zerr(gettext("\"%s\" is not a valid %s."), 4161 prop_id, pt_to_str(PT_TYPE)); 4162 saw_error = B_TRUE; 4163 return; 4164 } 4165 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 4166 sizeof (in_progress_fstab.zone_fs_type)); 4167 return; 4168 case PT_OPTIONS: 4169 if (pp->pv_type != PROP_VAL_SIMPLE && 4170 pp->pv_type != PROP_VAL_LIST) { 4171 zerr(gettext("A %s or %s value was expected " 4172 "here."), pvt_to_str(PROP_VAL_SIMPLE), 4173 pvt_to_str(PROP_VAL_LIST)); 4174 saw_error = B_TRUE; 4175 return; 4176 } 4177 zonecfg_free_fs_option_list( 4178 in_progress_fstab.zone_fs_options); 4179 in_progress_fstab.zone_fs_options = NULL; 4180 if (!(pp->pv_type == PROP_VAL_LIST && 4181 pp->pv_list == NULL)) 4182 add_property(cmd); 4183 return; 4184 default: 4185 break; 4186 } 4187 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4188 long_usage(CMD_SET, B_TRUE); 4189 usage(B_FALSE, HELP_PROPS); 4190 return; 4191 case RT_IPD: 4192 switch (prop_type) { 4193 case PT_DIR: 4194 (void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id, 4195 sizeof (in_progress_ipdtab.zone_fs_dir)); 4196 return; 4197 default: 4198 break; 4199 } 4200 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4201 long_usage(CMD_SET, B_TRUE); 4202 usage(B_FALSE, HELP_PROPS); 4203 return; 4204 case RT_NET: 4205 switch (prop_type) { 4206 case PT_ADDRESS: 4207 if (validate_net_address_syntax(prop_id) != Z_OK) { 4208 saw_error = B_TRUE; 4209 return; 4210 } 4211 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, 4212 prop_id, 4213 sizeof (in_progress_nwiftab.zone_nwif_address)); 4214 break; 4215 case PT_PHYSICAL: 4216 if (validate_net_physical_syntax(prop_id) != Z_OK) { 4217 saw_error = B_TRUE; 4218 return; 4219 } 4220 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 4221 prop_id, 4222 sizeof (in_progress_nwiftab.zone_nwif_physical)); 4223 break; 4224 case PT_DEFROUTER: 4225 if (validate_net_address_syntax(prop_id) != Z_OK) { 4226 saw_error = B_TRUE; 4227 return; 4228 } 4229 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter, 4230 prop_id, 4231 sizeof (in_progress_nwiftab.zone_nwif_defrouter)); 4232 break; 4233 default: 4234 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4235 B_TRUE); 4236 long_usage(CMD_SET, B_TRUE); 4237 usage(B_FALSE, HELP_PROPS); 4238 return; 4239 } 4240 return; 4241 case RT_DEVICE: 4242 switch (prop_type) { 4243 case PT_MATCH: 4244 (void) strlcpy(in_progress_devtab.zone_dev_match, 4245 prop_id, 4246 sizeof (in_progress_devtab.zone_dev_match)); 4247 break; 4248 default: 4249 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4250 B_TRUE); 4251 long_usage(CMD_SET, B_TRUE); 4252 usage(B_FALSE, HELP_PROPS); 4253 return; 4254 } 4255 return; 4256 case RT_RCTL: 4257 switch (prop_type) { 4258 case PT_NAME: 4259 if (!zonecfg_valid_rctlname(prop_id)) { 4260 zerr(gettext("'%s' is not a valid zone %s " 4261 "name."), prop_id, rt_to_str(RT_RCTL)); 4262 return; 4263 } 4264 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 4265 prop_id, 4266 sizeof (in_progress_rctltab.zone_rctl_name)); 4267 break; 4268 case PT_VALUE: 4269 if (pp->pv_type != PROP_VAL_COMPLEX && 4270 pp->pv_type != PROP_VAL_LIST) { 4271 zerr(gettext("A %s or %s value was expected " 4272 "here."), pvt_to_str(PROP_VAL_COMPLEX), 4273 pvt_to_str(PROP_VAL_LIST)); 4274 saw_error = B_TRUE; 4275 return; 4276 } 4277 zonecfg_free_rctl_value_list( 4278 in_progress_rctltab.zone_rctl_valptr); 4279 in_progress_rctltab.zone_rctl_valptr = NULL; 4280 if (!(pp->pv_type == PROP_VAL_LIST && 4281 pp->pv_list == NULL)) 4282 add_property(cmd); 4283 break; 4284 default: 4285 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4286 B_TRUE); 4287 long_usage(CMD_SET, B_TRUE); 4288 usage(B_FALSE, HELP_PROPS); 4289 return; 4290 } 4291 return; 4292 case RT_ATTR: 4293 switch (prop_type) { 4294 case PT_NAME: 4295 (void) strlcpy(in_progress_attrtab.zone_attr_name, 4296 prop_id, 4297 sizeof (in_progress_attrtab.zone_attr_name)); 4298 break; 4299 case PT_TYPE: 4300 (void) strlcpy(in_progress_attrtab.zone_attr_type, 4301 prop_id, 4302 sizeof (in_progress_attrtab.zone_attr_type)); 4303 break; 4304 case PT_VALUE: 4305 (void) strlcpy(in_progress_attrtab.zone_attr_value, 4306 prop_id, 4307 sizeof (in_progress_attrtab.zone_attr_value)); 4308 break; 4309 default: 4310 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4311 B_TRUE); 4312 long_usage(CMD_SET, B_TRUE); 4313 usage(B_FALSE, HELP_PROPS); 4314 return; 4315 } 4316 return; 4317 case RT_DATASET: 4318 switch (prop_type) { 4319 case PT_NAME: 4320 (void) strlcpy(in_progress_dstab.zone_dataset_name, 4321 prop_id, 4322 sizeof (in_progress_dstab.zone_dataset_name)); 4323 return; 4324 default: 4325 break; 4326 } 4327 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4328 long_usage(CMD_SET, B_TRUE); 4329 usage(B_FALSE, HELP_PROPS); 4330 return; 4331 case RT_DCPU: 4332 switch (prop_type) { 4333 char *lowp, *highp; 4334 4335 case PT_NCPUS: 4336 lowp = prop_id; 4337 if ((highp = strchr(prop_id, '-')) != NULL) 4338 *highp++ = '\0'; 4339 else 4340 highp = lowp; 4341 4342 /* Make sure the input makes sense. */ 4343 if (!zonecfg_valid_ncpus(lowp, highp)) { 4344 zerr(gettext("%s property is out of range."), 4345 pt_to_str(PT_NCPUS)); 4346 saw_error = B_TRUE; 4347 return; 4348 } 4349 4350 (void) strlcpy( 4351 in_progress_psettab.zone_ncpu_min, lowp, 4352 sizeof (in_progress_psettab.zone_ncpu_min)); 4353 (void) strlcpy( 4354 in_progress_psettab.zone_ncpu_max, highp, 4355 sizeof (in_progress_psettab.zone_ncpu_max)); 4356 return; 4357 case PT_IMPORTANCE: 4358 /* Make sure the value makes sense. */ 4359 if (!zonecfg_valid_importance(prop_id)) { 4360 zerr(gettext("%s property is out of range."), 4361 pt_to_str(PT_IMPORTANCE)); 4362 saw_error = B_TRUE; 4363 return; 4364 } 4365 4366 (void) strlcpy(in_progress_psettab.zone_importance, 4367 prop_id, 4368 sizeof (in_progress_psettab.zone_importance)); 4369 return; 4370 default: 4371 break; 4372 } 4373 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4374 long_usage(CMD_SET, B_TRUE); 4375 usage(B_FALSE, HELP_PROPS); 4376 return; 4377 case RT_PCAP: 4378 if (prop_type != PT_NCPUS) { 4379 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4380 B_TRUE); 4381 long_usage(CMD_SET, B_TRUE); 4382 usage(B_FALSE, HELP_PROPS); 4383 return; 4384 } 4385 4386 /* 4387 * We already checked that an rctl alias is allowed in 4388 * the add_resource() function. 4389 */ 4390 4391 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' || 4392 (int)(cap * 100) < 1) { 4393 zerr(gettext("%s property is out of range."), 4394 pt_to_str(PT_NCPUS)); 4395 saw_error = B_TRUE; 4396 return; 4397 } 4398 4399 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP, 4400 (int)(cap * 100))) != Z_OK) 4401 zone_perror(zone, err, B_TRUE); 4402 else 4403 need_to_commit = B_TRUE; 4404 return; 4405 case RT_MCAP: 4406 switch (prop_type) { 4407 case PT_PHYSICAL: 4408 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4409 zerr(gettext("A positive number with a " 4410 "required scale suffix (K, M, G or T) was " 4411 "expected here.")); 4412 saw_error = B_TRUE; 4413 } else if (mem_cap < ONE_MB) { 4414 zerr(gettext("%s value is too small. It must " 4415 "be at least 1M."), pt_to_str(PT_PHYSICAL)); 4416 saw_error = B_TRUE; 4417 } else { 4418 snprintf(in_progress_mcaptab.zone_physmem_cap, 4419 physmem_size, "%llu", mem_cap); 4420 } 4421 break; 4422 case PT_SWAP: 4423 /* 4424 * We have to check if an rctl is allowed here since 4425 * there might already be a rctl defined that blocks 4426 * the alias. 4427 */ 4428 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) { 4429 zone_perror(pt_to_str(PT_MAXSWAP), 4430 Z_ALIAS_DISALLOW, B_FALSE); 4431 saw_error = B_TRUE; 4432 return; 4433 } 4434 4435 if (global_zone) 4436 mem_limit = ONE_MB * 100; 4437 else 4438 mem_limit = ONE_MB * 50; 4439 4440 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4441 zerr(gettext("A positive number with a " 4442 "required scale suffix (K, M, G or T) was " 4443 "expected here.")); 4444 saw_error = B_TRUE; 4445 } else if (mem_cap < mem_limit) { 4446 char buf[128]; 4447 4448 (void) snprintf(buf, sizeof (buf), "%llu", 4449 mem_limit); 4450 bytes_to_units(buf, buf, sizeof (buf)); 4451 zerr(gettext("%s value is too small. It must " 4452 "be at least %s."), pt_to_str(PT_SWAP), 4453 buf); 4454 saw_error = B_TRUE; 4455 } else { 4456 if ((err = zonecfg_set_aliased_rctl(handle, 4457 ALIAS_MAXSWAP, mem_cap)) != Z_OK) 4458 zone_perror(zone, err, B_TRUE); 4459 else 4460 need_to_commit = B_TRUE; 4461 } 4462 break; 4463 case PT_LOCKED: 4464 /* 4465 * We have to check if an rctl is allowed here since 4466 * there might already be a rctl defined that blocks 4467 * the alias. 4468 */ 4469 if (!zonecfg_aliased_rctl_ok(handle, 4470 ALIAS_MAXLOCKEDMEM)) { 4471 zone_perror(pt_to_str(PT_LOCKED), 4472 Z_ALIAS_DISALLOW, B_FALSE); 4473 saw_error = B_TRUE; 4474 return; 4475 } 4476 4477 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4478 zerr(gettext("A non-negative number with a " 4479 "required scale suffix (K, M, G or T) was " 4480 "expected\nhere.")); 4481 saw_error = B_TRUE; 4482 } else { 4483 if ((err = zonecfg_set_aliased_rctl(handle, 4484 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK) 4485 zone_perror(zone, err, B_TRUE); 4486 else 4487 need_to_commit = B_TRUE; 4488 } 4489 break; 4490 default: 4491 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4492 B_TRUE); 4493 long_usage(CMD_SET, B_TRUE); 4494 usage(B_FALSE, HELP_PROPS); 4495 return; 4496 } 4497 4498 return; 4499 default: 4500 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 4501 long_usage(CMD_SET, B_TRUE); 4502 usage(B_FALSE, HELP_RESOURCES); 4503 return; 4504 } 4505 } 4506 4507 static void 4508 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec) 4509 { 4510 char *qstr; 4511 4512 if (*pval != '\0') { 4513 qstr = quoteit(pval); 4514 if (pnum == PT_SWAP || pnum == PT_LOCKED) 4515 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum), 4516 qstr); 4517 else 4518 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 4519 free(qstr); 4520 } else if (print_notspec) 4521 (void) fprintf(fp, gettext("\t%s not specified\n"), 4522 pt_to_str(pnum)); 4523 } 4524 4525 static void 4526 info_zonename(zone_dochandle_t handle, FILE *fp) 4527 { 4528 char zonename[ZONENAME_MAX]; 4529 4530 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 4531 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 4532 zonename); 4533 else 4534 (void) fprintf(fp, gettext("%s not specified\n"), 4535 pt_to_str(PT_ZONENAME)); 4536 } 4537 4538 static void 4539 info_zonepath(zone_dochandle_t handle, FILE *fp) 4540 { 4541 char zonepath[MAXPATHLEN]; 4542 4543 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 4544 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 4545 zonepath); 4546 else { 4547 (void) fprintf(fp, gettext("%s not specified\n"), 4548 pt_to_str(PT_ZONEPATH)); 4549 } 4550 } 4551 4552 static void 4553 info_brand(zone_dochandle_t handle, FILE *fp) 4554 { 4555 char brand[MAXNAMELEN]; 4556 4557 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK) 4558 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND), 4559 brand); 4560 else 4561 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND), 4562 gettext("not specified")); 4563 } 4564 4565 static void 4566 info_autoboot(zone_dochandle_t handle, FILE *fp) 4567 { 4568 boolean_t autoboot; 4569 int err; 4570 4571 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 4572 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 4573 autoboot ? "true" : "false"); 4574 else 4575 zone_perror(zone, err, B_TRUE); 4576 } 4577 4578 static void 4579 info_pool(zone_dochandle_t handle, FILE *fp) 4580 { 4581 char pool[MAXNAMELEN]; 4582 int err; 4583 4584 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 4585 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 4586 else 4587 zone_perror(zone, err, B_TRUE); 4588 } 4589 4590 static void 4591 info_limitpriv(zone_dochandle_t handle, FILE *fp) 4592 { 4593 char *limitpriv; 4594 int err; 4595 4596 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) { 4597 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV), 4598 limitpriv); 4599 free(limitpriv); 4600 } else { 4601 zone_perror(zone, err, B_TRUE); 4602 } 4603 } 4604 4605 static void 4606 info_bootargs(zone_dochandle_t handle, FILE *fp) 4607 { 4608 char bootargs[BOOTARGS_MAX]; 4609 int err; 4610 4611 if ((err = zonecfg_get_bootargs(handle, bootargs, 4612 sizeof (bootargs))) == Z_OK) { 4613 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS), 4614 bootargs); 4615 } else { 4616 zone_perror(zone, err, B_TRUE); 4617 } 4618 } 4619 4620 static void 4621 info_sched(zone_dochandle_t handle, FILE *fp) 4622 { 4623 char sched[MAXNAMELEN]; 4624 int err; 4625 4626 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched))) 4627 == Z_OK) { 4628 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched); 4629 } else { 4630 zone_perror(zone, err, B_TRUE); 4631 } 4632 } 4633 4634 static void 4635 info_iptype(zone_dochandle_t handle, FILE *fp) 4636 { 4637 zone_iptype_t iptype; 4638 int err; 4639 4640 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) { 4641 switch (iptype) { 4642 case ZS_SHARED: 4643 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4644 "shared"); 4645 break; 4646 case ZS_EXCLUSIVE: 4647 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4648 "exclusive"); 4649 break; 4650 } 4651 } else { 4652 zone_perror(zone, err, B_TRUE); 4653 } 4654 } 4655 4656 static void 4657 output_fs(FILE *fp, struct zone_fstab *fstab) 4658 { 4659 zone_fsopt_t *this; 4660 4661 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 4662 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 4663 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 4664 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 4665 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 4666 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 4667 for (this = fstab->zone_fs_options; this != NULL; 4668 this = this->zone_fsopt_next) { 4669 if (strchr(this->zone_fsopt_opt, '=')) 4670 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 4671 else 4672 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 4673 if (this->zone_fsopt_next != NULL) 4674 (void) fprintf(fp, ","); 4675 } 4676 (void) fprintf(fp, "]\n"); 4677 } 4678 4679 static void 4680 output_ipd(FILE *fp, struct zone_fstab *ipdtab) 4681 { 4682 (void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD)); 4683 output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE); 4684 } 4685 4686 static void 4687 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4688 { 4689 struct zone_fstab lookup, user; 4690 boolean_t output = B_FALSE; 4691 4692 if (zonecfg_setfsent(handle) != Z_OK) 4693 return; 4694 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 4695 if (cmd->cmd_prop_nv_pairs == 0) { 4696 output_fs(fp, &lookup); 4697 goto loopend; 4698 } 4699 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK) 4700 goto loopend; 4701 if (strlen(user.zone_fs_dir) > 0 && 4702 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 4703 goto loopend; /* no match */ 4704 if (strlen(user.zone_fs_special) > 0 && 4705 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 4706 goto loopend; /* no match */ 4707 if (strlen(user.zone_fs_type) > 0 && 4708 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 4709 goto loopend; /* no match */ 4710 output_fs(fp, &lookup); 4711 output = B_TRUE; 4712 loopend: 4713 zonecfg_free_fs_option_list(lookup.zone_fs_options); 4714 } 4715 (void) zonecfg_endfsent(handle); 4716 /* 4717 * If a property n/v pair was specified, warn the user if there was 4718 * nothing to output. 4719 */ 4720 if (!output && cmd->cmd_prop_nv_pairs > 0) 4721 (void) printf(gettext("No such %s resource.\n"), 4722 rt_to_str(RT_FS)); 4723 } 4724 4725 static void 4726 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4727 { 4728 struct zone_fstab lookup, user; 4729 boolean_t output = B_FALSE; 4730 4731 if (zonecfg_setipdent(handle) != Z_OK) 4732 return; 4733 while (zonecfg_getipdent(handle, &lookup) == Z_OK) { 4734 if (cmd->cmd_prop_nv_pairs == 0) { 4735 output_ipd(fp, &lookup); 4736 continue; 4737 } 4738 if (fill_in_ipdtab(cmd, &user, B_TRUE) != Z_OK) 4739 continue; 4740 if (strlen(user.zone_fs_dir) > 0 && 4741 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 4742 continue; /* no match */ 4743 output_ipd(fp, &lookup); 4744 output = B_TRUE; 4745 } 4746 (void) zonecfg_endipdent(handle); 4747 /* 4748 * If a property n/v pair was specified, warn the user if there was 4749 * nothing to output. 4750 */ 4751 if (!output && cmd->cmd_prop_nv_pairs > 0) 4752 (void) printf(gettext("No such %s resource.\n"), 4753 rt_to_str(RT_IPD)); 4754 } 4755 4756 static void 4757 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 4758 { 4759 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 4760 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 4761 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 4762 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE); 4763 } 4764 4765 static void 4766 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4767 { 4768 struct zone_nwiftab lookup, user; 4769 boolean_t output = B_FALSE; 4770 4771 if (zonecfg_setnwifent(handle) != Z_OK) 4772 return; 4773 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 4774 if (cmd->cmd_prop_nv_pairs == 0) { 4775 output_net(fp, &lookup); 4776 continue; 4777 } 4778 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK) 4779 continue; 4780 if (strlen(user.zone_nwif_physical) > 0 && 4781 strcmp(user.zone_nwif_physical, 4782 lookup.zone_nwif_physical) != 0) 4783 continue; /* no match */ 4784 /* If present make sure it matches */ 4785 if (strlen(user.zone_nwif_address) > 0 && 4786 !zonecfg_same_net_address(user.zone_nwif_address, 4787 lookup.zone_nwif_address)) 4788 continue; /* no match */ 4789 output_net(fp, &lookup); 4790 output = B_TRUE; 4791 } 4792 (void) zonecfg_endnwifent(handle); 4793 /* 4794 * If a property n/v pair was specified, warn the user if there was 4795 * nothing to output. 4796 */ 4797 if (!output && cmd->cmd_prop_nv_pairs > 0) 4798 (void) printf(gettext("No such %s resource.\n"), 4799 rt_to_str(RT_NET)); 4800 } 4801 4802 static void 4803 output_dev(FILE *fp, struct zone_devtab *devtab) 4804 { 4805 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE)); 4806 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 4807 } 4808 4809 static void 4810 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4811 { 4812 struct zone_devtab lookup, user; 4813 boolean_t output = B_FALSE; 4814 4815 if (zonecfg_setdevent(handle) != Z_OK) 4816 return; 4817 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 4818 if (cmd->cmd_prop_nv_pairs == 0) { 4819 output_dev(fp, &lookup); 4820 continue; 4821 } 4822 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK) 4823 continue; 4824 if (strlen(user.zone_dev_match) > 0 && 4825 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 4826 continue; /* no match */ 4827 output_dev(fp, &lookup); 4828 output = B_TRUE; 4829 } 4830 (void) zonecfg_enddevent(handle); 4831 /* 4832 * If a property n/v pair was specified, warn the user if there was 4833 * nothing to output. 4834 */ 4835 if (!output && cmd->cmd_prop_nv_pairs > 0) 4836 (void) printf(gettext("No such %s resource.\n"), 4837 rt_to_str(RT_DEVICE)); 4838 } 4839 4840 static void 4841 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 4842 { 4843 struct zone_rctlvaltab *valptr; 4844 4845 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 4846 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 4847 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 4848 valptr = valptr->zone_rctlval_next) { 4849 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 4850 pt_to_str(PT_VALUE), 4851 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 4852 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 4853 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 4854 } 4855 } 4856 4857 static void 4858 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4859 { 4860 struct zone_rctltab lookup, user; 4861 boolean_t output = B_FALSE; 4862 4863 if (zonecfg_setrctlent(handle) != Z_OK) 4864 return; 4865 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 4866 if (cmd->cmd_prop_nv_pairs == 0) { 4867 output_rctl(fp, &lookup); 4868 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK && 4869 (strlen(user.zone_rctl_name) == 0 || 4870 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 4871 output_rctl(fp, &lookup); 4872 output = B_TRUE; 4873 } 4874 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 4875 } 4876 (void) zonecfg_endrctlent(handle); 4877 /* 4878 * If a property n/v pair was specified, warn the user if there was 4879 * nothing to output. 4880 */ 4881 if (!output && cmd->cmd_prop_nv_pairs > 0) 4882 (void) printf(gettext("No such %s resource.\n"), 4883 rt_to_str(RT_RCTL)); 4884 } 4885 4886 static void 4887 output_attr(FILE *fp, struct zone_attrtab *attrtab) 4888 { 4889 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 4890 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 4891 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 4892 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 4893 } 4894 4895 static void 4896 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4897 { 4898 struct zone_attrtab lookup, user; 4899 boolean_t output = B_FALSE; 4900 4901 if (zonecfg_setattrent(handle) != Z_OK) 4902 return; 4903 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 4904 if (cmd->cmd_prop_nv_pairs == 0) { 4905 output_attr(fp, &lookup); 4906 continue; 4907 } 4908 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK) 4909 continue; 4910 if (strlen(user.zone_attr_name) > 0 && 4911 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 4912 continue; /* no match */ 4913 if (strlen(user.zone_attr_type) > 0 && 4914 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 4915 continue; /* no match */ 4916 if (strlen(user.zone_attr_value) > 0 && 4917 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 4918 continue; /* no match */ 4919 output_attr(fp, &lookup); 4920 output = B_TRUE; 4921 } 4922 (void) zonecfg_endattrent(handle); 4923 /* 4924 * If a property n/v pair was specified, warn the user if there was 4925 * nothing to output. 4926 */ 4927 if (!output && cmd->cmd_prop_nv_pairs > 0) 4928 (void) printf(gettext("No such %s resource.\n"), 4929 rt_to_str(RT_ATTR)); 4930 } 4931 4932 static void 4933 output_ds(FILE *fp, struct zone_dstab *dstab) 4934 { 4935 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 4936 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 4937 } 4938 4939 static void 4940 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4941 { 4942 struct zone_dstab lookup, user; 4943 boolean_t output = B_FALSE; 4944 4945 if (zonecfg_setdsent(handle) != Z_OK) 4946 return; 4947 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 4948 if (cmd->cmd_prop_nv_pairs == 0) { 4949 output_ds(fp, &lookup); 4950 continue; 4951 } 4952 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK) 4953 continue; 4954 if (strlen(user.zone_dataset_name) > 0 && 4955 strcmp(user.zone_dataset_name, 4956 lookup.zone_dataset_name) != 0) 4957 continue; /* no match */ 4958 output_ds(fp, &lookup); 4959 output = B_TRUE; 4960 } 4961 (void) zonecfg_enddsent(handle); 4962 /* 4963 * If a property n/v pair was specified, warn the user if there was 4964 * nothing to output. 4965 */ 4966 if (!output && cmd->cmd_prop_nv_pairs > 0) 4967 (void) printf(gettext("No such %s resource.\n"), 4968 rt_to_str(RT_DATASET)); 4969 } 4970 4971 static void 4972 output_pset(FILE *fp, struct zone_psettab *psettab) 4973 { 4974 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU)); 4975 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0) 4976 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS), 4977 psettab->zone_ncpu_max); 4978 else 4979 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS), 4980 psettab->zone_ncpu_min, psettab->zone_ncpu_max); 4981 if (psettab->zone_importance[0] != '\0') 4982 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE), 4983 psettab->zone_importance); 4984 } 4985 4986 static void 4987 info_pset(zone_dochandle_t handle, FILE *fp) 4988 { 4989 struct zone_psettab lookup; 4990 4991 if (zonecfg_getpsetent(handle, &lookup) == Z_OK) 4992 output_pset(fp, &lookup); 4993 } 4994 4995 static void 4996 output_pcap(FILE *fp) 4997 { 4998 uint64_t cap; 4999 5000 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) { 5001 float scaled = (float)cap / 100; 5002 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP)); 5003 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS), 5004 scaled); 5005 } 5006 } 5007 5008 static void 5009 info_pcap(FILE *fp) 5010 { 5011 output_pcap(fp); 5012 } 5013 5014 5015 static void 5016 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias) 5017 { 5018 uint64_t limit; 5019 5020 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) { 5021 /* convert memory based properties */ 5022 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) { 5023 char buf[128]; 5024 5025 (void) snprintf(buf, sizeof (buf), "%llu", limit); 5026 bytes_to_units(buf, buf, sizeof (buf)); 5027 (void) fprintf(fp, "[%s: %s]\n", alias, buf); 5028 return; 5029 } 5030 5031 (void) fprintf(fp, "[%s: %llu]\n", alias, limit); 5032 } 5033 } 5034 5035 static void 5036 bytes_to_units(char *str, char *buf, int bufsize) 5037 { 5038 unsigned long long num; 5039 unsigned long long save = 0; 5040 char *units = "BKMGT"; 5041 char *up = units; 5042 5043 num = strtoll(str, NULL, 10); 5044 5045 if (num < 1024) { 5046 (void) snprintf(buf, bufsize, "%llu", num); 5047 return; 5048 } 5049 5050 while ((num >= 1024) && (*up != 'T')) { 5051 up++; /* next unit of measurement */ 5052 save = num; 5053 num = (num + 512) >> 10; 5054 } 5055 5056 /* check if we should output a fraction. snprintf will round for us */ 5057 if (save % 1024 != 0 && ((save >> 10) < 10)) 5058 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024), 5059 *up); 5060 else 5061 (void) snprintf(buf, bufsize, "%llu%c", num, *up); 5062 } 5063 5064 static void 5065 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap, 5066 uint64_t maxswap, int showlocked, uint64_t maxlocked) 5067 { 5068 char buf[128]; 5069 5070 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP)); 5071 if (mcaptab->zone_physmem_cap[0] != '\0') { 5072 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf)); 5073 output_prop(fp, PT_PHYSICAL, buf, B_TRUE); 5074 } 5075 5076 if (showswap == Z_OK) { 5077 (void) snprintf(buf, sizeof (buf), "%llu", maxswap); 5078 bytes_to_units(buf, buf, sizeof (buf)); 5079 output_prop(fp, PT_SWAP, buf, B_TRUE); 5080 } 5081 5082 if (showlocked == Z_OK) { 5083 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked); 5084 bytes_to_units(buf, buf, sizeof (buf)); 5085 output_prop(fp, PT_LOCKED, buf, B_TRUE); 5086 } 5087 } 5088 5089 static void 5090 info_mcap(zone_dochandle_t handle, FILE *fp) 5091 { 5092 int res1, res2, res3; 5093 uint64_t swap_limit; 5094 uint64_t locked_limit; 5095 struct zone_mcaptab lookup; 5096 5097 bzero(&lookup, sizeof (lookup)); 5098 res1 = zonecfg_getmcapent(handle, &lookup); 5099 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit); 5100 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 5101 &locked_limit); 5102 5103 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK) 5104 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit); 5105 } 5106 5107 void 5108 info_func(cmd_t *cmd) 5109 { 5110 FILE *fp = stdout; 5111 boolean_t need_to_close = B_FALSE; 5112 char *pager; 5113 int type; 5114 int res1, res2; 5115 uint64_t swap_limit; 5116 uint64_t locked_limit; 5117 5118 assert(cmd != NULL); 5119 5120 if (initialize(B_TRUE) != Z_OK) 5121 return; 5122 5123 /* don't page error output */ 5124 if (interactive_mode) { 5125 if ((pager = getenv("PAGER")) == NULL) 5126 pager = PAGER; 5127 if ((fp = popen(pager, "w")) != NULL) 5128 need_to_close = B_TRUE; 5129 setbuf(fp, NULL); 5130 } 5131 5132 if (!global_scope) { 5133 switch (resource_scope) { 5134 case RT_FS: 5135 output_fs(fp, &in_progress_fstab); 5136 break; 5137 case RT_IPD: 5138 output_ipd(fp, &in_progress_ipdtab); 5139 break; 5140 case RT_NET: 5141 output_net(fp, &in_progress_nwiftab); 5142 break; 5143 case RT_DEVICE: 5144 output_dev(fp, &in_progress_devtab); 5145 break; 5146 case RT_RCTL: 5147 output_rctl(fp, &in_progress_rctltab); 5148 break; 5149 case RT_ATTR: 5150 output_attr(fp, &in_progress_attrtab); 5151 break; 5152 case RT_DATASET: 5153 output_ds(fp, &in_progress_dstab); 5154 break; 5155 case RT_DCPU: 5156 output_pset(fp, &in_progress_psettab); 5157 break; 5158 case RT_PCAP: 5159 output_pcap(fp); 5160 break; 5161 case RT_MCAP: 5162 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 5163 &swap_limit); 5164 res2 = zonecfg_get_aliased_rctl(handle, 5165 ALIAS_MAXLOCKEDMEM, &locked_limit); 5166 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit, 5167 res2, locked_limit); 5168 break; 5169 } 5170 goto cleanup; 5171 } 5172 5173 type = cmd->cmd_res_type; 5174 5175 if (gz_invalid_rt_property(type)) { 5176 zerr(gettext("%s is not a valid property for the global zone."), 5177 rt_to_str(type)); 5178 goto cleanup; 5179 } 5180 5181 if (gz_invalid_resource(type)) { 5182 zerr(gettext("%s is not a valid resource for the global zone."), 5183 rt_to_str(type)); 5184 goto cleanup; 5185 } 5186 5187 switch (cmd->cmd_res_type) { 5188 case RT_UNKNOWN: 5189 info_zonename(handle, fp); 5190 if (!global_zone) { 5191 info_zonepath(handle, fp); 5192 info_brand(handle, fp); 5193 info_autoboot(handle, fp); 5194 info_bootargs(handle, fp); 5195 } 5196 info_pool(handle, fp); 5197 if (!global_zone) { 5198 info_limitpriv(handle, fp); 5199 info_sched(handle, fp); 5200 info_iptype(handle, fp); 5201 } 5202 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5203 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5204 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5205 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5206 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5207 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5208 if (!global_zone) { 5209 info_ipd(handle, fp, cmd); 5210 info_fs(handle, fp, cmd); 5211 info_net(handle, fp, cmd); 5212 info_dev(handle, fp, cmd); 5213 } 5214 info_pset(handle, fp); 5215 info_pcap(fp); 5216 info_mcap(handle, fp); 5217 if (!global_zone) { 5218 info_attr(handle, fp, cmd); 5219 info_ds(handle, fp, cmd); 5220 } 5221 info_rctl(handle, fp, cmd); 5222 break; 5223 case RT_ZONENAME: 5224 info_zonename(handle, fp); 5225 break; 5226 case RT_ZONEPATH: 5227 info_zonepath(handle, fp); 5228 break; 5229 case RT_BRAND: 5230 info_brand(handle, fp); 5231 break; 5232 case RT_AUTOBOOT: 5233 info_autoboot(handle, fp); 5234 break; 5235 case RT_POOL: 5236 info_pool(handle, fp); 5237 break; 5238 case RT_LIMITPRIV: 5239 info_limitpriv(handle, fp); 5240 break; 5241 case RT_BOOTARGS: 5242 info_bootargs(handle, fp); 5243 break; 5244 case RT_SCHED: 5245 info_sched(handle, fp); 5246 break; 5247 case RT_IPTYPE: 5248 info_iptype(handle, fp); 5249 break; 5250 case RT_MAXLWPS: 5251 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5252 break; 5253 case RT_MAXSHMMEM: 5254 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5255 break; 5256 case RT_MAXSHMIDS: 5257 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5258 break; 5259 case RT_MAXMSGIDS: 5260 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5261 break; 5262 case RT_MAXSEMIDS: 5263 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5264 break; 5265 case RT_SHARES: 5266 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5267 break; 5268 case RT_FS: 5269 info_fs(handle, fp, cmd); 5270 break; 5271 case RT_IPD: 5272 info_ipd(handle, fp, cmd); 5273 break; 5274 case RT_NET: 5275 info_net(handle, fp, cmd); 5276 break; 5277 case RT_DEVICE: 5278 info_dev(handle, fp, cmd); 5279 break; 5280 case RT_RCTL: 5281 info_rctl(handle, fp, cmd); 5282 break; 5283 case RT_ATTR: 5284 info_attr(handle, fp, cmd); 5285 break; 5286 case RT_DATASET: 5287 info_ds(handle, fp, cmd); 5288 break; 5289 case RT_DCPU: 5290 info_pset(handle, fp); 5291 break; 5292 case RT_PCAP: 5293 info_pcap(fp); 5294 break; 5295 case RT_MCAP: 5296 info_mcap(handle, fp); 5297 break; 5298 default: 5299 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 5300 B_TRUE); 5301 } 5302 5303 cleanup: 5304 if (need_to_close) 5305 (void) pclose(fp); 5306 } 5307 5308 /* 5309 * Helper function for verify-- checks that a required string property 5310 * exists. 5311 */ 5312 static void 5313 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 5314 { 5315 if (strlen(attr) == 0) { 5316 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 5317 pt_to_str(pt)); 5318 saw_error = B_TRUE; 5319 if (*ret_val == Z_OK) 5320 *ret_val = Z_REQD_PROPERTY_MISSING; 5321 } 5322 } 5323 5324 static int 5325 do_subproc(char *cmdbuf) 5326 { 5327 char inbuf[MAX_CMD_LEN]; 5328 FILE *file; 5329 int status; 5330 5331 file = popen(cmdbuf, "r"); 5332 if (file == NULL) { 5333 zerr(gettext("Could not launch: %s"), cmdbuf); 5334 return (-1); 5335 } 5336 5337 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 5338 fprintf(stderr, "%s", inbuf); 5339 status = pclose(file); 5340 5341 if (WIFSIGNALED(status)) { 5342 zerr(gettext("%s unexpectedly terminated due to signal %d"), 5343 cmdbuf, WTERMSIG(status)); 5344 return (-1); 5345 } 5346 assert(WIFEXITED(status)); 5347 return (WEXITSTATUS(status)); 5348 } 5349 5350 static int 5351 brand_verify(zone_dochandle_t handle) 5352 { 5353 char xml_file[32]; 5354 char cmdbuf[MAX_CMD_LEN]; 5355 brand_handle_t bh; 5356 char brand[MAXNAMELEN]; 5357 int err; 5358 5359 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 5360 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 5361 return (Z_INVALID_DOCUMENT); 5362 } 5363 if ((bh = brand_open(brand)) == NULL) { 5364 zerr("%s: %s\n", zone, gettext("unknown brand.")); 5365 return (Z_INVALID_DOCUMENT); 5366 } 5367 5368 /* 5369 * Fetch the verify command, if any, from the brand configuration 5370 * and build the command line to execute it. 5371 */ 5372 strcpy(cmdbuf, EXEC_PREFIX); 5373 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN, 5374 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 5375 brand_close(bh); 5376 if (err != Z_OK) { 5377 zerr("%s: %s\n", zone, 5378 gettext("could not get brand verification command")); 5379 return (Z_INVALID_DOCUMENT); 5380 } 5381 5382 /* 5383 * If the brand doesn't provide a verification routine, we just 5384 * return success. 5385 */ 5386 if (strlen(cmdbuf) == EXEC_LEN) 5387 return (Z_OK); 5388 5389 /* 5390 * Dump the current config information for this zone to a file. 5391 */ 5392 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX"); 5393 if (mkstemp(xml_file) == NULL) 5394 return (Z_TEMP_FILE); 5395 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 5396 (void) unlink(xml_file); 5397 return (err); 5398 } 5399 5400 /* 5401 * Execute the verification command. 5402 */ 5403 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 5404 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 5405 err = Z_BRAND_ERROR; 5406 } else { 5407 err = do_subproc(cmdbuf); 5408 } 5409 5410 (void) unlink(xml_file); 5411 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 5412 } 5413 5414 /* 5415 * See the DTD for which attributes are required for which resources. 5416 * 5417 * This function can be called by commit_func(), which needs to save things, 5418 * in addition to the general call from parse_and_run(), which doesn't need 5419 * things saved. Since the parameters are standardized, we distinguish by 5420 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 5421 * that a save is needed. 5422 */ 5423 void 5424 verify_func(cmd_t *cmd) 5425 { 5426 struct zone_nwiftab nwiftab; 5427 struct zone_fstab fstab; 5428 struct zone_attrtab attrtab; 5429 struct zone_rctltab rctltab; 5430 struct zone_dstab dstab; 5431 struct zone_psettab psettab; 5432 char zonepath[MAXPATHLEN]; 5433 char sched[MAXNAMELEN]; 5434 char brand[MAXNAMELEN]; 5435 int err, ret_val = Z_OK, arg; 5436 int pset_res; 5437 boolean_t save = B_FALSE; 5438 boolean_t arg_err = B_FALSE; 5439 zone_iptype_t iptype; 5440 boolean_t has_cpu_shares = B_FALSE; 5441 boolean_t has_cpu_cap = B_FALSE; 5442 5443 optind = 0; 5444 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5445 switch (arg) { 5446 case '?': 5447 longer_usage(CMD_VERIFY); 5448 arg_err = B_TRUE; 5449 break; 5450 default: 5451 short_usage(CMD_VERIFY); 5452 arg_err = B_TRUE; 5453 break; 5454 } 5455 } 5456 if (arg_err) 5457 return; 5458 5459 if (optind > cmd->cmd_argc) { 5460 short_usage(CMD_VERIFY); 5461 return; 5462 } 5463 5464 if (zone_is_read_only(CMD_VERIFY)) 5465 return; 5466 5467 assert(cmd != NULL); 5468 5469 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 5470 save = B_TRUE; 5471 if (initialize(B_TRUE) != Z_OK) 5472 return; 5473 5474 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK && 5475 !global_zone) { 5476 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 5477 ret_val = Z_REQD_RESOURCE_MISSING; 5478 saw_error = B_TRUE; 5479 } 5480 if (strlen(zonepath) == 0 && !global_zone) { 5481 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 5482 ret_val = Z_REQD_RESOURCE_MISSING; 5483 saw_error = B_TRUE; 5484 } 5485 5486 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 5487 zone_perror(zone, err, B_TRUE); 5488 return; 5489 } 5490 if (strcmp(brand, NATIVE_BRAND_NAME) != 0) { 5491 if ((err = brand_verify(handle)) != Z_OK) { 5492 zone_perror(zone, err, B_TRUE); 5493 return; 5494 } 5495 } 5496 5497 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 5498 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE)); 5499 ret_val = Z_REQD_RESOURCE_MISSING; 5500 saw_error = B_TRUE; 5501 } 5502 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 5503 zone_perror(zone, err, B_TRUE); 5504 return; 5505 } 5506 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5507 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 5508 } 5509 (void) zonecfg_endipdent(handle); 5510 5511 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 5512 zone_perror(zone, err, B_TRUE); 5513 return; 5514 } 5515 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 5516 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 5517 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 5518 &ret_val); 5519 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 5520 5521 zonecfg_free_fs_option_list(fstab.zone_fs_options); 5522 } 5523 (void) zonecfg_endfsent(handle); 5524 5525 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 5526 zone_perror(zone, err, B_TRUE); 5527 return; 5528 } 5529 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 5530 /* 5531 * physical is required in all cases. 5532 * A shared IP requires an address, 5533 * and may include a default router, while 5534 * an exclusive IP must have neither an address 5535 * nor a default router. 5536 */ 5537 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 5538 PT_PHYSICAL, &ret_val); 5539 5540 switch (iptype) { 5541 case ZS_SHARED: 5542 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 5543 PT_ADDRESS, &ret_val); 5544 break; 5545 case ZS_EXCLUSIVE: 5546 if (strlen(nwiftab.zone_nwif_address) > 0) { 5547 zerr(gettext("%s: %s cannot be specified " 5548 "for an exclusive IP type"), 5549 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS)); 5550 saw_error = B_TRUE; 5551 if (ret_val == Z_OK) 5552 ret_val = Z_INVAL; 5553 } 5554 if (strlen(nwiftab.zone_nwif_defrouter) > 0) { 5555 zerr(gettext("%s: %s cannot be specified " 5556 "for an exclusive IP type"), 5557 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER)); 5558 saw_error = B_TRUE; 5559 if (ret_val == Z_OK) 5560 ret_val = Z_INVAL; 5561 } 5562 break; 5563 } 5564 } 5565 (void) zonecfg_endnwifent(handle); 5566 5567 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 5568 zone_perror(zone, err, B_TRUE); 5569 return; 5570 } 5571 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 5572 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 5573 &ret_val); 5574 5575 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0) 5576 has_cpu_shares = B_TRUE; 5577 5578 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0) 5579 has_cpu_cap = B_TRUE; 5580 5581 if (rctltab.zone_rctl_valptr == NULL) { 5582 zerr(gettext("%s: no %s specified"), 5583 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 5584 saw_error = B_TRUE; 5585 if (ret_val == Z_OK) 5586 ret_val = Z_REQD_PROPERTY_MISSING; 5587 } else { 5588 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 5589 } 5590 } 5591 (void) zonecfg_endrctlent(handle); 5592 5593 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK && 5594 has_cpu_shares) { 5595 zerr(gettext("%s zone.cpu-shares and %s are incompatible."), 5596 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 5597 saw_error = B_TRUE; 5598 if (ret_val == Z_OK) 5599 ret_val = Z_INCOMPATIBLE; 5600 } 5601 5602 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched, 5603 sizeof (sched)) == Z_OK && strlen(sched) > 0 && 5604 strcmp(sched, "FSS") != 0) { 5605 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are " 5606 "incompatible"), 5607 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched); 5608 saw_error = B_TRUE; 5609 if (ret_val == Z_OK) 5610 ret_val = Z_INCOMPATIBLE; 5611 } 5612 5613 if (pset_res == Z_OK && has_cpu_cap) { 5614 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."), 5615 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 5616 saw_error = B_TRUE; 5617 if (ret_val == Z_OK) 5618 ret_val = Z_INCOMPATIBLE; 5619 } 5620 5621 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 5622 zone_perror(zone, err, B_TRUE); 5623 return; 5624 } 5625 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 5626 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 5627 &ret_val); 5628 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 5629 &ret_val); 5630 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 5631 &ret_val); 5632 } 5633 (void) zonecfg_endattrent(handle); 5634 5635 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 5636 zone_perror(zone, err, B_TRUE); 5637 return; 5638 } 5639 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 5640 if (strlen(dstab.zone_dataset_name) == 0) { 5641 zerr("%s: %s %s", rt_to_str(RT_DATASET), 5642 pt_to_str(PT_NAME), gettext("not specified")); 5643 saw_error = B_TRUE; 5644 if (ret_val == Z_OK) 5645 ret_val = Z_REQD_PROPERTY_MISSING; 5646 } else if (!zfs_name_valid(dstab.zone_dataset_name, 5647 ZFS_TYPE_FILESYSTEM)) { 5648 zerr("%s: %s %s", rt_to_str(RT_DATASET), 5649 pt_to_str(PT_NAME), gettext("invalid")); 5650 saw_error = B_TRUE; 5651 if (ret_val == Z_OK) 5652 ret_val = Z_BAD_PROPERTY; 5653 } 5654 5655 } 5656 (void) zonecfg_enddsent(handle); 5657 5658 if (!global_scope) { 5659 zerr(gettext("resource specification incomplete")); 5660 saw_error = B_TRUE; 5661 if (ret_val == Z_OK) 5662 ret_val = Z_INSUFFICIENT_SPEC; 5663 } 5664 5665 if (save) { 5666 if (ret_val == Z_OK) { 5667 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 5668 need_to_commit = B_FALSE; 5669 (void) strlcpy(revert_zone, zone, 5670 sizeof (revert_zone)); 5671 } 5672 } else { 5673 zerr(gettext("Zone %s failed to verify"), zone); 5674 } 5675 } 5676 if (ret_val != Z_OK) 5677 zone_perror(zone, ret_val, B_TRUE); 5678 } 5679 5680 void 5681 cancel_func(cmd_t *cmd) 5682 { 5683 int arg; 5684 boolean_t arg_err = B_FALSE; 5685 5686 assert(cmd != NULL); 5687 5688 optind = 0; 5689 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5690 switch (arg) { 5691 case '?': 5692 longer_usage(CMD_CANCEL); 5693 arg_err = B_TRUE; 5694 break; 5695 default: 5696 short_usage(CMD_CANCEL); 5697 arg_err = B_TRUE; 5698 break; 5699 } 5700 } 5701 if (arg_err) 5702 return; 5703 5704 if (optind != cmd->cmd_argc) { 5705 short_usage(CMD_CANCEL); 5706 return; 5707 } 5708 5709 if (global_scope) 5710 scope_usage(CMD_CANCEL); 5711 global_scope = B_TRUE; 5712 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 5713 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 5714 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 5715 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 5716 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 5717 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 5718 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 5719 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 5720 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 5721 } 5722 5723 static int 5724 validate_attr_name(char *name) 5725 { 5726 int i; 5727 5728 if (!isalnum(name[0])) { 5729 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 5730 "numeric character."), rt_to_str(RT_ATTR), 5731 pt_to_str(PT_NAME), name); 5732 return (Z_INVAL); 5733 } 5734 for (i = 1; name[i]; i++) 5735 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 5736 zerr(gettext("Invalid %s %s %s: can only contain " 5737 "alpha-numeric characters, plus '-' and '.'."), 5738 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 5739 return (Z_INVAL); 5740 } 5741 return (Z_OK); 5742 } 5743 5744 static int 5745 validate_attr_type_val(struct zone_attrtab *attrtab) 5746 { 5747 boolean_t boolval; 5748 int64_t intval; 5749 char strval[MAXNAMELEN]; 5750 uint64_t uintval; 5751 5752 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 5753 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 5754 return (Z_OK); 5755 zerr(gettext("invalid %s value for %s=%s"), 5756 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 5757 return (Z_ERR); 5758 } 5759 5760 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 5761 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 5762 return (Z_OK); 5763 zerr(gettext("invalid %s value for %s=%s"), 5764 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 5765 return (Z_ERR); 5766 } 5767 5768 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 5769 if (zonecfg_get_attr_string(attrtab, strval, 5770 sizeof (strval)) == Z_OK) 5771 return (Z_OK); 5772 zerr(gettext("invalid %s value for %s=%s"), 5773 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 5774 return (Z_ERR); 5775 } 5776 5777 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 5778 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 5779 return (Z_OK); 5780 zerr(gettext("invalid %s value for %s=%s"), 5781 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 5782 return (Z_ERR); 5783 } 5784 5785 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 5786 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 5787 return (Z_ERR); 5788 } 5789 5790 /* 5791 * Helper function for end_func-- checks the existence of a given property 5792 * and emits a message if not specified. 5793 */ 5794 static int 5795 end_check_reqd(char *attr, int pt, boolean_t *validation_failed) 5796 { 5797 if (strlen(attr) == 0) { 5798 *validation_failed = B_TRUE; 5799 zerr(gettext("%s not specified"), pt_to_str(pt)); 5800 return (Z_ERR); 5801 } 5802 return (Z_OK); 5803 } 5804 5805 void 5806 end_func(cmd_t *cmd) 5807 { 5808 boolean_t validation_failed = B_FALSE; 5809 boolean_t arg_err = B_FALSE; 5810 struct zone_fstab tmp_fstab; 5811 struct zone_nwiftab tmp_nwiftab; 5812 struct zone_devtab tmp_devtab; 5813 struct zone_rctltab tmp_rctltab; 5814 struct zone_attrtab tmp_attrtab; 5815 struct zone_dstab tmp_dstab; 5816 int err, arg, res1, res2, res3; 5817 uint64_t swap_limit; 5818 uint64_t locked_limit; 5819 uint64_t proc_cap; 5820 5821 assert(cmd != NULL); 5822 5823 optind = 0; 5824 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5825 switch (arg) { 5826 case '?': 5827 longer_usage(CMD_END); 5828 arg_err = B_TRUE; 5829 break; 5830 default: 5831 short_usage(CMD_END); 5832 arg_err = B_TRUE; 5833 break; 5834 } 5835 } 5836 if (arg_err) 5837 return; 5838 5839 if (optind != cmd->cmd_argc) { 5840 short_usage(CMD_END); 5841 return; 5842 } 5843 5844 if (global_scope) { 5845 scope_usage(CMD_END); 5846 return; 5847 } 5848 5849 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 5850 5851 switch (resource_scope) { 5852 case RT_FS: 5853 /* First make sure everything was filled in. */ 5854 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 5855 PT_DIR, &validation_failed) == Z_OK) { 5856 if (in_progress_fstab.zone_fs_dir[0] != '/') { 5857 zerr(gettext("%s %s is not an absolute path."), 5858 pt_to_str(PT_DIR), 5859 in_progress_fstab.zone_fs_dir); 5860 validation_failed = B_TRUE; 5861 } 5862 } 5863 5864 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 5865 PT_SPECIAL, &validation_failed); 5866 5867 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 5868 in_progress_fstab.zone_fs_raw[0] != '/') { 5869 zerr(gettext("%s %s is not an absolute path."), 5870 pt_to_str(PT_RAW), 5871 in_progress_fstab.zone_fs_raw); 5872 validation_failed = B_TRUE; 5873 } 5874 5875 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 5876 &validation_failed); 5877 5878 if (validation_failed) { 5879 saw_error = B_TRUE; 5880 return; 5881 } 5882 5883 if (end_op == CMD_ADD) { 5884 /* Make sure there isn't already one like this. */ 5885 bzero(&tmp_fstab, sizeof (tmp_fstab)); 5886 (void) strlcpy(tmp_fstab.zone_fs_dir, 5887 in_progress_fstab.zone_fs_dir, 5888 sizeof (tmp_fstab.zone_fs_dir)); 5889 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 5890 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 5891 if (err == Z_OK) { 5892 zerr(gettext("A %s resource " 5893 "with the %s '%s' already exists."), 5894 rt_to_str(RT_FS), pt_to_str(PT_DIR), 5895 in_progress_fstab.zone_fs_dir); 5896 saw_error = B_TRUE; 5897 return; 5898 } 5899 err = zonecfg_add_filesystem(handle, 5900 &in_progress_fstab); 5901 } else { 5902 err = zonecfg_modify_filesystem(handle, &old_fstab, 5903 &in_progress_fstab); 5904 } 5905 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 5906 in_progress_fstab.zone_fs_options = NULL; 5907 break; 5908 5909 case RT_IPD: 5910 /* First make sure everything was filled in. */ 5911 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 5912 &validation_failed) == Z_OK) { 5913 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 5914 zerr(gettext("%s %s is not an absolute path."), 5915 pt_to_str(PT_DIR), 5916 in_progress_ipdtab.zone_fs_dir); 5917 validation_failed = B_TRUE; 5918 } 5919 } 5920 if (validation_failed) { 5921 saw_error = B_TRUE; 5922 return; 5923 } 5924 5925 if (end_op == CMD_ADD) { 5926 /* Make sure there isn't already one like this. */ 5927 bzero(&tmp_fstab, sizeof (tmp_fstab)); 5928 (void) strlcpy(tmp_fstab.zone_fs_dir, 5929 in_progress_ipdtab.zone_fs_dir, 5930 sizeof (tmp_fstab.zone_fs_dir)); 5931 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 5932 if (err == Z_OK) { 5933 zerr(gettext("An %s resource " 5934 "with the %s '%s' already exists."), 5935 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 5936 in_progress_ipdtab.zone_fs_dir); 5937 saw_error = B_TRUE; 5938 return; 5939 } 5940 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 5941 } else { 5942 err = zonecfg_modify_ipd(handle, &old_ipdtab, 5943 &in_progress_ipdtab); 5944 } 5945 break; 5946 case RT_NET: 5947 /* 5948 * First make sure everything was filled in. 5949 * Since we don't know whether IP will be shared 5950 * or exclusive here, some checks are deferred until 5951 * the verify command. 5952 */ 5953 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 5954 PT_PHYSICAL, &validation_failed); 5955 5956 if (validation_failed) { 5957 saw_error = B_TRUE; 5958 return; 5959 } 5960 if (end_op == CMD_ADD) { 5961 /* Make sure there isn't already one like this. */ 5962 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 5963 (void) strlcpy(tmp_nwiftab.zone_nwif_physical, 5964 in_progress_nwiftab.zone_nwif_physical, 5965 sizeof (tmp_nwiftab.zone_nwif_physical)); 5966 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 5967 in_progress_nwiftab.zone_nwif_address, 5968 sizeof (tmp_nwiftab.zone_nwif_address)); 5969 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 5970 zerr(gettext("A %s resource with the %s '%s', " 5971 "and %s '%s' already exists."), 5972 rt_to_str(RT_NET), 5973 pt_to_str(PT_PHYSICAL), 5974 in_progress_nwiftab.zone_nwif_physical, 5975 pt_to_str(PT_ADDRESS), 5976 in_progress_nwiftab.zone_nwif_address); 5977 saw_error = B_TRUE; 5978 return; 5979 } 5980 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 5981 } else { 5982 err = zonecfg_modify_nwif(handle, &old_nwiftab, 5983 &in_progress_nwiftab); 5984 } 5985 break; 5986 5987 case RT_DEVICE: 5988 /* First make sure everything was filled in. */ 5989 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 5990 PT_MATCH, &validation_failed); 5991 5992 if (validation_failed) { 5993 saw_error = B_TRUE; 5994 return; 5995 } 5996 5997 if (end_op == CMD_ADD) { 5998 /* Make sure there isn't already one like this. */ 5999 (void) strlcpy(tmp_devtab.zone_dev_match, 6000 in_progress_devtab.zone_dev_match, 6001 sizeof (tmp_devtab.zone_dev_match)); 6002 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 6003 zerr(gettext("A %s resource with the %s '%s' " 6004 "already exists."), rt_to_str(RT_DEVICE), 6005 pt_to_str(PT_MATCH), 6006 in_progress_devtab.zone_dev_match); 6007 saw_error = B_TRUE; 6008 return; 6009 } 6010 err = zonecfg_add_dev(handle, &in_progress_devtab); 6011 } else { 6012 err = zonecfg_modify_dev(handle, &old_devtab, 6013 &in_progress_devtab); 6014 } 6015 break; 6016 6017 case RT_RCTL: 6018 /* First make sure everything was filled in. */ 6019 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 6020 PT_NAME, &validation_failed); 6021 6022 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 6023 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 6024 validation_failed = B_TRUE; 6025 } 6026 6027 if (validation_failed) { 6028 saw_error = B_TRUE; 6029 return; 6030 } 6031 6032 if (end_op == CMD_ADD) { 6033 /* Make sure there isn't already one like this. */ 6034 (void) strlcpy(tmp_rctltab.zone_rctl_name, 6035 in_progress_rctltab.zone_rctl_name, 6036 sizeof (tmp_rctltab.zone_rctl_name)); 6037 tmp_rctltab.zone_rctl_valptr = NULL; 6038 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 6039 zonecfg_free_rctl_value_list( 6040 tmp_rctltab.zone_rctl_valptr); 6041 if (err == Z_OK) { 6042 zerr(gettext("A %s resource " 6043 "with the %s '%s' already exists."), 6044 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 6045 in_progress_rctltab.zone_rctl_name); 6046 saw_error = B_TRUE; 6047 return; 6048 } 6049 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 6050 } else { 6051 err = zonecfg_modify_rctl(handle, &old_rctltab, 6052 &in_progress_rctltab); 6053 } 6054 if (err == Z_OK) { 6055 zonecfg_free_rctl_value_list( 6056 in_progress_rctltab.zone_rctl_valptr); 6057 in_progress_rctltab.zone_rctl_valptr = NULL; 6058 } 6059 break; 6060 6061 case RT_ATTR: 6062 /* First make sure everything was filled in. */ 6063 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 6064 PT_NAME, &validation_failed); 6065 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 6066 PT_TYPE, &validation_failed); 6067 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 6068 PT_VALUE, &validation_failed); 6069 6070 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 6071 Z_OK) 6072 validation_failed = B_TRUE; 6073 6074 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 6075 validation_failed = B_TRUE; 6076 6077 if (validation_failed) { 6078 saw_error = B_TRUE; 6079 return; 6080 } 6081 if (end_op == CMD_ADD) { 6082 /* Make sure there isn't already one like this. */ 6083 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 6084 (void) strlcpy(tmp_attrtab.zone_attr_name, 6085 in_progress_attrtab.zone_attr_name, 6086 sizeof (tmp_attrtab.zone_attr_name)); 6087 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 6088 zerr(gettext("An %s resource " 6089 "with the %s '%s' already exists."), 6090 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 6091 in_progress_attrtab.zone_attr_name); 6092 saw_error = B_TRUE; 6093 return; 6094 } 6095 err = zonecfg_add_attr(handle, &in_progress_attrtab); 6096 } else { 6097 err = zonecfg_modify_attr(handle, &old_attrtab, 6098 &in_progress_attrtab); 6099 } 6100 break; 6101 case RT_DATASET: 6102 /* First make sure everything was filled in. */ 6103 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 6104 zerr("%s %s", pt_to_str(PT_NAME), 6105 gettext("not specified")); 6106 saw_error = B_TRUE; 6107 validation_failed = B_TRUE; 6108 } 6109 if (validation_failed) 6110 return; 6111 if (end_op == CMD_ADD) { 6112 /* Make sure there isn't already one like this. */ 6113 bzero(&tmp_dstab, sizeof (tmp_dstab)); 6114 (void) strlcpy(tmp_dstab.zone_dataset_name, 6115 in_progress_dstab.zone_dataset_name, 6116 sizeof (tmp_dstab.zone_dataset_name)); 6117 err = zonecfg_lookup_ds(handle, &tmp_dstab); 6118 if (err == Z_OK) { 6119 zerr(gettext("A %s resource " 6120 "with the %s '%s' already exists."), 6121 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 6122 in_progress_dstab.zone_dataset_name); 6123 saw_error = B_TRUE; 6124 return; 6125 } 6126 err = zonecfg_add_ds(handle, &in_progress_dstab); 6127 } else { 6128 err = zonecfg_modify_ds(handle, &old_dstab, 6129 &in_progress_dstab); 6130 } 6131 break; 6132 case RT_DCPU: 6133 /* Make sure everything was filled in. */ 6134 if (end_check_reqd(in_progress_psettab.zone_ncpu_min, 6135 PT_NCPUS, &validation_failed) != Z_OK) { 6136 saw_error = B_TRUE; 6137 return; 6138 } 6139 6140 if (end_op == CMD_ADD) { 6141 err = zonecfg_add_pset(handle, &in_progress_psettab); 6142 } else { 6143 err = zonecfg_modify_pset(handle, &in_progress_psettab); 6144 } 6145 break; 6146 case RT_PCAP: 6147 /* Make sure everything was filled in. */ 6148 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap) 6149 != Z_OK) { 6150 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS)); 6151 saw_error = B_TRUE; 6152 validation_failed = B_TRUE; 6153 return; 6154 } 6155 err = Z_OK; 6156 break; 6157 case RT_MCAP: 6158 /* Make sure everything was filled in. */ 6159 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ? 6160 Z_ERR : Z_OK; 6161 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 6162 &swap_limit); 6163 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 6164 &locked_limit); 6165 6166 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 6167 zerr(gettext("No property was specified. One of %s, " 6168 "%s or %s is required."), pt_to_str(PT_PHYSICAL), 6169 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED)); 6170 saw_error = B_TRUE; 6171 return; 6172 } 6173 6174 /* if phys & locked are both set, verify locked <= phys */ 6175 if (res1 == Z_OK && res3 == Z_OK) { 6176 uint64_t phys_limit; 6177 char *endp; 6178 6179 phys_limit = strtoull( 6180 in_progress_mcaptab.zone_physmem_cap, &endp, 10); 6181 if (phys_limit < locked_limit) { 6182 zerr(gettext("The %s cap must be less than or " 6183 "equal to the %s cap."), 6184 pt_to_str(PT_LOCKED), 6185 pt_to_str(PT_PHYSICAL)); 6186 saw_error = B_TRUE; 6187 return; 6188 } 6189 } 6190 6191 err = Z_OK; 6192 if (res1 == Z_OK) { 6193 /* 6194 * We could be ending from either an add operation 6195 * or a select operation. Since all of the properties 6196 * within this resource are optional, we always use 6197 * modify on the mcap entry. zonecfg_modify_mcap() 6198 * will handle both adding and modifying a memory cap. 6199 */ 6200 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab); 6201 } else if (end_op == CMD_SELECT) { 6202 /* 6203 * If we're ending from a select and the physical 6204 * memory cap is empty then the user could have cleared 6205 * the physical cap value, so try to delete the entry. 6206 */ 6207 (void) zonecfg_delete_mcap(handle); 6208 } 6209 break; 6210 default: 6211 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 6212 B_TRUE); 6213 saw_error = B_TRUE; 6214 return; 6215 } 6216 6217 if (err != Z_OK) { 6218 zone_perror(zone, err, B_TRUE); 6219 } else { 6220 need_to_commit = B_TRUE; 6221 global_scope = B_TRUE; 6222 end_op = -1; 6223 } 6224 } 6225 6226 void 6227 commit_func(cmd_t *cmd) 6228 { 6229 int arg; 6230 boolean_t arg_err = B_FALSE; 6231 6232 optind = 0; 6233 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6234 switch (arg) { 6235 case '?': 6236 longer_usage(CMD_COMMIT); 6237 arg_err = B_TRUE; 6238 break; 6239 default: 6240 short_usage(CMD_COMMIT); 6241 arg_err = B_TRUE; 6242 break; 6243 } 6244 } 6245 if (arg_err) 6246 return; 6247 6248 if (optind != cmd->cmd_argc) { 6249 short_usage(CMD_COMMIT); 6250 return; 6251 } 6252 6253 if (zone_is_read_only(CMD_COMMIT)) 6254 return; 6255 6256 assert(cmd != NULL); 6257 6258 cmd->cmd_argc = 1; 6259 /* 6260 * cmd_arg normally comes from a strdup() in the lexer, and the 6261 * whole cmd structure and its (char *) attributes are freed at 6262 * the completion of each command, so the strdup() below is needed 6263 * to match this and prevent a core dump from trying to free() 6264 * something that can't be. 6265 */ 6266 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 6267 zone_perror(zone, Z_NOMEM, B_TRUE); 6268 exit(Z_ERR); 6269 } 6270 cmd->cmd_argv[1] = NULL; 6271 verify_func(cmd); 6272 } 6273 6274 void 6275 revert_func(cmd_t *cmd) 6276 { 6277 char line[128]; /* enough to ask a question */ 6278 boolean_t force = B_FALSE; 6279 boolean_t arg_err = B_FALSE; 6280 int err, arg, answer; 6281 6282 optind = 0; 6283 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 6284 switch (arg) { 6285 case '?': 6286 longer_usage(CMD_REVERT); 6287 arg_err = B_TRUE; 6288 break; 6289 case 'F': 6290 force = B_TRUE; 6291 break; 6292 default: 6293 short_usage(CMD_REVERT); 6294 arg_err = B_TRUE; 6295 break; 6296 } 6297 } 6298 if (arg_err) 6299 return; 6300 6301 if (optind != cmd->cmd_argc) { 6302 short_usage(CMD_REVERT); 6303 return; 6304 } 6305 6306 if (zone_is_read_only(CMD_REVERT)) 6307 return; 6308 6309 if (zonecfg_check_handle(handle) != Z_OK) { 6310 zerr(gettext("No changes to revert.")); 6311 saw_error = B_TRUE; 6312 return; 6313 } 6314 6315 if (!force) { 6316 (void) snprintf(line, sizeof (line), 6317 gettext("Are you sure you want to revert")); 6318 if ((answer = ask_yesno(B_FALSE, line)) == -1) { 6319 zerr(gettext("Input not from terminal and -F not " 6320 "specified:\n%s command ignored, exiting."), 6321 cmd_to_str(CMD_REVERT)); 6322 exit(Z_ERR); 6323 } 6324 if (answer != 1) 6325 return; 6326 } 6327 6328 /* 6329 * Time for a new handle: finish the old one off first 6330 * then get a new one properly to avoid leaks. 6331 */ 6332 zonecfg_fini_handle(handle); 6333 if ((handle = zonecfg_init_handle()) == NULL) { 6334 zone_perror(execname, Z_NOMEM, B_TRUE); 6335 exit(Z_ERR); 6336 } 6337 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 6338 saw_error = B_TRUE; 6339 got_handle = B_FALSE; 6340 if (err == Z_NO_ZONE) 6341 zerr(gettext("%s: no such saved zone to revert to."), 6342 revert_zone); 6343 else 6344 zone_perror(zone, err, B_TRUE); 6345 } 6346 (void) strlcpy(zone, revert_zone, sizeof (zone)); 6347 } 6348 6349 void 6350 help_func(cmd_t *cmd) 6351 { 6352 int i; 6353 6354 assert(cmd != NULL); 6355 6356 if (cmd->cmd_argc == 0) { 6357 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 6358 return; 6359 } 6360 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 6361 usage(B_TRUE, HELP_USAGE); 6362 return; 6363 } 6364 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 6365 usage(B_TRUE, HELP_SUBCMDS); 6366 return; 6367 } 6368 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 6369 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS); 6370 return; 6371 } 6372 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 6373 longer_usage(CMD_HELP); 6374 return; 6375 } 6376 6377 for (i = 0; i <= CMD_MAX; i++) { 6378 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 6379 longer_usage(i); 6380 return; 6381 } 6382 } 6383 /* We do not use zerr() here because we do not want its extra \n. */ 6384 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 6385 cmd->cmd_argv[0]); 6386 usage(B_FALSE, HELP_META); 6387 } 6388 6389 static int 6390 string_to_yyin(char *string) 6391 { 6392 if ((yyin = tmpfile()) == NULL) { 6393 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6394 return (Z_ERR); 6395 } 6396 if (fwrite(string, strlen(string), 1, yyin) != 1) { 6397 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6398 return (Z_ERR); 6399 } 6400 if (fseek(yyin, 0, SEEK_SET) != 0) { 6401 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6402 return (Z_ERR); 6403 } 6404 return (Z_OK); 6405 } 6406 6407 /* This is the back-end helper function for read_input() below. */ 6408 6409 static int 6410 cleanup() 6411 { 6412 int answer; 6413 cmd_t *cmd; 6414 6415 if (!interactive_mode && !cmd_file_mode) { 6416 /* 6417 * If we're not in interactive mode, and we're not in command 6418 * file mode, then we must be in commands-from-the-command-line 6419 * mode. As such, we can't loop back and ask for more input. 6420 * It was OK to prompt for such things as whether or not to 6421 * really delete a zone in the command handler called from 6422 * yyparse() above, but "really quit?" makes no sense in this 6423 * context. So disable prompting. 6424 */ 6425 ok_to_prompt = B_FALSE; 6426 } 6427 if (!global_scope) { 6428 if (!time_to_exit) { 6429 /* 6430 * Just print a simple error message in the -1 case, 6431 * since exit_func() already handles that case, and 6432 * EOF means we are finished anyway. 6433 */ 6434 answer = ask_yesno(B_FALSE, 6435 gettext("Resource incomplete; really quit")); 6436 if (answer == -1) { 6437 zerr(gettext("Resource incomplete.")); 6438 return (Z_ERR); 6439 } 6440 if (answer != 1) { 6441 yyin = stdin; 6442 return (Z_REPEAT); 6443 } 6444 } else { 6445 saw_error = B_TRUE; 6446 } 6447 } 6448 /* 6449 * Make sure we tried something and that the handle checks 6450 * out, or we would get a false error trying to commit. 6451 */ 6452 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 6453 if ((cmd = alloc_cmd()) == NULL) { 6454 zone_perror(zone, Z_NOMEM, B_TRUE); 6455 return (Z_ERR); 6456 } 6457 cmd->cmd_argc = 0; 6458 cmd->cmd_argv[0] = NULL; 6459 commit_func(cmd); 6460 free_cmd(cmd); 6461 /* 6462 * need_to_commit will get set back to FALSE if the 6463 * configuration is saved successfully. 6464 */ 6465 if (need_to_commit) { 6466 if (force_exit) { 6467 zerr(gettext("Configuration not saved.")); 6468 return (Z_ERR); 6469 } 6470 answer = ask_yesno(B_FALSE, 6471 gettext("Configuration not saved; really quit")); 6472 if (answer == -1) { 6473 zerr(gettext("Configuration not saved.")); 6474 return (Z_ERR); 6475 } 6476 if (answer != 1) { 6477 time_to_exit = B_FALSE; 6478 yyin = stdin; 6479 return (Z_REPEAT); 6480 } 6481 } 6482 } 6483 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 6484 } 6485 6486 /* 6487 * read_input() is the driver of this program. It is a wrapper around 6488 * yyparse(), printing appropriate prompts when needed, checking for 6489 * exit conditions and reacting appropriately [the latter in its cleanup() 6490 * helper function]. 6491 * 6492 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 6493 * so do_interactive() knows that we are not really done (i.e, we asked 6494 * the user if we should really quit and the user said no). 6495 */ 6496 static int 6497 read_input() 6498 { 6499 boolean_t yyin_is_a_tty = isatty(fileno(yyin)); 6500 /* 6501 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 6502 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 6503 */ 6504 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 6505 6506 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 6507 newline_terminated = B_TRUE; 6508 for (;;) { 6509 if (yyin_is_a_tty) { 6510 if (newline_terminated) { 6511 if (global_scope) 6512 (void) snprintf(prompt, sizeof (prompt), 6513 "%s:%s> ", execname, zone); 6514 else 6515 (void) snprintf(prompt, sizeof (prompt), 6516 "%s:%s:%s> ", execname, zone, 6517 rt_to_str(resource_scope)); 6518 } 6519 /* 6520 * If the user hits ^C then we want to catch it and 6521 * start over. If the user hits EOF then we want to 6522 * bail out. 6523 */ 6524 line = gl_get_line(gl, prompt, NULL, -1); 6525 if (gl_return_status(gl) == GLR_SIGNAL) { 6526 gl_abandon_line(gl); 6527 continue; 6528 } 6529 if (line == NULL) 6530 break; 6531 (void) string_to_yyin(line); 6532 while (!feof(yyin)) 6533 yyparse(); 6534 } else { 6535 yyparse(); 6536 } 6537 /* Bail out on an error in command file mode. */ 6538 if (saw_error && cmd_file_mode && !interactive_mode) 6539 time_to_exit = B_TRUE; 6540 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 6541 break; 6542 } 6543 return (cleanup()); 6544 } 6545 6546 /* 6547 * This function is used in the zonecfg-interactive-mode scenario: it just 6548 * calls read_input() until we are done. 6549 */ 6550 6551 static int 6552 do_interactive(void) 6553 { 6554 int err; 6555 6556 interactive_mode = B_TRUE; 6557 if (!read_only_mode) { 6558 /* 6559 * Try to set things up proactively in interactive mode, so 6560 * that if the zone in question does not exist yet, we can 6561 * provide the user with a clue. 6562 */ 6563 (void) initialize(B_FALSE); 6564 } 6565 do { 6566 err = read_input(); 6567 } while (err == Z_REPEAT); 6568 return (err); 6569 } 6570 6571 /* 6572 * cmd_file is slightly more complicated, as it has to open the command file 6573 * and set yyin appropriately. Once that is done, though, it just calls 6574 * read_input(), and only once, since prompting is not possible. 6575 */ 6576 6577 static int 6578 cmd_file(char *file) 6579 { 6580 FILE *infile; 6581 int err; 6582 struct stat statbuf; 6583 boolean_t using_real_file = (strcmp(file, "-") != 0); 6584 6585 if (using_real_file) { 6586 /* 6587 * zerr() prints a line number in cmd_file_mode, which we do 6588 * not want here, so temporarily unset it. 6589 */ 6590 cmd_file_mode = B_FALSE; 6591 if ((infile = fopen(file, "r")) == NULL) { 6592 zerr(gettext("could not open file %s: %s"), 6593 file, strerror(errno)); 6594 return (Z_ERR); 6595 } 6596 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 6597 zerr(gettext("could not stat file %s: %s"), 6598 file, strerror(errno)); 6599 err = Z_ERR; 6600 goto done; 6601 } 6602 if (!S_ISREG(statbuf.st_mode)) { 6603 zerr(gettext("%s is not a regular file."), file); 6604 err = Z_ERR; 6605 goto done; 6606 } 6607 yyin = infile; 6608 cmd_file_mode = B_TRUE; 6609 ok_to_prompt = B_FALSE; 6610 } else { 6611 /* 6612 * "-f -" is essentially the same as interactive mode, 6613 * so treat it that way. 6614 */ 6615 interactive_mode = B_TRUE; 6616 } 6617 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 6618 if ((err = read_input()) == Z_REPEAT) 6619 err = Z_ERR; 6620 done: 6621 if (using_real_file) 6622 (void) fclose(infile); 6623 return (err); 6624 } 6625 6626 /* 6627 * Since yacc is based on reading from a (FILE *) whereas what we get from 6628 * the command line is in argv format, we need to convert when the user 6629 * gives us commands directly from the command line. That is done here by 6630 * concatenating the argv list into a space-separated string, writing it 6631 * to a temp file, and rewinding the file so yyin can be set to it. Then 6632 * we call read_input(), and only once, since prompting about whether to 6633 * continue or quit would make no sense in this context. 6634 */ 6635 6636 static int 6637 one_command_at_a_time(int argc, char *argv[]) 6638 { 6639 char *command; 6640 size_t len = 2; /* terminal \n\0 */ 6641 int i, err; 6642 6643 for (i = 0; i < argc; i++) 6644 len += strlen(argv[i]) + 1; 6645 if ((command = malloc(len)) == NULL) { 6646 zone_perror(execname, Z_NOMEM, B_TRUE); 6647 return (Z_ERR); 6648 } 6649 (void) strlcpy(command, argv[0], len); 6650 for (i = 1; i < argc; i++) { 6651 (void) strlcat(command, " ", len); 6652 (void) strlcat(command, argv[i], len); 6653 } 6654 (void) strlcat(command, "\n", len); 6655 err = string_to_yyin(command); 6656 free(command); 6657 if (err != Z_OK) 6658 return (err); 6659 while (!feof(yyin)) 6660 yyparse(); 6661 return (cleanup()); 6662 } 6663 6664 static char * 6665 get_execbasename(char *execfullname) 6666 { 6667 char *last_slash, *execbasename; 6668 6669 /* guard against '/' at end of command invocation */ 6670 for (;;) { 6671 last_slash = strrchr(execfullname, '/'); 6672 if (last_slash == NULL) { 6673 execbasename = execfullname; 6674 break; 6675 } else { 6676 execbasename = last_slash + 1; 6677 if (*execbasename == '\0') { 6678 *last_slash = '\0'; 6679 continue; 6680 } 6681 break; 6682 } 6683 } 6684 return (execbasename); 6685 } 6686 6687 int 6688 main(int argc, char *argv[]) 6689 { 6690 int err, arg; 6691 struct stat st; 6692 6693 /* This must be before anything goes to stdout. */ 6694 setbuf(stdout, NULL); 6695 6696 saw_error = B_FALSE; 6697 cmd_file_mode = B_FALSE; 6698 execname = get_execbasename(argv[0]); 6699 6700 (void) setlocale(LC_ALL, ""); 6701 (void) textdomain(TEXT_DOMAIN); 6702 6703 if (getzoneid() != GLOBAL_ZONEID) { 6704 zerr(gettext("%s can only be run from the global zone."), 6705 execname); 6706 exit(Z_ERR); 6707 } 6708 6709 if (argc < 2) { 6710 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS); 6711 exit(Z_USAGE); 6712 } 6713 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 6714 (void) one_command_at_a_time(argc - 1, &(argv[1])); 6715 exit(Z_OK); 6716 } 6717 6718 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 6719 switch (arg) { 6720 case '?': 6721 if (optopt == '?') 6722 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS); 6723 else 6724 usage(B_FALSE, HELP_USAGE); 6725 exit(Z_USAGE); 6726 /* NOTREACHED */ 6727 case 'f': 6728 cmd_file_name = optarg; 6729 cmd_file_mode = B_TRUE; 6730 break; 6731 case 'R': 6732 if (*optarg != '/') { 6733 zerr(gettext("root path must be absolute: %s"), 6734 optarg); 6735 exit(Z_USAGE); 6736 } 6737 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 6738 zerr(gettext( 6739 "root path must be a directory: %s"), 6740 optarg); 6741 exit(Z_USAGE); 6742 } 6743 zonecfg_set_root(optarg); 6744 break; 6745 case 'z': 6746 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) { 6747 global_zone = B_TRUE; 6748 } else if (zonecfg_validate_zonename(optarg) != Z_OK) { 6749 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE); 6750 usage(B_FALSE, HELP_SYNTAX); 6751 exit(Z_USAGE); 6752 } 6753 (void) strlcpy(zone, optarg, sizeof (zone)); 6754 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 6755 break; 6756 default: 6757 usage(B_FALSE, HELP_USAGE); 6758 exit(Z_USAGE); 6759 } 6760 } 6761 6762 if (optind > argc || strcmp(zone, "") == 0) { 6763 usage(B_FALSE, HELP_USAGE); 6764 exit(Z_USAGE); 6765 } 6766 6767 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 6768 read_only_mode = B_FALSE; 6769 } else if (err == Z_ACCES) { 6770 read_only_mode = B_TRUE; 6771 /* skip this message in one-off from command line mode */ 6772 if (optind == argc) 6773 (void) fprintf(stderr, gettext("WARNING: you do not " 6774 "have write access to this zone's configuration " 6775 "file;\ngoing into read-only mode.\n")); 6776 } else { 6777 fprintf(stderr, "%s: Could not access zone configuration " 6778 "store: %s\n", execname, zonecfg_strerror(err)); 6779 exit(Z_ERR); 6780 } 6781 6782 if ((handle = zonecfg_init_handle()) == NULL) { 6783 zone_perror(execname, Z_NOMEM, B_TRUE); 6784 exit(Z_ERR); 6785 } 6786 6787 /* 6788 * This may get set back to FALSE again in cmd_file() if cmd_file_name 6789 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 6790 */ 6791 if (isatty(STDIN_FILENO)) 6792 ok_to_prompt = B_TRUE; 6793 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 6794 exit(Z_ERR); 6795 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 6796 exit(Z_ERR); 6797 (void) sigset(SIGINT, SIG_IGN); 6798 if (optind == argc) { 6799 if (!cmd_file_mode) 6800 err = do_interactive(); 6801 else 6802 err = cmd_file(cmd_file_name); 6803 } else { 6804 err = one_command_at_a_time(argc - optind, &(argv[optind])); 6805 } 6806 zonecfg_fini_handle(handle); 6807 if (brand != NULL) 6808 brand_close(brand); 6809 (void) del_GetLine(gl); 6810 return (err); 6811 } 6812