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