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