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