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