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