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 (strcmp(path, "/") == 0) { 2055 zerr(gettext("/ is not allowed as a %s."), 2056 pt_to_str(PT_ZONEPATH)); 2057 return (Z_ERR); 2058 } 2059 return (Z_OK); 2060 } 2061 2062 static void 2063 add_resource(cmd_t *cmd) 2064 { 2065 int type; 2066 struct zone_psettab tmp_psettab; 2067 struct zone_mcaptab tmp_mcaptab; 2068 uint64_t tmp; 2069 uint64_t tmp_mcap; 2070 char pool[MAXNAMELEN]; 2071 2072 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2073 long_usage(CMD_ADD, B_TRUE); 2074 goto bad; 2075 } 2076 2077 switch (type) { 2078 case RT_FS: 2079 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 2080 return; 2081 case RT_IPD: 2082 if (state_atleast(ZONE_STATE_INSTALLED)) { 2083 zerr(gettext("Zone %s already installed; %s %s not " 2084 "allowed."), zone, cmd_to_str(CMD_ADD), 2085 rt_to_str(RT_IPD)); 2086 goto bad; 2087 } 2088 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 2089 return; 2090 case RT_NET: 2091 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 2092 return; 2093 case RT_DEVICE: 2094 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 2095 return; 2096 case RT_RCTL: 2097 if (global_zone) 2098 zerr(gettext("WARNING: Setting a global zone resource " 2099 "control too low could deny\nservice " 2100 "to even the root user; " 2101 "this could render the system impossible\n" 2102 "to administer. Please use caution.")); 2103 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 2104 return; 2105 case RT_ATTR: 2106 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 2107 return; 2108 case RT_DATASET: 2109 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 2110 return; 2111 case RT_DCPU: 2112 /* Make sure there isn't already a cpu-set or cpu-cap entry. */ 2113 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2114 zerr(gettext("The %s resource already exists."), 2115 rt_to_str(RT_DCPU)); 2116 goto bad; 2117 } 2118 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != 2119 Z_NO_ENTRY) { 2120 zerr(gettext("The %s resource already exists."), 2121 rt_to_str(RT_PCAP)); 2122 goto bad; 2123 } 2124 2125 /* Make sure the pool property isn't set. */ 2126 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 2127 strlen(pool) > 0) { 2128 zerr(gettext("The %s property is already set. " 2129 "A persistent pool is incompatible with\nthe %s " 2130 "resource."), 2131 pt_to_str(PT_POOL), rt_to_str(RT_DCPU)); 2132 goto bad; 2133 } 2134 2135 bzero(&in_progress_psettab, sizeof (in_progress_psettab)); 2136 return; 2137 case RT_PCAP: 2138 /* 2139 * Make sure there isn't already a cpu-set or incompatible 2140 * cpu-cap rctls. 2141 */ 2142 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2143 zerr(gettext("The %s resource already exists."), 2144 rt_to_str(RT_DCPU)); 2145 goto bad; 2146 } 2147 2148 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) { 2149 case Z_ALIAS_DISALLOW: 2150 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW, 2151 B_FALSE); 2152 goto bad; 2153 2154 case Z_OK: 2155 zerr(gettext("The %s resource already exists."), 2156 rt_to_str(RT_PCAP)); 2157 goto bad; 2158 2159 default: 2160 break; 2161 } 2162 return; 2163 case RT_MCAP: 2164 /* 2165 * Make sure there isn't already a mem-cap entry or max-swap 2166 * or max-locked rctl. 2167 */ 2168 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK || 2169 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap) 2170 == Z_OK || 2171 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 2172 &tmp_mcap) == Z_OK) { 2173 zerr(gettext("The %s resource or a related resource " 2174 "control already exists."), rt_to_str(RT_MCAP)); 2175 goto bad; 2176 } 2177 if (global_zone) 2178 zerr(gettext("WARNING: Setting a global zone memory " 2179 "cap too low could deny\nservice " 2180 "to even the root user; " 2181 "this could render the system impossible\n" 2182 "to administer. Please use caution.")); 2183 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab)); 2184 return; 2185 case RT_ADMIN: 2186 bzero(&in_progress_admintab, sizeof (in_progress_admintab)); 2187 return; 2188 default: 2189 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 2190 long_usage(CMD_ADD, B_TRUE); 2191 usage(B_FALSE, HELP_RESOURCES); 2192 } 2193 bad: 2194 global_scope = B_TRUE; 2195 end_op = -1; 2196 } 2197 2198 static void 2199 do_complex_rctl_val(complex_property_ptr_t cp) 2200 { 2201 struct zone_rctlvaltab *rctlvaltab; 2202 complex_property_ptr_t cx; 2203 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE, 2204 seen_action = B_FALSE; 2205 rctlblk_t *rctlblk; 2206 int err; 2207 2208 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 2209 zone_perror(zone, Z_NOMEM, B_TRUE); 2210 exit(Z_ERR); 2211 } 2212 for (cx = cp; cx != NULL; cx = cx->cp_next) { 2213 switch (cx->cp_type) { 2214 case PT_PRIV: 2215 if (seen_priv) { 2216 zerr(gettext("%s already specified"), 2217 pt_to_str(PT_PRIV)); 2218 goto bad; 2219 } 2220 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2221 cx->cp_value, 2222 sizeof (rctlvaltab->zone_rctlval_priv)); 2223 seen_priv = B_TRUE; 2224 break; 2225 case PT_LIMIT: 2226 if (seen_limit) { 2227 zerr(gettext("%s already specified"), 2228 pt_to_str(PT_LIMIT)); 2229 goto bad; 2230 } 2231 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2232 cx->cp_value, 2233 sizeof (rctlvaltab->zone_rctlval_limit)); 2234 seen_limit = B_TRUE; 2235 break; 2236 case PT_ACTION: 2237 if (seen_action) { 2238 zerr(gettext("%s already specified"), 2239 pt_to_str(PT_ACTION)); 2240 goto bad; 2241 } 2242 (void) strlcpy(rctlvaltab->zone_rctlval_action, 2243 cx->cp_value, 2244 sizeof (rctlvaltab->zone_rctlval_action)); 2245 seen_action = B_TRUE; 2246 break; 2247 default: 2248 zone_perror(pt_to_str(PT_VALUE), 2249 Z_NO_PROPERTY_TYPE, B_TRUE); 2250 long_usage(CMD_ADD, B_TRUE); 2251 usage(B_FALSE, HELP_PROPS); 2252 zonecfg_free_rctl_value_list(rctlvaltab); 2253 return; 2254 } 2255 } 2256 if (!seen_priv) 2257 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV)); 2258 if (!seen_limit) 2259 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT)); 2260 if (!seen_action) 2261 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION)); 2262 if (!seen_priv || !seen_limit || !seen_action) 2263 goto bad; 2264 rctlvaltab->zone_rctlval_next = NULL; 2265 rctlblk = alloca(rctlblk_size()); 2266 /* 2267 * Make sure the rctl value looks roughly correct; we won't know if 2268 * it's truly OK until we verify the configuration on the target 2269 * system. 2270 */ 2271 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK || 2272 !zonecfg_valid_rctlblk(rctlblk)) { 2273 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL), 2274 pt_to_str(PT_VALUE)); 2275 goto bad; 2276 } 2277 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab); 2278 if (err != Z_OK) 2279 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE); 2280 return; 2281 2282 bad: 2283 zonecfg_free_rctl_value_list(rctlvaltab); 2284 } 2285 2286 static void 2287 add_property(cmd_t *cmd) 2288 { 2289 char *prop_id; 2290 int err, res_type, prop_type; 2291 property_value_ptr_t pp; 2292 list_property_ptr_t l; 2293 2294 res_type = resource_scope; 2295 prop_type = cmd->cmd_prop_name[0]; 2296 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2297 long_usage(CMD_ADD, B_TRUE); 2298 return; 2299 } 2300 2301 if (cmd->cmd_prop_nv_pairs != 1) { 2302 long_usage(CMD_ADD, B_TRUE); 2303 return; 2304 } 2305 2306 if (initialize(B_TRUE) != Z_OK) 2307 return; 2308 2309 switch (res_type) { 2310 case RT_FS: 2311 if (prop_type != PT_OPTIONS) { 2312 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2313 B_TRUE); 2314 long_usage(CMD_ADD, B_TRUE); 2315 usage(B_FALSE, HELP_PROPS); 2316 return; 2317 } 2318 pp = cmd->cmd_property_ptr[0]; 2319 if (pp->pv_type != PROP_VAL_SIMPLE && 2320 pp->pv_type != PROP_VAL_LIST) { 2321 zerr(gettext("A %s or %s value was expected here."), 2322 pvt_to_str(PROP_VAL_SIMPLE), 2323 pvt_to_str(PROP_VAL_LIST)); 2324 saw_error = B_TRUE; 2325 return; 2326 } 2327 if (pp->pv_type == PROP_VAL_SIMPLE) { 2328 if (pp->pv_simple == NULL) { 2329 long_usage(CMD_ADD, B_TRUE); 2330 return; 2331 } 2332 prop_id = pp->pv_simple; 2333 err = zonecfg_add_fs_option(&in_progress_fstab, 2334 prop_id); 2335 if (err != Z_OK) 2336 zone_perror(pt_to_str(prop_type), err, B_TRUE); 2337 } else { 2338 list_property_ptr_t list; 2339 2340 for (list = pp->pv_list; list != NULL; 2341 list = list->lp_next) { 2342 prop_id = list->lp_simple; 2343 if (prop_id == NULL) 2344 break; 2345 err = zonecfg_add_fs_option( 2346 &in_progress_fstab, prop_id); 2347 if (err != Z_OK) 2348 zone_perror(pt_to_str(prop_type), err, 2349 B_TRUE); 2350 } 2351 } 2352 return; 2353 case RT_RCTL: 2354 if (prop_type != PT_VALUE) { 2355 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2356 B_TRUE); 2357 long_usage(CMD_ADD, B_TRUE); 2358 usage(B_FALSE, HELP_PROPS); 2359 return; 2360 } 2361 pp = cmd->cmd_property_ptr[0]; 2362 if (pp->pv_type != PROP_VAL_COMPLEX && 2363 pp->pv_type != PROP_VAL_LIST) { 2364 zerr(gettext("A %s or %s value was expected here."), 2365 pvt_to_str(PROP_VAL_COMPLEX), 2366 pvt_to_str(PROP_VAL_LIST)); 2367 saw_error = B_TRUE; 2368 return; 2369 } 2370 if (pp->pv_type == PROP_VAL_COMPLEX) { 2371 do_complex_rctl_val(pp->pv_complex); 2372 return; 2373 } 2374 for (l = pp->pv_list; l != NULL; l = l->lp_next) 2375 do_complex_rctl_val(l->lp_complex); 2376 return; 2377 default: 2378 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 2379 long_usage(CMD_ADD, B_TRUE); 2380 usage(B_FALSE, HELP_RESOURCES); 2381 return; 2382 } 2383 } 2384 2385 static boolean_t 2386 gz_invalid_resource(int type) 2387 { 2388 return (global_zone && (type == RT_FS || type == RT_IPD || 2389 type == RT_NET || type == RT_DEVICE || type == RT_ATTR || 2390 type == RT_DATASET)); 2391 } 2392 2393 static boolean_t 2394 gz_invalid_rt_property(int type) 2395 { 2396 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH || 2397 type == RT_AUTOBOOT || type == RT_LIMITPRIV || 2398 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED || 2399 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED)); 2400 } 2401 2402 static boolean_t 2403 gz_invalid_property(int type) 2404 { 2405 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH || 2406 type == PT_AUTOBOOT || type == PT_LIMITPRIV || 2407 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED || 2408 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED)); 2409 } 2410 2411 void 2412 add_func(cmd_t *cmd) 2413 { 2414 int arg; 2415 boolean_t arg_err = B_FALSE; 2416 2417 assert(cmd != NULL); 2418 2419 optind = 0; 2420 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 2421 switch (arg) { 2422 case '?': 2423 longer_usage(CMD_ADD); 2424 arg_err = B_TRUE; 2425 break; 2426 default: 2427 short_usage(CMD_ADD); 2428 arg_err = B_TRUE; 2429 break; 2430 } 2431 } 2432 if (arg_err) 2433 return; 2434 2435 if (optind != cmd->cmd_argc) { 2436 short_usage(CMD_ADD); 2437 return; 2438 } 2439 2440 if (zone_is_read_only(CMD_ADD)) 2441 return; 2442 2443 if (initialize(B_TRUE) != Z_OK) 2444 return; 2445 if (global_scope) { 2446 if (gz_invalid_resource(cmd->cmd_res_type)) { 2447 zerr(gettext("Cannot add a %s resource to the " 2448 "global zone."), rt_to_str(cmd->cmd_res_type)); 2449 saw_error = B_TRUE; 2450 return; 2451 } 2452 2453 global_scope = B_FALSE; 2454 resource_scope = cmd->cmd_res_type; 2455 end_op = CMD_ADD; 2456 add_resource(cmd); 2457 } else 2458 add_property(cmd); 2459 } 2460 2461 /* 2462 * This routine has an unusual implementation, because it tries very 2463 * hard to succeed in the face of a variety of failure modes. 2464 * The most common and most vexing occurs when the index file and 2465 * the /etc/zones/<zonename.xml> file are not both present. In 2466 * this case, delete must eradicate as much of the zone state as is left 2467 * so that the user can later create a new zone with the same name. 2468 */ 2469 void 2470 delete_func(cmd_t *cmd) 2471 { 2472 int err, arg, answer; 2473 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 2474 boolean_t force = B_FALSE; 2475 boolean_t arg_err = B_FALSE; 2476 2477 optind = 0; 2478 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2479 switch (arg) { 2480 case '?': 2481 longer_usage(CMD_DELETE); 2482 arg_err = B_TRUE; 2483 break; 2484 case 'F': 2485 force = B_TRUE; 2486 break; 2487 default: 2488 short_usage(CMD_DELETE); 2489 arg_err = B_TRUE; 2490 break; 2491 } 2492 } 2493 if (arg_err) 2494 return; 2495 2496 if (optind != cmd->cmd_argc) { 2497 short_usage(CMD_DELETE); 2498 return; 2499 } 2500 2501 if (zone_is_read_only(CMD_DELETE)) 2502 return; 2503 2504 if (!force) { 2505 /* 2506 * Initialize sets up the global called "handle" and warns the 2507 * user if the zone is not configured. In force mode, we don't 2508 * trust that evaluation, and hence skip it. (We don't need the 2509 * handle to be loaded anyway, since zonecfg_destroy is done by 2510 * zonename). However, we also have to take care to emulate the 2511 * messages spit out by initialize; see below. 2512 */ 2513 if (initialize(B_TRUE) != Z_OK) 2514 return; 2515 2516 (void) snprintf(line, sizeof (line), 2517 gettext("Are you sure you want to delete zone %s"), zone); 2518 if ((answer = ask_yesno(B_FALSE, line)) == -1) { 2519 zerr(gettext("Input not from terminal and -F not " 2520 "specified:\n%s command ignored, exiting."), 2521 cmd_to_str(CMD_DELETE)); 2522 exit(Z_ERR); 2523 } 2524 if (answer != 1) 2525 return; 2526 } 2527 2528 /* 2529 * This function removes the authorizations from user_attr 2530 * that correspond to those specified in the configuration 2531 */ 2532 if (initialize(B_TRUE) == Z_OK) { 2533 (void) zonecfg_deauthorize_users(handle, zone); 2534 } 2535 if ((err = zonecfg_destroy(zone, force)) != Z_OK) { 2536 if ((err == Z_BAD_ZONE_STATE) && !force) { 2537 zerr(gettext("Zone %s not in %s state; %s not " 2538 "allowed. Use -F to force %s."), 2539 zone, zone_state_str(ZONE_STATE_CONFIGURED), 2540 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE)); 2541 } else { 2542 zone_perror(zone, err, B_TRUE); 2543 } 2544 } 2545 need_to_commit = B_FALSE; 2546 2547 /* 2548 * Emulate initialize's messaging; if there wasn't a valid handle to 2549 * begin with, then user had typed delete (or delete -F) multiple 2550 * times. So we emit a message. 2551 * 2552 * We only do this in the 'force' case because normally, initialize() 2553 * takes care of this for us. 2554 */ 2555 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode) 2556 (void) printf(gettext("Use '%s' to begin " 2557 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE)); 2558 2559 /* 2560 * Time for a new handle: finish the old one off first 2561 * then get a new one properly to avoid leaks. 2562 */ 2563 if (got_handle) { 2564 zonecfg_fini_handle(handle); 2565 if ((handle = zonecfg_init_handle()) == NULL) { 2566 zone_perror(execname, Z_NOMEM, B_TRUE); 2567 exit(Z_ERR); 2568 } 2569 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) { 2570 /* If there was no zone before, that's OK */ 2571 if (err != Z_NO_ZONE) 2572 zone_perror(zone, err, B_TRUE); 2573 got_handle = B_FALSE; 2574 } 2575 } 2576 } 2577 2578 static int 2579 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only) 2580 { 2581 int err, i; 2582 property_value_ptr_t pp; 2583 2584 if ((err = initialize(B_TRUE)) != Z_OK) 2585 return (err); 2586 2587 bzero(fstab, sizeof (*fstab)); 2588 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2589 pp = cmd->cmd_property_ptr[i]; 2590 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2591 zerr(gettext("A simple value was expected here.")); 2592 saw_error = B_TRUE; 2593 return (Z_INSUFFICIENT_SPEC); 2594 } 2595 switch (cmd->cmd_prop_name[i]) { 2596 case PT_DIR: 2597 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 2598 sizeof (fstab->zone_fs_dir)); 2599 break; 2600 case PT_SPECIAL: 2601 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 2602 sizeof (fstab->zone_fs_special)); 2603 break; 2604 case PT_RAW: 2605 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 2606 sizeof (fstab->zone_fs_raw)); 2607 break; 2608 case PT_TYPE: 2609 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 2610 sizeof (fstab->zone_fs_type)); 2611 break; 2612 default: 2613 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2614 Z_NO_PROPERTY_TYPE, B_TRUE); 2615 return (Z_INSUFFICIENT_SPEC); 2616 } 2617 } 2618 if (fill_in_only) 2619 return (Z_OK); 2620 return (zonecfg_lookup_filesystem(handle, fstab)); 2621 } 2622 2623 static int 2624 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, boolean_t fill_in_only) 2625 { 2626 int err, i; 2627 property_value_ptr_t pp; 2628 2629 if ((err = initialize(B_TRUE)) != Z_OK) 2630 return (err); 2631 2632 bzero(ipdtab, sizeof (*ipdtab)); 2633 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2634 pp = cmd->cmd_property_ptr[i]; 2635 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2636 zerr(gettext("A simple value was expected here.")); 2637 saw_error = B_TRUE; 2638 return (Z_INSUFFICIENT_SPEC); 2639 } 2640 switch (cmd->cmd_prop_name[i]) { 2641 case PT_DIR: 2642 (void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple, 2643 sizeof (ipdtab->zone_fs_dir)); 2644 break; 2645 default: 2646 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2647 Z_NO_PROPERTY_TYPE, B_TRUE); 2648 return (Z_INSUFFICIENT_SPEC); 2649 } 2650 } 2651 if (fill_in_only) 2652 return (Z_OK); 2653 return (zonecfg_lookup_ipd(handle, ipdtab)); 2654 } 2655 2656 static int 2657 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, 2658 boolean_t fill_in_only) 2659 { 2660 int err, i; 2661 property_value_ptr_t pp; 2662 2663 if ((err = initialize(B_TRUE)) != Z_OK) 2664 return (err); 2665 2666 bzero(nwiftab, sizeof (*nwiftab)); 2667 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2668 pp = cmd->cmd_property_ptr[i]; 2669 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2670 zerr(gettext("A simple value was expected here.")); 2671 saw_error = B_TRUE; 2672 return (Z_INSUFFICIENT_SPEC); 2673 } 2674 switch (cmd->cmd_prop_name[i]) { 2675 case PT_ADDRESS: 2676 (void) strlcpy(nwiftab->zone_nwif_address, 2677 pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 2678 break; 2679 case PT_PHYSICAL: 2680 (void) strlcpy(nwiftab->zone_nwif_physical, 2681 pp->pv_simple, 2682 sizeof (nwiftab->zone_nwif_physical)); 2683 break; 2684 case PT_DEFROUTER: 2685 (void) strlcpy(nwiftab->zone_nwif_defrouter, 2686 pp->pv_simple, 2687 sizeof (nwiftab->zone_nwif_defrouter)); 2688 break; 2689 default: 2690 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2691 Z_NO_PROPERTY_TYPE, B_TRUE); 2692 return (Z_INSUFFICIENT_SPEC); 2693 } 2694 } 2695 if (fill_in_only) 2696 return (Z_OK); 2697 err = zonecfg_lookup_nwif(handle, nwiftab); 2698 return (err); 2699 } 2700 2701 static int 2702 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only) 2703 { 2704 int err, i; 2705 property_value_ptr_t pp; 2706 2707 if ((err = initialize(B_TRUE)) != Z_OK) 2708 return (err); 2709 2710 bzero(devtab, sizeof (*devtab)); 2711 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2712 pp = cmd->cmd_property_ptr[i]; 2713 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2714 zerr(gettext("A simple value was expected here.")); 2715 saw_error = B_TRUE; 2716 return (Z_INSUFFICIENT_SPEC); 2717 } 2718 switch (cmd->cmd_prop_name[i]) { 2719 case PT_MATCH: 2720 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2721 sizeof (devtab->zone_dev_match)); 2722 break; 2723 default: 2724 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2725 Z_NO_PROPERTY_TYPE, B_TRUE); 2726 return (Z_INSUFFICIENT_SPEC); 2727 } 2728 } 2729 if (fill_in_only) 2730 return (Z_OK); 2731 err = zonecfg_lookup_dev(handle, devtab); 2732 return (err); 2733 } 2734 2735 static int 2736 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, 2737 boolean_t fill_in_only) 2738 { 2739 int err, i; 2740 property_value_ptr_t pp; 2741 2742 if ((err = initialize(B_TRUE)) != Z_OK) 2743 return (err); 2744 2745 bzero(rctltab, sizeof (*rctltab)); 2746 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2747 pp = cmd->cmd_property_ptr[i]; 2748 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2749 zerr(gettext("A simple value was expected here.")); 2750 saw_error = B_TRUE; 2751 return (Z_INSUFFICIENT_SPEC); 2752 } 2753 switch (cmd->cmd_prop_name[i]) { 2754 case PT_NAME: 2755 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2756 sizeof (rctltab->zone_rctl_name)); 2757 break; 2758 default: 2759 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2760 Z_NO_PROPERTY_TYPE, B_TRUE); 2761 return (Z_INSUFFICIENT_SPEC); 2762 } 2763 } 2764 if (fill_in_only) 2765 return (Z_OK); 2766 err = zonecfg_lookup_rctl(handle, rctltab); 2767 return (err); 2768 } 2769 2770 static int 2771 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, 2772 boolean_t fill_in_only) 2773 { 2774 int err, i; 2775 property_value_ptr_t pp; 2776 2777 if ((err = initialize(B_TRUE)) != Z_OK) 2778 return (err); 2779 2780 bzero(attrtab, sizeof (*attrtab)); 2781 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2782 pp = cmd->cmd_property_ptr[i]; 2783 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2784 zerr(gettext("A simple value was expected here.")); 2785 saw_error = B_TRUE; 2786 return (Z_INSUFFICIENT_SPEC); 2787 } 2788 switch (cmd->cmd_prop_name[i]) { 2789 case PT_NAME: 2790 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2791 sizeof (attrtab->zone_attr_name)); 2792 break; 2793 case PT_TYPE: 2794 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2795 sizeof (attrtab->zone_attr_type)); 2796 break; 2797 case PT_VALUE: 2798 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2799 sizeof (attrtab->zone_attr_value)); 2800 break; 2801 default: 2802 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2803 Z_NO_PROPERTY_TYPE, B_TRUE); 2804 return (Z_INSUFFICIENT_SPEC); 2805 } 2806 } 2807 if (fill_in_only) 2808 return (Z_OK); 2809 err = zonecfg_lookup_attr(handle, attrtab); 2810 return (err); 2811 } 2812 2813 static int 2814 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only) 2815 { 2816 int err, i; 2817 property_value_ptr_t pp; 2818 2819 if ((err = initialize(B_TRUE)) != Z_OK) 2820 return (err); 2821 2822 dstab->zone_dataset_name[0] = '\0'; 2823 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2824 pp = cmd->cmd_property_ptr[i]; 2825 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2826 zerr(gettext("A simple value was expected here.")); 2827 saw_error = B_TRUE; 2828 return (Z_INSUFFICIENT_SPEC); 2829 } 2830 switch (cmd->cmd_prop_name[i]) { 2831 case PT_NAME: 2832 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2833 sizeof (dstab->zone_dataset_name)); 2834 break; 2835 default: 2836 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2837 Z_NO_PROPERTY_TYPE, B_TRUE); 2838 return (Z_INSUFFICIENT_SPEC); 2839 } 2840 } 2841 if (fill_in_only) 2842 return (Z_OK); 2843 return (zonecfg_lookup_ds(handle, dstab)); 2844 } 2845 2846 static int 2847 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab, 2848 boolean_t fill_in_only) 2849 { 2850 int err, i; 2851 property_value_ptr_t pp; 2852 2853 if ((err = initialize(B_TRUE)) != Z_OK) 2854 return (err); 2855 2856 bzero(admintab, sizeof (*admintab)); 2857 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2858 pp = cmd->cmd_property_ptr[i]; 2859 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2860 zerr(gettext("A simple value was expected here.")); 2861 saw_error = B_TRUE; 2862 return (Z_INSUFFICIENT_SPEC); 2863 } 2864 switch (cmd->cmd_prop_name[i]) { 2865 case PT_USER: 2866 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple, 2867 sizeof (admintab->zone_admin_user)); 2868 break; 2869 case PT_AUTHS: 2870 (void) strlcpy(admintab->zone_admin_auths, 2871 pp->pv_simple, sizeof (admintab->zone_admin_auths)); 2872 break; 2873 default: 2874 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2875 Z_NO_PROPERTY_TYPE, B_TRUE); 2876 return (Z_INSUFFICIENT_SPEC); 2877 } 2878 } 2879 if (fill_in_only) 2880 return (Z_OK); 2881 err = zonecfg_lookup_admin(handle, admintab); 2882 return (err); 2883 } 2884 2885 static void 2886 remove_aliased_rctl(int type, char *name) 2887 { 2888 int err; 2889 uint64_t tmp; 2890 2891 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) { 2892 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2893 zonecfg_strerror(err)); 2894 saw_error = B_TRUE; 2895 return; 2896 } 2897 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) { 2898 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2899 zonecfg_strerror(err)); 2900 saw_error = B_TRUE; 2901 } else { 2902 need_to_commit = B_TRUE; 2903 } 2904 } 2905 2906 static boolean_t 2907 prompt_remove_resource(cmd_t *cmd, char *rsrc) 2908 { 2909 int num; 2910 int answer; 2911 int arg; 2912 boolean_t force = B_FALSE; 2913 char prompt[128]; 2914 boolean_t arg_err = B_FALSE; 2915 2916 optind = 0; 2917 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 2918 switch (arg) { 2919 case 'F': 2920 force = B_TRUE; 2921 break; 2922 default: 2923 arg_err = B_TRUE; 2924 break; 2925 } 2926 } 2927 if (arg_err) 2928 return (B_FALSE); 2929 2930 2931 num = zonecfg_num_resources(handle, rsrc); 2932 2933 if (num == 0) { 2934 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY, 2935 B_TRUE); 2936 return (B_FALSE); 2937 } 2938 if (num > 1 && !force) { 2939 if (!interactive_mode) { 2940 zerr(gettext("There are multiple instances of this " 2941 "resource. Either qualify the resource to\n" 2942 "remove a single instance or use the -F option to " 2943 "remove all instances.")); 2944 saw_error = B_TRUE; 2945 return (B_FALSE); 2946 } 2947 (void) snprintf(prompt, sizeof (prompt), gettext( 2948 "Are you sure you want to remove ALL '%s' resources"), 2949 rsrc); 2950 answer = ask_yesno(B_FALSE, prompt); 2951 if (answer == -1) { 2952 zerr(gettext("Resource incomplete.")); 2953 return (B_FALSE); 2954 } 2955 if (answer != 1) 2956 return (B_FALSE); 2957 } 2958 return (B_TRUE); 2959 } 2960 2961 static void 2962 remove_fs(cmd_t *cmd) 2963 { 2964 int err; 2965 2966 /* traditional, qualified fs removal */ 2967 if (cmd->cmd_prop_nv_pairs > 0) { 2968 struct zone_fstab fstab; 2969 2970 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) { 2971 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2972 return; 2973 } 2974 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 2975 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2976 else 2977 need_to_commit = B_TRUE; 2978 zonecfg_free_fs_option_list(fstab.zone_fs_options); 2979 return; 2980 } 2981 2982 /* 2983 * unqualified fs removal. remove all fs's but prompt if more 2984 * than one. 2985 */ 2986 if (!prompt_remove_resource(cmd, "fs")) 2987 return; 2988 2989 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK) 2990 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 2991 else 2992 need_to_commit = B_TRUE; 2993 } 2994 2995 static void 2996 remove_ipd(cmd_t *cmd) 2997 { 2998 int err; 2999 3000 if (state_atleast(ZONE_STATE_INSTALLED)) { 3001 zerr(gettext("Zone %s already installed; %s %s not allowed."), 3002 zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD)); 3003 return; 3004 } 3005 3006 /* traditional, qualified ipd removal */ 3007 if (cmd->cmd_prop_nv_pairs > 0) { 3008 struct zone_fstab fstab; 3009 3010 if ((err = fill_in_ipdtab(cmd, &fstab, B_FALSE)) != Z_OK) { 3011 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 3012 return; 3013 } 3014 if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK) 3015 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 3016 else 3017 need_to_commit = B_TRUE; 3018 return; 3019 } 3020 3021 /* 3022 * unqualified ipd removal. remove all ipds but prompt if more 3023 * than one. 3024 */ 3025 if (!prompt_remove_resource(cmd, "inherit-pkg-dir")) 3026 return; 3027 3028 if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir")) 3029 != Z_OK) 3030 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, B_TRUE); 3031 else 3032 need_to_commit = B_TRUE; 3033 } 3034 3035 static void 3036 remove_net(cmd_t *cmd) 3037 { 3038 int err; 3039 3040 /* traditional, qualified net removal */ 3041 if (cmd->cmd_prop_nv_pairs > 0) { 3042 struct zone_nwiftab nwiftab; 3043 3044 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) { 3045 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3046 return; 3047 } 3048 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 3049 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3050 else 3051 need_to_commit = B_TRUE; 3052 return; 3053 } 3054 3055 /* 3056 * unqualified net removal. remove all nets but prompt if more 3057 * than one. 3058 */ 3059 if (!prompt_remove_resource(cmd, "net")) 3060 return; 3061 3062 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK) 3063 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3064 else 3065 need_to_commit = B_TRUE; 3066 } 3067 3068 static void 3069 remove_device(cmd_t *cmd) 3070 { 3071 int err; 3072 3073 /* traditional, qualified device removal */ 3074 if (cmd->cmd_prop_nv_pairs > 0) { 3075 struct zone_devtab devtab; 3076 3077 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) { 3078 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3079 return; 3080 } 3081 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 3082 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3083 else 3084 need_to_commit = B_TRUE; 3085 return; 3086 } 3087 3088 /* 3089 * unqualified device removal. remove all devices but prompt if more 3090 * than one. 3091 */ 3092 if (!prompt_remove_resource(cmd, "device")) 3093 return; 3094 3095 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK) 3096 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3097 else 3098 need_to_commit = B_TRUE; 3099 } 3100 3101 static void 3102 remove_attr(cmd_t *cmd) 3103 { 3104 int err; 3105 3106 /* traditional, qualified attr removal */ 3107 if (cmd->cmd_prop_nv_pairs > 0) { 3108 struct zone_attrtab attrtab; 3109 3110 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) { 3111 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3112 return; 3113 } 3114 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 3115 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3116 else 3117 need_to_commit = B_TRUE; 3118 return; 3119 } 3120 3121 /* 3122 * unqualified attr removal. remove all attrs but prompt if more 3123 * than one. 3124 */ 3125 if (!prompt_remove_resource(cmd, "attr")) 3126 return; 3127 3128 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK) 3129 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3130 else 3131 need_to_commit = B_TRUE; 3132 } 3133 3134 static void 3135 remove_dataset(cmd_t *cmd) 3136 { 3137 int err; 3138 3139 /* traditional, qualified dataset removal */ 3140 if (cmd->cmd_prop_nv_pairs > 0) { 3141 struct zone_dstab dstab; 3142 3143 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) { 3144 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3145 return; 3146 } 3147 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 3148 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3149 else 3150 need_to_commit = B_TRUE; 3151 return; 3152 } 3153 3154 /* 3155 * unqualified dataset removal. remove all datasets but prompt if more 3156 * than one. 3157 */ 3158 if (!prompt_remove_resource(cmd, "dataset")) 3159 return; 3160 3161 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK) 3162 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3163 else 3164 need_to_commit = B_TRUE; 3165 } 3166 3167 static void 3168 remove_rctl(cmd_t *cmd) 3169 { 3170 int err; 3171 3172 /* traditional, qualified rctl removal */ 3173 if (cmd->cmd_prop_nv_pairs > 0) { 3174 struct zone_rctltab rctltab; 3175 3176 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) { 3177 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3178 return; 3179 } 3180 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) 3181 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3182 else 3183 need_to_commit = B_TRUE; 3184 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 3185 return; 3186 } 3187 3188 /* 3189 * unqualified rctl removal. remove all rctls but prompt if more 3190 * than one. 3191 */ 3192 if (!prompt_remove_resource(cmd, "rctl")) 3193 return; 3194 3195 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK) 3196 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3197 else 3198 need_to_commit = B_TRUE; 3199 } 3200 3201 static void 3202 remove_pset() 3203 { 3204 int err; 3205 struct zone_psettab psettab; 3206 3207 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) { 3208 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE); 3209 return; 3210 } 3211 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 3212 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE); 3213 else 3214 need_to_commit = B_TRUE; 3215 } 3216 3217 static void 3218 remove_pcap() 3219 { 3220 int err; 3221 uint64_t tmp; 3222 3223 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) { 3224 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP), 3225 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 3226 saw_error = B_TRUE; 3227 return; 3228 } 3229 3230 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK) 3231 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE); 3232 else 3233 need_to_commit = B_TRUE; 3234 } 3235 3236 static void 3237 remove_mcap() 3238 { 3239 int err, res1, res2, res3; 3240 uint64_t tmp; 3241 struct zone_mcaptab mcaptab; 3242 boolean_t revert = B_FALSE; 3243 3244 res1 = zonecfg_lookup_mcap(handle, &mcaptab); 3245 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp); 3246 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp); 3247 3248 /* if none of these exist, there is no resource to remove */ 3249 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 3250 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP), 3251 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 3252 saw_error = B_TRUE; 3253 return; 3254 } 3255 if (res1 == Z_OK) { 3256 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) { 3257 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3258 revert = B_TRUE; 3259 } else { 3260 need_to_commit = B_TRUE; 3261 } 3262 } 3263 if (res2 == Z_OK) { 3264 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP)) 3265 != Z_OK) { 3266 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3267 revert = B_TRUE; 3268 } else { 3269 need_to_commit = B_TRUE; 3270 } 3271 } 3272 if (res3 == Z_OK) { 3273 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM)) 3274 != Z_OK) { 3275 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3276 revert = B_TRUE; 3277 } else { 3278 need_to_commit = B_TRUE; 3279 } 3280 } 3281 3282 if (revert) 3283 need_to_commit = B_FALSE; 3284 } 3285 3286 static void 3287 remove_admin(cmd_t *cmd) 3288 { 3289 int err; 3290 3291 /* traditional, qualified attr removal */ 3292 if (cmd->cmd_prop_nv_pairs > 0) { 3293 struct zone_admintab admintab; 3294 3295 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) { 3296 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3297 err, B_TRUE); 3298 return; 3299 } 3300 if ((err = zonecfg_delete_admin(handle, &admintab, 3301 zone)) 3302 != Z_OK) 3303 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3304 err, B_TRUE); 3305 else 3306 need_to_commit = B_TRUE; 3307 return; 3308 } else { 3309 /* 3310 * unqualified admin removal. 3311 * remove all admins but prompt if more 3312 * than one. 3313 */ 3314 if (!prompt_remove_resource(cmd, "admin")) 3315 return; 3316 3317 if ((err = zonecfg_delete_admins(handle, zone)) 3318 != Z_OK) 3319 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3320 err, B_TRUE); 3321 else 3322 need_to_commit = B_TRUE; 3323 } 3324 } 3325 3326 static void 3327 remove_resource(cmd_t *cmd) 3328 { 3329 int type; 3330 int arg; 3331 boolean_t arg_err = B_FALSE; 3332 3333 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3334 long_usage(CMD_REMOVE, B_TRUE); 3335 return; 3336 } 3337 3338 optind = 0; 3339 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 3340 switch (arg) { 3341 case '?': 3342 longer_usage(CMD_REMOVE); 3343 arg_err = B_TRUE; 3344 break; 3345 case 'F': 3346 break; 3347 default: 3348 short_usage(CMD_REMOVE); 3349 arg_err = B_TRUE; 3350 break; 3351 } 3352 } 3353 if (arg_err) 3354 return; 3355 3356 if (initialize(B_TRUE) != Z_OK) 3357 return; 3358 3359 switch (type) { 3360 case RT_FS: 3361 remove_fs(cmd); 3362 return; 3363 case RT_IPD: 3364 remove_ipd(cmd); 3365 return; 3366 case RT_NET: 3367 remove_net(cmd); 3368 return; 3369 case RT_DEVICE: 3370 remove_device(cmd); 3371 return; 3372 case RT_RCTL: 3373 remove_rctl(cmd); 3374 return; 3375 case RT_ATTR: 3376 remove_attr(cmd); 3377 return; 3378 case RT_DATASET: 3379 remove_dataset(cmd); 3380 return; 3381 case RT_DCPU: 3382 remove_pset(); 3383 return; 3384 case RT_PCAP: 3385 remove_pcap(); 3386 return; 3387 case RT_MCAP: 3388 remove_mcap(); 3389 return; 3390 case RT_ADMIN: 3391 remove_admin(cmd); 3392 return; 3393 default: 3394 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 3395 long_usage(CMD_REMOVE, B_TRUE); 3396 usage(B_FALSE, HELP_RESOURCES); 3397 return; 3398 } 3399 } 3400 3401 static void 3402 remove_property(cmd_t *cmd) 3403 { 3404 char *prop_id; 3405 int err, res_type, prop_type; 3406 property_value_ptr_t pp; 3407 struct zone_rctlvaltab *rctlvaltab; 3408 complex_property_ptr_t cx; 3409 3410 res_type = resource_scope; 3411 prop_type = cmd->cmd_prop_name[0]; 3412 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3413 long_usage(CMD_REMOVE, B_TRUE); 3414 return; 3415 } 3416 3417 if (cmd->cmd_prop_nv_pairs != 1) { 3418 long_usage(CMD_ADD, B_TRUE); 3419 return; 3420 } 3421 3422 if (initialize(B_TRUE) != Z_OK) 3423 return; 3424 3425 switch (res_type) { 3426 case RT_FS: 3427 if (prop_type != PT_OPTIONS) { 3428 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3429 B_TRUE); 3430 long_usage(CMD_REMOVE, B_TRUE); 3431 usage(B_FALSE, HELP_PROPS); 3432 return; 3433 } 3434 pp = cmd->cmd_property_ptr[0]; 3435 if (pp->pv_type == PROP_VAL_COMPLEX) { 3436 zerr(gettext("A %s or %s value was expected here."), 3437 pvt_to_str(PROP_VAL_SIMPLE), 3438 pvt_to_str(PROP_VAL_LIST)); 3439 saw_error = B_TRUE; 3440 return; 3441 } 3442 if (pp->pv_type == PROP_VAL_SIMPLE) { 3443 if (pp->pv_simple == NULL) { 3444 long_usage(CMD_ADD, B_TRUE); 3445 return; 3446 } 3447 prop_id = pp->pv_simple; 3448 err = zonecfg_remove_fs_option(&in_progress_fstab, 3449 prop_id); 3450 if (err != Z_OK) 3451 zone_perror(pt_to_str(prop_type), err, B_TRUE); 3452 } else { 3453 list_property_ptr_t list; 3454 3455 for (list = pp->pv_list; list != NULL; 3456 list = list->lp_next) { 3457 prop_id = list->lp_simple; 3458 if (prop_id == NULL) 3459 break; 3460 err = zonecfg_remove_fs_option( 3461 &in_progress_fstab, prop_id); 3462 if (err != Z_OK) 3463 zone_perror(pt_to_str(prop_type), err, 3464 B_TRUE); 3465 } 3466 } 3467 return; 3468 case RT_RCTL: 3469 if (prop_type != PT_VALUE) { 3470 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3471 B_TRUE); 3472 long_usage(CMD_REMOVE, B_TRUE); 3473 usage(B_FALSE, HELP_PROPS); 3474 return; 3475 } 3476 pp = cmd->cmd_property_ptr[0]; 3477 if (pp->pv_type != PROP_VAL_COMPLEX) { 3478 zerr(gettext("A %s value was expected here."), 3479 pvt_to_str(PROP_VAL_COMPLEX)); 3480 saw_error = B_TRUE; 3481 return; 3482 } 3483 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 3484 zone_perror(zone, Z_NOMEM, B_TRUE); 3485 exit(Z_ERR); 3486 } 3487 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) { 3488 switch (cx->cp_type) { 3489 case PT_PRIV: 3490 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 3491 cx->cp_value, 3492 sizeof (rctlvaltab->zone_rctlval_priv)); 3493 break; 3494 case PT_LIMIT: 3495 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 3496 cx->cp_value, 3497 sizeof (rctlvaltab->zone_rctlval_limit)); 3498 break; 3499 case PT_ACTION: 3500 (void) strlcpy(rctlvaltab->zone_rctlval_action, 3501 cx->cp_value, 3502 sizeof (rctlvaltab->zone_rctlval_action)); 3503 break; 3504 default: 3505 zone_perror(pt_to_str(prop_type), 3506 Z_NO_PROPERTY_TYPE, B_TRUE); 3507 long_usage(CMD_ADD, B_TRUE); 3508 usage(B_FALSE, HELP_PROPS); 3509 zonecfg_free_rctl_value_list(rctlvaltab); 3510 return; 3511 } 3512 } 3513 rctlvaltab->zone_rctlval_next = NULL; 3514 err = zonecfg_remove_rctl_value(&in_progress_rctltab, 3515 rctlvaltab); 3516 if (err != Z_OK) 3517 zone_perror(pt_to_str(prop_type), err, B_TRUE); 3518 zonecfg_free_rctl_value_list(rctlvaltab); 3519 return; 3520 case RT_NET: 3521 if (prop_type != PT_DEFROUTER) { 3522 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3523 B_TRUE); 3524 long_usage(CMD_REMOVE, B_TRUE); 3525 usage(B_FALSE, HELP_PROPS); 3526 return; 3527 } else { 3528 bzero(&in_progress_nwiftab.zone_nwif_defrouter, 3529 sizeof (in_progress_nwiftab.zone_nwif_defrouter)); 3530 return; 3531 } 3532 default: 3533 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 3534 long_usage(CMD_REMOVE, B_TRUE); 3535 usage(B_FALSE, HELP_RESOURCES); 3536 return; 3537 } 3538 } 3539 3540 void 3541 remove_func(cmd_t *cmd) 3542 { 3543 if (zone_is_read_only(CMD_REMOVE)) 3544 return; 3545 3546 assert(cmd != NULL); 3547 3548 if (global_scope) { 3549 if (gz_invalid_resource(cmd->cmd_res_type)) { 3550 zerr(gettext("%s is not a valid resource for the " 3551 "global zone."), rt_to_str(cmd->cmd_res_type)); 3552 saw_error = B_TRUE; 3553 return; 3554 } 3555 remove_resource(cmd); 3556 } else { 3557 remove_property(cmd); 3558 } 3559 } 3560 3561 static void 3562 clear_property(cmd_t *cmd) 3563 { 3564 int res_type, prop_type; 3565 3566 res_type = resource_scope; 3567 prop_type = cmd->cmd_res_type; 3568 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3569 long_usage(CMD_CLEAR, B_TRUE); 3570 return; 3571 } 3572 3573 if (initialize(B_TRUE) != Z_OK) 3574 return; 3575 3576 switch (res_type) { 3577 case RT_FS: 3578 if (prop_type == PT_RAW) { 3579 in_progress_fstab.zone_fs_raw[0] = '\0'; 3580 need_to_commit = B_TRUE; 3581 return; 3582 } 3583 break; 3584 case RT_DCPU: 3585 if (prop_type == PT_IMPORTANCE) { 3586 in_progress_psettab.zone_importance[0] = '\0'; 3587 need_to_commit = B_TRUE; 3588 return; 3589 } 3590 break; 3591 case RT_MCAP: 3592 switch (prop_type) { 3593 case PT_PHYSICAL: 3594 in_progress_mcaptab.zone_physmem_cap[0] = '\0'; 3595 need_to_commit = B_TRUE; 3596 return; 3597 case PT_SWAP: 3598 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP); 3599 return; 3600 case PT_LOCKED: 3601 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM); 3602 return; 3603 } 3604 break; 3605 default: 3606 break; 3607 } 3608 3609 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE); 3610 } 3611 3612 static void 3613 clear_global(cmd_t *cmd) 3614 { 3615 int err, type; 3616 3617 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3618 long_usage(CMD_CLEAR, B_TRUE); 3619 return; 3620 } 3621 3622 if (initialize(B_TRUE) != Z_OK) 3623 return; 3624 3625 switch (type) { 3626 case PT_ZONENAME: 3627 /* FALLTHRU */ 3628 case PT_ZONEPATH: 3629 /* FALLTHRU */ 3630 case PT_BRAND: 3631 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE); 3632 return; 3633 case PT_AUTOBOOT: 3634 /* false is default; we'll treat as equivalent to clearing */ 3635 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK) 3636 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE); 3637 else 3638 need_to_commit = B_TRUE; 3639 return; 3640 case PT_POOL: 3641 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK) 3642 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE); 3643 else 3644 need_to_commit = B_TRUE; 3645 return; 3646 case PT_LIMITPRIV: 3647 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK) 3648 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE); 3649 else 3650 need_to_commit = B_TRUE; 3651 return; 3652 case PT_BOOTARGS: 3653 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK) 3654 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE); 3655 else 3656 need_to_commit = B_TRUE; 3657 return; 3658 case PT_SCHED: 3659 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK) 3660 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE); 3661 else 3662 need_to_commit = B_TRUE; 3663 return; 3664 case PT_IPTYPE: 3665 /* shared is default; we'll treat as equivalent to clearing */ 3666 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK) 3667 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE); 3668 else 3669 need_to_commit = B_TRUE; 3670 return; 3671 case PT_MAXLWPS: 3672 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS); 3673 return; 3674 case PT_MAXSHMMEM: 3675 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM); 3676 return; 3677 case PT_MAXSHMIDS: 3678 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS); 3679 return; 3680 case PT_MAXMSGIDS: 3681 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS); 3682 return; 3683 case PT_MAXSEMIDS: 3684 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS); 3685 return; 3686 case PT_SHARES: 3687 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES); 3688 return; 3689 case PT_HOSTID: 3690 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK) 3691 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE); 3692 else 3693 need_to_commit = B_TRUE; 3694 return; 3695 case PT_FS_ALLOWED: 3696 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK) 3697 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE); 3698 else 3699 need_to_commit = B_TRUE; 3700 return; 3701 default: 3702 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE); 3703 long_usage(CMD_CLEAR, B_TRUE); 3704 usage(B_FALSE, HELP_PROPS); 3705 return; 3706 } 3707 } 3708 3709 void 3710 clear_func(cmd_t *cmd) 3711 { 3712 if (zone_is_read_only(CMD_CLEAR)) 3713 return; 3714 3715 assert(cmd != NULL); 3716 3717 if (global_scope) { 3718 if (gz_invalid_property(cmd->cmd_res_type)) { 3719 zerr(gettext("%s is not a valid property for the " 3720 "global zone."), pt_to_str(cmd->cmd_res_type)); 3721 saw_error = B_TRUE; 3722 return; 3723 } 3724 3725 clear_global(cmd); 3726 } else { 3727 clear_property(cmd); 3728 } 3729 } 3730 3731 void 3732 select_func(cmd_t *cmd) 3733 { 3734 int type, err, res; 3735 uint64_t limit; 3736 uint64_t tmp; 3737 3738 if (zone_is_read_only(CMD_SELECT)) 3739 return; 3740 3741 assert(cmd != NULL); 3742 3743 if (global_scope) { 3744 global_scope = B_FALSE; 3745 resource_scope = cmd->cmd_res_type; 3746 end_op = CMD_SELECT; 3747 } else { 3748 scope_usage(CMD_SELECT); 3749 return; 3750 } 3751 3752 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3753 long_usage(CMD_SELECT, B_TRUE); 3754 return; 3755 } 3756 3757 if (initialize(B_TRUE) != Z_OK) 3758 return; 3759 3760 switch (type) { 3761 case RT_FS: 3762 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) { 3763 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE); 3764 global_scope = B_TRUE; 3765 } 3766 bcopy(&old_fstab, &in_progress_fstab, 3767 sizeof (struct zone_fstab)); 3768 return; 3769 case RT_IPD: 3770 if (state_atleast(ZONE_STATE_INCOMPLETE)) { 3771 zerr(gettext("Zone %s not in %s state; %s %s not " 3772 "allowed."), zone, 3773 zone_state_str(ZONE_STATE_CONFIGURED), 3774 cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD)); 3775 global_scope = B_TRUE; 3776 end_op = -1; 3777 return; 3778 } 3779 if ((err = fill_in_ipdtab(cmd, &old_ipdtab, B_FALSE)) != Z_OK) { 3780 z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, B_TRUE); 3781 global_scope = B_TRUE; 3782 } 3783 bcopy(&old_ipdtab, &in_progress_ipdtab, 3784 sizeof (struct zone_fstab)); 3785 return; 3786 case RT_NET: 3787 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE)) 3788 != Z_OK) { 3789 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE); 3790 global_scope = B_TRUE; 3791 } 3792 bcopy(&old_nwiftab, &in_progress_nwiftab, 3793 sizeof (struct zone_nwiftab)); 3794 return; 3795 case RT_DEVICE: 3796 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) { 3797 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE); 3798 global_scope = B_TRUE; 3799 } 3800 bcopy(&old_devtab, &in_progress_devtab, 3801 sizeof (struct zone_devtab)); 3802 return; 3803 case RT_RCTL: 3804 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE)) 3805 != Z_OK) { 3806 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE); 3807 global_scope = B_TRUE; 3808 } 3809 bcopy(&old_rctltab, &in_progress_rctltab, 3810 sizeof (struct zone_rctltab)); 3811 return; 3812 case RT_ATTR: 3813 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE)) 3814 != Z_OK) { 3815 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE); 3816 global_scope = B_TRUE; 3817 } 3818 bcopy(&old_attrtab, &in_progress_attrtab, 3819 sizeof (struct zone_attrtab)); 3820 return; 3821 case RT_DATASET: 3822 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) { 3823 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE); 3824 global_scope = B_TRUE; 3825 } 3826 bcopy(&old_dstab, &in_progress_dstab, 3827 sizeof (struct zone_dstab)); 3828 return; 3829 case RT_DCPU: 3830 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) { 3831 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE); 3832 global_scope = B_TRUE; 3833 } 3834 bcopy(&old_psettab, &in_progress_psettab, 3835 sizeof (struct zone_psettab)); 3836 return; 3837 case RT_PCAP: 3838 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) 3839 != Z_OK) { 3840 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE); 3841 global_scope = B_TRUE; 3842 } 3843 return; 3844 case RT_MCAP: 3845 /* if none of these exist, there is no resource to select */ 3846 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK && 3847 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit) 3848 != Z_OK && 3849 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit) 3850 != Z_OK) { 3851 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE, 3852 B_TRUE); 3853 global_scope = B_TRUE; 3854 } 3855 if (res == Z_OK) 3856 bcopy(&old_mcaptab, &in_progress_mcaptab, 3857 sizeof (struct zone_mcaptab)); 3858 else 3859 bzero(&in_progress_mcaptab, 3860 sizeof (in_progress_mcaptab)); 3861 return; 3862 case RT_ADMIN: 3863 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE)) 3864 != Z_OK) { 3865 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err, 3866 B_TRUE); 3867 global_scope = B_TRUE; 3868 } 3869 bcopy(&old_admintab, &in_progress_admintab, 3870 sizeof (struct zone_admintab)); 3871 return; 3872 default: 3873 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 3874 long_usage(CMD_SELECT, B_TRUE); 3875 usage(B_FALSE, HELP_RESOURCES); 3876 return; 3877 } 3878 } 3879 3880 /* 3881 * Network "addresses" can be one of the following forms: 3882 * <IPv4 address> 3883 * <IPv4 address>/<prefix length> 3884 * <IPv6 address>/<prefix length> 3885 * <host name> 3886 * <host name>/<prefix length> 3887 * In other words, the "/" followed by a prefix length is allowed but not 3888 * required for IPv4 addresses and host names, and required for IPv6 addresses. 3889 * If a prefix length is given, it must be in the allowable range: 0 to 32 for 3890 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses. 3891 * Host names must start with an alpha-numeric character, and all subsequent 3892 * characters must be either alpha-numeric or "-". 3893 */ 3894 3895 static int 3896 validate_net_address_syntax(char *address) 3897 { 3898 char *slashp, part1[MAXHOSTNAMELEN]; 3899 struct in6_addr in6; 3900 struct in_addr in4; 3901 int prefixlen, i; 3902 3903 /* 3904 * Copy the part before any '/' into part1 or copy the whole 3905 * thing if there is no '/'. 3906 */ 3907 if ((slashp = strchr(address, '/')) != NULL) { 3908 *slashp = '\0'; 3909 (void) strlcpy(part1, address, sizeof (part1)); 3910 *slashp = '/'; 3911 prefixlen = atoi(++slashp); 3912 } else { 3913 (void) strlcpy(part1, address, sizeof (part1)); 3914 } 3915 3916 if (inet_pton(AF_INET6, part1, &in6) == 1) { 3917 if (slashp == NULL) { 3918 zerr(gettext("%s: IPv6 addresses " 3919 "require /prefix-length suffix."), address); 3920 return (Z_ERR); 3921 } 3922 if (prefixlen < 0 || prefixlen > 128) { 3923 zerr(gettext("%s: IPv6 address " 3924 "prefix lengths must be 0 - 128."), address); 3925 return (Z_ERR); 3926 } 3927 return (Z_OK); 3928 } 3929 3930 /* At this point, any /prefix must be for IPv4. */ 3931 if (slashp != NULL) { 3932 if (prefixlen < 0 || prefixlen > 32) { 3933 zerr(gettext("%s: IPv4 address " 3934 "prefix lengths must be 0 - 32."), address); 3935 return (Z_ERR); 3936 } 3937 } 3938 if (inet_pton(AF_INET, part1, &in4) == 1) 3939 return (Z_OK); 3940 3941 /* address may also be a host name */ 3942 if (!isalnum(part1[0])) { 3943 zerr(gettext("%s: bogus host name or network address syntax"), 3944 part1); 3945 saw_error = B_TRUE; 3946 usage(B_FALSE, HELP_NETADDR); 3947 return (Z_ERR); 3948 } 3949 for (i = 1; part1[i]; i++) 3950 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') { 3951 zerr(gettext("%s: bogus host name or " 3952 "network address syntax"), part1); 3953 saw_error = B_TRUE; 3954 usage(B_FALSE, HELP_NETADDR); 3955 return (Z_ERR); 3956 } 3957 return (Z_OK); 3958 } 3959 3960 static int 3961 validate_net_physical_syntax(const char *ifname) 3962 { 3963 ifspec_t ifnameprop; 3964 zone_iptype_t iptype; 3965 3966 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 3967 zerr(gettext("zone configuration has an invalid or nonexistent " 3968 "ip-type property")); 3969 return (Z_ERR); 3970 } 3971 switch (iptype) { 3972 case ZS_SHARED: 3973 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) { 3974 zerr(gettext("%s: invalid physical interface name"), 3975 ifname); 3976 return (Z_ERR); 3977 } 3978 if (ifnameprop.ifsp_lunvalid) { 3979 zerr(gettext("%s: LUNs not allowed in physical " 3980 "interface names"), ifname); 3981 return (Z_ERR); 3982 } 3983 break; 3984 case ZS_EXCLUSIVE: 3985 if (dladm_valid_linkname(ifname) == B_FALSE) { 3986 if (strchr(ifname, ':') != NULL) 3987 zerr(gettext("%s: physical interface name " 3988 "required; logical interface name not " 3989 "allowed"), ifname); 3990 else 3991 zerr(gettext("%s: invalid physical interface " 3992 "name"), ifname); 3993 return (Z_ERR); 3994 } 3995 break; 3996 } 3997 return (Z_OK); 3998 } 3999 4000 static boolean_t 4001 valid_fs_type(const char *type) 4002 { 4003 /* 4004 * Is this a valid path component? 4005 */ 4006 if (strlen(type) + 1 > MAXNAMELEN) 4007 return (B_FALSE); 4008 /* 4009 * Make sure a bad value for "type" doesn't make 4010 * /usr/lib/fs/<type>/mount turn into something else. 4011 */ 4012 if (strchr(type, '/') != NULL || type[0] == '\0' || 4013 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 4014 return (B_FALSE); 4015 /* 4016 * More detailed verification happens later by zoneadm(1m). 4017 */ 4018 return (B_TRUE); 4019 } 4020 4021 static boolean_t 4022 allow_exclusive() 4023 { 4024 brand_handle_t bh; 4025 char brand[MAXNAMELEN]; 4026 boolean_t ret; 4027 4028 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 4029 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 4030 return (B_FALSE); 4031 } 4032 if ((bh = brand_open(brand)) == NULL) { 4033 zerr("%s: %s\n", zone, gettext("unknown brand.")); 4034 return (B_FALSE); 4035 } 4036 ret = brand_allow_exclusive_ip(bh); 4037 brand_close(bh); 4038 if (!ret) 4039 zerr(gettext("%s cannot be '%s' when %s is '%s'."), 4040 pt_to_str(PT_IPTYPE), "exclusive", 4041 pt_to_str(PT_BRAND), brand); 4042 return (ret); 4043 } 4044 4045 static void 4046 set_aliased_rctl(char *alias, int prop_type, char *s) 4047 { 4048 uint64_t limit; 4049 int err; 4050 char tmp[128]; 4051 4052 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0) 4053 zerr(gettext("WARNING: Setting a global zone resource " 4054 "control too low could deny\nservice " 4055 "to even the root user; " 4056 "this could render the system impossible\n" 4057 "to administer. Please use caution.")); 4058 4059 /* convert memory based properties */ 4060 if (prop_type == PT_MAXSHMMEM) { 4061 if (!zonecfg_valid_memlimit(s, &limit)) { 4062 zerr(gettext("A non-negative number with a required " 4063 "scale suffix (K, M, G or T) was expected\nhere.")); 4064 saw_error = B_TRUE; 4065 return; 4066 } 4067 4068 (void) snprintf(tmp, sizeof (tmp), "%llu", limit); 4069 s = tmp; 4070 } 4071 4072 if (!zonecfg_aliased_rctl_ok(handle, alias)) { 4073 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE); 4074 saw_error = B_TRUE; 4075 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) { 4076 zerr(gettext("%s property is out of range."), 4077 pt_to_str(prop_type)); 4078 saw_error = B_TRUE; 4079 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit)) 4080 != Z_OK) { 4081 zone_perror(zone, err, B_TRUE); 4082 saw_error = B_TRUE; 4083 } else { 4084 need_to_commit = B_TRUE; 4085 } 4086 } 4087 4088 void 4089 set_func(cmd_t *cmd) 4090 { 4091 char *prop_id; 4092 int arg, err, res_type, prop_type; 4093 property_value_ptr_t pp; 4094 boolean_t autoboot; 4095 zone_iptype_t iptype; 4096 boolean_t force_set = B_FALSE; 4097 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap); 4098 uint64_t mem_cap, mem_limit; 4099 float cap; 4100 char *unitp; 4101 struct zone_psettab tmp_psettab; 4102 boolean_t arg_err = B_FALSE; 4103 4104 if (zone_is_read_only(CMD_SET)) 4105 return; 4106 4107 assert(cmd != NULL); 4108 4109 optind = opterr = 0; 4110 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 4111 switch (arg) { 4112 case 'F': 4113 force_set = B_TRUE; 4114 break; 4115 default: 4116 if (optopt == '?') 4117 longer_usage(CMD_SET); 4118 else 4119 short_usage(CMD_SET); 4120 arg_err = B_TRUE; 4121 break; 4122 } 4123 } 4124 if (arg_err) 4125 return; 4126 4127 prop_type = cmd->cmd_prop_name[0]; 4128 if (global_scope) { 4129 if (gz_invalid_property(prop_type)) { 4130 zerr(gettext("%s is not a valid property for the " 4131 "global zone."), pt_to_str(prop_type)); 4132 saw_error = B_TRUE; 4133 return; 4134 } 4135 4136 if (prop_type == PT_ZONENAME) { 4137 res_type = RT_ZONENAME; 4138 } else if (prop_type == PT_ZONEPATH) { 4139 res_type = RT_ZONEPATH; 4140 } else if (prop_type == PT_AUTOBOOT) { 4141 res_type = RT_AUTOBOOT; 4142 } else if (prop_type == PT_BRAND) { 4143 res_type = RT_BRAND; 4144 } else if (prop_type == PT_POOL) { 4145 res_type = RT_POOL; 4146 } else if (prop_type == PT_LIMITPRIV) { 4147 res_type = RT_LIMITPRIV; 4148 } else if (prop_type == PT_BOOTARGS) { 4149 res_type = RT_BOOTARGS; 4150 } else if (prop_type == PT_SCHED) { 4151 res_type = RT_SCHED; 4152 } else if (prop_type == PT_IPTYPE) { 4153 res_type = RT_IPTYPE; 4154 } else if (prop_type == PT_MAXLWPS) { 4155 res_type = RT_MAXLWPS; 4156 } else if (prop_type == PT_MAXSHMMEM) { 4157 res_type = RT_MAXSHMMEM; 4158 } else if (prop_type == PT_MAXSHMIDS) { 4159 res_type = RT_MAXSHMIDS; 4160 } else if (prop_type == PT_MAXMSGIDS) { 4161 res_type = RT_MAXMSGIDS; 4162 } else if (prop_type == PT_MAXSEMIDS) { 4163 res_type = RT_MAXSEMIDS; 4164 } else if (prop_type == PT_SHARES) { 4165 res_type = RT_SHARES; 4166 } else if (prop_type == PT_HOSTID) { 4167 res_type = RT_HOSTID; 4168 } else if (prop_type == PT_FS_ALLOWED) { 4169 res_type = RT_FS_ALLOWED; 4170 } else { 4171 zerr(gettext("Cannot set a resource-specific property " 4172 "from the global scope.")); 4173 saw_error = B_TRUE; 4174 return; 4175 } 4176 } else { 4177 res_type = resource_scope; 4178 } 4179 4180 if (force_set) { 4181 if (res_type != RT_ZONEPATH) { 4182 zerr(gettext("Only zonepath setting can be forced.")); 4183 saw_error = B_TRUE; 4184 return; 4185 } 4186 if (!zonecfg_in_alt_root()) { 4187 zerr(gettext("Zonepath is changeable only in an " 4188 "alternate root.")); 4189 saw_error = B_TRUE; 4190 return; 4191 } 4192 } 4193 4194 pp = cmd->cmd_property_ptr[0]; 4195 /* 4196 * A nasty expression but not that complicated: 4197 * 1. fs options are simple or list (tested below) 4198 * 2. rctl value's are complex or list (tested below) 4199 * Anything else should be simple. 4200 */ 4201 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 4202 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 4203 (pp->pv_type != PROP_VAL_SIMPLE || 4204 (prop_id = pp->pv_simple) == NULL)) { 4205 zerr(gettext("A %s value was expected here."), 4206 pvt_to_str(PROP_VAL_SIMPLE)); 4207 saw_error = B_TRUE; 4208 return; 4209 } 4210 if (prop_type == PT_UNKNOWN) { 4211 long_usage(CMD_SET, B_TRUE); 4212 return; 4213 } 4214 4215 /* 4216 * Special case: the user can change the zone name prior to 'create'; 4217 * if the zone already exists, we fall through letting initialize() 4218 * and the rest of the logic run. 4219 */ 4220 if (res_type == RT_ZONENAME && got_handle == B_FALSE && 4221 !state_atleast(ZONE_STATE_CONFIGURED)) { 4222 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) { 4223 zone_perror(prop_id, err, B_TRUE); 4224 usage(B_FALSE, HELP_SYNTAX); 4225 return; 4226 } 4227 (void) strlcpy(zone, prop_id, sizeof (zone)); 4228 return; 4229 } 4230 4231 if (initialize(B_TRUE) != Z_OK) 4232 return; 4233 4234 switch (res_type) { 4235 case RT_ZONENAME: 4236 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 4237 /* 4238 * Use prop_id instead of 'zone' here, since we're 4239 * reporting a problem about the *new* zonename. 4240 */ 4241 zone_perror(prop_id, err, B_TRUE); 4242 usage(B_FALSE, HELP_SYNTAX); 4243 } else { 4244 need_to_commit = B_TRUE; 4245 (void) strlcpy(zone, prop_id, sizeof (zone)); 4246 } 4247 return; 4248 case RT_ZONEPATH: 4249 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) { 4250 zerr(gettext("Zone %s already installed; %s %s not " 4251 "allowed."), zone, cmd_to_str(CMD_SET), 4252 rt_to_str(RT_ZONEPATH)); 4253 return; 4254 } 4255 if (validate_zonepath_syntax(prop_id) != Z_OK) { 4256 saw_error = B_TRUE; 4257 return; 4258 } 4259 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 4260 zone_perror(zone, err, B_TRUE); 4261 else 4262 need_to_commit = B_TRUE; 4263 return; 4264 case RT_BRAND: 4265 if (state_atleast(ZONE_STATE_INSTALLED)) { 4266 zerr(gettext("Zone %s already installed; %s %s not " 4267 "allowed."), zone, cmd_to_str(CMD_SET), 4268 rt_to_str(RT_BRAND)); 4269 return; 4270 } 4271 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK) 4272 zone_perror(zone, err, B_TRUE); 4273 else 4274 need_to_commit = B_TRUE; 4275 return; 4276 case RT_AUTOBOOT: 4277 if (strcmp(prop_id, "true") == 0) { 4278 autoboot = B_TRUE; 4279 } else if (strcmp(prop_id, "false") == 0) { 4280 autoboot = B_FALSE; 4281 } else { 4282 zerr(gettext("%s value must be '%s' or '%s'."), 4283 pt_to_str(PT_AUTOBOOT), "true", "false"); 4284 saw_error = B_TRUE; 4285 return; 4286 } 4287 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 4288 zone_perror(zone, err, B_TRUE); 4289 else 4290 need_to_commit = B_TRUE; 4291 return; 4292 case RT_POOL: 4293 /* don't allow use of the reserved temporary pool names */ 4294 if (strncmp("SUNW", prop_id, 4) == 0) { 4295 zerr(gettext("pool names starting with SUNW are " 4296 "reserved.")); 4297 saw_error = B_TRUE; 4298 return; 4299 } 4300 4301 /* can't set pool if dedicated-cpu exists */ 4302 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 4303 zerr(gettext("The %s resource already exists. " 4304 "A persistent pool is incompatible\nwith the %s " 4305 "resource."), rt_to_str(RT_DCPU), 4306 rt_to_str(RT_DCPU)); 4307 saw_error = B_TRUE; 4308 return; 4309 } 4310 4311 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 4312 zone_perror(zone, err, B_TRUE); 4313 else 4314 need_to_commit = B_TRUE; 4315 return; 4316 case RT_LIMITPRIV: 4317 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK) 4318 zone_perror(zone, err, B_TRUE); 4319 else 4320 need_to_commit = B_TRUE; 4321 return; 4322 case RT_BOOTARGS: 4323 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK) 4324 zone_perror(zone, err, B_TRUE); 4325 else 4326 need_to_commit = B_TRUE; 4327 return; 4328 case RT_SCHED: 4329 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK) 4330 zone_perror(zone, err, B_TRUE); 4331 else 4332 need_to_commit = B_TRUE; 4333 return; 4334 case RT_IPTYPE: 4335 if (strcmp(prop_id, "shared") == 0) { 4336 iptype = ZS_SHARED; 4337 } else if (strcmp(prop_id, "exclusive") == 0) { 4338 iptype = ZS_EXCLUSIVE; 4339 } else { 4340 zerr(gettext("%s value must be '%s' or '%s'."), 4341 pt_to_str(PT_IPTYPE), "shared", "exclusive"); 4342 saw_error = B_TRUE; 4343 return; 4344 } 4345 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) { 4346 saw_error = B_TRUE; 4347 return; 4348 } 4349 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK) 4350 zone_perror(zone, err, B_TRUE); 4351 else 4352 need_to_commit = B_TRUE; 4353 return; 4354 case RT_MAXLWPS: 4355 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id); 4356 return; 4357 case RT_MAXSHMMEM: 4358 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id); 4359 return; 4360 case RT_MAXSHMIDS: 4361 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id); 4362 return; 4363 case RT_MAXMSGIDS: 4364 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id); 4365 return; 4366 case RT_MAXSEMIDS: 4367 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id); 4368 return; 4369 case RT_SHARES: 4370 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id); 4371 return; 4372 case RT_HOSTID: 4373 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) { 4374 if (err == Z_TOO_BIG) { 4375 zerr(gettext("hostid string is too large: %s"), 4376 prop_id); 4377 saw_error = B_TRUE; 4378 } else { 4379 zone_perror(pt_to_str(prop_type), err, B_TRUE); 4380 } 4381 return; 4382 } 4383 need_to_commit = B_TRUE; 4384 return; 4385 case RT_FS_ALLOWED: 4386 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK) 4387 zone_perror(zone, err, B_TRUE); 4388 else 4389 need_to_commit = B_TRUE; 4390 return; 4391 case RT_FS: 4392 switch (prop_type) { 4393 case PT_DIR: 4394 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 4395 sizeof (in_progress_fstab.zone_fs_dir)); 4396 return; 4397 case PT_SPECIAL: 4398 (void) strlcpy(in_progress_fstab.zone_fs_special, 4399 prop_id, 4400 sizeof (in_progress_fstab.zone_fs_special)); 4401 return; 4402 case PT_RAW: 4403 (void) strlcpy(in_progress_fstab.zone_fs_raw, 4404 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 4405 return; 4406 case PT_TYPE: 4407 if (!valid_fs_type(prop_id)) { 4408 zerr(gettext("\"%s\" is not a valid %s."), 4409 prop_id, pt_to_str(PT_TYPE)); 4410 saw_error = B_TRUE; 4411 return; 4412 } 4413 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 4414 sizeof (in_progress_fstab.zone_fs_type)); 4415 return; 4416 case PT_OPTIONS: 4417 if (pp->pv_type != PROP_VAL_SIMPLE && 4418 pp->pv_type != PROP_VAL_LIST) { 4419 zerr(gettext("A %s or %s value was expected " 4420 "here."), pvt_to_str(PROP_VAL_SIMPLE), 4421 pvt_to_str(PROP_VAL_LIST)); 4422 saw_error = B_TRUE; 4423 return; 4424 } 4425 zonecfg_free_fs_option_list( 4426 in_progress_fstab.zone_fs_options); 4427 in_progress_fstab.zone_fs_options = NULL; 4428 if (!(pp->pv_type == PROP_VAL_LIST && 4429 pp->pv_list == NULL)) 4430 add_property(cmd); 4431 return; 4432 default: 4433 break; 4434 } 4435 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4436 long_usage(CMD_SET, B_TRUE); 4437 usage(B_FALSE, HELP_PROPS); 4438 return; 4439 case RT_IPD: 4440 switch (prop_type) { 4441 case PT_DIR: 4442 (void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id, 4443 sizeof (in_progress_ipdtab.zone_fs_dir)); 4444 return; 4445 default: 4446 break; 4447 } 4448 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4449 long_usage(CMD_SET, B_TRUE); 4450 usage(B_FALSE, HELP_PROPS); 4451 return; 4452 case RT_NET: 4453 switch (prop_type) { 4454 case PT_ADDRESS: 4455 if (validate_net_address_syntax(prop_id) != Z_OK) { 4456 saw_error = B_TRUE; 4457 return; 4458 } 4459 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, 4460 prop_id, 4461 sizeof (in_progress_nwiftab.zone_nwif_address)); 4462 break; 4463 case PT_PHYSICAL: 4464 if (validate_net_physical_syntax(prop_id) != Z_OK) { 4465 saw_error = B_TRUE; 4466 return; 4467 } 4468 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 4469 prop_id, 4470 sizeof (in_progress_nwiftab.zone_nwif_physical)); 4471 break; 4472 case PT_DEFROUTER: 4473 if (validate_net_address_syntax(prop_id) != Z_OK) { 4474 saw_error = B_TRUE; 4475 return; 4476 } 4477 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter, 4478 prop_id, 4479 sizeof (in_progress_nwiftab.zone_nwif_defrouter)); 4480 break; 4481 default: 4482 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4483 B_TRUE); 4484 long_usage(CMD_SET, B_TRUE); 4485 usage(B_FALSE, HELP_PROPS); 4486 return; 4487 } 4488 return; 4489 case RT_DEVICE: 4490 switch (prop_type) { 4491 case PT_MATCH: 4492 (void) strlcpy(in_progress_devtab.zone_dev_match, 4493 prop_id, 4494 sizeof (in_progress_devtab.zone_dev_match)); 4495 break; 4496 default: 4497 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4498 B_TRUE); 4499 long_usage(CMD_SET, B_TRUE); 4500 usage(B_FALSE, HELP_PROPS); 4501 return; 4502 } 4503 return; 4504 case RT_RCTL: 4505 switch (prop_type) { 4506 case PT_NAME: 4507 if (!zonecfg_valid_rctlname(prop_id)) { 4508 zerr(gettext("'%s' is not a valid zone %s " 4509 "name."), prop_id, rt_to_str(RT_RCTL)); 4510 return; 4511 } 4512 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 4513 prop_id, 4514 sizeof (in_progress_rctltab.zone_rctl_name)); 4515 break; 4516 case PT_VALUE: 4517 if (pp->pv_type != PROP_VAL_COMPLEX && 4518 pp->pv_type != PROP_VAL_LIST) { 4519 zerr(gettext("A %s or %s value was expected " 4520 "here."), pvt_to_str(PROP_VAL_COMPLEX), 4521 pvt_to_str(PROP_VAL_LIST)); 4522 saw_error = B_TRUE; 4523 return; 4524 } 4525 zonecfg_free_rctl_value_list( 4526 in_progress_rctltab.zone_rctl_valptr); 4527 in_progress_rctltab.zone_rctl_valptr = NULL; 4528 if (!(pp->pv_type == PROP_VAL_LIST && 4529 pp->pv_list == NULL)) 4530 add_property(cmd); 4531 break; 4532 default: 4533 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4534 B_TRUE); 4535 long_usage(CMD_SET, B_TRUE); 4536 usage(B_FALSE, HELP_PROPS); 4537 return; 4538 } 4539 return; 4540 case RT_ATTR: 4541 switch (prop_type) { 4542 case PT_NAME: 4543 (void) strlcpy(in_progress_attrtab.zone_attr_name, 4544 prop_id, 4545 sizeof (in_progress_attrtab.zone_attr_name)); 4546 break; 4547 case PT_TYPE: 4548 (void) strlcpy(in_progress_attrtab.zone_attr_type, 4549 prop_id, 4550 sizeof (in_progress_attrtab.zone_attr_type)); 4551 break; 4552 case PT_VALUE: 4553 (void) strlcpy(in_progress_attrtab.zone_attr_value, 4554 prop_id, 4555 sizeof (in_progress_attrtab.zone_attr_value)); 4556 break; 4557 default: 4558 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4559 B_TRUE); 4560 long_usage(CMD_SET, B_TRUE); 4561 usage(B_FALSE, HELP_PROPS); 4562 return; 4563 } 4564 return; 4565 case RT_DATASET: 4566 switch (prop_type) { 4567 case PT_NAME: 4568 (void) strlcpy(in_progress_dstab.zone_dataset_name, 4569 prop_id, 4570 sizeof (in_progress_dstab.zone_dataset_name)); 4571 return; 4572 default: 4573 break; 4574 } 4575 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4576 long_usage(CMD_SET, B_TRUE); 4577 usage(B_FALSE, HELP_PROPS); 4578 return; 4579 case RT_DCPU: 4580 switch (prop_type) { 4581 char *lowp, *highp; 4582 4583 case PT_NCPUS: 4584 lowp = prop_id; 4585 if ((highp = strchr(prop_id, '-')) != NULL) 4586 *highp++ = '\0'; 4587 else 4588 highp = lowp; 4589 4590 /* Make sure the input makes sense. */ 4591 if (!zonecfg_valid_ncpus(lowp, highp)) { 4592 zerr(gettext("%s property is out of range."), 4593 pt_to_str(PT_NCPUS)); 4594 saw_error = B_TRUE; 4595 return; 4596 } 4597 4598 (void) strlcpy( 4599 in_progress_psettab.zone_ncpu_min, lowp, 4600 sizeof (in_progress_psettab.zone_ncpu_min)); 4601 (void) strlcpy( 4602 in_progress_psettab.zone_ncpu_max, highp, 4603 sizeof (in_progress_psettab.zone_ncpu_max)); 4604 return; 4605 case PT_IMPORTANCE: 4606 /* Make sure the value makes sense. */ 4607 if (!zonecfg_valid_importance(prop_id)) { 4608 zerr(gettext("%s property is out of range."), 4609 pt_to_str(PT_IMPORTANCE)); 4610 saw_error = B_TRUE; 4611 return; 4612 } 4613 4614 (void) strlcpy(in_progress_psettab.zone_importance, 4615 prop_id, 4616 sizeof (in_progress_psettab.zone_importance)); 4617 return; 4618 default: 4619 break; 4620 } 4621 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4622 long_usage(CMD_SET, B_TRUE); 4623 usage(B_FALSE, HELP_PROPS); 4624 return; 4625 case RT_PCAP: 4626 if (prop_type != PT_NCPUS) { 4627 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4628 B_TRUE); 4629 long_usage(CMD_SET, B_TRUE); 4630 usage(B_FALSE, HELP_PROPS); 4631 return; 4632 } 4633 4634 /* 4635 * We already checked that an rctl alias is allowed in 4636 * the add_resource() function. 4637 */ 4638 4639 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' || 4640 (int)(cap * 100) < 1) { 4641 zerr(gettext("%s property is out of range."), 4642 pt_to_str(PT_NCPUS)); 4643 saw_error = B_TRUE; 4644 return; 4645 } 4646 4647 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP, 4648 (int)(cap * 100))) != Z_OK) 4649 zone_perror(zone, err, B_TRUE); 4650 else 4651 need_to_commit = B_TRUE; 4652 return; 4653 case RT_MCAP: 4654 switch (prop_type) { 4655 case PT_PHYSICAL: 4656 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4657 zerr(gettext("A positive number with a " 4658 "required scale suffix (K, M, G or T) was " 4659 "expected here.")); 4660 saw_error = B_TRUE; 4661 } else if (mem_cap < ONE_MB) { 4662 zerr(gettext("%s value is too small. It must " 4663 "be at least 1M."), pt_to_str(PT_PHYSICAL)); 4664 saw_error = B_TRUE; 4665 } else { 4666 snprintf(in_progress_mcaptab.zone_physmem_cap, 4667 physmem_size, "%llu", mem_cap); 4668 } 4669 break; 4670 case PT_SWAP: 4671 /* 4672 * We have to check if an rctl is allowed here since 4673 * there might already be a rctl defined that blocks 4674 * the alias. 4675 */ 4676 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) { 4677 zone_perror(pt_to_str(PT_MAXSWAP), 4678 Z_ALIAS_DISALLOW, B_FALSE); 4679 saw_error = B_TRUE; 4680 return; 4681 } 4682 4683 if (global_zone) 4684 mem_limit = ONE_MB * 100; 4685 else 4686 mem_limit = ONE_MB * 50; 4687 4688 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4689 zerr(gettext("A positive number with a " 4690 "required scale suffix (K, M, G or T) was " 4691 "expected here.")); 4692 saw_error = B_TRUE; 4693 } else if (mem_cap < mem_limit) { 4694 char buf[128]; 4695 4696 (void) snprintf(buf, sizeof (buf), "%llu", 4697 mem_limit); 4698 bytes_to_units(buf, buf, sizeof (buf)); 4699 zerr(gettext("%s value is too small. It must " 4700 "be at least %s."), pt_to_str(PT_SWAP), 4701 buf); 4702 saw_error = B_TRUE; 4703 } else { 4704 if ((err = zonecfg_set_aliased_rctl(handle, 4705 ALIAS_MAXSWAP, mem_cap)) != Z_OK) 4706 zone_perror(zone, err, B_TRUE); 4707 else 4708 need_to_commit = B_TRUE; 4709 } 4710 break; 4711 case PT_LOCKED: 4712 /* 4713 * We have to check if an rctl is allowed here since 4714 * there might already be a rctl defined that blocks 4715 * the alias. 4716 */ 4717 if (!zonecfg_aliased_rctl_ok(handle, 4718 ALIAS_MAXLOCKEDMEM)) { 4719 zone_perror(pt_to_str(PT_LOCKED), 4720 Z_ALIAS_DISALLOW, B_FALSE); 4721 saw_error = B_TRUE; 4722 return; 4723 } 4724 4725 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4726 zerr(gettext("A non-negative number with a " 4727 "required scale suffix (K, M, G or T) was " 4728 "expected\nhere.")); 4729 saw_error = B_TRUE; 4730 } else { 4731 if ((err = zonecfg_set_aliased_rctl(handle, 4732 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK) 4733 zone_perror(zone, err, B_TRUE); 4734 else 4735 need_to_commit = B_TRUE; 4736 } 4737 break; 4738 default: 4739 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4740 B_TRUE); 4741 long_usage(CMD_SET, B_TRUE); 4742 usage(B_FALSE, HELP_PROPS); 4743 return; 4744 } 4745 return; 4746 case RT_ADMIN: 4747 switch (prop_type) { 4748 case PT_USER: 4749 (void) strlcpy(in_progress_admintab.zone_admin_user, 4750 prop_id, 4751 sizeof (in_progress_admintab.zone_admin_user)); 4752 return; 4753 case PT_AUTHS: 4754 (void) strlcpy(in_progress_admintab.zone_admin_auths, 4755 prop_id, 4756 sizeof (in_progress_admintab.zone_admin_auths)); 4757 return; 4758 default: 4759 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4760 B_TRUE); 4761 long_usage(CMD_SET, B_TRUE); 4762 usage(B_FALSE, HELP_PROPS); 4763 return; 4764 } 4765 default: 4766 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 4767 long_usage(CMD_SET, B_TRUE); 4768 usage(B_FALSE, HELP_RESOURCES); 4769 return; 4770 } 4771 } 4772 4773 static void 4774 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec) 4775 { 4776 char *qstr; 4777 4778 if (*pval != '\0') { 4779 qstr = quoteit(pval); 4780 if (pnum == PT_SWAP || pnum == PT_LOCKED) 4781 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum), 4782 qstr); 4783 else 4784 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 4785 free(qstr); 4786 } else if (print_notspec) 4787 (void) fprintf(fp, gettext("\t%s not specified\n"), 4788 pt_to_str(pnum)); 4789 } 4790 4791 static void 4792 info_zonename(zone_dochandle_t handle, FILE *fp) 4793 { 4794 char zonename[ZONENAME_MAX]; 4795 4796 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 4797 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 4798 zonename); 4799 else 4800 (void) fprintf(fp, gettext("%s not specified\n"), 4801 pt_to_str(PT_ZONENAME)); 4802 } 4803 4804 static void 4805 info_zonepath(zone_dochandle_t handle, FILE *fp) 4806 { 4807 char zonepath[MAXPATHLEN]; 4808 4809 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 4810 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 4811 zonepath); 4812 else { 4813 (void) fprintf(fp, gettext("%s not specified\n"), 4814 pt_to_str(PT_ZONEPATH)); 4815 } 4816 } 4817 4818 static void 4819 info_brand(zone_dochandle_t handle, FILE *fp) 4820 { 4821 char brand[MAXNAMELEN]; 4822 4823 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK) 4824 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND), 4825 brand); 4826 else 4827 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND), 4828 gettext("not specified")); 4829 } 4830 4831 static void 4832 info_autoboot(zone_dochandle_t handle, FILE *fp) 4833 { 4834 boolean_t autoboot; 4835 int err; 4836 4837 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 4838 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 4839 autoboot ? "true" : "false"); 4840 else 4841 zone_perror(zone, err, B_TRUE); 4842 } 4843 4844 static void 4845 info_pool(zone_dochandle_t handle, FILE *fp) 4846 { 4847 char pool[MAXNAMELEN]; 4848 int err; 4849 4850 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 4851 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 4852 else 4853 zone_perror(zone, err, B_TRUE); 4854 } 4855 4856 static void 4857 info_limitpriv(zone_dochandle_t handle, FILE *fp) 4858 { 4859 char *limitpriv; 4860 int err; 4861 4862 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) { 4863 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV), 4864 limitpriv); 4865 free(limitpriv); 4866 } else { 4867 zone_perror(zone, err, B_TRUE); 4868 } 4869 } 4870 4871 static void 4872 info_bootargs(zone_dochandle_t handle, FILE *fp) 4873 { 4874 char bootargs[BOOTARGS_MAX]; 4875 int err; 4876 4877 if ((err = zonecfg_get_bootargs(handle, bootargs, 4878 sizeof (bootargs))) == Z_OK) { 4879 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS), 4880 bootargs); 4881 } else { 4882 zone_perror(zone, err, B_TRUE); 4883 } 4884 } 4885 4886 static void 4887 info_sched(zone_dochandle_t handle, FILE *fp) 4888 { 4889 char sched[MAXNAMELEN]; 4890 int err; 4891 4892 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched))) 4893 == Z_OK) { 4894 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched); 4895 } else { 4896 zone_perror(zone, err, B_TRUE); 4897 } 4898 } 4899 4900 static void 4901 info_iptype(zone_dochandle_t handle, FILE *fp) 4902 { 4903 zone_iptype_t iptype; 4904 int err; 4905 4906 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) { 4907 switch (iptype) { 4908 case ZS_SHARED: 4909 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4910 "shared"); 4911 break; 4912 case ZS_EXCLUSIVE: 4913 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4914 "exclusive"); 4915 break; 4916 } 4917 } else { 4918 zone_perror(zone, err, B_TRUE); 4919 } 4920 } 4921 4922 static void 4923 info_hostid(zone_dochandle_t handle, FILE *fp) 4924 { 4925 char hostidp[HW_HOSTID_LEN]; 4926 int err; 4927 4928 if ((err = zonecfg_get_hostid(handle, hostidp, 4929 sizeof (hostidp))) == Z_OK) { 4930 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp); 4931 } else if (err == Z_BAD_PROPERTY) { 4932 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID)); 4933 } else { 4934 zone_perror(zone, err, B_TRUE); 4935 } 4936 } 4937 4938 static void 4939 info_fs_allowed(zone_dochandle_t handle, FILE *fp) 4940 { 4941 char fsallowedp[ZONE_FS_ALLOWED_MAX]; 4942 int err; 4943 4944 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp, 4945 sizeof (fsallowedp))) == Z_OK) { 4946 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED), 4947 fsallowedp); 4948 } else if (err == Z_BAD_PROPERTY) { 4949 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED)); 4950 } else { 4951 zone_perror(zone, err, B_TRUE); 4952 } 4953 } 4954 4955 static void 4956 output_fs(FILE *fp, struct zone_fstab *fstab) 4957 { 4958 zone_fsopt_t *this; 4959 4960 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 4961 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 4962 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 4963 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 4964 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 4965 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 4966 for (this = fstab->zone_fs_options; this != NULL; 4967 this = this->zone_fsopt_next) { 4968 if (strchr(this->zone_fsopt_opt, '=')) 4969 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 4970 else 4971 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 4972 if (this->zone_fsopt_next != NULL) 4973 (void) fprintf(fp, ","); 4974 } 4975 (void) fprintf(fp, "]\n"); 4976 } 4977 4978 static void 4979 output_ipd(FILE *fp, struct zone_fstab *ipdtab) 4980 { 4981 (void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD)); 4982 output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE); 4983 } 4984 4985 static void 4986 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4987 { 4988 struct zone_fstab lookup, user; 4989 boolean_t output = B_FALSE; 4990 4991 if (zonecfg_setfsent(handle) != Z_OK) 4992 return; 4993 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 4994 if (cmd->cmd_prop_nv_pairs == 0) { 4995 output_fs(fp, &lookup); 4996 goto loopend; 4997 } 4998 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK) 4999 goto loopend; 5000 if (strlen(user.zone_fs_dir) > 0 && 5001 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 5002 goto loopend; /* no match */ 5003 if (strlen(user.zone_fs_special) > 0 && 5004 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 5005 goto loopend; /* no match */ 5006 if (strlen(user.zone_fs_type) > 0 && 5007 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 5008 goto loopend; /* no match */ 5009 output_fs(fp, &lookup); 5010 output = B_TRUE; 5011 loopend: 5012 zonecfg_free_fs_option_list(lookup.zone_fs_options); 5013 } 5014 (void) zonecfg_endfsent(handle); 5015 /* 5016 * If a property n/v pair was specified, warn the user if there was 5017 * nothing to output. 5018 */ 5019 if (!output && cmd->cmd_prop_nv_pairs > 0) 5020 (void) printf(gettext("No such %s resource.\n"), 5021 rt_to_str(RT_FS)); 5022 } 5023 5024 static void 5025 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5026 { 5027 struct zone_fstab lookup, user; 5028 boolean_t output = B_FALSE; 5029 5030 if (zonecfg_setipdent(handle) != Z_OK) 5031 return; 5032 while (zonecfg_getipdent(handle, &lookup) == Z_OK) { 5033 if (cmd->cmd_prop_nv_pairs == 0) { 5034 output_ipd(fp, &lookup); 5035 continue; 5036 } 5037 if (fill_in_ipdtab(cmd, &user, B_TRUE) != Z_OK) 5038 continue; 5039 if (strlen(user.zone_fs_dir) > 0 && 5040 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 5041 continue; /* no match */ 5042 output_ipd(fp, &lookup); 5043 output = B_TRUE; 5044 } 5045 (void) zonecfg_endipdent(handle); 5046 /* 5047 * If a property n/v pair was specified, warn the user if there was 5048 * nothing to output. 5049 */ 5050 if (!output && cmd->cmd_prop_nv_pairs > 0) 5051 (void) printf(gettext("No such %s resource.\n"), 5052 rt_to_str(RT_IPD)); 5053 } 5054 5055 static void 5056 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 5057 { 5058 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 5059 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 5060 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 5061 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE); 5062 } 5063 5064 static void 5065 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5066 { 5067 struct zone_nwiftab lookup, user; 5068 boolean_t output = B_FALSE; 5069 5070 if (zonecfg_setnwifent(handle) != Z_OK) 5071 return; 5072 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 5073 if (cmd->cmd_prop_nv_pairs == 0) { 5074 output_net(fp, &lookup); 5075 continue; 5076 } 5077 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK) 5078 continue; 5079 if (strlen(user.zone_nwif_physical) > 0 && 5080 strcmp(user.zone_nwif_physical, 5081 lookup.zone_nwif_physical) != 0) 5082 continue; /* no match */ 5083 /* If present make sure it matches */ 5084 if (strlen(user.zone_nwif_address) > 0 && 5085 !zonecfg_same_net_address(user.zone_nwif_address, 5086 lookup.zone_nwif_address)) 5087 continue; /* no match */ 5088 output_net(fp, &lookup); 5089 output = B_TRUE; 5090 } 5091 (void) zonecfg_endnwifent(handle); 5092 /* 5093 * If a property n/v pair was specified, warn the user if there was 5094 * nothing to output. 5095 */ 5096 if (!output && cmd->cmd_prop_nv_pairs > 0) 5097 (void) printf(gettext("No such %s resource.\n"), 5098 rt_to_str(RT_NET)); 5099 } 5100 5101 static void 5102 output_dev(FILE *fp, struct zone_devtab *devtab) 5103 { 5104 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE)); 5105 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 5106 } 5107 5108 static void 5109 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5110 { 5111 struct zone_devtab lookup, user; 5112 boolean_t output = B_FALSE; 5113 5114 if (zonecfg_setdevent(handle) != Z_OK) 5115 return; 5116 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 5117 if (cmd->cmd_prop_nv_pairs == 0) { 5118 output_dev(fp, &lookup); 5119 continue; 5120 } 5121 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK) 5122 continue; 5123 if (strlen(user.zone_dev_match) > 0 && 5124 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 5125 continue; /* no match */ 5126 output_dev(fp, &lookup); 5127 output = B_TRUE; 5128 } 5129 (void) zonecfg_enddevent(handle); 5130 /* 5131 * If a property n/v pair was specified, warn the user if there was 5132 * nothing to output. 5133 */ 5134 if (!output && cmd->cmd_prop_nv_pairs > 0) 5135 (void) printf(gettext("No such %s resource.\n"), 5136 rt_to_str(RT_DEVICE)); 5137 } 5138 5139 static void 5140 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 5141 { 5142 struct zone_rctlvaltab *valptr; 5143 5144 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 5145 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 5146 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 5147 valptr = valptr->zone_rctlval_next) { 5148 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 5149 pt_to_str(PT_VALUE), 5150 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 5151 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 5152 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 5153 } 5154 } 5155 5156 static void 5157 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5158 { 5159 struct zone_rctltab lookup, user; 5160 boolean_t output = B_FALSE; 5161 5162 if (zonecfg_setrctlent(handle) != Z_OK) 5163 return; 5164 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 5165 if (cmd->cmd_prop_nv_pairs == 0) { 5166 output_rctl(fp, &lookup); 5167 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK && 5168 (strlen(user.zone_rctl_name) == 0 || 5169 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 5170 output_rctl(fp, &lookup); 5171 output = B_TRUE; 5172 } 5173 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 5174 } 5175 (void) zonecfg_endrctlent(handle); 5176 /* 5177 * If a property n/v pair was specified, warn the user if there was 5178 * nothing to output. 5179 */ 5180 if (!output && cmd->cmd_prop_nv_pairs > 0) 5181 (void) printf(gettext("No such %s resource.\n"), 5182 rt_to_str(RT_RCTL)); 5183 } 5184 5185 static void 5186 output_attr(FILE *fp, struct zone_attrtab *attrtab) 5187 { 5188 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 5189 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 5190 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 5191 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 5192 } 5193 5194 static void 5195 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5196 { 5197 struct zone_attrtab lookup, user; 5198 boolean_t output = B_FALSE; 5199 5200 if (zonecfg_setattrent(handle) != Z_OK) 5201 return; 5202 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 5203 if (cmd->cmd_prop_nv_pairs == 0) { 5204 output_attr(fp, &lookup); 5205 continue; 5206 } 5207 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK) 5208 continue; 5209 if (strlen(user.zone_attr_name) > 0 && 5210 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 5211 continue; /* no match */ 5212 if (strlen(user.zone_attr_type) > 0 && 5213 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 5214 continue; /* no match */ 5215 if (strlen(user.zone_attr_value) > 0 && 5216 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 5217 continue; /* no match */ 5218 output_attr(fp, &lookup); 5219 output = B_TRUE; 5220 } 5221 (void) zonecfg_endattrent(handle); 5222 /* 5223 * If a property n/v pair was specified, warn the user if there was 5224 * nothing to output. 5225 */ 5226 if (!output && cmd->cmd_prop_nv_pairs > 0) 5227 (void) printf(gettext("No such %s resource.\n"), 5228 rt_to_str(RT_ATTR)); 5229 } 5230 5231 static void 5232 output_ds(FILE *fp, struct zone_dstab *dstab) 5233 { 5234 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 5235 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 5236 } 5237 5238 static void 5239 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5240 { 5241 struct zone_dstab lookup, user; 5242 boolean_t output = B_FALSE; 5243 5244 if (zonecfg_setdsent(handle) != Z_OK) 5245 return; 5246 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 5247 if (cmd->cmd_prop_nv_pairs == 0) { 5248 output_ds(fp, &lookup); 5249 continue; 5250 } 5251 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK) 5252 continue; 5253 if (strlen(user.zone_dataset_name) > 0 && 5254 strcmp(user.zone_dataset_name, 5255 lookup.zone_dataset_name) != 0) 5256 continue; /* no match */ 5257 output_ds(fp, &lookup); 5258 output = B_TRUE; 5259 } 5260 (void) zonecfg_enddsent(handle); 5261 /* 5262 * If a property n/v pair was specified, warn the user if there was 5263 * nothing to output. 5264 */ 5265 if (!output && cmd->cmd_prop_nv_pairs > 0) 5266 (void) printf(gettext("No such %s resource.\n"), 5267 rt_to_str(RT_DATASET)); 5268 } 5269 5270 static void 5271 output_pset(FILE *fp, struct zone_psettab *psettab) 5272 { 5273 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU)); 5274 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0) 5275 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS), 5276 psettab->zone_ncpu_max); 5277 else 5278 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS), 5279 psettab->zone_ncpu_min, psettab->zone_ncpu_max); 5280 if (psettab->zone_importance[0] != '\0') 5281 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE), 5282 psettab->zone_importance); 5283 } 5284 5285 static void 5286 info_pset(zone_dochandle_t handle, FILE *fp) 5287 { 5288 struct zone_psettab lookup; 5289 5290 if (zonecfg_getpsetent(handle, &lookup) == Z_OK) 5291 output_pset(fp, &lookup); 5292 } 5293 5294 static void 5295 output_pcap(FILE *fp) 5296 { 5297 uint64_t cap; 5298 5299 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) { 5300 float scaled = (float)cap / 100; 5301 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP)); 5302 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS), 5303 scaled); 5304 } 5305 } 5306 5307 static void 5308 info_pcap(FILE *fp) 5309 { 5310 output_pcap(fp); 5311 } 5312 5313 5314 static void 5315 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias) 5316 { 5317 uint64_t limit; 5318 5319 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) { 5320 /* convert memory based properties */ 5321 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) { 5322 char buf[128]; 5323 5324 (void) snprintf(buf, sizeof (buf), "%llu", limit); 5325 bytes_to_units(buf, buf, sizeof (buf)); 5326 (void) fprintf(fp, "[%s: %s]\n", alias, buf); 5327 return; 5328 } 5329 5330 (void) fprintf(fp, "[%s: %llu]\n", alias, limit); 5331 } 5332 } 5333 5334 static void 5335 bytes_to_units(char *str, char *buf, int bufsize) 5336 { 5337 unsigned long long num; 5338 unsigned long long save = 0; 5339 char *units = "BKMGT"; 5340 char *up = units; 5341 5342 num = strtoll(str, NULL, 10); 5343 5344 if (num < 1024) { 5345 (void) snprintf(buf, bufsize, "%llu", num); 5346 return; 5347 } 5348 5349 while ((num >= 1024) && (*up != 'T')) { 5350 up++; /* next unit of measurement */ 5351 save = num; 5352 num = (num + 512) >> 10; 5353 } 5354 5355 /* check if we should output a fraction. snprintf will round for us */ 5356 if (save % 1024 != 0 && ((save >> 10) < 10)) 5357 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024), 5358 *up); 5359 else 5360 (void) snprintf(buf, bufsize, "%llu%c", num, *up); 5361 } 5362 5363 static void 5364 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap, 5365 uint64_t maxswap, int showlocked, uint64_t maxlocked) 5366 { 5367 char buf[128]; 5368 5369 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP)); 5370 if (mcaptab->zone_physmem_cap[0] != '\0') { 5371 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf)); 5372 output_prop(fp, PT_PHYSICAL, buf, B_TRUE); 5373 } 5374 5375 if (showswap == Z_OK) { 5376 (void) snprintf(buf, sizeof (buf), "%llu", maxswap); 5377 bytes_to_units(buf, buf, sizeof (buf)); 5378 output_prop(fp, PT_SWAP, buf, B_TRUE); 5379 } 5380 5381 if (showlocked == Z_OK) { 5382 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked); 5383 bytes_to_units(buf, buf, sizeof (buf)); 5384 output_prop(fp, PT_LOCKED, buf, B_TRUE); 5385 } 5386 } 5387 5388 static void 5389 info_mcap(zone_dochandle_t handle, FILE *fp) 5390 { 5391 int res1, res2, res3; 5392 uint64_t swap_limit; 5393 uint64_t locked_limit; 5394 struct zone_mcaptab lookup; 5395 5396 bzero(&lookup, sizeof (lookup)); 5397 res1 = zonecfg_getmcapent(handle, &lookup); 5398 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit); 5399 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 5400 &locked_limit); 5401 5402 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK) 5403 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit); 5404 } 5405 5406 static void 5407 output_auth(FILE *fp, struct zone_admintab *admintab) 5408 { 5409 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN)); 5410 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE); 5411 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE); 5412 } 5413 5414 static void 5415 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5416 { 5417 struct zone_admintab lookup, user; 5418 boolean_t output = B_FALSE; 5419 int err; 5420 5421 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 5422 zone_perror(zone, err, B_TRUE); 5423 return; 5424 } 5425 while (zonecfg_getadminent(handle, &lookup) == Z_OK) { 5426 if (cmd->cmd_prop_nv_pairs == 0) { 5427 output_auth(fp, &lookup); 5428 continue; 5429 } 5430 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK) 5431 continue; 5432 if (strlen(user.zone_admin_user) > 0 && 5433 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0) 5434 continue; /* no match */ 5435 output_auth(fp, &lookup); 5436 output = B_TRUE; 5437 } 5438 (void) zonecfg_endadminent(handle); 5439 /* 5440 * If a property n/v pair was specified, warn the user if there was 5441 * nothing to output. 5442 */ 5443 if (!output && cmd->cmd_prop_nv_pairs > 0) 5444 (void) printf(gettext("No such %s resource.\n"), 5445 rt_to_str(RT_ADMIN)); 5446 } 5447 5448 void 5449 info_func(cmd_t *cmd) 5450 { 5451 FILE *fp = stdout; 5452 boolean_t need_to_close = B_FALSE; 5453 char *pager; 5454 int type; 5455 int res1, res2; 5456 uint64_t swap_limit; 5457 uint64_t locked_limit; 5458 struct stat statbuf; 5459 5460 assert(cmd != NULL); 5461 5462 if (initialize(B_TRUE) != Z_OK) 5463 return; 5464 5465 /* don't page error output */ 5466 if (interactive_mode) { 5467 if ((pager = getenv("PAGER")) == NULL) 5468 pager = PAGER; 5469 5470 if (stat(pager, &statbuf) == 0) { 5471 if ((fp = popen(pager, "w")) != NULL) 5472 need_to_close = B_TRUE; 5473 else 5474 fp = stdout; 5475 } else { 5476 zerr(gettext("PAGER %s does not exist (%s)."), 5477 pager, strerror(errno)); 5478 } 5479 5480 setbuf(fp, NULL); 5481 } 5482 5483 if (!global_scope) { 5484 switch (resource_scope) { 5485 case RT_FS: 5486 output_fs(fp, &in_progress_fstab); 5487 break; 5488 case RT_IPD: 5489 output_ipd(fp, &in_progress_ipdtab); 5490 break; 5491 case RT_NET: 5492 output_net(fp, &in_progress_nwiftab); 5493 break; 5494 case RT_DEVICE: 5495 output_dev(fp, &in_progress_devtab); 5496 break; 5497 case RT_RCTL: 5498 output_rctl(fp, &in_progress_rctltab); 5499 break; 5500 case RT_ATTR: 5501 output_attr(fp, &in_progress_attrtab); 5502 break; 5503 case RT_DATASET: 5504 output_ds(fp, &in_progress_dstab); 5505 break; 5506 case RT_DCPU: 5507 output_pset(fp, &in_progress_psettab); 5508 break; 5509 case RT_PCAP: 5510 output_pcap(fp); 5511 break; 5512 case RT_MCAP: 5513 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 5514 &swap_limit); 5515 res2 = zonecfg_get_aliased_rctl(handle, 5516 ALIAS_MAXLOCKEDMEM, &locked_limit); 5517 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit, 5518 res2, locked_limit); 5519 break; 5520 case RT_ADMIN: 5521 output_auth(fp, &in_progress_admintab); 5522 break; 5523 } 5524 goto cleanup; 5525 } 5526 5527 type = cmd->cmd_res_type; 5528 5529 if (gz_invalid_rt_property(type)) { 5530 zerr(gettext("%s is not a valid property for the global zone."), 5531 rt_to_str(type)); 5532 goto cleanup; 5533 } 5534 5535 if (gz_invalid_resource(type)) { 5536 zerr(gettext("%s is not a valid resource for the global zone."), 5537 rt_to_str(type)); 5538 goto cleanup; 5539 } 5540 5541 switch (cmd->cmd_res_type) { 5542 case RT_UNKNOWN: 5543 info_zonename(handle, fp); 5544 if (!global_zone) { 5545 info_zonepath(handle, fp); 5546 info_brand(handle, fp); 5547 info_autoboot(handle, fp); 5548 info_bootargs(handle, fp); 5549 } 5550 info_pool(handle, fp); 5551 if (!global_zone) { 5552 info_limitpriv(handle, fp); 5553 info_sched(handle, fp); 5554 info_iptype(handle, fp); 5555 info_hostid(handle, fp); 5556 info_fs_allowed(handle, fp); 5557 } 5558 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5559 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5560 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5561 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5562 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5563 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5564 if (!global_zone) { 5565 info_ipd(handle, fp, cmd); 5566 info_fs(handle, fp, cmd); 5567 info_net(handle, fp, cmd); 5568 info_dev(handle, fp, cmd); 5569 } 5570 info_pset(handle, fp); 5571 info_pcap(fp); 5572 info_mcap(handle, fp); 5573 if (!global_zone) { 5574 info_attr(handle, fp, cmd); 5575 info_ds(handle, fp, cmd); 5576 info_auth(handle, fp, cmd); 5577 } 5578 info_rctl(handle, fp, cmd); 5579 break; 5580 case RT_ZONENAME: 5581 info_zonename(handle, fp); 5582 break; 5583 case RT_ZONEPATH: 5584 info_zonepath(handle, fp); 5585 break; 5586 case RT_BRAND: 5587 info_brand(handle, fp); 5588 break; 5589 case RT_AUTOBOOT: 5590 info_autoboot(handle, fp); 5591 break; 5592 case RT_POOL: 5593 info_pool(handle, fp); 5594 break; 5595 case RT_LIMITPRIV: 5596 info_limitpriv(handle, fp); 5597 break; 5598 case RT_BOOTARGS: 5599 info_bootargs(handle, fp); 5600 break; 5601 case RT_SCHED: 5602 info_sched(handle, fp); 5603 break; 5604 case RT_IPTYPE: 5605 info_iptype(handle, fp); 5606 break; 5607 case RT_MAXLWPS: 5608 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5609 break; 5610 case RT_MAXSHMMEM: 5611 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5612 break; 5613 case RT_MAXSHMIDS: 5614 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5615 break; 5616 case RT_MAXMSGIDS: 5617 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5618 break; 5619 case RT_MAXSEMIDS: 5620 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5621 break; 5622 case RT_SHARES: 5623 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5624 break; 5625 case RT_FS: 5626 info_fs(handle, fp, cmd); 5627 break; 5628 case RT_IPD: 5629 info_ipd(handle, fp, cmd); 5630 break; 5631 case RT_NET: 5632 info_net(handle, fp, cmd); 5633 break; 5634 case RT_DEVICE: 5635 info_dev(handle, fp, cmd); 5636 break; 5637 case RT_RCTL: 5638 info_rctl(handle, fp, cmd); 5639 break; 5640 case RT_ATTR: 5641 info_attr(handle, fp, cmd); 5642 break; 5643 case RT_DATASET: 5644 info_ds(handle, fp, cmd); 5645 break; 5646 case RT_DCPU: 5647 info_pset(handle, fp); 5648 break; 5649 case RT_PCAP: 5650 info_pcap(fp); 5651 break; 5652 case RT_MCAP: 5653 info_mcap(handle, fp); 5654 break; 5655 case RT_HOSTID: 5656 info_hostid(handle, fp); 5657 break; 5658 case RT_ADMIN: 5659 info_auth(handle, fp, cmd); 5660 break; 5661 case RT_FS_ALLOWED: 5662 info_fs_allowed(handle, fp); 5663 break; 5664 default: 5665 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 5666 B_TRUE); 5667 } 5668 5669 cleanup: 5670 if (need_to_close) 5671 (void) pclose(fp); 5672 } 5673 5674 /* 5675 * Helper function for verify-- checks that a required string property 5676 * exists. 5677 */ 5678 static void 5679 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 5680 { 5681 if (strlen(attr) == 0) { 5682 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 5683 pt_to_str(pt)); 5684 saw_error = B_TRUE; 5685 if (*ret_val == Z_OK) 5686 *ret_val = Z_REQD_PROPERTY_MISSING; 5687 } 5688 } 5689 5690 static int 5691 do_subproc(char *cmdbuf) 5692 { 5693 char inbuf[MAX_CMD_LEN]; 5694 FILE *file; 5695 int status; 5696 5697 file = popen(cmdbuf, "r"); 5698 if (file == NULL) { 5699 zerr(gettext("Could not launch: %s"), cmdbuf); 5700 return (-1); 5701 } 5702 5703 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 5704 fprintf(stderr, "%s", inbuf); 5705 status = pclose(file); 5706 5707 if (WIFSIGNALED(status)) { 5708 zerr(gettext("%s unexpectedly terminated due to signal %d"), 5709 cmdbuf, WTERMSIG(status)); 5710 return (-1); 5711 } 5712 assert(WIFEXITED(status)); 5713 return (WEXITSTATUS(status)); 5714 } 5715 5716 static int 5717 brand_verify(zone_dochandle_t handle) 5718 { 5719 char xml_file[32]; 5720 char cmdbuf[MAX_CMD_LEN]; 5721 brand_handle_t bh; 5722 char brand[MAXNAMELEN]; 5723 int err; 5724 5725 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 5726 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 5727 return (Z_INVALID_DOCUMENT); 5728 } 5729 if ((bh = brand_open(brand)) == NULL) { 5730 zerr("%s: %s\n", zone, gettext("unknown brand.")); 5731 return (Z_INVALID_DOCUMENT); 5732 } 5733 5734 /* 5735 * Fetch the verify command, if any, from the brand configuration 5736 * and build the command line to execute it. 5737 */ 5738 strcpy(cmdbuf, EXEC_PREFIX); 5739 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN, 5740 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 5741 brand_close(bh); 5742 if (err != Z_OK) { 5743 zerr("%s: %s\n", zone, 5744 gettext("could not get brand verification command")); 5745 return (Z_INVALID_DOCUMENT); 5746 } 5747 5748 /* 5749 * If the brand doesn't provide a verification routine, we just 5750 * return success. 5751 */ 5752 if (strlen(cmdbuf) == EXEC_LEN) 5753 return (Z_OK); 5754 5755 /* 5756 * Dump the current config information for this zone to a file. 5757 */ 5758 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX"); 5759 if (mkstemp(xml_file) == NULL) 5760 return (Z_TEMP_FILE); 5761 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 5762 (void) unlink(xml_file); 5763 return (err); 5764 } 5765 5766 /* 5767 * Execute the verification command. 5768 */ 5769 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 5770 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 5771 err = Z_BRAND_ERROR; 5772 } else { 5773 err = do_subproc(cmdbuf); 5774 } 5775 5776 (void) unlink(xml_file); 5777 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 5778 } 5779 5780 /* 5781 * See the DTD for which attributes are required for which resources. 5782 * 5783 * This function can be called by commit_func(), which needs to save things, 5784 * in addition to the general call from parse_and_run(), which doesn't need 5785 * things saved. Since the parameters are standardized, we distinguish by 5786 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 5787 * that a save is needed. 5788 */ 5789 void 5790 verify_func(cmd_t *cmd) 5791 { 5792 struct zone_nwiftab nwiftab; 5793 struct zone_fstab fstab; 5794 struct zone_attrtab attrtab; 5795 struct zone_rctltab rctltab; 5796 struct zone_dstab dstab; 5797 struct zone_psettab psettab; 5798 struct zone_admintab admintab; 5799 char zonepath[MAXPATHLEN]; 5800 char sched[MAXNAMELEN]; 5801 char brand[MAXNAMELEN]; 5802 char hostidp[HW_HOSTID_LEN]; 5803 char fsallowedp[ZONE_FS_ALLOWED_MAX]; 5804 int err, ret_val = Z_OK, arg; 5805 int pset_res; 5806 boolean_t save = B_FALSE; 5807 boolean_t arg_err = B_FALSE; 5808 zone_iptype_t iptype; 5809 boolean_t has_cpu_shares = B_FALSE; 5810 boolean_t has_cpu_cap = B_FALSE; 5811 5812 optind = 0; 5813 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5814 switch (arg) { 5815 case '?': 5816 longer_usage(CMD_VERIFY); 5817 arg_err = B_TRUE; 5818 break; 5819 default: 5820 short_usage(CMD_VERIFY); 5821 arg_err = B_TRUE; 5822 break; 5823 } 5824 } 5825 if (arg_err) 5826 return; 5827 5828 if (optind > cmd->cmd_argc) { 5829 short_usage(CMD_VERIFY); 5830 return; 5831 } 5832 5833 if (zone_is_read_only(CMD_VERIFY)) 5834 return; 5835 5836 assert(cmd != NULL); 5837 5838 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 5839 save = B_TRUE; 5840 if (initialize(B_TRUE) != Z_OK) 5841 return; 5842 5843 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK && 5844 !global_zone) { 5845 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 5846 ret_val = Z_REQD_RESOURCE_MISSING; 5847 saw_error = B_TRUE; 5848 } 5849 if (strlen(zonepath) == 0 && !global_zone) { 5850 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 5851 ret_val = Z_REQD_RESOURCE_MISSING; 5852 saw_error = B_TRUE; 5853 } 5854 5855 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 5856 zone_perror(zone, err, B_TRUE); 5857 return; 5858 } 5859 if ((err = brand_verify(handle)) != Z_OK) { 5860 zone_perror(zone, err, B_TRUE); 5861 return; 5862 } 5863 5864 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 5865 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE)); 5866 ret_val = Z_REQD_RESOURCE_MISSING; 5867 saw_error = B_TRUE; 5868 } 5869 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 5870 zone_perror(zone, err, B_TRUE); 5871 return; 5872 } 5873 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5874 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 5875 } 5876 (void) zonecfg_endipdent(handle); 5877 5878 if (zonecfg_get_hostid(handle, hostidp, 5879 sizeof (hostidp)) == Z_INVALID_PROPERTY) { 5880 zerr(gettext("%s: invalid hostid: %s"), 5881 zone, hostidp); 5882 return; 5883 } 5884 5885 if (zonecfg_get_fs_allowed(handle, fsallowedp, 5886 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) { 5887 zerr(gettext("%s: invalid fs-allowed: %s"), 5888 zone, fsallowedp); 5889 return; 5890 } 5891 5892 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 5893 zone_perror(zone, err, B_TRUE); 5894 return; 5895 } 5896 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 5897 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 5898 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 5899 &ret_val); 5900 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 5901 5902 zonecfg_free_fs_option_list(fstab.zone_fs_options); 5903 } 5904 (void) zonecfg_endfsent(handle); 5905 5906 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 5907 zone_perror(zone, err, B_TRUE); 5908 return; 5909 } 5910 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 5911 /* 5912 * physical is required in all cases. 5913 * A shared IP requires an address, 5914 * and may include a default router, while 5915 * an exclusive IP must have neither an address 5916 * nor a default router. 5917 * The physical interface name must be valid in all cases. 5918 */ 5919 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 5920 PT_PHYSICAL, &ret_val); 5921 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) != 5922 Z_OK) { 5923 saw_error = B_TRUE; 5924 if (ret_val == Z_OK) 5925 ret_val = Z_INVAL; 5926 } 5927 5928 switch (iptype) { 5929 case ZS_SHARED: 5930 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 5931 PT_ADDRESS, &ret_val); 5932 break; 5933 case ZS_EXCLUSIVE: 5934 if (strlen(nwiftab.zone_nwif_address) > 0) { 5935 zerr(gettext("%s: %s cannot be specified " 5936 "for an exclusive IP type"), 5937 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS)); 5938 saw_error = B_TRUE; 5939 if (ret_val == Z_OK) 5940 ret_val = Z_INVAL; 5941 } 5942 if (strlen(nwiftab.zone_nwif_defrouter) > 0) { 5943 zerr(gettext("%s: %s cannot be specified " 5944 "for an exclusive IP type"), 5945 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER)); 5946 saw_error = B_TRUE; 5947 if (ret_val == Z_OK) 5948 ret_val = Z_INVAL; 5949 } 5950 break; 5951 } 5952 } 5953 (void) zonecfg_endnwifent(handle); 5954 5955 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 5956 zone_perror(zone, err, B_TRUE); 5957 return; 5958 } 5959 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 5960 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 5961 &ret_val); 5962 5963 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0) 5964 has_cpu_shares = B_TRUE; 5965 5966 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0) 5967 has_cpu_cap = B_TRUE; 5968 5969 if (rctltab.zone_rctl_valptr == NULL) { 5970 zerr(gettext("%s: no %s specified"), 5971 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 5972 saw_error = B_TRUE; 5973 if (ret_val == Z_OK) 5974 ret_val = Z_REQD_PROPERTY_MISSING; 5975 } else { 5976 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 5977 } 5978 } 5979 (void) zonecfg_endrctlent(handle); 5980 5981 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK && 5982 has_cpu_shares) { 5983 zerr(gettext("%s zone.cpu-shares and %s are incompatible."), 5984 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 5985 saw_error = B_TRUE; 5986 if (ret_val == Z_OK) 5987 ret_val = Z_INCOMPATIBLE; 5988 } 5989 5990 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched, 5991 sizeof (sched)) == Z_OK && strlen(sched) > 0 && 5992 strcmp(sched, "FSS") != 0) { 5993 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are " 5994 "incompatible"), 5995 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched); 5996 saw_error = B_TRUE; 5997 if (ret_val == Z_OK) 5998 ret_val = Z_INCOMPATIBLE; 5999 } 6000 6001 if (pset_res == Z_OK && has_cpu_cap) { 6002 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."), 6003 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 6004 saw_error = B_TRUE; 6005 if (ret_val == Z_OK) 6006 ret_val = Z_INCOMPATIBLE; 6007 } 6008 6009 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 6010 zone_perror(zone, err, B_TRUE); 6011 return; 6012 } 6013 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 6014 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 6015 &ret_val); 6016 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 6017 &ret_val); 6018 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 6019 &ret_val); 6020 } 6021 (void) zonecfg_endattrent(handle); 6022 6023 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 6024 zone_perror(zone, err, B_TRUE); 6025 return; 6026 } 6027 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 6028 if (strlen(dstab.zone_dataset_name) == 0) { 6029 zerr("%s: %s %s", rt_to_str(RT_DATASET), 6030 pt_to_str(PT_NAME), gettext("not specified")); 6031 saw_error = B_TRUE; 6032 if (ret_val == Z_OK) 6033 ret_val = Z_REQD_PROPERTY_MISSING; 6034 } else if (!zfs_name_valid(dstab.zone_dataset_name, 6035 ZFS_TYPE_FILESYSTEM)) { 6036 zerr("%s: %s %s", rt_to_str(RT_DATASET), 6037 pt_to_str(PT_NAME), gettext("invalid")); 6038 saw_error = B_TRUE; 6039 if (ret_val == Z_OK) 6040 ret_val = Z_BAD_PROPERTY; 6041 } 6042 6043 } 6044 (void) zonecfg_enddsent(handle); 6045 6046 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 6047 zone_perror(zone, err, B_TRUE); 6048 return; 6049 } 6050 while (zonecfg_getadminent(handle, &admintab) == Z_OK) { 6051 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN, 6052 PT_USER, &ret_val); 6053 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN, 6054 PT_AUTHS, &ret_val); 6055 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user) 6056 == NULL)) { 6057 zerr(gettext("%s %s is not a valid username"), 6058 pt_to_str(PT_USER), 6059 admintab.zone_admin_user); 6060 ret_val = Z_BAD_PROPERTY; 6061 } 6062 if ((ret_val == Z_OK) && (!zonecfg_valid_auths( 6063 admintab.zone_admin_auths, zone))) { 6064 ret_val = Z_BAD_PROPERTY; 6065 } 6066 } 6067 (void) zonecfg_endadminent(handle); 6068 6069 if (!global_scope) { 6070 zerr(gettext("resource specification incomplete")); 6071 saw_error = B_TRUE; 6072 if (ret_val == Z_OK) 6073 ret_val = Z_INSUFFICIENT_SPEC; 6074 } 6075 6076 if (save) { 6077 if (ret_val == Z_OK) { 6078 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 6079 need_to_commit = B_FALSE; 6080 (void) strlcpy(revert_zone, zone, 6081 sizeof (revert_zone)); 6082 } 6083 } else { 6084 zerr(gettext("Zone %s failed to verify"), zone); 6085 } 6086 } 6087 if (ret_val != Z_OK) 6088 zone_perror(zone, ret_val, B_TRUE); 6089 } 6090 6091 void 6092 cancel_func(cmd_t *cmd) 6093 { 6094 int arg; 6095 boolean_t arg_err = B_FALSE; 6096 6097 assert(cmd != NULL); 6098 6099 optind = 0; 6100 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6101 switch (arg) { 6102 case '?': 6103 longer_usage(CMD_CANCEL); 6104 arg_err = B_TRUE; 6105 break; 6106 default: 6107 short_usage(CMD_CANCEL); 6108 arg_err = B_TRUE; 6109 break; 6110 } 6111 } 6112 if (arg_err) 6113 return; 6114 6115 if (optind != cmd->cmd_argc) { 6116 short_usage(CMD_CANCEL); 6117 return; 6118 } 6119 6120 if (global_scope) 6121 scope_usage(CMD_CANCEL); 6122 global_scope = B_TRUE; 6123 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 6124 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 6125 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 6126 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 6127 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 6128 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 6129 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 6130 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 6131 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 6132 } 6133 6134 static int 6135 validate_attr_name(char *name) 6136 { 6137 int i; 6138 6139 if (!isalnum(name[0])) { 6140 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 6141 "numeric character."), rt_to_str(RT_ATTR), 6142 pt_to_str(PT_NAME), name); 6143 return (Z_INVAL); 6144 } 6145 for (i = 1; name[i]; i++) 6146 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 6147 zerr(gettext("Invalid %s %s %s: can only contain " 6148 "alpha-numeric characters, plus '-' and '.'."), 6149 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 6150 return (Z_INVAL); 6151 } 6152 return (Z_OK); 6153 } 6154 6155 static int 6156 validate_attr_type_val(struct zone_attrtab *attrtab) 6157 { 6158 boolean_t boolval; 6159 int64_t intval; 6160 char strval[MAXNAMELEN]; 6161 uint64_t uintval; 6162 6163 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 6164 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 6165 return (Z_OK); 6166 zerr(gettext("invalid %s value for %s=%s"), 6167 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 6168 return (Z_ERR); 6169 } 6170 6171 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 6172 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 6173 return (Z_OK); 6174 zerr(gettext("invalid %s value for %s=%s"), 6175 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 6176 return (Z_ERR); 6177 } 6178 6179 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 6180 if (zonecfg_get_attr_string(attrtab, strval, 6181 sizeof (strval)) == Z_OK) 6182 return (Z_OK); 6183 zerr(gettext("invalid %s value for %s=%s"), 6184 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 6185 return (Z_ERR); 6186 } 6187 6188 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 6189 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 6190 return (Z_OK); 6191 zerr(gettext("invalid %s value for %s=%s"), 6192 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 6193 return (Z_ERR); 6194 } 6195 6196 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 6197 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 6198 return (Z_ERR); 6199 } 6200 6201 /* 6202 * Helper function for end_func-- checks the existence of a given property 6203 * and emits a message if not specified. 6204 */ 6205 static int 6206 end_check_reqd(char *attr, int pt, boolean_t *validation_failed) 6207 { 6208 if (strlen(attr) == 0) { 6209 *validation_failed = B_TRUE; 6210 zerr(gettext("%s not specified"), pt_to_str(pt)); 6211 return (Z_ERR); 6212 } 6213 return (Z_OK); 6214 } 6215 6216 void 6217 end_func(cmd_t *cmd) 6218 { 6219 boolean_t validation_failed = B_FALSE; 6220 boolean_t arg_err = B_FALSE; 6221 struct zone_fstab tmp_fstab; 6222 struct zone_nwiftab tmp_nwiftab; 6223 struct zone_devtab tmp_devtab; 6224 struct zone_rctltab tmp_rctltab; 6225 struct zone_attrtab tmp_attrtab; 6226 struct zone_dstab tmp_dstab; 6227 struct zone_admintab tmp_admintab; 6228 int err, arg, res1, res2, res3; 6229 uint64_t swap_limit; 6230 uint64_t locked_limit; 6231 uint64_t proc_cap; 6232 6233 assert(cmd != NULL); 6234 6235 optind = 0; 6236 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6237 switch (arg) { 6238 case '?': 6239 longer_usage(CMD_END); 6240 arg_err = B_TRUE; 6241 break; 6242 default: 6243 short_usage(CMD_END); 6244 arg_err = B_TRUE; 6245 break; 6246 } 6247 } 6248 if (arg_err) 6249 return; 6250 6251 if (optind != cmd->cmd_argc) { 6252 short_usage(CMD_END); 6253 return; 6254 } 6255 6256 if (global_scope) { 6257 scope_usage(CMD_END); 6258 return; 6259 } 6260 6261 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 6262 6263 switch (resource_scope) { 6264 case RT_FS: 6265 /* First make sure everything was filled in. */ 6266 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 6267 PT_DIR, &validation_failed) == Z_OK) { 6268 if (in_progress_fstab.zone_fs_dir[0] != '/') { 6269 zerr(gettext("%s %s is not an absolute path."), 6270 pt_to_str(PT_DIR), 6271 in_progress_fstab.zone_fs_dir); 6272 validation_failed = B_TRUE; 6273 } 6274 } 6275 6276 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 6277 PT_SPECIAL, &validation_failed); 6278 6279 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 6280 in_progress_fstab.zone_fs_raw[0] != '/') { 6281 zerr(gettext("%s %s is not an absolute path."), 6282 pt_to_str(PT_RAW), 6283 in_progress_fstab.zone_fs_raw); 6284 validation_failed = B_TRUE; 6285 } 6286 6287 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 6288 &validation_failed); 6289 6290 if (validation_failed) { 6291 saw_error = B_TRUE; 6292 return; 6293 } 6294 6295 if (end_op == CMD_ADD) { 6296 /* Make sure there isn't already one like this. */ 6297 bzero(&tmp_fstab, sizeof (tmp_fstab)); 6298 (void) strlcpy(tmp_fstab.zone_fs_dir, 6299 in_progress_fstab.zone_fs_dir, 6300 sizeof (tmp_fstab.zone_fs_dir)); 6301 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 6302 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 6303 if (err == Z_OK) { 6304 zerr(gettext("A %s resource " 6305 "with the %s '%s' already exists."), 6306 rt_to_str(RT_FS), pt_to_str(PT_DIR), 6307 in_progress_fstab.zone_fs_dir); 6308 saw_error = B_TRUE; 6309 return; 6310 } 6311 err = zonecfg_add_filesystem(handle, 6312 &in_progress_fstab); 6313 } else { 6314 err = zonecfg_modify_filesystem(handle, &old_fstab, 6315 &in_progress_fstab); 6316 } 6317 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 6318 in_progress_fstab.zone_fs_options = NULL; 6319 break; 6320 6321 case RT_IPD: 6322 /* First make sure everything was filled in. */ 6323 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 6324 &validation_failed) == Z_OK) { 6325 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 6326 zerr(gettext("%s %s is not an absolute path."), 6327 pt_to_str(PT_DIR), 6328 in_progress_ipdtab.zone_fs_dir); 6329 validation_failed = B_TRUE; 6330 } 6331 } 6332 if (validation_failed) { 6333 saw_error = B_TRUE; 6334 return; 6335 } 6336 6337 if (end_op == CMD_ADD) { 6338 /* Make sure there isn't already one like this. */ 6339 bzero(&tmp_fstab, sizeof (tmp_fstab)); 6340 (void) strlcpy(tmp_fstab.zone_fs_dir, 6341 in_progress_ipdtab.zone_fs_dir, 6342 sizeof (tmp_fstab.zone_fs_dir)); 6343 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 6344 if (err == Z_OK) { 6345 zerr(gettext("An %s resource " 6346 "with the %s '%s' already exists."), 6347 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 6348 in_progress_ipdtab.zone_fs_dir); 6349 saw_error = B_TRUE; 6350 return; 6351 } 6352 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 6353 } else { 6354 err = zonecfg_modify_ipd(handle, &old_ipdtab, 6355 &in_progress_ipdtab); 6356 } 6357 break; 6358 case RT_NET: 6359 /* 6360 * First make sure everything was filled in. 6361 * Since we don't know whether IP will be shared 6362 * or exclusive here, some checks are deferred until 6363 * the verify command. 6364 */ 6365 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 6366 PT_PHYSICAL, &validation_failed); 6367 6368 if (validation_failed) { 6369 saw_error = B_TRUE; 6370 return; 6371 } 6372 if (end_op == CMD_ADD) { 6373 /* Make sure there isn't already one like this. */ 6374 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 6375 (void) strlcpy(tmp_nwiftab.zone_nwif_physical, 6376 in_progress_nwiftab.zone_nwif_physical, 6377 sizeof (tmp_nwiftab.zone_nwif_physical)); 6378 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 6379 in_progress_nwiftab.zone_nwif_address, 6380 sizeof (tmp_nwiftab.zone_nwif_address)); 6381 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 6382 zerr(gettext("A %s resource with the %s '%s', " 6383 "and %s '%s' already exists."), 6384 rt_to_str(RT_NET), 6385 pt_to_str(PT_PHYSICAL), 6386 in_progress_nwiftab.zone_nwif_physical, 6387 pt_to_str(PT_ADDRESS), 6388 in_progress_nwiftab.zone_nwif_address); 6389 saw_error = B_TRUE; 6390 return; 6391 } 6392 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 6393 } else { 6394 err = zonecfg_modify_nwif(handle, &old_nwiftab, 6395 &in_progress_nwiftab); 6396 } 6397 break; 6398 6399 case RT_DEVICE: 6400 /* First make sure everything was filled in. */ 6401 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 6402 PT_MATCH, &validation_failed); 6403 6404 if (validation_failed) { 6405 saw_error = B_TRUE; 6406 return; 6407 } 6408 6409 if (end_op == CMD_ADD) { 6410 /* Make sure there isn't already one like this. */ 6411 (void) strlcpy(tmp_devtab.zone_dev_match, 6412 in_progress_devtab.zone_dev_match, 6413 sizeof (tmp_devtab.zone_dev_match)); 6414 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 6415 zerr(gettext("A %s resource with the %s '%s' " 6416 "already exists."), rt_to_str(RT_DEVICE), 6417 pt_to_str(PT_MATCH), 6418 in_progress_devtab.zone_dev_match); 6419 saw_error = B_TRUE; 6420 return; 6421 } 6422 err = zonecfg_add_dev(handle, &in_progress_devtab); 6423 } else { 6424 err = zonecfg_modify_dev(handle, &old_devtab, 6425 &in_progress_devtab); 6426 } 6427 break; 6428 6429 case RT_RCTL: 6430 /* First make sure everything was filled in. */ 6431 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 6432 PT_NAME, &validation_failed); 6433 6434 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 6435 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 6436 validation_failed = B_TRUE; 6437 } 6438 6439 if (validation_failed) { 6440 saw_error = B_TRUE; 6441 return; 6442 } 6443 6444 if (end_op == CMD_ADD) { 6445 /* Make sure there isn't already one like this. */ 6446 (void) strlcpy(tmp_rctltab.zone_rctl_name, 6447 in_progress_rctltab.zone_rctl_name, 6448 sizeof (tmp_rctltab.zone_rctl_name)); 6449 tmp_rctltab.zone_rctl_valptr = NULL; 6450 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 6451 zonecfg_free_rctl_value_list( 6452 tmp_rctltab.zone_rctl_valptr); 6453 if (err == Z_OK) { 6454 zerr(gettext("A %s resource " 6455 "with the %s '%s' already exists."), 6456 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 6457 in_progress_rctltab.zone_rctl_name); 6458 saw_error = B_TRUE; 6459 return; 6460 } 6461 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 6462 } else { 6463 err = zonecfg_modify_rctl(handle, &old_rctltab, 6464 &in_progress_rctltab); 6465 } 6466 if (err == Z_OK) { 6467 zonecfg_free_rctl_value_list( 6468 in_progress_rctltab.zone_rctl_valptr); 6469 in_progress_rctltab.zone_rctl_valptr = NULL; 6470 } 6471 break; 6472 6473 case RT_ATTR: 6474 /* First make sure everything was filled in. */ 6475 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 6476 PT_NAME, &validation_failed); 6477 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 6478 PT_TYPE, &validation_failed); 6479 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 6480 PT_VALUE, &validation_failed); 6481 6482 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 6483 Z_OK) 6484 validation_failed = B_TRUE; 6485 6486 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 6487 validation_failed = B_TRUE; 6488 6489 if (validation_failed) { 6490 saw_error = B_TRUE; 6491 return; 6492 } 6493 if (end_op == CMD_ADD) { 6494 /* Make sure there isn't already one like this. */ 6495 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 6496 (void) strlcpy(tmp_attrtab.zone_attr_name, 6497 in_progress_attrtab.zone_attr_name, 6498 sizeof (tmp_attrtab.zone_attr_name)); 6499 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 6500 zerr(gettext("An %s resource " 6501 "with the %s '%s' already exists."), 6502 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 6503 in_progress_attrtab.zone_attr_name); 6504 saw_error = B_TRUE; 6505 return; 6506 } 6507 err = zonecfg_add_attr(handle, &in_progress_attrtab); 6508 } else { 6509 err = zonecfg_modify_attr(handle, &old_attrtab, 6510 &in_progress_attrtab); 6511 } 6512 break; 6513 case RT_DATASET: 6514 /* First make sure everything was filled in. */ 6515 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 6516 zerr("%s %s", pt_to_str(PT_NAME), 6517 gettext("not specified")); 6518 saw_error = B_TRUE; 6519 validation_failed = B_TRUE; 6520 } 6521 if (validation_failed) 6522 return; 6523 if (end_op == CMD_ADD) { 6524 /* Make sure there isn't already one like this. */ 6525 bzero(&tmp_dstab, sizeof (tmp_dstab)); 6526 (void) strlcpy(tmp_dstab.zone_dataset_name, 6527 in_progress_dstab.zone_dataset_name, 6528 sizeof (tmp_dstab.zone_dataset_name)); 6529 err = zonecfg_lookup_ds(handle, &tmp_dstab); 6530 if (err == Z_OK) { 6531 zerr(gettext("A %s resource " 6532 "with the %s '%s' already exists."), 6533 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 6534 in_progress_dstab.zone_dataset_name); 6535 saw_error = B_TRUE; 6536 return; 6537 } 6538 err = zonecfg_add_ds(handle, &in_progress_dstab); 6539 } else { 6540 err = zonecfg_modify_ds(handle, &old_dstab, 6541 &in_progress_dstab); 6542 } 6543 break; 6544 case RT_DCPU: 6545 /* Make sure everything was filled in. */ 6546 if (end_check_reqd(in_progress_psettab.zone_ncpu_min, 6547 PT_NCPUS, &validation_failed) != Z_OK) { 6548 saw_error = B_TRUE; 6549 return; 6550 } 6551 6552 if (end_op == CMD_ADD) { 6553 err = zonecfg_add_pset(handle, &in_progress_psettab); 6554 } else { 6555 err = zonecfg_modify_pset(handle, &in_progress_psettab); 6556 } 6557 break; 6558 case RT_PCAP: 6559 /* Make sure everything was filled in. */ 6560 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap) 6561 != Z_OK) { 6562 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS)); 6563 saw_error = B_TRUE; 6564 validation_failed = B_TRUE; 6565 return; 6566 } 6567 err = Z_OK; 6568 break; 6569 case RT_MCAP: 6570 /* Make sure everything was filled in. */ 6571 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ? 6572 Z_ERR : Z_OK; 6573 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 6574 &swap_limit); 6575 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 6576 &locked_limit); 6577 6578 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 6579 zerr(gettext("No property was specified. One of %s, " 6580 "%s or %s is required."), pt_to_str(PT_PHYSICAL), 6581 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED)); 6582 saw_error = B_TRUE; 6583 return; 6584 } 6585 6586 /* if phys & locked are both set, verify locked <= phys */ 6587 if (res1 == Z_OK && res3 == Z_OK) { 6588 uint64_t phys_limit; 6589 char *endp; 6590 6591 phys_limit = strtoull( 6592 in_progress_mcaptab.zone_physmem_cap, &endp, 10); 6593 if (phys_limit < locked_limit) { 6594 zerr(gettext("The %s cap must be less than or " 6595 "equal to the %s cap."), 6596 pt_to_str(PT_LOCKED), 6597 pt_to_str(PT_PHYSICAL)); 6598 saw_error = B_TRUE; 6599 return; 6600 } 6601 } 6602 6603 err = Z_OK; 6604 if (res1 == Z_OK) { 6605 /* 6606 * We could be ending from either an add operation 6607 * or a select operation. Since all of the properties 6608 * within this resource are optional, we always use 6609 * modify on the mcap entry. zonecfg_modify_mcap() 6610 * will handle both adding and modifying a memory cap. 6611 */ 6612 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab); 6613 } else if (end_op == CMD_SELECT) { 6614 /* 6615 * If we're ending from a select and the physical 6616 * memory cap is empty then the user could have cleared 6617 * the physical cap value, so try to delete the entry. 6618 */ 6619 (void) zonecfg_delete_mcap(handle); 6620 } 6621 break; 6622 case RT_ADMIN: 6623 /* First make sure everything was filled in. */ 6624 if (end_check_reqd(in_progress_admintab.zone_admin_user, 6625 PT_USER, &validation_failed) == Z_OK) { 6626 if (getpwnam(in_progress_admintab.zone_admin_user) 6627 == NULL) { 6628 zerr(gettext("%s %s is not a valid username"), 6629 pt_to_str(PT_USER), 6630 in_progress_admintab.zone_admin_user); 6631 validation_failed = B_TRUE; 6632 } 6633 } 6634 6635 if (end_check_reqd(in_progress_admintab.zone_admin_auths, 6636 PT_AUTHS, &validation_failed) == Z_OK) { 6637 if (!zonecfg_valid_auths( 6638 in_progress_admintab.zone_admin_auths, 6639 zone)) { 6640 validation_failed = B_TRUE; 6641 } 6642 } 6643 6644 if (validation_failed) { 6645 saw_error = B_TRUE; 6646 return; 6647 } 6648 6649 if (end_op == CMD_ADD) { 6650 /* Make sure there isn't already one like this. */ 6651 bzero(&tmp_admintab, sizeof (tmp_admintab)); 6652 (void) strlcpy(tmp_admintab.zone_admin_user, 6653 in_progress_admintab.zone_admin_user, 6654 sizeof (tmp_admintab.zone_admin_user)); 6655 err = zonecfg_lookup_admin( 6656 handle, &tmp_admintab); 6657 if (err == Z_OK) { 6658 zerr(gettext("A %s resource " 6659 "with the %s '%s' already exists."), 6660 rt_to_str(RT_ADMIN), 6661 pt_to_str(PT_USER), 6662 in_progress_admintab.zone_admin_user); 6663 saw_error = B_TRUE; 6664 return; 6665 } 6666 err = zonecfg_add_admin(handle, 6667 &in_progress_admintab, zone); 6668 } else { 6669 err = zonecfg_modify_admin(handle, 6670 &old_admintab, &in_progress_admintab, 6671 zone); 6672 } 6673 break; 6674 default: 6675 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 6676 B_TRUE); 6677 saw_error = B_TRUE; 6678 return; 6679 } 6680 6681 if (err != Z_OK) { 6682 zone_perror(zone, err, B_TRUE); 6683 } else { 6684 need_to_commit = B_TRUE; 6685 global_scope = B_TRUE; 6686 end_op = -1; 6687 } 6688 } 6689 6690 void 6691 commit_func(cmd_t *cmd) 6692 { 6693 int arg; 6694 boolean_t arg_err = B_FALSE; 6695 6696 optind = 0; 6697 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6698 switch (arg) { 6699 case '?': 6700 longer_usage(CMD_COMMIT); 6701 arg_err = B_TRUE; 6702 break; 6703 default: 6704 short_usage(CMD_COMMIT); 6705 arg_err = B_TRUE; 6706 break; 6707 } 6708 } 6709 if (arg_err) 6710 return; 6711 6712 if (optind != cmd->cmd_argc) { 6713 short_usage(CMD_COMMIT); 6714 return; 6715 } 6716 6717 if (zone_is_read_only(CMD_COMMIT)) 6718 return; 6719 6720 assert(cmd != NULL); 6721 6722 cmd->cmd_argc = 1; 6723 /* 6724 * cmd_arg normally comes from a strdup() in the lexer, and the 6725 * whole cmd structure and its (char *) attributes are freed at 6726 * the completion of each command, so the strdup() below is needed 6727 * to match this and prevent a core dump from trying to free() 6728 * something that can't be. 6729 */ 6730 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 6731 zone_perror(zone, Z_NOMEM, B_TRUE); 6732 exit(Z_ERR); 6733 } 6734 cmd->cmd_argv[1] = NULL; 6735 verify_func(cmd); 6736 } 6737 6738 void 6739 revert_func(cmd_t *cmd) 6740 { 6741 char line[128]; /* enough to ask a question */ 6742 boolean_t force = B_FALSE; 6743 boolean_t arg_err = B_FALSE; 6744 int err, arg, answer; 6745 6746 optind = 0; 6747 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 6748 switch (arg) { 6749 case '?': 6750 longer_usage(CMD_REVERT); 6751 arg_err = B_TRUE; 6752 break; 6753 case 'F': 6754 force = B_TRUE; 6755 break; 6756 default: 6757 short_usage(CMD_REVERT); 6758 arg_err = B_TRUE; 6759 break; 6760 } 6761 } 6762 if (arg_err) 6763 return; 6764 6765 if (optind != cmd->cmd_argc) { 6766 short_usage(CMD_REVERT); 6767 return; 6768 } 6769 6770 if (zone_is_read_only(CMD_REVERT)) 6771 return; 6772 6773 if (!global_scope) { 6774 zerr(gettext("You can only use %s in the global scope.\nUse" 6775 " '%s' to cancel changes to a resource specification."), 6776 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL)); 6777 saw_error = B_TRUE; 6778 return; 6779 } 6780 6781 if (zonecfg_check_handle(handle) != Z_OK) { 6782 zerr(gettext("No changes to revert.")); 6783 saw_error = B_TRUE; 6784 return; 6785 } 6786 6787 if (!force) { 6788 (void) snprintf(line, sizeof (line), 6789 gettext("Are you sure you want to revert")); 6790 if ((answer = ask_yesno(B_FALSE, line)) == -1) { 6791 zerr(gettext("Input not from terminal and -F not " 6792 "specified:\n%s command ignored, exiting."), 6793 cmd_to_str(CMD_REVERT)); 6794 exit(Z_ERR); 6795 } 6796 if (answer != 1) 6797 return; 6798 } 6799 6800 /* 6801 * Reset any pending admins that were 6802 * removed from the previous zone 6803 */ 6804 zonecfg_remove_userauths(handle, "", zone, B_FALSE); 6805 6806 /* 6807 * Time for a new handle: finish the old one off first 6808 * then get a new one properly to avoid leaks. 6809 */ 6810 zonecfg_fini_handle(handle); 6811 if ((handle = zonecfg_init_handle()) == NULL) { 6812 zone_perror(execname, Z_NOMEM, B_TRUE); 6813 exit(Z_ERR); 6814 } 6815 6816 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 6817 saw_error = B_TRUE; 6818 got_handle = B_FALSE; 6819 if (err == Z_NO_ZONE) 6820 zerr(gettext("%s: no such saved zone to revert to."), 6821 revert_zone); 6822 else 6823 zone_perror(zone, err, B_TRUE); 6824 } 6825 (void) strlcpy(zone, revert_zone, sizeof (zone)); 6826 } 6827 6828 void 6829 help_func(cmd_t *cmd) 6830 { 6831 int i; 6832 6833 assert(cmd != NULL); 6834 6835 if (cmd->cmd_argc == 0) { 6836 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 6837 return; 6838 } 6839 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 6840 usage(B_TRUE, HELP_USAGE); 6841 return; 6842 } 6843 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 6844 usage(B_TRUE, HELP_SUBCMDS); 6845 return; 6846 } 6847 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 6848 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS); 6849 return; 6850 } 6851 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 6852 longer_usage(CMD_HELP); 6853 return; 6854 } 6855 6856 for (i = 0; i <= CMD_MAX; i++) { 6857 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 6858 longer_usage(i); 6859 return; 6860 } 6861 } 6862 /* We do not use zerr() here because we do not want its extra \n. */ 6863 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 6864 cmd->cmd_argv[0]); 6865 usage(B_FALSE, HELP_META); 6866 } 6867 6868 static int 6869 string_to_yyin(char *string) 6870 { 6871 if ((yyin = tmpfile()) == NULL) { 6872 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6873 return (Z_ERR); 6874 } 6875 if (fwrite(string, strlen(string), 1, yyin) != 1) { 6876 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6877 return (Z_ERR); 6878 } 6879 if (fseek(yyin, 0, SEEK_SET) != 0) { 6880 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 6881 return (Z_ERR); 6882 } 6883 return (Z_OK); 6884 } 6885 6886 /* This is the back-end helper function for read_input() below. */ 6887 6888 static int 6889 cleanup() 6890 { 6891 int answer; 6892 cmd_t *cmd; 6893 6894 if (!interactive_mode && !cmd_file_mode) { 6895 /* 6896 * If we're not in interactive mode, and we're not in command 6897 * file mode, then we must be in commands-from-the-command-line 6898 * mode. As such, we can't loop back and ask for more input. 6899 * It was OK to prompt for such things as whether or not to 6900 * really delete a zone in the command handler called from 6901 * yyparse() above, but "really quit?" makes no sense in this 6902 * context. So disable prompting. 6903 */ 6904 ok_to_prompt = B_FALSE; 6905 } 6906 if (!global_scope) { 6907 if (!time_to_exit) { 6908 /* 6909 * Just print a simple error message in the -1 case, 6910 * since exit_func() already handles that case, and 6911 * EOF means we are finished anyway. 6912 */ 6913 answer = ask_yesno(B_FALSE, 6914 gettext("Resource incomplete; really quit")); 6915 if (answer == -1) { 6916 zerr(gettext("Resource incomplete.")); 6917 return (Z_ERR); 6918 } 6919 if (answer != 1) { 6920 yyin = stdin; 6921 return (Z_REPEAT); 6922 } 6923 } else { 6924 saw_error = B_TRUE; 6925 } 6926 } 6927 /* 6928 * Make sure we tried something and that the handle checks 6929 * out, or we would get a false error trying to commit. 6930 */ 6931 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 6932 if ((cmd = alloc_cmd()) == NULL) { 6933 zone_perror(zone, Z_NOMEM, B_TRUE); 6934 return (Z_ERR); 6935 } 6936 cmd->cmd_argc = 0; 6937 cmd->cmd_argv[0] = NULL; 6938 commit_func(cmd); 6939 free_cmd(cmd); 6940 /* 6941 * need_to_commit will get set back to FALSE if the 6942 * configuration is saved successfully. 6943 */ 6944 if (need_to_commit) { 6945 if (force_exit) { 6946 zerr(gettext("Configuration not saved.")); 6947 return (Z_ERR); 6948 } 6949 answer = ask_yesno(B_FALSE, 6950 gettext("Configuration not saved; really quit")); 6951 if (answer == -1) { 6952 zerr(gettext("Configuration not saved.")); 6953 return (Z_ERR); 6954 } 6955 if (answer != 1) { 6956 time_to_exit = B_FALSE; 6957 yyin = stdin; 6958 return (Z_REPEAT); 6959 } 6960 } 6961 } 6962 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 6963 } 6964 6965 /* 6966 * read_input() is the driver of this program. It is a wrapper around 6967 * yyparse(), printing appropriate prompts when needed, checking for 6968 * exit conditions and reacting appropriately [the latter in its cleanup() 6969 * helper function]. 6970 * 6971 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 6972 * so do_interactive() knows that we are not really done (i.e, we asked 6973 * the user if we should really quit and the user said no). 6974 */ 6975 static int 6976 read_input() 6977 { 6978 boolean_t yyin_is_a_tty = isatty(fileno(yyin)); 6979 /* 6980 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 6981 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 6982 */ 6983 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 6984 6985 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 6986 newline_terminated = B_TRUE; 6987 for (;;) { 6988 if (yyin_is_a_tty) { 6989 if (newline_terminated) { 6990 if (global_scope) 6991 (void) snprintf(prompt, sizeof (prompt), 6992 "%s:%s> ", execname, zone); 6993 else 6994 (void) snprintf(prompt, sizeof (prompt), 6995 "%s:%s:%s> ", execname, zone, 6996 rt_to_str(resource_scope)); 6997 } 6998 /* 6999 * If the user hits ^C then we want to catch it and 7000 * start over. If the user hits EOF then we want to 7001 * bail out. 7002 */ 7003 line = gl_get_line(gl, prompt, NULL, -1); 7004 if (gl_return_status(gl) == GLR_SIGNAL) { 7005 gl_abandon_line(gl); 7006 continue; 7007 } 7008 if (line == NULL) 7009 break; 7010 (void) string_to_yyin(line); 7011 while (!feof(yyin)) 7012 yyparse(); 7013 } else { 7014 yyparse(); 7015 } 7016 /* Bail out on an error in command file mode. */ 7017 if (saw_error && cmd_file_mode && !interactive_mode) 7018 time_to_exit = B_TRUE; 7019 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 7020 break; 7021 } 7022 return (cleanup()); 7023 } 7024 7025 /* 7026 * This function is used in the zonecfg-interactive-mode scenario: it just 7027 * calls read_input() until we are done. 7028 */ 7029 7030 static int 7031 do_interactive(void) 7032 { 7033 int err; 7034 7035 interactive_mode = B_TRUE; 7036 if (!read_only_mode) { 7037 /* 7038 * Try to set things up proactively in interactive mode, so 7039 * that if the zone in question does not exist yet, we can 7040 * provide the user with a clue. 7041 */ 7042 (void) initialize(B_FALSE); 7043 } 7044 do { 7045 err = read_input(); 7046 } while (err == Z_REPEAT); 7047 return (err); 7048 } 7049 7050 /* 7051 * cmd_file is slightly more complicated, as it has to open the command file 7052 * and set yyin appropriately. Once that is done, though, it just calls 7053 * read_input(), and only once, since prompting is not possible. 7054 */ 7055 7056 static int 7057 cmd_file(char *file) 7058 { 7059 FILE *infile; 7060 int err; 7061 struct stat statbuf; 7062 boolean_t using_real_file = (strcmp(file, "-") != 0); 7063 7064 if (using_real_file) { 7065 /* 7066 * zerr() prints a line number in cmd_file_mode, which we do 7067 * not want here, so temporarily unset it. 7068 */ 7069 cmd_file_mode = B_FALSE; 7070 if ((infile = fopen(file, "r")) == NULL) { 7071 zerr(gettext("could not open file %s: %s"), 7072 file, strerror(errno)); 7073 return (Z_ERR); 7074 } 7075 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 7076 zerr(gettext("could not stat file %s: %s"), 7077 file, strerror(errno)); 7078 err = Z_ERR; 7079 goto done; 7080 } 7081 if (!S_ISREG(statbuf.st_mode)) { 7082 zerr(gettext("%s is not a regular file."), file); 7083 err = Z_ERR; 7084 goto done; 7085 } 7086 yyin = infile; 7087 cmd_file_mode = B_TRUE; 7088 ok_to_prompt = B_FALSE; 7089 } else { 7090 /* 7091 * "-f -" is essentially the same as interactive mode, 7092 * so treat it that way. 7093 */ 7094 interactive_mode = B_TRUE; 7095 } 7096 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 7097 if ((err = read_input()) == Z_REPEAT) 7098 err = Z_ERR; 7099 done: 7100 if (using_real_file) 7101 (void) fclose(infile); 7102 return (err); 7103 } 7104 7105 /* 7106 * Since yacc is based on reading from a (FILE *) whereas what we get from 7107 * the command line is in argv format, we need to convert when the user 7108 * gives us commands directly from the command line. That is done here by 7109 * concatenating the argv list into a space-separated string, writing it 7110 * to a temp file, and rewinding the file so yyin can be set to it. Then 7111 * we call read_input(), and only once, since prompting about whether to 7112 * continue or quit would make no sense in this context. 7113 */ 7114 7115 static int 7116 one_command_at_a_time(int argc, char *argv[]) 7117 { 7118 char *command; 7119 size_t len = 2; /* terminal \n\0 */ 7120 int i, err; 7121 7122 for (i = 0; i < argc; i++) 7123 len += strlen(argv[i]) + 1; 7124 if ((command = malloc(len)) == NULL) { 7125 zone_perror(execname, Z_NOMEM, B_TRUE); 7126 return (Z_ERR); 7127 } 7128 (void) strlcpy(command, argv[0], len); 7129 for (i = 1; i < argc; i++) { 7130 (void) strlcat(command, " ", len); 7131 (void) strlcat(command, argv[i], len); 7132 } 7133 (void) strlcat(command, "\n", len); 7134 err = string_to_yyin(command); 7135 free(command); 7136 if (err != Z_OK) 7137 return (err); 7138 while (!feof(yyin)) 7139 yyparse(); 7140 return (cleanup()); 7141 } 7142 7143 static char * 7144 get_execbasename(char *execfullname) 7145 { 7146 char *last_slash, *execbasename; 7147 7148 /* guard against '/' at end of command invocation */ 7149 for (;;) { 7150 last_slash = strrchr(execfullname, '/'); 7151 if (last_slash == NULL) { 7152 execbasename = execfullname; 7153 break; 7154 } else { 7155 execbasename = last_slash + 1; 7156 if (*execbasename == '\0') { 7157 *last_slash = '\0'; 7158 continue; 7159 } 7160 break; 7161 } 7162 } 7163 return (execbasename); 7164 } 7165 7166 int 7167 main(int argc, char *argv[]) 7168 { 7169 int err, arg; 7170 struct stat st; 7171 7172 /* This must be before anything goes to stdout. */ 7173 setbuf(stdout, NULL); 7174 7175 saw_error = B_FALSE; 7176 cmd_file_mode = B_FALSE; 7177 execname = get_execbasename(argv[0]); 7178 7179 (void) setlocale(LC_ALL, ""); 7180 (void) textdomain(TEXT_DOMAIN); 7181 7182 if (getzoneid() != GLOBAL_ZONEID) { 7183 zerr(gettext("%s can only be run from the global zone."), 7184 execname); 7185 exit(Z_ERR); 7186 } 7187 7188 if (argc < 2) { 7189 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS); 7190 exit(Z_USAGE); 7191 } 7192 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 7193 (void) one_command_at_a_time(argc - 1, &(argv[1])); 7194 exit(Z_OK); 7195 } 7196 7197 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 7198 switch (arg) { 7199 case '?': 7200 if (optopt == '?') 7201 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS); 7202 else 7203 usage(B_FALSE, HELP_USAGE); 7204 exit(Z_USAGE); 7205 /* NOTREACHED */ 7206 case 'f': 7207 cmd_file_name = optarg; 7208 cmd_file_mode = B_TRUE; 7209 break; 7210 case 'R': 7211 if (*optarg != '/') { 7212 zerr(gettext("root path must be absolute: %s"), 7213 optarg); 7214 exit(Z_USAGE); 7215 } 7216 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 7217 zerr(gettext( 7218 "root path must be a directory: %s"), 7219 optarg); 7220 exit(Z_USAGE); 7221 } 7222 zonecfg_set_root(optarg); 7223 break; 7224 case 'z': 7225 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) { 7226 global_zone = B_TRUE; 7227 } else if (zonecfg_validate_zonename(optarg) != Z_OK) { 7228 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE); 7229 usage(B_FALSE, HELP_SYNTAX); 7230 exit(Z_USAGE); 7231 } 7232 (void) strlcpy(zone, optarg, sizeof (zone)); 7233 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 7234 break; 7235 default: 7236 usage(B_FALSE, HELP_USAGE); 7237 exit(Z_USAGE); 7238 } 7239 } 7240 7241 if (optind > argc || strcmp(zone, "") == 0) { 7242 usage(B_FALSE, HELP_USAGE); 7243 exit(Z_USAGE); 7244 } 7245 7246 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 7247 read_only_mode = B_FALSE; 7248 } else if (err == Z_ACCES) { 7249 read_only_mode = B_TRUE; 7250 /* skip this message in one-off from command line mode */ 7251 if (optind == argc) 7252 (void) fprintf(stderr, gettext("WARNING: you do not " 7253 "have write access to this zone's configuration " 7254 "file;\ngoing into read-only mode.\n")); 7255 } else { 7256 fprintf(stderr, "%s: Could not access zone configuration " 7257 "store: %s\n", execname, zonecfg_strerror(err)); 7258 exit(Z_ERR); 7259 } 7260 7261 if ((handle = zonecfg_init_handle()) == NULL) { 7262 zone_perror(execname, Z_NOMEM, B_TRUE); 7263 exit(Z_ERR); 7264 } 7265 7266 /* 7267 * This may get set back to FALSE again in cmd_file() if cmd_file_name 7268 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 7269 */ 7270 if (isatty(STDIN_FILENO)) 7271 ok_to_prompt = B_TRUE; 7272 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 7273 exit(Z_ERR); 7274 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 7275 exit(Z_ERR); 7276 (void) sigset(SIGINT, SIG_IGN); 7277 if (optind == argc) { 7278 if (!cmd_file_mode) 7279 err = do_interactive(); 7280 else 7281 err = cmd_file(cmd_file_name); 7282 } else { 7283 err = one_command_at_a_time(argc - optind, &(argv[optind])); 7284 } 7285 zonecfg_fini_handle(handle); 7286 if (brand != NULL) 7287 brand_close(brand); 7288 (void) del_GetLine(gl); 7289 return (err); 7290 } 7291