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