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