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