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