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