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