1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * zonecfg is a lex/yacc based command interpreter used to manage zone 31 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which 32 * the grammar (see zonecfg_grammar.y) builds up into commands, some of 33 * which takes resources and/or properties as arguments. See the block 34 * comments near the end of zonecfg_grammar.y for how the data structures 35 * which keep track of these resources and properties are built up. 36 * 37 * The resource/property data structures are inserted into a command 38 * structure (see zonecfg.h), which also keeps track of command names, 39 * miscellaneous arguments, and function handlers. The grammar selects 40 * the appropriate function handler, each of which takes a pointer to a 41 * command structure as its sole argument, and invokes it. The grammar 42 * itself is "entered" (a la the Matrix) by yyparse(), which is called 43 * from read_input(), our main driving function. That in turn is called 44 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each 45 * of which is called from main() depending on how the program was invoked. 46 * 47 * The rest of this module consists of the various function handlers and 48 * their helper functions. Some of these functions, particularly the 49 * X_to_str() functions, which maps command, resource and property numbers 50 * to strings, are used quite liberally, as doing so results in a better 51 * program w/rt I18N, reducing the need for translation notes. 52 */ 53 54 #include <sys/mntent.h> 55 #include <sys/varargs.h> 56 #include <sys/sysmacros.h> 57 58 #include <errno.h> 59 #include <fcntl.h> 60 #include <strings.h> 61 #include <unistd.h> 62 #include <ctype.h> 63 #include <stdlib.h> 64 #include <assert.h> 65 #include <sys/stat.h> 66 #include <zone.h> 67 #include <arpa/inet.h> 68 #include <netdb.h> 69 #include <locale.h> 70 #include <libintl.h> 71 #include <alloca.h> 72 #include <signal.h> 73 #include <wait.h> 74 #include <libtecla.h> 75 #include <libzfs.h> 76 #include <sys/brand.h> 77 #include <libbrand.h> 78 79 #include <libzonecfg.h> 80 #include "zonecfg.h" 81 82 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 83 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 84 #endif 85 86 #define PAGER "/usr/bin/more" 87 #define EXEC_PREFIX "exec " 88 #define EXEC_LEN (strlen(EXEC_PREFIX)) 89 90 struct help { 91 uint_t cmd_num; 92 char *cmd_name; 93 uint_t flags; 94 char *short_usage; 95 }; 96 97 extern int yyparse(void); 98 extern int lex_lineno; 99 100 #define MAX_LINE_LEN 1024 101 #define MAX_CMD_HIST 1024 102 #define MAX_CMD_LEN 1024 103 104 /* 105 * Each SHELP_ should be a simple string. 106 */ 107 108 #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \ 109 "add <property-name> <property-value>\n\t(resource scope)" 110 #define SHELP_CANCEL "cancel" 111 #define SHELP_COMMIT "commit" 112 #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]" 113 #define SHELP_DELETE "delete [-F]" 114 #define SHELP_END "end" 115 #define SHELP_EXIT "exit [-F]" 116 #define SHELP_EXPORT "export [-f output-file]" 117 #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]" 118 #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]" 119 #define SHELP_REMOVE "remove <resource-type> { <property-name>=<property-" \ 120 "value> }\n\t(global scope)\nremove <property-name> <property-value>" \ 121 "\n\t(resource scope)" 122 #define SHELP_REVERT "revert [-F]" 123 #define SHELP_SELECT "select <resource-type> { <property-name>=" \ 124 "<property-value> }" 125 #define SHELP_SET "set <property-name>=<property-value>" 126 #define SHELP_VERIFY "verify" 127 128 static struct help helptab[] = { 129 { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, }, 130 { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, }, 131 { CMD_COMMIT, "commit", 0, SHELP_COMMIT, }, 132 { CMD_CREATE, "create", 0, SHELP_CREATE, }, 133 { CMD_DELETE, "delete", 0, SHELP_DELETE, }, 134 { CMD_END, "end", 0, SHELP_END, }, 135 { CMD_EXIT, "exit", 0, SHELP_EXIT, }, 136 { CMD_EXPORT, "export", 0, SHELP_EXPORT, }, 137 { CMD_HELP, "help", 0, SHELP_HELP }, 138 { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, }, 139 { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, }, 140 { CMD_REVERT, "revert", 0, SHELP_REVERT, }, 141 { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, }, 142 { CMD_SET, "set", HELP_PROPS, SHELP_SET, }, 143 { CMD_VERIFY, "verify", 0, SHELP_VERIFY, }, 144 { 0 }, 145 }; 146 147 #define MAX_RT_STRLEN 16 148 149 /* These *must* match the order of the RT_ define's from zonecfg.h */ 150 static char *res_types[] = { 151 "unknown", 152 "zonename", 153 "zonepath", 154 "autoboot", 155 "pool", 156 "fs", 157 "inherit-pkg-dir", 158 "net", 159 "device", 160 "rctl", 161 "attr", 162 "dataset", 163 "limitpriv", 164 "bootargs", 165 "brand", 166 NULL 167 }; 168 169 /* These *must* match the order of the PT_ define's from zonecfg.h */ 170 static char *prop_types[] = { 171 "unknown", 172 "zonename", 173 "zonepath", 174 "autoboot", 175 "pool", 176 "dir", 177 "special", 178 "type", 179 "options", 180 "address", 181 "physical", 182 "name", 183 "value", 184 "match", 185 "priv", 186 "limit", 187 "action", 188 "raw", 189 "limitpriv", 190 "bootargs", 191 "brand", 192 NULL 193 }; 194 195 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */ 196 static char *prop_val_types[] = { 197 "simple", 198 "complex", 199 "list", 200 }; 201 202 /* 203 * The various _cmds[] lists below are for command tab-completion. 204 */ 205 206 /* 207 * remove has a space afterwards because it has qualifiers; the other commands 208 * that have qualifiers (add, select and set) don't need a space here because 209 * they have their own _cmds[] lists below. 210 */ 211 static const char *global_scope_cmds[] = { 212 "add", 213 "commit", 214 "create", 215 "delete", 216 "exit", 217 "export", 218 "help", 219 "info", 220 "remove ", 221 "revert", 222 "select", 223 "set", 224 "verify", 225 NULL 226 }; 227 228 static const char *add_cmds[] = { 229 "add fs", 230 "add inherit-pkg-dir", 231 "add net", 232 "add device", 233 "add rctl", 234 "add attr", 235 "add dataset", 236 NULL 237 }; 238 239 static const char *remove_cmds[] = { 240 "remove fs ", 241 "remove inherit-pkg-dir ", 242 "remove net ", 243 "remove device ", 244 "remove rctl ", 245 "remove attr ", 246 "remove dataset ", 247 NULL 248 }; 249 250 static const char *select_cmds[] = { 251 "select fs ", 252 "select inherit-pkg-dir ", 253 "select net ", 254 "select device ", 255 "select rctl ", 256 "select attr ", 257 "select dataset ", 258 NULL 259 }; 260 261 static const char *set_cmds[] = { 262 "set zonename=", 263 "set zonepath=", 264 "set brand=", 265 "set autoboot=", 266 "set pool=", 267 "set limitpriv=", 268 "set bootargs=", 269 NULL 270 }; 271 272 static const char *info_cmds[] = { 273 "info fs ", 274 "info inherit-pkg-dir ", 275 "info net ", 276 "info device ", 277 "info rctl ", 278 "info attr ", 279 "info dataset ", 280 "info zonename", 281 "info zonepath", 282 "info autoboot", 283 "info pool", 284 "info limitpriv", 285 "info bootargs", 286 NULL 287 }; 288 289 static const char *fs_res_scope_cmds[] = { 290 "add options ", 291 "cancel", 292 "end", 293 "exit", 294 "help", 295 "info", 296 "remove options ", 297 "set dir=", 298 "set raw=", 299 "set special=", 300 "set type=", 301 NULL 302 }; 303 304 static const char *net_res_scope_cmds[] = { 305 "cancel", 306 "end", 307 "exit", 308 "help", 309 "info", 310 "set address=", 311 "set physical=", 312 NULL 313 }; 314 315 static const char *ipd_res_scope_cmds[] = { 316 "cancel", 317 "end", 318 "exit", 319 "help", 320 "info", 321 "set dir=", 322 NULL 323 }; 324 325 static const char *device_res_scope_cmds[] = { 326 "cancel", 327 "end", 328 "exit", 329 "help", 330 "info", 331 "set match=", 332 NULL 333 }; 334 335 static const char *attr_res_scope_cmds[] = { 336 "cancel", 337 "end", 338 "exit", 339 "help", 340 "info", 341 "set name=", 342 "set type=", 343 "set value=", 344 NULL 345 }; 346 347 static const char *rctl_res_scope_cmds[] = { 348 "add value ", 349 "cancel", 350 "end", 351 "exit", 352 "help", 353 "info", 354 "remove value ", 355 "set name=", 356 NULL 357 }; 358 359 static const char *dataset_res_scope_cmds[] = { 360 "cancel", 361 "end", 362 "exit", 363 "help", 364 "info", 365 "set name=", 366 NULL 367 }; 368 369 /* Global variables */ 370 371 /* set early in main(), never modified thereafter, used all over the place */ 372 static char *execname; 373 374 /* set in main(), used all over the place */ 375 static zone_dochandle_t handle; 376 377 /* used all over the place */ 378 static char zone[ZONENAME_MAX]; 379 static char revert_zone[ZONENAME_MAX]; 380 381 /* global brand operations */ 382 static brand_handle_t brand; 383 384 /* set in modifying functions, checked in read_input() */ 385 static bool need_to_commit = FALSE; 386 bool saw_error; 387 388 /* set in yacc parser, checked in read_input() */ 389 bool newline_terminated; 390 391 /* set in main(), checked in lex error handler */ 392 bool cmd_file_mode; 393 394 /* set in exit_func(), checked in read_input() */ 395 static bool time_to_exit = FALSE, force_exit = FALSE; 396 397 /* used in short_usage() and zerr() */ 398 static char *cmd_file_name = NULL; 399 400 /* checked in read_input() and other places */ 401 static bool ok_to_prompt = FALSE; 402 403 /* set and checked in initialize() */ 404 static bool got_handle = FALSE; 405 406 /* initialized in do_interactive(), checked in initialize() */ 407 static bool interactive_mode; 408 409 /* set in main(), checked in multiple places */ 410 static bool read_only_mode; 411 412 static bool global_scope = TRUE; /* scope is outer/global or inner/resource */ 413 static int resource_scope; /* should be in the RT_ list from zonecfg.h */ 414 static int end_op = -1; /* operation on end is either add or modify */ 415 416 int num_prop_vals; /* for grammar */ 417 418 /* 419 * These are for keeping track of resources as they are specified as part of 420 * the multi-step process. They should be initialized by add_resource() or 421 * select_func() and filled in by add_property() or set_func(). 422 */ 423 static struct zone_fstab old_fstab, in_progress_fstab; 424 static struct zone_fstab old_ipdtab, in_progress_ipdtab; 425 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab; 426 static struct zone_devtab old_devtab, in_progress_devtab; 427 static struct zone_rctltab old_rctltab, in_progress_rctltab; 428 static struct zone_attrtab old_attrtab, in_progress_attrtab; 429 static struct zone_dstab old_dstab, in_progress_dstab; 430 431 static GetLine *gl; /* The gl_get_line() resource object */ 432 433 /* Functions begin here */ 434 435 static bool 436 initial_match(const char *line1, const char *line2, int word_end) 437 { 438 if (word_end <= 0) 439 return (TRUE); 440 return (strncmp(line1, line2, word_end) == 0); 441 } 442 443 static int 444 add_stuff(WordCompletion *cpl, const char *line1, const char **list, 445 int word_end) 446 { 447 int i, err; 448 449 for (i = 0; list[i] != NULL; i++) { 450 if (initial_match(line1, list[i], word_end)) { 451 err = cpl_add_completion(cpl, line1, 0, word_end, 452 list[i] + word_end, "", ""); 453 if (err != 0) 454 return (err); 455 } 456 } 457 return (0); 458 } 459 460 static 461 /* ARGSUSED */ 462 CPL_MATCH_FN(cmd_cpl_fn) 463 { 464 if (global_scope) { 465 /* 466 * The MAX/MIN tests below are to make sure we have at least 467 * enough characters to distinguish from other prefixes (MAX) 468 * but only check MIN(what we have, what we're checking). 469 */ 470 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0) 471 return (add_stuff(cpl, line, add_cmds, word_end)); 472 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0) 473 return (add_stuff(cpl, line, select_cmds, word_end)); 474 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0) 475 return (add_stuff(cpl, line, set_cmds, word_end)); 476 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0) 477 return (add_stuff(cpl, line, remove_cmds, word_end)); 478 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0) 479 return (add_stuff(cpl, line, info_cmds, word_end)); 480 return (add_stuff(cpl, line, global_scope_cmds, word_end)); 481 } 482 switch (resource_scope) { 483 case RT_FS: 484 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end)); 485 case RT_IPD: 486 return (add_stuff(cpl, line, ipd_res_scope_cmds, word_end)); 487 case RT_NET: 488 return (add_stuff(cpl, line, net_res_scope_cmds, word_end)); 489 case RT_DEVICE: 490 return (add_stuff(cpl, line, device_res_scope_cmds, word_end)); 491 case RT_RCTL: 492 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end)); 493 case RT_ATTR: 494 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end)); 495 case RT_DATASET: 496 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end)); 497 } 498 return (0); 499 } 500 501 /* 502 * For the main CMD_func() functions below, several of them call getopt() 503 * then check optind against argc to make sure an extra parameter was not 504 * passed in. The reason this is not caught in the grammar is that the 505 * grammar just checks for a miscellaneous TOKEN, which is *expected* to 506 * be "-F" (for example), but could be anything. So (for example) this 507 * check will prevent "create bogus". 508 */ 509 510 cmd_t * 511 alloc_cmd(void) 512 { 513 return (calloc(1, sizeof (cmd_t))); 514 } 515 516 void 517 free_cmd(cmd_t *cmd) 518 { 519 int i; 520 521 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++) 522 if (cmd->cmd_property_ptr[i] != NULL) { 523 property_value_ptr_t pp = cmd->cmd_property_ptr[i]; 524 525 switch (pp->pv_type) { 526 case PROP_VAL_SIMPLE: 527 free(pp->pv_simple); 528 break; 529 case PROP_VAL_COMPLEX: 530 free_complex(pp->pv_complex); 531 break; 532 case PROP_VAL_LIST: 533 free_list(pp->pv_list); 534 break; 535 } 536 } 537 for (i = 0; i < cmd->cmd_argc; i++) 538 free(cmd->cmd_argv[i]); 539 free(cmd); 540 } 541 542 complex_property_ptr_t 543 alloc_complex(void) 544 { 545 return (calloc(1, sizeof (complex_property_t))); 546 } 547 548 void 549 free_complex(complex_property_ptr_t complex) 550 { 551 if (complex == NULL) 552 return; 553 free_complex(complex->cp_next); 554 if (complex->cp_value != NULL) 555 free(complex->cp_value); 556 free(complex); 557 } 558 559 list_property_ptr_t 560 alloc_list(void) 561 { 562 return (calloc(1, sizeof (list_property_t))); 563 } 564 565 void 566 free_list(list_property_ptr_t list) 567 { 568 if (list == NULL) 569 return; 570 if (list->lp_simple != NULL) 571 free(list->lp_simple); 572 free_complex(list->lp_complex); 573 free_list(list->lp_next); 574 free(list); 575 } 576 577 void 578 free_outer_list(list_property_ptr_t list) 579 { 580 if (list == NULL) 581 return; 582 free_outer_list(list->lp_next); 583 free(list); 584 } 585 586 static struct zone_rctlvaltab * 587 alloc_rctlvaltab(void) 588 { 589 return (calloc(1, sizeof (struct zone_rctlvaltab))); 590 } 591 592 static char * 593 rt_to_str(int res_type) 594 { 595 assert(res_type >= RT_MIN && res_type <= RT_MAX); 596 return (res_types[res_type]); 597 } 598 599 static char * 600 pt_to_str(int prop_type) 601 { 602 assert(prop_type >= PT_MIN && prop_type <= PT_MAX); 603 return (prop_types[prop_type]); 604 } 605 606 static char * 607 pvt_to_str(int pv_type) 608 { 609 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX); 610 return (prop_val_types[pv_type]); 611 } 612 613 static char * 614 cmd_to_str(int cmd_num) 615 { 616 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 617 return (helptab[cmd_num].cmd_name); 618 } 619 620 /* 621 * This is a separate function rather than a set of define's because of the 622 * gettext() wrapping. 623 */ 624 625 /* 626 * TRANSLATION_NOTE 627 * Each string below should have \t follow \n whenever needed; the 628 * initial \t and the terminal \n will be provided by the calling function. 629 */ 630 631 static char * 632 long_help(int cmd_num) 633 { 634 static char line[1024]; /* arbitrary large amount */ 635 636 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 637 switch (cmd_num) { 638 case CMD_HELP: 639 return (gettext("Prints help message.")); 640 case CMD_CREATE: 641 (void) snprintf(line, sizeof (line), 642 gettext("Creates a configuration for the " 643 "specified zone. %s should be\n\tused to " 644 "begin configuring a new zone. If overwriting an " 645 "existing\n\tconfiguration, the -F flag can be " 646 "used to force the action. If\n\t-t template is " 647 "given, creates a configuration identical to the\n" 648 "\tspecified template, except that the zone name " 649 "is changed from\n\ttemplate to zonename. '%s -a' " 650 "creates a configuration from a\n\tdetached " 651 "zonepath. '%s -b' results in a blank " 652 "configuration.\n\t'%s' with no arguments applies " 653 "the Sun default settings."), 654 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE), 655 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE)); 656 return (line); 657 case CMD_EXIT: 658 return (gettext("Exits the program. The -F flag can " 659 "be used to force the action.")); 660 case CMD_EXPORT: 661 return (gettext("Prints configuration to standard " 662 "output, or to output-file if\n\tspecified, in " 663 "a form suitable for use in a command-file.")); 664 case CMD_ADD: 665 return (gettext("Add specified resource to " 666 "configuration.")); 667 case CMD_DELETE: 668 return (gettext("Deletes the specified zone. The -F " 669 "flag can be used to force the\n\taction.")); 670 case CMD_REMOVE: 671 return (gettext("Remove specified resource from " 672 "configuration. Note that the curly\n\tbraces " 673 "('{', '}') mean one or more of whatever " 674 "is between them.")); 675 case CMD_SELECT: 676 (void) snprintf(line, sizeof (line), 677 gettext("Selects a resource to modify. " 678 "Resource modification is completed\n\twith the " 679 "command \"%s\". The property name/value pairs " 680 "must uniquely\n\tidentify a resource. Note that " 681 "the curly braces ('{', '}') mean one\n\tor more " 682 "of whatever is between them."), 683 cmd_to_str(CMD_END)); 684 return (line); 685 case CMD_SET: 686 return (gettext("Sets property values.")); 687 case CMD_INFO: 688 return (gettext("Displays information about the " 689 "current configuration. If resource\n\ttype is " 690 "specified, displays only information about " 691 "resources of\n\tthe relevant type. If resource " 692 "id is specified, displays only\n\tinformation " 693 "about that resource.")); 694 case CMD_VERIFY: 695 return (gettext("Verifies current configuration " 696 "for correctness (some resource types\n\thave " 697 "required properties).")); 698 case CMD_COMMIT: 699 (void) snprintf(line, sizeof (line), 700 gettext("Commits current configuration. " 701 "Configuration must be committed to\n\tbe used by " 702 "%s. Until the configuration is committed, " 703 "changes \n\tcan be removed with the %s " 704 "command. This operation is\n\tattempted " 705 "automatically upon completion of a %s " 706 "session."), "zoneadm", cmd_to_str(CMD_REVERT), 707 "zonecfg"); 708 return (line); 709 case CMD_REVERT: 710 return (gettext("Reverts configuration back to the " 711 "last committed state. The -F flag\n\tcan be " 712 "used to force the action.")); 713 case CMD_CANCEL: 714 return (gettext("Cancels resource/property " 715 "specification.")); 716 case CMD_END: 717 return (gettext("Ends resource/property " 718 "specification.")); 719 } 720 /* NOTREACHED */ 721 return (NULL); 722 } 723 724 /* 725 * Called with verbose TRUE when help is explicitly requested, FALSE for 726 * unexpected errors. 727 */ 728 729 void 730 usage(bool verbose, uint_t flags) 731 { 732 FILE *fp = verbose ? stdout : stderr, *newfp; 733 bool need_to_close = FALSE; 734 char *pager; 735 int i; 736 737 /* don't page error output */ 738 if (verbose && interactive_mode) { 739 if ((pager = getenv("PAGER")) == NULL) 740 pager = PAGER; 741 if ((newfp = popen(pager, "w")) != NULL) { 742 need_to_close = TRUE; 743 fp = newfp; 744 } 745 } 746 if (flags & HELP_META) { 747 (void) fprintf(fp, gettext("More help is available for the " 748 "following:\n")); 749 (void) fprintf(fp, "\n\tcommands ('%s commands')\n", 750 cmd_to_str(CMD_HELP)); 751 (void) fprintf(fp, "\tsyntax ('%s syntax')\n", 752 cmd_to_str(CMD_HELP)); 753 (void) fprintf(fp, "\tusage ('%s usage')\n\n", 754 cmd_to_str(CMD_HELP)); 755 (void) fprintf(fp, gettext("You may also obtain help on any " 756 "command by typing '%s <command-name>.'\n"), 757 cmd_to_str(CMD_HELP)); 758 } 759 if (flags & HELP_RES_SCOPE) { 760 switch (resource_scope) { 761 case RT_FS: 762 (void) fprintf(fp, gettext("The '%s' resource scope is " 763 "used to configure a file-system.\n"), 764 rt_to_str(resource_scope)); 765 (void) fprintf(fp, gettext("Valid commands:\n")); 766 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 767 pt_to_str(PT_DIR), gettext("<path>")); 768 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 769 pt_to_str(PT_SPECIAL), gettext("<path>")); 770 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 771 pt_to_str(PT_RAW), gettext("<raw-device>")); 772 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 773 pt_to_str(PT_TYPE), gettext("<file-system type>")); 774 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD), 775 pt_to_str(PT_OPTIONS), 776 gettext("<file-system options>")); 777 (void) fprintf(fp, "\t%s %s %s\n", 778 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS), 779 gettext("<file-system options>")); 780 (void) fprintf(fp, gettext("Consult the file-system " 781 "specific manual page, such as mount_ufs(1M), " 782 "for\ndetails about file-system options. Note " 783 "that any file-system options with an\nembedded " 784 "'=' character must be enclosed in double quotes, " 785 /*CSTYLED*/ 786 "such as \"%s=5\".\n"), MNTOPT_RETRY); 787 break; 788 case RT_IPD: 789 (void) fprintf(fp, gettext("The '%s' resource scope is " 790 "used to configure a directory\ninherited from the " 791 "global zone into a non-global zone in read-only " 792 "mode.\n"), rt_to_str(resource_scope)); 793 (void) fprintf(fp, gettext("Valid commands:\n")); 794 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 795 pt_to_str(PT_DIR), gettext("<path>")); 796 break; 797 case RT_NET: 798 (void) fprintf(fp, gettext("The '%s' resource scope is " 799 "used to configure a network interface.\n"), 800 rt_to_str(resource_scope)); 801 (void) fprintf(fp, gettext("Valid commands:\n")); 802 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 803 pt_to_str(PT_ADDRESS), gettext("<IP-address>")); 804 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 805 pt_to_str(PT_PHYSICAL), gettext("<interface>")); 806 (void) fprintf(fp, gettext("See ifconfig(1M) for " 807 "details of the <interface> string.\n")); 808 break; 809 case RT_DEVICE: 810 (void) fprintf(fp, gettext("The '%s' resource scope is " 811 "used to configure a device node.\n"), 812 rt_to_str(resource_scope)); 813 (void) fprintf(fp, gettext("Valid commands:\n")); 814 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 815 pt_to_str(PT_MATCH), gettext("<device-path>")); 816 break; 817 case RT_RCTL: 818 (void) fprintf(fp, gettext("The '%s' resource scope is " 819 "used to configure a resource control.\n"), 820 rt_to_str(resource_scope)); 821 (void) fprintf(fp, gettext("Valid commands:\n")); 822 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 823 pt_to_str(PT_NAME), gettext("<string>")); 824 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 825 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 826 pt_to_str(PT_PRIV), gettext("<priv-value>"), 827 pt_to_str(PT_LIMIT), gettext("<number>"), 828 pt_to_str(PT_ACTION), gettext("<action-value>")); 829 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 830 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE), 831 pt_to_str(PT_PRIV), gettext("<priv-value>"), 832 pt_to_str(PT_LIMIT), gettext("<number>"), 833 pt_to_str(PT_ACTION), gettext("<action-value>")); 834 (void) fprintf(fp, "%s\n\t%s := privileged\n" 835 "\t%s := none | deny\n", gettext("Where"), 836 gettext("<priv-value>"), gettext("<action-value>")); 837 break; 838 case RT_ATTR: 839 (void) fprintf(fp, gettext("The '%s' resource scope is " 840 "used to configure a generic attribute.\n"), 841 rt_to_str(resource_scope)); 842 (void) fprintf(fp, gettext("Valid commands:\n")); 843 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 844 pt_to_str(PT_NAME), gettext("<name>")); 845 (void) fprintf(fp, "\t%s %s=boolean\n", 846 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 847 (void) fprintf(fp, "\t%s %s=true | false\n", 848 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE)); 849 (void) fprintf(fp, gettext("or\n")); 850 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET), 851 pt_to_str(PT_TYPE)); 852 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 853 pt_to_str(PT_VALUE), gettext("<integer>")); 854 (void) fprintf(fp, gettext("or\n")); 855 (void) fprintf(fp, "\t%s %s=string\n", 856 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 857 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 858 pt_to_str(PT_VALUE), gettext("<string>")); 859 (void) fprintf(fp, gettext("or\n")); 860 (void) fprintf(fp, "\t%s %s=uint\n", 861 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 862 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 863 pt_to_str(PT_VALUE), gettext("<unsigned integer>")); 864 break; 865 case RT_DATASET: 866 (void) fprintf(fp, gettext("The '%s' resource scope is " 867 "used to export ZFS datasets.\n"), 868 rt_to_str(resource_scope)); 869 (void) fprintf(fp, gettext("Valid commands:\n")); 870 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 871 pt_to_str(PT_NAME), gettext("<name>")); 872 break; 873 } 874 (void) fprintf(fp, gettext("And from any resource scope, you " 875 "can:\n")); 876 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END), 877 gettext("(to conclude this operation)")); 878 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL), 879 gettext("(to cancel this operation)")); 880 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT), 881 gettext("(to exit the zonecfg utility)")); 882 } 883 if (flags & HELP_USAGE) { 884 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"), 885 execname, cmd_to_str(CMD_HELP)); 886 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n", 887 execname, gettext("interactive")); 888 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname); 889 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n", 890 execname); 891 } 892 if (flags & HELP_SUBCMDS) { 893 (void) fprintf(fp, "%s:\n\n", gettext("Commands")); 894 for (i = 0; i <= CMD_MAX; i++) { 895 (void) fprintf(fp, "%s\n", helptab[i].short_usage); 896 if (verbose) 897 (void) fprintf(fp, "\t%s\n\n", long_help(i)); 898 } 899 } 900 if (flags & HELP_SYNTAX) { 901 if (!verbose) 902 (void) fprintf(fp, "\n"); 903 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n"); 904 (void) fprintf(fp, gettext("\t(except the reserved words " 905 "'%s' and anything starting with '%s')\n"), "global", 906 "SUNW"); 907 (void) fprintf(fp, 908 gettext("\tName must be less than %d characters.\n"), 909 ZONENAME_MAX); 910 if (verbose) 911 (void) fprintf(fp, "\n"); 912 } 913 if (flags & HELP_NETADDR) { 914 (void) fprintf(fp, gettext("\n<net-addr> :=")); 915 (void) fprintf(fp, 916 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n")); 917 (void) fprintf(fp, 918 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n")); 919 (void) fprintf(fp, 920 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n")); 921 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and " 922 "IPv6 address syntax.\n")); 923 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n")); 924 (void) fprintf(fp, 925 gettext("<IPv6-prefix-length> := [0-128]\n")); 926 (void) fprintf(fp, 927 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n")); 928 } 929 if (flags & HELP_RESOURCES) { 930 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t" 931 "%s\n\n", 932 gettext("resource type"), rt_to_str(RT_FS), 933 rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE), 934 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR), 935 rt_to_str(RT_DATASET)); 936 } 937 if (flags & HELP_PROPS) { 938 (void) fprintf(fp, gettext("For resource type ... there are " 939 "property types ...:\n")); 940 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 941 pt_to_str(PT_ZONENAME)); 942 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 943 pt_to_str(PT_ZONEPATH)); 944 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 945 pt_to_str(PT_BRAND)); 946 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 947 pt_to_str(PT_AUTOBOOT)); 948 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 949 pt_to_str(PT_BOOTARGS)); 950 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 951 pt_to_str(PT_POOL)); 952 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 953 pt_to_str(PT_LIMITPRIV)); 954 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s\n", rt_to_str(RT_FS), 955 pt_to_str(PT_DIR), pt_to_str(PT_SPECIAL), 956 pt_to_str(PT_RAW), pt_to_str(PT_TYPE), 957 pt_to_str(PT_OPTIONS)); 958 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_IPD), 959 pt_to_str(PT_DIR)); 960 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_NET), 961 pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL)); 962 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE), 963 pt_to_str(PT_MATCH)); 964 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL), 965 pt_to_str(PT_NAME), pt_to_str(PT_VALUE)); 966 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR), 967 pt_to_str(PT_NAME), pt_to_str(PT_TYPE), 968 pt_to_str(PT_VALUE)); 969 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET), 970 pt_to_str(PT_NAME)); 971 } 972 if (need_to_close) 973 (void) pclose(fp); 974 } 975 976 /* PRINTFLIKE1 */ 977 static void 978 zerr(const char *fmt, ...) 979 { 980 va_list alist; 981 static int last_lineno; 982 983 /* lex_lineno has already been incremented in the lexer; compensate */ 984 if (cmd_file_mode && lex_lineno > last_lineno) { 985 if (strcmp(cmd_file_name, "-") == 0) 986 (void) fprintf(stderr, gettext("On line %d:\n"), 987 lex_lineno - 1); 988 else 989 (void) fprintf(stderr, gettext("On line %d of %s:\n"), 990 lex_lineno - 1, cmd_file_name); 991 last_lineno = lex_lineno; 992 } 993 va_start(alist, fmt); 994 (void) vfprintf(stderr, fmt, alist); 995 (void) fprintf(stderr, "\n"); 996 va_end(alist); 997 } 998 999 static void 1000 zone_perror(char *prefix, int err, bool set_saw) 1001 { 1002 zerr("%s: %s", prefix, zonecfg_strerror(err)); 1003 if (set_saw) 1004 saw_error = TRUE; 1005 } 1006 1007 /* 1008 * zone_perror() expects a single string, but for remove and select 1009 * we have both the command and the resource type, so this wrapper 1010 * function serves the same purpose in a slightly different way. 1011 */ 1012 1013 static void 1014 z_cmd_rt_perror(int cmd_num, int res_num, int err, bool set_saw) 1015 { 1016 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num), 1017 zonecfg_strerror(err)); 1018 if (set_saw) 1019 saw_error = TRUE; 1020 } 1021 1022 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */ 1023 static int 1024 initialize(bool handle_expected) 1025 { 1026 int err; 1027 char brandname[MAXNAMELEN]; 1028 1029 if (zonecfg_check_handle(handle) != Z_OK) { 1030 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) { 1031 got_handle = TRUE; 1032 if (zonecfg_get_brand(handle, brandname, 1033 sizeof (brandname)) != Z_OK) { 1034 zerr("Zone %s is inconsistent: missing " 1035 "brand attribute", zone); 1036 exit(Z_ERR); 1037 } 1038 if ((brand = brand_open(brandname)) == NULL) { 1039 zerr("Zone %s uses non-existent brand \"%s\"." 1040 " Unable to continue", zone, brandname); 1041 exit(Z_ERR); 1042 } 1043 } else { 1044 zone_perror(zone, err, handle_expected || got_handle); 1045 if (err == Z_NO_ZONE && !got_handle && 1046 interactive_mode && !read_only_mode) 1047 (void) printf(gettext("Use '%s' to begin " 1048 "configuring a new zone.\n"), 1049 cmd_to_str(CMD_CREATE)); 1050 return (err); 1051 } 1052 } 1053 return (Z_OK); 1054 } 1055 1056 static bool 1057 state_atleast(zone_state_t state) 1058 { 1059 zone_state_t state_num; 1060 int err; 1061 1062 if ((err = zone_get_state(zone, &state_num)) != Z_OK) { 1063 /* all states are greater than "non-existent" */ 1064 if (err == Z_NO_ZONE) 1065 return (B_FALSE); 1066 zerr(gettext("Unexpectedly failed to determine state " 1067 "of zone %s: %s"), zone, zonecfg_strerror(err)); 1068 exit(Z_ERR); 1069 } 1070 return (state_num >= state); 1071 } 1072 1073 /* 1074 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc. 1075 */ 1076 1077 void 1078 short_usage(int command) 1079 { 1080 /* lex_lineno has already been incremented in the lexer; compensate */ 1081 if (cmd_file_mode) { 1082 if (strcmp(cmd_file_name, "-") == 0) 1083 (void) fprintf(stderr, 1084 gettext("syntax error on line %d\n"), 1085 lex_lineno - 1); 1086 else 1087 (void) fprintf(stderr, 1088 gettext("syntax error on line %d of %s\n"), 1089 lex_lineno - 1, cmd_file_name); 1090 } 1091 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"), 1092 helptab[command].short_usage); 1093 saw_error = TRUE; 1094 } 1095 1096 /* 1097 * long_usage() is for bad semantics: e.g., wrong property type for a given 1098 * resource type. It is also used by longer_usage() below. 1099 */ 1100 1101 void 1102 long_usage(uint_t cmd_num, bool set_saw) 1103 { 1104 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"), 1105 helptab[cmd_num].short_usage); 1106 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num)); 1107 if (set_saw) 1108 saw_error = TRUE; 1109 } 1110 1111 /* 1112 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also 1113 * any extra usage() flags as appropriate for whatever command. 1114 */ 1115 1116 void 1117 longer_usage(uint_t cmd_num) 1118 { 1119 long_usage(cmd_num, FALSE); 1120 if (helptab[cmd_num].flags != 0) { 1121 (void) printf("\n"); 1122 usage(TRUE, helptab[cmd_num].flags); 1123 } 1124 } 1125 1126 /* 1127 * scope_usage() is simply used when a command is called from the wrong scope. 1128 */ 1129 1130 static void 1131 scope_usage(uint_t cmd_num) 1132 { 1133 zerr(gettext("The %s command only makes sense in the %s scope."), 1134 cmd_to_str(cmd_num), 1135 global_scope ? gettext("resource") : gettext("global")); 1136 saw_error = TRUE; 1137 } 1138 1139 /* 1140 * On input, TRUE => yes, FALSE => no. 1141 * On return, TRUE => 1, FALSE => no, could not ask => -1. 1142 */ 1143 1144 static int 1145 ask_yesno(bool default_answer, const char *question) 1146 { 1147 char line[64]; /* should be enough to answer yes or no */ 1148 1149 if (!ok_to_prompt) { 1150 saw_error = TRUE; 1151 return (-1); 1152 } 1153 for (;;) { 1154 if (printf("%s (%s)? ", question, 1155 default_answer ? "[y]/n" : "y/[n]") < 0) 1156 return (-1); 1157 if (fgets(line, sizeof (line), stdin) == NULL) 1158 return (-1); 1159 1160 if (line[0] == '\n') 1161 return (default_answer ? 1 : 0); 1162 if (tolower(line[0]) == 'y') 1163 return (1); 1164 if (tolower(line[0]) == 'n') 1165 return (0); 1166 } 1167 } 1168 1169 /* 1170 * Prints warning if zone already exists. 1171 * In interactive mode, prompts if we should continue anyway and returns Z_OK 1172 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR. 1173 * 1174 * Note that if a zone exists and its state is >= INSTALLED, an error message 1175 * will be printed and this function will return Z_ERR regardless of mode. 1176 */ 1177 1178 static int 1179 check_if_zone_already_exists(bool force) 1180 { 1181 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 1182 zone_dochandle_t tmphandle; 1183 int res, answer; 1184 1185 if ((tmphandle = zonecfg_init_handle()) == NULL) { 1186 zone_perror(execname, Z_NOMEM, TRUE); 1187 exit(Z_ERR); 1188 } 1189 res = zonecfg_get_handle(zone, tmphandle); 1190 zonecfg_fini_handle(tmphandle); 1191 if (res != Z_OK) 1192 return (Z_OK); 1193 1194 if (state_atleast(ZONE_STATE_INSTALLED)) { 1195 zerr(gettext("Zone %s already installed; %s not allowed."), 1196 zone, cmd_to_str(CMD_CREATE)); 1197 return (Z_ERR); 1198 } 1199 1200 if (force) { 1201 (void) printf(gettext("Zone %s already exists; overwriting.\n"), 1202 zone); 1203 return (Z_OK); 1204 } 1205 (void) snprintf(line, sizeof (line), 1206 gettext("Zone %s already exists; %s anyway"), zone, 1207 cmd_to_str(CMD_CREATE)); 1208 if ((answer = ask_yesno(FALSE, line)) == -1) { 1209 zerr(gettext("Zone exists, input not from terminal and -F not " 1210 "specified:\n%s command ignored, exiting."), 1211 cmd_to_str(CMD_CREATE)); 1212 exit(Z_ERR); 1213 } 1214 return (answer == 1 ? Z_OK : Z_ERR); 1215 } 1216 1217 static bool 1218 zone_is_read_only(int cmd_num) 1219 { 1220 if (strncmp(zone, "SUNW", 4) == 0) { 1221 zerr(gettext("%s: zones beginning with SUNW are read-only."), 1222 zone); 1223 saw_error = TRUE; 1224 return (TRUE); 1225 } 1226 if (read_only_mode) { 1227 zerr(gettext("%s: cannot %s in read-only mode."), zone, 1228 cmd_to_str(cmd_num)); 1229 saw_error = TRUE; 1230 return (TRUE); 1231 } 1232 return (FALSE); 1233 } 1234 1235 /* 1236 * Create a new configuration. 1237 */ 1238 void 1239 create_func(cmd_t *cmd) 1240 { 1241 int err, arg; 1242 char zone_template[ZONENAME_MAX]; 1243 char attach_path[MAXPATHLEN]; 1244 zone_dochandle_t tmphandle; 1245 bool force = FALSE; 1246 bool attach = FALSE; 1247 1248 assert(cmd != NULL); 1249 1250 /* This is the default if no arguments are given. */ 1251 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template)); 1252 1253 optind = 0; 1254 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:")) 1255 != EOF) { 1256 switch (arg) { 1257 case '?': 1258 if (optopt == '?') 1259 longer_usage(CMD_CREATE); 1260 else 1261 short_usage(CMD_CREATE); 1262 return; 1263 case 'a': 1264 (void) strlcpy(attach_path, optarg, 1265 sizeof (attach_path)); 1266 attach = TRUE; 1267 break; 1268 case 'b': 1269 (void) strlcpy(zone_template, "SUNWblank", 1270 sizeof (zone_template)); 1271 break; 1272 case 'F': 1273 force = TRUE; 1274 break; 1275 case 't': 1276 (void) strlcpy(zone_template, optarg, 1277 sizeof (zone_template)); 1278 break; 1279 default: 1280 short_usage(CMD_CREATE); 1281 return; 1282 } 1283 } 1284 if (optind != cmd->cmd_argc) { 1285 short_usage(CMD_CREATE); 1286 return; 1287 } 1288 1289 if (zone_is_read_only(CMD_CREATE)) 1290 return; 1291 1292 if (check_if_zone_already_exists(force) != Z_OK) 1293 return; 1294 1295 /* 1296 * Get a temporary handle first. If that fails, the old handle 1297 * will not be lost. Then finish whichever one we don't need, 1298 * to avoid leaks. Then get the handle for zone_template, and 1299 * set the name to zone: this "copy, rename" method is how 1300 * create -[b|t] works. 1301 */ 1302 if ((tmphandle = zonecfg_init_handle()) == NULL) { 1303 zone_perror(execname, Z_NOMEM, TRUE); 1304 exit(Z_ERR); 1305 } 1306 1307 if (attach) 1308 err = zonecfg_get_attach_handle(attach_path, zone, B_FALSE, 1309 tmphandle); 1310 else 1311 err = zonecfg_get_template_handle(zone_template, zone, 1312 tmphandle); 1313 1314 if (err != Z_OK) { 1315 zonecfg_fini_handle(tmphandle); 1316 if (attach && err == Z_NO_ZONE) 1317 (void) fprintf(stderr, gettext("invalid path to " 1318 "detached zone\n")); 1319 else if (attach && err == Z_INVALID_DOCUMENT) 1320 (void) fprintf(stderr, gettext("Cannot attach to an " 1321 "earlier release of the operating system\n")); 1322 else 1323 zone_perror(zone_template, err, TRUE); 1324 return; 1325 } 1326 1327 need_to_commit = TRUE; 1328 zonecfg_fini_handle(handle); 1329 handle = tmphandle; 1330 got_handle = TRUE; 1331 } 1332 1333 /* 1334 * This malloc()'s memory, which must be freed by the caller. 1335 */ 1336 static char * 1337 quoteit(char *instr) 1338 { 1339 char *outstr; 1340 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */ 1341 1342 if ((outstr = malloc(outstrsize)) == NULL) { 1343 zone_perror(zone, Z_NOMEM, FALSE); 1344 exit(Z_ERR); 1345 } 1346 if (strchr(instr, ' ') == NULL) { 1347 (void) strlcpy(outstr, instr, outstrsize); 1348 return (outstr); 1349 } 1350 (void) snprintf(outstr, outstrsize, "\"%s\"", instr); 1351 return (outstr); 1352 } 1353 1354 static void 1355 export_prop(FILE *of, int prop_num, char *prop_id) 1356 { 1357 char *quote_str; 1358 1359 if (strlen(prop_id) == 0) 1360 return; 1361 quote_str = quoteit(prop_id); 1362 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1363 pt_to_str(prop_num), quote_str); 1364 free(quote_str); 1365 } 1366 1367 void 1368 export_func(cmd_t *cmd) 1369 { 1370 struct zone_nwiftab nwiftab; 1371 struct zone_fstab fstab; 1372 struct zone_devtab devtab; 1373 struct zone_attrtab attrtab; 1374 struct zone_rctltab rctltab; 1375 struct zone_dstab dstab; 1376 struct zone_rctlvaltab *valptr; 1377 int err, arg; 1378 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN]; 1379 char bootargs[BOOTARGS_MAX]; 1380 char brand[MAXNAMELEN]; 1381 char *limitpriv; 1382 FILE *of; 1383 boolean_t autoboot; 1384 bool need_to_close = FALSE; 1385 1386 assert(cmd != NULL); 1387 1388 outfile[0] = '\0'; 1389 optind = 0; 1390 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) { 1391 switch (arg) { 1392 case '?': 1393 if (optopt == '?') 1394 longer_usage(CMD_EXPORT); 1395 else 1396 short_usage(CMD_EXPORT); 1397 return; 1398 case 'f': 1399 (void) strlcpy(outfile, optarg, sizeof (outfile)); 1400 break; 1401 default: 1402 short_usage(CMD_EXPORT); 1403 return; 1404 } 1405 } 1406 if (optind != cmd->cmd_argc) { 1407 short_usage(CMD_EXPORT); 1408 return; 1409 } 1410 if (strlen(outfile) == 0) { 1411 of = stdout; 1412 } else { 1413 if ((of = fopen(outfile, "w")) == NULL) { 1414 zerr(gettext("opening file %s: %s"), 1415 outfile, strerror(errno)); 1416 goto done; 1417 } 1418 setbuf(of, NULL); 1419 need_to_close = TRUE; 1420 } 1421 1422 if ((err = initialize(TRUE)) != Z_OK) 1423 goto done; 1424 1425 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE)); 1426 1427 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK && 1428 strlen(zonepath) > 0) 1429 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1430 pt_to_str(PT_ZONEPATH), zonepath); 1431 1432 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) && 1433 (strcmp(brand, NATIVE_BRAND_NAME) != 0)) 1434 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1435 pt_to_str(PT_BRAND), brand); 1436 1437 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK) 1438 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1439 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false"); 1440 1441 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK && 1442 strlen(bootargs) > 0) { 1443 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1444 pt_to_str(PT_BOOTARGS), bootargs); 1445 } 1446 1447 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 1448 strlen(pool) > 0) 1449 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1450 pt_to_str(PT_POOL), pool); 1451 1452 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK && 1453 strlen(limitpriv) > 0) { 1454 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1455 pt_to_str(PT_LIMITPRIV), limitpriv); 1456 free(limitpriv); 1457 } 1458 1459 1460 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 1461 zone_perror(zone, err, FALSE); 1462 goto done; 1463 } 1464 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 1465 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1466 rt_to_str(RT_IPD)); 1467 export_prop(of, PT_DIR, fstab.zone_fs_dir); 1468 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1469 } 1470 (void) zonecfg_endipdent(handle); 1471 1472 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 1473 zone_perror(zone, err, FALSE); 1474 goto done; 1475 } 1476 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 1477 zone_fsopt_t *optptr; 1478 1479 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1480 rt_to_str(RT_FS)); 1481 export_prop(of, PT_DIR, fstab.zone_fs_dir); 1482 export_prop(of, PT_SPECIAL, fstab.zone_fs_special); 1483 export_prop(of, PT_RAW, fstab.zone_fs_raw); 1484 export_prop(of, PT_TYPE, fstab.zone_fs_type); 1485 for (optptr = fstab.zone_fs_options; optptr != NULL; 1486 optptr = optptr->zone_fsopt_next) { 1487 /* 1488 * Simple property values with embedded equal signs 1489 * need to be quoted to prevent the lexer from 1490 * mis-parsing them as complex name=value pairs. 1491 */ 1492 if (strchr(optptr->zone_fsopt_opt, '=')) 1493 (void) fprintf(of, "%s %s \"%s\"\n", 1494 cmd_to_str(CMD_ADD), 1495 pt_to_str(PT_OPTIONS), 1496 optptr->zone_fsopt_opt); 1497 else 1498 (void) fprintf(of, "%s %s %s\n", 1499 cmd_to_str(CMD_ADD), 1500 pt_to_str(PT_OPTIONS), 1501 optptr->zone_fsopt_opt); 1502 } 1503 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1504 zonecfg_free_fs_option_list(fstab.zone_fs_options); 1505 } 1506 (void) zonecfg_endfsent(handle); 1507 1508 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 1509 zone_perror(zone, err, FALSE); 1510 goto done; 1511 } 1512 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 1513 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1514 rt_to_str(RT_NET)); 1515 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address); 1516 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical); 1517 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1518 } 1519 (void) zonecfg_endnwifent(handle); 1520 1521 if ((err = zonecfg_setdevent(handle)) != Z_OK) { 1522 zone_perror(zone, err, FALSE); 1523 goto done; 1524 } 1525 while (zonecfg_getdevent(handle, &devtab) == Z_OK) { 1526 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1527 rt_to_str(RT_DEVICE)); 1528 export_prop(of, PT_MATCH, devtab.zone_dev_match); 1529 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1530 } 1531 (void) zonecfg_enddevent(handle); 1532 1533 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 1534 zone_perror(zone, err, FALSE); 1535 goto done; 1536 } 1537 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 1538 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD)); 1539 export_prop(of, PT_NAME, rctltab.zone_rctl_name); 1540 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL; 1541 valptr = valptr->zone_rctlval_next) { 1542 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n", 1543 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 1544 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 1545 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 1546 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 1547 } 1548 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1549 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 1550 } 1551 (void) zonecfg_endrctlent(handle); 1552 1553 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 1554 zone_perror(zone, err, FALSE); 1555 goto done; 1556 } 1557 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 1558 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1559 rt_to_str(RT_ATTR)); 1560 export_prop(of, PT_NAME, attrtab.zone_attr_name); 1561 export_prop(of, PT_TYPE, attrtab.zone_attr_type); 1562 export_prop(of, PT_VALUE, attrtab.zone_attr_value); 1563 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1564 } 1565 (void) zonecfg_endattrent(handle); 1566 1567 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 1568 zone_perror(zone, err, FALSE); 1569 goto done; 1570 } 1571 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 1572 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1573 rt_to_str(RT_DATASET)); 1574 export_prop(of, PT_NAME, dstab.zone_dataset_name); 1575 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1576 } 1577 (void) zonecfg_enddsent(handle); 1578 1579 done: 1580 if (need_to_close) 1581 (void) fclose(of); 1582 } 1583 1584 void 1585 exit_func(cmd_t *cmd) 1586 { 1587 int arg, answer; 1588 1589 optind = 0; 1590 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 1591 switch (arg) { 1592 case '?': 1593 longer_usage(CMD_EXIT); 1594 return; 1595 case 'F': 1596 force_exit = TRUE; 1597 break; 1598 default: 1599 short_usage(CMD_EXIT); 1600 return; 1601 } 1602 } 1603 if (optind < cmd->cmd_argc) { 1604 short_usage(CMD_EXIT); 1605 return; 1606 } 1607 1608 if (global_scope || force_exit) { 1609 time_to_exit = TRUE; 1610 return; 1611 } 1612 1613 answer = ask_yesno(FALSE, "Resource incomplete; really quit"); 1614 if (answer == -1) { 1615 zerr(gettext("Resource incomplete, input " 1616 "not from terminal and -F not specified:\n%s command " 1617 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT)); 1618 exit(Z_ERR); 1619 } else if (answer == 1) { 1620 time_to_exit = TRUE; 1621 } 1622 /* (answer == 0) => just return */ 1623 } 1624 1625 static int 1626 validate_zonepath_syntax(char *path) 1627 { 1628 if (path[0] != '/') { 1629 zerr(gettext("%s is not an absolute path."), path); 1630 return (Z_ERR); 1631 } 1632 if (strcmp(path, "/") == 0) { 1633 zerr(gettext("/ is not allowed as a %s."), 1634 pt_to_str(PT_ZONEPATH)); 1635 return (Z_ERR); 1636 } 1637 return (Z_OK); 1638 } 1639 1640 static void 1641 add_resource(cmd_t *cmd) 1642 { 1643 int type; 1644 1645 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 1646 long_usage(CMD_ADD, TRUE); 1647 goto bad; 1648 } 1649 1650 switch (type) { 1651 case RT_FS: 1652 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 1653 return; 1654 case RT_IPD: 1655 if (state_atleast(ZONE_STATE_INSTALLED)) { 1656 zerr(gettext("Zone %s already installed; %s %s not " 1657 "allowed."), zone, cmd_to_str(CMD_ADD), 1658 rt_to_str(RT_IPD)); 1659 goto bad; 1660 } 1661 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 1662 return; 1663 case RT_NET: 1664 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 1665 return; 1666 case RT_DEVICE: 1667 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 1668 return; 1669 case RT_RCTL: 1670 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 1671 return; 1672 case RT_ATTR: 1673 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 1674 return; 1675 case RT_DATASET: 1676 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 1677 return; 1678 default: 1679 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 1680 long_usage(CMD_ADD, TRUE); 1681 usage(FALSE, HELP_RESOURCES); 1682 } 1683 bad: 1684 global_scope = TRUE; 1685 end_op = -1; 1686 } 1687 1688 static void 1689 do_complex_rctl_val(complex_property_ptr_t cp) 1690 { 1691 struct zone_rctlvaltab *rctlvaltab; 1692 complex_property_ptr_t cx; 1693 bool seen_priv = FALSE, seen_limit = FALSE, seen_action = FALSE; 1694 rctlblk_t *rctlblk; 1695 int err; 1696 1697 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 1698 zone_perror(zone, Z_NOMEM, TRUE); 1699 exit(Z_ERR); 1700 } 1701 for (cx = cp; cx != NULL; cx = cx->cp_next) { 1702 switch (cx->cp_type) { 1703 case PT_PRIV: 1704 if (seen_priv) { 1705 zerr(gettext("%s already specified"), 1706 pt_to_str(PT_PRIV)); 1707 goto bad; 1708 } 1709 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 1710 cx->cp_value, 1711 sizeof (rctlvaltab->zone_rctlval_priv)); 1712 seen_priv = TRUE; 1713 break; 1714 case PT_LIMIT: 1715 if (seen_limit) { 1716 zerr(gettext("%s already specified"), 1717 pt_to_str(PT_LIMIT)); 1718 goto bad; 1719 } 1720 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 1721 cx->cp_value, 1722 sizeof (rctlvaltab->zone_rctlval_limit)); 1723 seen_limit = TRUE; 1724 break; 1725 case PT_ACTION: 1726 if (seen_action) { 1727 zerr(gettext("%s already specified"), 1728 pt_to_str(PT_ACTION)); 1729 goto bad; 1730 } 1731 (void) strlcpy(rctlvaltab->zone_rctlval_action, 1732 cx->cp_value, 1733 sizeof (rctlvaltab->zone_rctlval_action)); 1734 seen_action = TRUE; 1735 break; 1736 default: 1737 zone_perror(pt_to_str(PT_VALUE), 1738 Z_NO_PROPERTY_TYPE, TRUE); 1739 long_usage(CMD_ADD, TRUE); 1740 usage(FALSE, HELP_PROPS); 1741 zonecfg_free_rctl_value_list(rctlvaltab); 1742 return; 1743 } 1744 } 1745 if (!seen_priv) 1746 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV)); 1747 if (!seen_limit) 1748 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT)); 1749 if (!seen_action) 1750 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION)); 1751 if (!seen_priv || !seen_limit || !seen_action) 1752 goto bad; 1753 rctlvaltab->zone_rctlval_next = NULL; 1754 rctlblk = alloca(rctlblk_size()); 1755 /* 1756 * Make sure the rctl value looks roughly correct; we won't know if 1757 * it's truly OK until we verify the configuration on the target 1758 * system. 1759 */ 1760 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK || 1761 !zonecfg_valid_rctlblk(rctlblk)) { 1762 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL), 1763 pt_to_str(PT_VALUE)); 1764 goto bad; 1765 } 1766 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab); 1767 if (err != Z_OK) 1768 zone_perror(pt_to_str(PT_VALUE), err, TRUE); 1769 return; 1770 1771 bad: 1772 zonecfg_free_rctl_value_list(rctlvaltab); 1773 } 1774 1775 static void 1776 add_property(cmd_t *cmd) 1777 { 1778 char *prop_id; 1779 int err, res_type, prop_type; 1780 property_value_ptr_t pp; 1781 list_property_ptr_t l; 1782 1783 res_type = resource_scope; 1784 prop_type = cmd->cmd_prop_name[0]; 1785 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 1786 long_usage(CMD_ADD, TRUE); 1787 return; 1788 } 1789 1790 if (cmd->cmd_prop_nv_pairs != 1) { 1791 long_usage(CMD_ADD, TRUE); 1792 return; 1793 } 1794 1795 if (initialize(TRUE) != Z_OK) 1796 return; 1797 1798 switch (res_type) { 1799 case RT_FS: 1800 if (prop_type != PT_OPTIONS) { 1801 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 1802 TRUE); 1803 long_usage(CMD_ADD, TRUE); 1804 usage(FALSE, HELP_PROPS); 1805 return; 1806 } 1807 pp = cmd->cmd_property_ptr[0]; 1808 if (pp->pv_type != PROP_VAL_SIMPLE && 1809 pp->pv_type != PROP_VAL_LIST) { 1810 zerr(gettext("A %s or %s value was expected here."), 1811 pvt_to_str(PROP_VAL_SIMPLE), 1812 pvt_to_str(PROP_VAL_LIST)); 1813 saw_error = TRUE; 1814 return; 1815 } 1816 if (pp->pv_type == PROP_VAL_SIMPLE) { 1817 if (pp->pv_simple == NULL) { 1818 long_usage(CMD_ADD, TRUE); 1819 return; 1820 } 1821 prop_id = pp->pv_simple; 1822 err = zonecfg_add_fs_option(&in_progress_fstab, 1823 prop_id); 1824 if (err != Z_OK) 1825 zone_perror(pt_to_str(prop_type), err, TRUE); 1826 } else { 1827 list_property_ptr_t list; 1828 1829 for (list = pp->pv_list; list != NULL; 1830 list = list->lp_next) { 1831 prop_id = list->lp_simple; 1832 if (prop_id == NULL) 1833 break; 1834 err = zonecfg_add_fs_option( 1835 &in_progress_fstab, prop_id); 1836 if (err != Z_OK) 1837 zone_perror(pt_to_str(prop_type), err, 1838 TRUE); 1839 } 1840 } 1841 return; 1842 case RT_RCTL: 1843 if (prop_type != PT_VALUE) { 1844 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 1845 TRUE); 1846 long_usage(CMD_ADD, TRUE); 1847 usage(FALSE, HELP_PROPS); 1848 return; 1849 } 1850 pp = cmd->cmd_property_ptr[0]; 1851 if (pp->pv_type != PROP_VAL_COMPLEX && 1852 pp->pv_type != PROP_VAL_LIST) { 1853 zerr(gettext("A %s or %s value was expected here."), 1854 pvt_to_str(PROP_VAL_COMPLEX), 1855 pvt_to_str(PROP_VAL_LIST)); 1856 saw_error = TRUE; 1857 return; 1858 } 1859 if (pp->pv_type == PROP_VAL_COMPLEX) { 1860 do_complex_rctl_val(pp->pv_complex); 1861 return; 1862 } 1863 for (l = pp->pv_list; l != NULL; l = l->lp_next) 1864 do_complex_rctl_val(l->lp_complex); 1865 return; 1866 default: 1867 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 1868 long_usage(CMD_ADD, TRUE); 1869 usage(FALSE, HELP_RESOURCES); 1870 return; 1871 } 1872 } 1873 1874 void 1875 add_func(cmd_t *cmd) 1876 { 1877 int arg; 1878 1879 assert(cmd != NULL); 1880 1881 optind = 0; 1882 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 1883 switch (arg) { 1884 case '?': 1885 longer_usage(CMD_ADD); 1886 return; 1887 default: 1888 short_usage(CMD_ADD); 1889 return; 1890 } 1891 } 1892 if (optind != cmd->cmd_argc) { 1893 short_usage(CMD_ADD); 1894 return; 1895 } 1896 1897 if (zone_is_read_only(CMD_ADD)) 1898 return; 1899 1900 if (initialize(TRUE) != Z_OK) 1901 return; 1902 if (global_scope) { 1903 global_scope = FALSE; 1904 resource_scope = cmd->cmd_res_type; 1905 end_op = CMD_ADD; 1906 add_resource(cmd); 1907 } else 1908 add_property(cmd); 1909 } 1910 1911 /* 1912 * This routine has an unusual implementation, because it tries very 1913 * hard to succeed in the face of a variety of failure modes. 1914 * The most common and most vexing occurs when the index file and 1915 * the /etc/zones/<zonename.xml> file are not both present. In 1916 * this case, delete must eradicate as much of the zone state as is left 1917 * so that the user can later create a new zone with the same name. 1918 */ 1919 void 1920 delete_func(cmd_t *cmd) 1921 { 1922 int err, arg, answer; 1923 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 1924 bool force = FALSE; 1925 1926 optind = 0; 1927 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 1928 switch (arg) { 1929 case '?': 1930 longer_usage(CMD_DELETE); 1931 return; 1932 case 'F': 1933 force = TRUE; 1934 break; 1935 default: 1936 short_usage(CMD_DELETE); 1937 return; 1938 } 1939 } 1940 if (optind != cmd->cmd_argc) { 1941 short_usage(CMD_DELETE); 1942 return; 1943 } 1944 1945 if (zone_is_read_only(CMD_DELETE)) 1946 return; 1947 1948 if (!force) { 1949 /* 1950 * Initialize sets up the global called "handle" and warns the 1951 * user if the zone is not configured. In force mode, we don't 1952 * trust that evaluation, and hence skip it. (We don't need the 1953 * handle to be loaded anyway, since zonecfg_destroy is done by 1954 * zonename). However, we also have to take care to emulate the 1955 * messages spit out by initialize; see below. 1956 */ 1957 if (initialize(TRUE) != Z_OK) 1958 return; 1959 1960 (void) snprintf(line, sizeof (line), 1961 gettext("Are you sure you want to delete zone %s"), zone); 1962 if ((answer = ask_yesno(FALSE, line)) == -1) { 1963 zerr(gettext("Input not from terminal and -F not " 1964 "specified:\n%s command ignored, exiting."), 1965 cmd_to_str(CMD_DELETE)); 1966 exit(Z_ERR); 1967 } 1968 if (answer != 1) 1969 return; 1970 } 1971 1972 if ((err = zonecfg_destroy(zone, force)) != Z_OK) { 1973 if ((err == Z_BAD_ZONE_STATE) && !force) { 1974 zerr(gettext("Zone %s not in %s state; %s not " 1975 "allowed. Use -F to force %s."), 1976 zone, zone_state_str(ZONE_STATE_CONFIGURED), 1977 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE)); 1978 } else { 1979 zone_perror(zone, err, TRUE); 1980 } 1981 } 1982 need_to_commit = FALSE; 1983 1984 /* 1985 * Emulate initialize's messaging; if there wasn't a valid handle to 1986 * begin with, then user had typed delete (or delete -F) multiple 1987 * times. So we emit a message. 1988 * 1989 * We only do this in the 'force' case because normally, initialize() 1990 * takes care of this for us. 1991 */ 1992 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode) 1993 (void) printf(gettext("Use '%s' to begin " 1994 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE)); 1995 1996 /* 1997 * Time for a new handle: finish the old one off first 1998 * then get a new one properly to avoid leaks. 1999 */ 2000 if (got_handle) { 2001 zonecfg_fini_handle(handle); 2002 if ((handle = zonecfg_init_handle()) == NULL) { 2003 zone_perror(execname, Z_NOMEM, TRUE); 2004 exit(Z_ERR); 2005 } 2006 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) { 2007 /* If there was no zone before, that's OK */ 2008 if (err != Z_NO_ZONE) 2009 zone_perror(zone, err, TRUE); 2010 got_handle = FALSE; 2011 } 2012 } 2013 } 2014 2015 static int 2016 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, bool fill_in_only) 2017 { 2018 int err, i; 2019 property_value_ptr_t pp; 2020 2021 if ((err = initialize(TRUE)) != Z_OK) 2022 return (err); 2023 2024 bzero(fstab, sizeof (*fstab)); 2025 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2026 pp = cmd->cmd_property_ptr[i]; 2027 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2028 zerr(gettext("A simple value was expected here.")); 2029 saw_error = TRUE; 2030 return (Z_INSUFFICIENT_SPEC); 2031 } 2032 switch (cmd->cmd_prop_name[i]) { 2033 case PT_DIR: 2034 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 2035 sizeof (fstab->zone_fs_dir)); 2036 break; 2037 case PT_SPECIAL: 2038 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 2039 sizeof (fstab->zone_fs_special)); 2040 break; 2041 case PT_RAW: 2042 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 2043 sizeof (fstab->zone_fs_raw)); 2044 break; 2045 case PT_TYPE: 2046 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 2047 sizeof (fstab->zone_fs_type)); 2048 break; 2049 default: 2050 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2051 Z_NO_PROPERTY_TYPE, TRUE); 2052 return (Z_INSUFFICIENT_SPEC); 2053 } 2054 } 2055 if (fill_in_only) 2056 return (Z_OK); 2057 return (zonecfg_lookup_filesystem(handle, fstab)); 2058 } 2059 2060 static int 2061 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, bool fill_in_only) 2062 { 2063 int err, i; 2064 property_value_ptr_t pp; 2065 2066 if ((err = initialize(TRUE)) != Z_OK) 2067 return (err); 2068 2069 bzero(ipdtab, sizeof (*ipdtab)); 2070 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2071 pp = cmd->cmd_property_ptr[i]; 2072 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2073 zerr(gettext("A simple value was expected here.")); 2074 saw_error = TRUE; 2075 return (Z_INSUFFICIENT_SPEC); 2076 } 2077 switch (cmd->cmd_prop_name[i]) { 2078 case PT_DIR: 2079 (void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple, 2080 sizeof (ipdtab->zone_fs_dir)); 2081 break; 2082 default: 2083 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2084 Z_NO_PROPERTY_TYPE, TRUE); 2085 return (Z_INSUFFICIENT_SPEC); 2086 } 2087 } 2088 if (fill_in_only) 2089 return (Z_OK); 2090 return (zonecfg_lookup_ipd(handle, ipdtab)); 2091 } 2092 2093 static int 2094 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, bool fill_in_only) 2095 { 2096 int err, i; 2097 property_value_ptr_t pp; 2098 2099 if ((err = initialize(TRUE)) != Z_OK) 2100 return (err); 2101 2102 bzero(nwiftab, sizeof (*nwiftab)); 2103 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2104 pp = cmd->cmd_property_ptr[i]; 2105 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2106 zerr(gettext("A simple value was expected here.")); 2107 saw_error = TRUE; 2108 return (Z_INSUFFICIENT_SPEC); 2109 } 2110 switch (cmd->cmd_prop_name[i]) { 2111 case PT_ADDRESS: 2112 (void) strlcpy(nwiftab->zone_nwif_address, 2113 pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 2114 break; 2115 case PT_PHYSICAL: 2116 (void) strlcpy(nwiftab->zone_nwif_physical, 2117 pp->pv_simple, 2118 sizeof (nwiftab->zone_nwif_physical)); 2119 break; 2120 default: 2121 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2122 Z_NO_PROPERTY_TYPE, TRUE); 2123 return (Z_INSUFFICIENT_SPEC); 2124 } 2125 } 2126 if (fill_in_only) 2127 return (Z_OK); 2128 err = zonecfg_lookup_nwif(handle, nwiftab); 2129 return (err); 2130 } 2131 2132 static int 2133 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, bool fill_in_only) 2134 { 2135 int err, i; 2136 property_value_ptr_t pp; 2137 2138 if ((err = initialize(TRUE)) != Z_OK) 2139 return (err); 2140 2141 bzero(devtab, sizeof (*devtab)); 2142 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2143 pp = cmd->cmd_property_ptr[i]; 2144 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2145 zerr(gettext("A simple value was expected here.")); 2146 saw_error = TRUE; 2147 return (Z_INSUFFICIENT_SPEC); 2148 } 2149 switch (cmd->cmd_prop_name[i]) { 2150 case PT_MATCH: 2151 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2152 sizeof (devtab->zone_dev_match)); 2153 break; 2154 default: 2155 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2156 Z_NO_PROPERTY_TYPE, TRUE); 2157 return (Z_INSUFFICIENT_SPEC); 2158 } 2159 } 2160 if (fill_in_only) 2161 return (Z_OK); 2162 err = zonecfg_lookup_dev(handle, devtab); 2163 return (err); 2164 } 2165 2166 static int 2167 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, bool fill_in_only) 2168 { 2169 int err, i; 2170 property_value_ptr_t pp; 2171 2172 if ((err = initialize(TRUE)) != Z_OK) 2173 return (err); 2174 2175 bzero(rctltab, sizeof (*rctltab)); 2176 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2177 pp = cmd->cmd_property_ptr[i]; 2178 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2179 zerr(gettext("A simple value was expected here.")); 2180 saw_error = TRUE; 2181 return (Z_INSUFFICIENT_SPEC); 2182 } 2183 switch (cmd->cmd_prop_name[i]) { 2184 case PT_NAME: 2185 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2186 sizeof (rctltab->zone_rctl_name)); 2187 break; 2188 default: 2189 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2190 Z_NO_PROPERTY_TYPE, TRUE); 2191 return (Z_INSUFFICIENT_SPEC); 2192 } 2193 } 2194 if (fill_in_only) 2195 return (Z_OK); 2196 err = zonecfg_lookup_rctl(handle, rctltab); 2197 return (err); 2198 } 2199 2200 static int 2201 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, bool fill_in_only) 2202 { 2203 int err, i; 2204 property_value_ptr_t pp; 2205 2206 if ((err = initialize(TRUE)) != Z_OK) 2207 return (err); 2208 2209 bzero(attrtab, sizeof (*attrtab)); 2210 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2211 pp = cmd->cmd_property_ptr[i]; 2212 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2213 zerr(gettext("A simple value was expected here.")); 2214 saw_error = TRUE; 2215 return (Z_INSUFFICIENT_SPEC); 2216 } 2217 switch (cmd->cmd_prop_name[i]) { 2218 case PT_NAME: 2219 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2220 sizeof (attrtab->zone_attr_name)); 2221 break; 2222 case PT_TYPE: 2223 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2224 sizeof (attrtab->zone_attr_type)); 2225 break; 2226 case PT_VALUE: 2227 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2228 sizeof (attrtab->zone_attr_value)); 2229 break; 2230 default: 2231 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2232 Z_NO_PROPERTY_TYPE, TRUE); 2233 return (Z_INSUFFICIENT_SPEC); 2234 } 2235 } 2236 if (fill_in_only) 2237 return (Z_OK); 2238 err = zonecfg_lookup_attr(handle, attrtab); 2239 return (err); 2240 } 2241 2242 static int 2243 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, bool fill_in_only) 2244 { 2245 int err, i; 2246 property_value_ptr_t pp; 2247 2248 if ((err = initialize(TRUE)) != Z_OK) 2249 return (err); 2250 2251 dstab->zone_dataset_name[0] = '\0'; 2252 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2253 pp = cmd->cmd_property_ptr[i]; 2254 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2255 zerr(gettext("A simple value was expected here.")); 2256 saw_error = TRUE; 2257 return (Z_INSUFFICIENT_SPEC); 2258 } 2259 switch (cmd->cmd_prop_name[i]) { 2260 case PT_NAME: 2261 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2262 sizeof (dstab->zone_dataset_name)); 2263 break; 2264 default: 2265 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2266 Z_NO_PROPERTY_TYPE, TRUE); 2267 return (Z_INSUFFICIENT_SPEC); 2268 } 2269 } 2270 if (fill_in_only) 2271 return (Z_OK); 2272 return (zonecfg_lookup_ds(handle, dstab)); 2273 } 2274 2275 static void 2276 remove_resource(cmd_t *cmd) 2277 { 2278 int err, type; 2279 struct zone_fstab fstab; 2280 struct zone_nwiftab nwiftab; 2281 struct zone_devtab devtab; 2282 struct zone_attrtab attrtab; 2283 struct zone_rctltab rctltab; 2284 struct zone_dstab dstab; 2285 2286 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2287 long_usage(CMD_REMOVE, TRUE); 2288 return; 2289 } 2290 2291 if (initialize(TRUE) != Z_OK) 2292 return; 2293 2294 switch (type) { 2295 case RT_FS: 2296 if ((err = fill_in_fstab(cmd, &fstab, FALSE)) != Z_OK) { 2297 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2298 return; 2299 } 2300 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 2301 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2302 else 2303 need_to_commit = TRUE; 2304 zonecfg_free_fs_option_list(fstab.zone_fs_options); 2305 return; 2306 case RT_IPD: 2307 if (state_atleast(ZONE_STATE_INSTALLED)) { 2308 zerr(gettext("Zone %s already installed; %s %s not " 2309 "allowed."), zone, cmd_to_str(CMD_REMOVE), 2310 rt_to_str(RT_IPD)); 2311 return; 2312 } 2313 if ((err = fill_in_ipdtab(cmd, &fstab, FALSE)) != Z_OK) { 2314 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2315 return; 2316 } 2317 if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK) 2318 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2319 else 2320 need_to_commit = TRUE; 2321 return; 2322 case RT_NET: 2323 if ((err = fill_in_nwiftab(cmd, &nwiftab, FALSE)) != Z_OK) { 2324 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2325 return; 2326 } 2327 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 2328 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2329 else 2330 need_to_commit = TRUE; 2331 return; 2332 case RT_DEVICE: 2333 if ((err = fill_in_devtab(cmd, &devtab, FALSE)) != Z_OK) { 2334 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2335 return; 2336 } 2337 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 2338 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2339 else 2340 need_to_commit = TRUE; 2341 return; 2342 case RT_RCTL: 2343 if ((err = fill_in_rctltab(cmd, &rctltab, FALSE)) != Z_OK) { 2344 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2345 return; 2346 } 2347 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) 2348 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2349 else 2350 need_to_commit = TRUE; 2351 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 2352 return; 2353 case RT_ATTR: 2354 if ((err = fill_in_attrtab(cmd, &attrtab, FALSE)) != Z_OK) { 2355 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2356 return; 2357 } 2358 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 2359 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2360 else 2361 need_to_commit = TRUE; 2362 return; 2363 case RT_DATASET: 2364 if ((err = fill_in_dstab(cmd, &dstab, FALSE)) != Z_OK) { 2365 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2366 return; 2367 } 2368 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 2369 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2370 else 2371 need_to_commit = TRUE; 2372 return; 2373 default: 2374 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 2375 long_usage(CMD_REMOVE, TRUE); 2376 usage(FALSE, HELP_RESOURCES); 2377 return; 2378 } 2379 } 2380 2381 static void 2382 remove_property(cmd_t *cmd) 2383 { 2384 char *prop_id; 2385 int err, res_type, prop_type; 2386 property_value_ptr_t pp; 2387 struct zone_rctlvaltab *rctlvaltab; 2388 complex_property_ptr_t cx; 2389 2390 res_type = resource_scope; 2391 prop_type = cmd->cmd_prop_name[0]; 2392 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2393 long_usage(CMD_REMOVE, TRUE); 2394 return; 2395 } 2396 2397 if (cmd->cmd_prop_nv_pairs != 1) { 2398 long_usage(CMD_ADD, TRUE); 2399 return; 2400 } 2401 2402 if (initialize(TRUE) != Z_OK) 2403 return; 2404 2405 switch (res_type) { 2406 case RT_FS: 2407 if (prop_type != PT_OPTIONS) { 2408 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2409 TRUE); 2410 long_usage(CMD_REMOVE, TRUE); 2411 usage(FALSE, HELP_PROPS); 2412 return; 2413 } 2414 pp = cmd->cmd_property_ptr[0]; 2415 if (pp->pv_type == PROP_VAL_COMPLEX) { 2416 zerr(gettext("A %s or %s value was expected here."), 2417 pvt_to_str(PROP_VAL_SIMPLE), 2418 pvt_to_str(PROP_VAL_LIST)); 2419 saw_error = TRUE; 2420 return; 2421 } 2422 if (pp->pv_type == PROP_VAL_SIMPLE) { 2423 if (pp->pv_simple == NULL) { 2424 long_usage(CMD_ADD, TRUE); 2425 return; 2426 } 2427 prop_id = pp->pv_simple; 2428 err = zonecfg_remove_fs_option(&in_progress_fstab, 2429 prop_id); 2430 if (err != Z_OK) 2431 zone_perror(pt_to_str(prop_type), err, TRUE); 2432 } else { 2433 list_property_ptr_t list; 2434 2435 for (list = pp->pv_list; list != NULL; 2436 list = list->lp_next) { 2437 prop_id = list->lp_simple; 2438 if (prop_id == NULL) 2439 break; 2440 err = zonecfg_remove_fs_option( 2441 &in_progress_fstab, prop_id); 2442 if (err != Z_OK) 2443 zone_perror(pt_to_str(prop_type), err, 2444 TRUE); 2445 } 2446 } 2447 return; 2448 case RT_RCTL: 2449 if (prop_type != PT_VALUE) { 2450 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2451 TRUE); 2452 long_usage(CMD_REMOVE, TRUE); 2453 usage(FALSE, HELP_PROPS); 2454 return; 2455 } 2456 pp = cmd->cmd_property_ptr[0]; 2457 if (pp->pv_type != PROP_VAL_COMPLEX) { 2458 zerr(gettext("A %s value was expected here."), 2459 pvt_to_str(PROP_VAL_COMPLEX)); 2460 saw_error = TRUE; 2461 return; 2462 } 2463 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 2464 zone_perror(zone, Z_NOMEM, TRUE); 2465 exit(Z_ERR); 2466 } 2467 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) { 2468 switch (cx->cp_type) { 2469 case PT_PRIV: 2470 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2471 cx->cp_value, 2472 sizeof (rctlvaltab->zone_rctlval_priv)); 2473 break; 2474 case PT_LIMIT: 2475 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2476 cx->cp_value, 2477 sizeof (rctlvaltab->zone_rctlval_limit)); 2478 break; 2479 case PT_ACTION: 2480 (void) strlcpy(rctlvaltab->zone_rctlval_action, 2481 cx->cp_value, 2482 sizeof (rctlvaltab->zone_rctlval_action)); 2483 break; 2484 default: 2485 zone_perror(pt_to_str(prop_type), 2486 Z_NO_PROPERTY_TYPE, TRUE); 2487 long_usage(CMD_ADD, TRUE); 2488 usage(FALSE, HELP_PROPS); 2489 zonecfg_free_rctl_value_list(rctlvaltab); 2490 return; 2491 } 2492 } 2493 rctlvaltab->zone_rctlval_next = NULL; 2494 err = zonecfg_remove_rctl_value(&in_progress_rctltab, 2495 rctlvaltab); 2496 if (err != Z_OK) 2497 zone_perror(pt_to_str(prop_type), err, TRUE); 2498 zonecfg_free_rctl_value_list(rctlvaltab); 2499 return; 2500 default: 2501 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 2502 long_usage(CMD_REMOVE, TRUE); 2503 usage(FALSE, HELP_RESOURCES); 2504 return; 2505 } 2506 } 2507 2508 void 2509 remove_func(cmd_t *cmd) 2510 { 2511 if (zone_is_read_only(CMD_REMOVE)) 2512 return; 2513 2514 assert(cmd != NULL); 2515 2516 if (global_scope) 2517 remove_resource(cmd); 2518 else 2519 remove_property(cmd); 2520 } 2521 2522 void 2523 select_func(cmd_t *cmd) 2524 { 2525 int type, err; 2526 2527 if (zone_is_read_only(CMD_SELECT)) 2528 return; 2529 2530 assert(cmd != NULL); 2531 2532 if (global_scope) { 2533 global_scope = FALSE; 2534 resource_scope = cmd->cmd_res_type; 2535 end_op = CMD_SELECT; 2536 } else { 2537 scope_usage(CMD_SELECT); 2538 return; 2539 } 2540 2541 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2542 long_usage(CMD_SELECT, TRUE); 2543 return; 2544 } 2545 2546 if (initialize(TRUE) != Z_OK) 2547 return; 2548 2549 switch (type) { 2550 case RT_FS: 2551 if ((err = fill_in_fstab(cmd, &old_fstab, FALSE)) != Z_OK) { 2552 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, TRUE); 2553 global_scope = TRUE; 2554 } 2555 bcopy(&old_fstab, &in_progress_fstab, 2556 sizeof (struct zone_fstab)); 2557 return; 2558 case RT_IPD: 2559 if (state_atleast(ZONE_STATE_INCOMPLETE)) { 2560 zerr(gettext("Zone %s not in %s state; %s %s not " 2561 "allowed."), zone, 2562 zone_state_str(ZONE_STATE_CONFIGURED), 2563 cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD)); 2564 global_scope = TRUE; 2565 end_op = -1; 2566 return; 2567 } 2568 if ((err = fill_in_ipdtab(cmd, &old_ipdtab, FALSE)) != Z_OK) { 2569 z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, TRUE); 2570 global_scope = TRUE; 2571 } 2572 bcopy(&old_ipdtab, &in_progress_ipdtab, 2573 sizeof (struct zone_fstab)); 2574 return; 2575 case RT_NET: 2576 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, FALSE)) != Z_OK) { 2577 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, TRUE); 2578 global_scope = TRUE; 2579 } 2580 bcopy(&old_nwiftab, &in_progress_nwiftab, 2581 sizeof (struct zone_nwiftab)); 2582 return; 2583 case RT_DEVICE: 2584 if ((err = fill_in_devtab(cmd, &old_devtab, FALSE)) != Z_OK) { 2585 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, TRUE); 2586 global_scope = TRUE; 2587 } 2588 bcopy(&old_devtab, &in_progress_devtab, 2589 sizeof (struct zone_devtab)); 2590 return; 2591 case RT_RCTL: 2592 if ((err = fill_in_rctltab(cmd, &old_rctltab, FALSE)) != Z_OK) { 2593 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, TRUE); 2594 global_scope = TRUE; 2595 } 2596 bcopy(&old_rctltab, &in_progress_rctltab, 2597 sizeof (struct zone_rctltab)); 2598 return; 2599 case RT_ATTR: 2600 if ((err = fill_in_attrtab(cmd, &old_attrtab, FALSE)) != Z_OK) { 2601 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, TRUE); 2602 global_scope = TRUE; 2603 } 2604 bcopy(&old_attrtab, &in_progress_attrtab, 2605 sizeof (struct zone_attrtab)); 2606 return; 2607 case RT_DATASET: 2608 if ((err = fill_in_dstab(cmd, &old_dstab, FALSE)) != Z_OK) { 2609 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, TRUE); 2610 global_scope = TRUE; 2611 } 2612 bcopy(&old_dstab, &in_progress_dstab, 2613 sizeof (struct zone_dstab)); 2614 return; 2615 default: 2616 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 2617 long_usage(CMD_SELECT, TRUE); 2618 usage(FALSE, HELP_RESOURCES); 2619 return; 2620 } 2621 } 2622 2623 /* 2624 * Network "addresses" can be one of the following forms: 2625 * <IPv4 address> 2626 * <IPv4 address>/<prefix length> 2627 * <IPv6 address>/<prefix length> 2628 * <host name> 2629 * <host name>/<prefix length> 2630 * In other words, the "/" followed by a prefix length is allowed but not 2631 * required for IPv4 addresses and host names, and required for IPv6 addresses. 2632 * If a prefix length is given, it must be in the allowable range: 0 to 32 for 2633 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses. 2634 * Host names must start with an alpha-numeric character, and all subsequent 2635 * characters must be either alpha-numeric or "-". 2636 */ 2637 2638 static int 2639 validate_net_address_syntax(char *address) 2640 { 2641 char *slashp, part1[MAXHOSTNAMELEN]; 2642 struct in6_addr in6; 2643 struct in_addr in4; 2644 int prefixlen, i; 2645 2646 /* 2647 * Copy the part before any '/' into part1 or copy the whole 2648 * thing if there is no '/'. 2649 */ 2650 if ((slashp = strchr(address, '/')) != NULL) { 2651 *slashp = '\0'; 2652 (void) strlcpy(part1, address, sizeof (part1)); 2653 *slashp = '/'; 2654 prefixlen = atoi(++slashp); 2655 } else { 2656 (void) strlcpy(part1, address, sizeof (part1)); 2657 } 2658 2659 if (inet_pton(AF_INET6, part1, &in6) == 1) { 2660 if (slashp == NULL) { 2661 zerr(gettext("%s: IPv6 addresses " 2662 "require /prefix-length suffix."), address); 2663 return (Z_ERR); 2664 } 2665 if (prefixlen < 0 || prefixlen > 128) { 2666 zerr(gettext("%s: IPv6 address " 2667 "prefix lengths must be 0 - 128."), address); 2668 return (Z_ERR); 2669 } 2670 return (Z_OK); 2671 } 2672 2673 /* At this point, any /prefix must be for IPv4. */ 2674 if (slashp != NULL) { 2675 if (prefixlen < 0 || prefixlen > 32) { 2676 zerr(gettext("%s: IPv4 address " 2677 "prefix lengths must be 0 - 32."), address); 2678 return (Z_ERR); 2679 } 2680 } 2681 if (inet_pton(AF_INET, part1, &in4) == 1) 2682 return (Z_OK); 2683 2684 /* address may also be a host name */ 2685 if (!isalnum(part1[0])) { 2686 zerr(gettext("%s: bogus host name or network address syntax"), 2687 part1); 2688 saw_error = TRUE; 2689 usage(FALSE, HELP_NETADDR); 2690 return (Z_ERR); 2691 } 2692 for (i = 1; part1[i]; i++) 2693 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') { 2694 zerr(gettext("%s: bogus host name or " 2695 "network address syntax"), part1); 2696 saw_error = TRUE; 2697 usage(FALSE, HELP_NETADDR); 2698 return (Z_ERR); 2699 } 2700 return (Z_OK); 2701 } 2702 2703 static int 2704 validate_net_physical_syntax(char *ifname) 2705 { 2706 if (strchr(ifname, ':') == NULL) 2707 return (Z_OK); 2708 zerr(gettext("%s: physical interface name required; " 2709 "logical interface name not allowed"), ifname); 2710 return (Z_ERR); 2711 } 2712 2713 static boolean_t 2714 valid_fs_type(const char *type) 2715 { 2716 /* 2717 * Is this a valid path component? 2718 */ 2719 if (strlen(type) + 1 > MAXNAMELEN) 2720 return (B_FALSE); 2721 /* 2722 * Make sure a bad value for "type" doesn't make 2723 * /usr/lib/fs/<type>/mount turn into something else. 2724 */ 2725 if (strchr(type, '/') != NULL || type[0] == '\0' || 2726 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 2727 return (B_FALSE); 2728 /* 2729 * More detailed verification happens later by zoneadm(1m). 2730 */ 2731 return (B_TRUE); 2732 } 2733 2734 void 2735 set_func(cmd_t *cmd) 2736 { 2737 char *prop_id; 2738 int arg, err, res_type, prop_type; 2739 property_value_ptr_t pp; 2740 boolean_t autoboot; 2741 boolean_t force_set = FALSE; 2742 2743 if (zone_is_read_only(CMD_SET)) 2744 return; 2745 2746 assert(cmd != NULL); 2747 2748 optind = opterr = 0; 2749 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 2750 switch (arg) { 2751 case 'F': 2752 force_set = TRUE; 2753 break; 2754 default: 2755 if (optopt == '?') 2756 longer_usage(CMD_SET); 2757 else 2758 short_usage(CMD_SET); 2759 return; 2760 } 2761 } 2762 2763 prop_type = cmd->cmd_prop_name[0]; 2764 if (global_scope) { 2765 if (prop_type == PT_ZONENAME) { 2766 res_type = RT_ZONENAME; 2767 } else if (prop_type == PT_ZONEPATH) { 2768 res_type = RT_ZONEPATH; 2769 } else if (prop_type == PT_AUTOBOOT) { 2770 res_type = RT_AUTOBOOT; 2771 } else if (prop_type == PT_BRAND) { 2772 res_type = RT_BRAND; 2773 } else if (prop_type == PT_POOL) { 2774 res_type = RT_POOL; 2775 } else if (prop_type == PT_LIMITPRIV) { 2776 res_type = RT_LIMITPRIV; 2777 } else if (prop_type == PT_BOOTARGS) { 2778 res_type = RT_BOOTARGS; 2779 } else { 2780 zerr(gettext("Cannot set a resource-specific property " 2781 "from the global scope.")); 2782 saw_error = TRUE; 2783 return; 2784 } 2785 } else { 2786 res_type = resource_scope; 2787 } 2788 2789 if (force_set) { 2790 if (res_type != RT_ZONEPATH) { 2791 zerr(gettext("Only zonepath setting can be forced.")); 2792 saw_error = TRUE; 2793 return; 2794 } 2795 if (!zonecfg_in_alt_root()) { 2796 zerr(gettext("Zonepath is changeable only in an " 2797 "alternate root.")); 2798 saw_error = TRUE; 2799 return; 2800 } 2801 } 2802 2803 pp = cmd->cmd_property_ptr[0]; 2804 /* 2805 * A nasty expression but not that complicated: 2806 * 1. fs options are simple or list (tested below) 2807 * 2. rctl value's are complex or list (tested below) 2808 * Anything else should be simple. 2809 */ 2810 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 2811 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 2812 (pp->pv_type != PROP_VAL_SIMPLE || 2813 (prop_id = pp->pv_simple) == NULL)) { 2814 zerr(gettext("A %s value was expected here."), 2815 pvt_to_str(PROP_VAL_SIMPLE)); 2816 saw_error = TRUE; 2817 return; 2818 } 2819 if (prop_type == PT_UNKNOWN) { 2820 long_usage(CMD_SET, TRUE); 2821 return; 2822 } 2823 2824 /* 2825 * Special case: the user can change the zone name prior to 'create'; 2826 * if the zone already exists, we fall through letting initialize() 2827 * and the rest of the logic run. 2828 */ 2829 if (res_type == RT_ZONENAME && got_handle == FALSE && 2830 !state_atleast(ZONE_STATE_CONFIGURED)) { 2831 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) { 2832 zone_perror(prop_id, err, TRUE); 2833 usage(FALSE, HELP_SYNTAX); 2834 return; 2835 } 2836 (void) strlcpy(zone, prop_id, sizeof (zone)); 2837 return; 2838 } 2839 2840 if (initialize(TRUE) != Z_OK) 2841 return; 2842 2843 switch (res_type) { 2844 case RT_ZONENAME: 2845 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 2846 /* 2847 * Use prop_id instead of 'zone' here, since we're 2848 * reporting a problem about the *new* zonename. 2849 */ 2850 zone_perror(prop_id, err, TRUE); 2851 usage(FALSE, HELP_SYNTAX); 2852 } else { 2853 need_to_commit = TRUE; 2854 (void) strlcpy(zone, prop_id, sizeof (zone)); 2855 } 2856 return; 2857 case RT_ZONEPATH: 2858 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) { 2859 zerr(gettext("Zone %s already installed; %s %s not " 2860 "allowed."), zone, cmd_to_str(CMD_SET), 2861 rt_to_str(RT_ZONEPATH)); 2862 return; 2863 } 2864 if (validate_zonepath_syntax(prop_id) != Z_OK) { 2865 saw_error = TRUE; 2866 return; 2867 } 2868 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 2869 zone_perror(zone, err, TRUE); 2870 else 2871 need_to_commit = TRUE; 2872 return; 2873 case RT_BRAND: 2874 if (state_atleast(ZONE_STATE_INSTALLED)) { 2875 zerr(gettext("Zone %s already installed; %s %s not " 2876 "allowed."), zone, cmd_to_str(CMD_SET), 2877 rt_to_str(RT_BRAND)); 2878 return; 2879 } 2880 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK) 2881 zone_perror(zone, err, TRUE); 2882 else 2883 need_to_commit = TRUE; 2884 return; 2885 case RT_AUTOBOOT: 2886 if (strcmp(prop_id, "true") == 0) { 2887 autoboot = B_TRUE; 2888 } else if (strcmp(prop_id, "false") == 0) { 2889 autoboot = B_FALSE; 2890 } else { 2891 zerr(gettext("%s value must be '%s' or '%s'."), 2892 pt_to_str(PT_AUTOBOOT), "true", "false"); 2893 saw_error = TRUE; 2894 return; 2895 } 2896 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 2897 zone_perror(zone, err, TRUE); 2898 else 2899 need_to_commit = TRUE; 2900 return; 2901 case RT_POOL: 2902 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 2903 zone_perror(zone, err, TRUE); 2904 else 2905 need_to_commit = TRUE; 2906 return; 2907 case RT_LIMITPRIV: 2908 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK) 2909 zone_perror(zone, err, TRUE); 2910 else 2911 need_to_commit = TRUE; 2912 return; 2913 case RT_BOOTARGS: 2914 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK) 2915 zone_perror(zone, err, TRUE); 2916 else 2917 need_to_commit = TRUE; 2918 return; 2919 case RT_FS: 2920 switch (prop_type) { 2921 case PT_DIR: 2922 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 2923 sizeof (in_progress_fstab.zone_fs_dir)); 2924 return; 2925 case PT_SPECIAL: 2926 (void) strlcpy(in_progress_fstab.zone_fs_special, 2927 prop_id, 2928 sizeof (in_progress_fstab.zone_fs_special)); 2929 return; 2930 case PT_RAW: 2931 (void) strlcpy(in_progress_fstab.zone_fs_raw, 2932 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 2933 return; 2934 case PT_TYPE: 2935 if (!valid_fs_type(prop_id)) { 2936 zerr(gettext("\"%s\" is not a valid %s."), 2937 prop_id, pt_to_str(PT_TYPE)); 2938 saw_error = TRUE; 2939 return; 2940 } 2941 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 2942 sizeof (in_progress_fstab.zone_fs_type)); 2943 return; 2944 case PT_OPTIONS: 2945 if (pp->pv_type != PROP_VAL_SIMPLE && 2946 pp->pv_type != PROP_VAL_LIST) { 2947 zerr(gettext("A %s or %s value was expected " 2948 "here."), pvt_to_str(PROP_VAL_SIMPLE), 2949 pvt_to_str(PROP_VAL_LIST)); 2950 saw_error = TRUE; 2951 return; 2952 } 2953 zonecfg_free_fs_option_list( 2954 in_progress_fstab.zone_fs_options); 2955 in_progress_fstab.zone_fs_options = NULL; 2956 if (!(pp->pv_type == PROP_VAL_LIST && 2957 pp->pv_list == NULL)) 2958 add_property(cmd); 2959 return; 2960 default: 2961 break; 2962 } 2963 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 2964 long_usage(CMD_SET, TRUE); 2965 usage(FALSE, HELP_PROPS); 2966 return; 2967 case RT_IPD: 2968 switch (prop_type) { 2969 case PT_DIR: 2970 (void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id, 2971 sizeof (in_progress_ipdtab.zone_fs_dir)); 2972 return; 2973 default: 2974 break; 2975 } 2976 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 2977 long_usage(CMD_SET, TRUE); 2978 usage(FALSE, HELP_PROPS); 2979 return; 2980 case RT_NET: 2981 switch (prop_type) { 2982 case PT_ADDRESS: 2983 if (validate_net_address_syntax(prop_id) != Z_OK) { 2984 saw_error = TRUE; 2985 return; 2986 } 2987 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, 2988 prop_id, 2989 sizeof (in_progress_nwiftab.zone_nwif_address)); 2990 break; 2991 case PT_PHYSICAL: 2992 if (validate_net_physical_syntax(prop_id) != Z_OK) { 2993 saw_error = TRUE; 2994 return; 2995 } 2996 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 2997 prop_id, 2998 sizeof (in_progress_nwiftab.zone_nwif_physical)); 2999 break; 3000 default: 3001 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3002 TRUE); 3003 long_usage(CMD_SET, TRUE); 3004 usage(FALSE, HELP_PROPS); 3005 return; 3006 } 3007 return; 3008 case RT_DEVICE: 3009 switch (prop_type) { 3010 case PT_MATCH: 3011 (void) strlcpy(in_progress_devtab.zone_dev_match, 3012 prop_id, 3013 sizeof (in_progress_devtab.zone_dev_match)); 3014 break; 3015 default: 3016 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3017 TRUE); 3018 long_usage(CMD_SET, TRUE); 3019 usage(FALSE, HELP_PROPS); 3020 return; 3021 } 3022 return; 3023 case RT_RCTL: 3024 switch (prop_type) { 3025 case PT_NAME: 3026 if (!zonecfg_valid_rctlname(prop_id)) { 3027 zerr(gettext("'%s' is not a valid zone %s " 3028 "name."), prop_id, rt_to_str(RT_RCTL)); 3029 return; 3030 } 3031 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 3032 prop_id, 3033 sizeof (in_progress_rctltab.zone_rctl_name)); 3034 break; 3035 case PT_VALUE: 3036 if (pp->pv_type != PROP_VAL_COMPLEX && 3037 pp->pv_type != PROP_VAL_LIST) { 3038 zerr(gettext("A %s or %s value was expected " 3039 "here."), pvt_to_str(PROP_VAL_COMPLEX), 3040 pvt_to_str(PROP_VAL_LIST)); 3041 saw_error = TRUE; 3042 return; 3043 } 3044 zonecfg_free_rctl_value_list( 3045 in_progress_rctltab.zone_rctl_valptr); 3046 in_progress_rctltab.zone_rctl_valptr = NULL; 3047 if (!(pp->pv_type == PROP_VAL_LIST && 3048 pp->pv_list == NULL)) 3049 add_property(cmd); 3050 break; 3051 default: 3052 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3053 TRUE); 3054 long_usage(CMD_SET, TRUE); 3055 usage(FALSE, HELP_PROPS); 3056 return; 3057 } 3058 return; 3059 case RT_ATTR: 3060 switch (prop_type) { 3061 case PT_NAME: 3062 (void) strlcpy(in_progress_attrtab.zone_attr_name, 3063 prop_id, 3064 sizeof (in_progress_attrtab.zone_attr_name)); 3065 break; 3066 case PT_TYPE: 3067 (void) strlcpy(in_progress_attrtab.zone_attr_type, 3068 prop_id, 3069 sizeof (in_progress_attrtab.zone_attr_type)); 3070 break; 3071 case PT_VALUE: 3072 (void) strlcpy(in_progress_attrtab.zone_attr_value, 3073 prop_id, 3074 sizeof (in_progress_attrtab.zone_attr_value)); 3075 break; 3076 default: 3077 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3078 TRUE); 3079 long_usage(CMD_SET, TRUE); 3080 usage(FALSE, HELP_PROPS); 3081 return; 3082 } 3083 return; 3084 case RT_DATASET: 3085 switch (prop_type) { 3086 case PT_NAME: 3087 (void) strlcpy(in_progress_dstab.zone_dataset_name, 3088 prop_id, 3089 sizeof (in_progress_dstab.zone_dataset_name)); 3090 return; 3091 default: 3092 break; 3093 } 3094 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 3095 long_usage(CMD_SET, TRUE); 3096 usage(FALSE, HELP_PROPS); 3097 return; 3098 default: 3099 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 3100 long_usage(CMD_SET, TRUE); 3101 usage(FALSE, HELP_RESOURCES); 3102 return; 3103 } 3104 } 3105 3106 static void 3107 output_prop(FILE *fp, int pnum, char *pval, bool print_notspec) 3108 { 3109 char *qstr; 3110 3111 if (*pval != '\0') { 3112 qstr = quoteit(pval); 3113 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 3114 free(qstr); 3115 } else if (print_notspec) 3116 (void) fprintf(fp, gettext("\t%s not specified\n"), 3117 pt_to_str(pnum)); 3118 } 3119 3120 static void 3121 info_zonename(zone_dochandle_t handle, FILE *fp) 3122 { 3123 char zonename[ZONENAME_MAX]; 3124 3125 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 3126 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 3127 zonename); 3128 else 3129 (void) fprintf(fp, gettext("%s not specified\n"), 3130 pt_to_str(PT_ZONENAME)); 3131 } 3132 3133 static void 3134 info_zonepath(zone_dochandle_t handle, FILE *fp) 3135 { 3136 char zonepath[MAXPATHLEN]; 3137 3138 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 3139 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 3140 zonepath); 3141 else { 3142 (void) fprintf(fp, gettext("%s not specified\n"), 3143 pt_to_str(PT_ZONEPATH)); 3144 } 3145 } 3146 3147 static void 3148 info_brand(zone_dochandle_t handle, FILE *fp) 3149 { 3150 char brand[MAXNAMELEN]; 3151 3152 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK) 3153 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND), 3154 brand); 3155 else 3156 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND), 3157 gettext("not specified")); 3158 } 3159 3160 static void 3161 info_autoboot(zone_dochandle_t handle, FILE *fp) 3162 { 3163 boolean_t autoboot; 3164 int err; 3165 3166 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 3167 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 3168 autoboot ? "true" : "false"); 3169 else 3170 zone_perror(zone, err, TRUE); 3171 } 3172 3173 static void 3174 info_pool(zone_dochandle_t handle, FILE *fp) 3175 { 3176 char pool[MAXNAMELEN]; 3177 int err; 3178 3179 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 3180 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 3181 else 3182 zone_perror(zone, err, TRUE); 3183 } 3184 3185 static void 3186 info_limitpriv(zone_dochandle_t handle, FILE *fp) 3187 { 3188 char *limitpriv; 3189 int err; 3190 3191 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) { 3192 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV), 3193 limitpriv); 3194 free(limitpriv); 3195 } else { 3196 zone_perror(zone, err, TRUE); 3197 } 3198 } 3199 3200 static void 3201 info_bootargs(zone_dochandle_t handle, FILE *fp) 3202 { 3203 char bootargs[BOOTARGS_MAX]; 3204 int err; 3205 3206 if ((err = zonecfg_get_bootargs(handle, bootargs, 3207 sizeof (bootargs))) == Z_OK) { 3208 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS), 3209 bootargs); 3210 } else { 3211 zone_perror(zone, err, TRUE); 3212 } 3213 } 3214 3215 static void 3216 output_fs(FILE *fp, struct zone_fstab *fstab) 3217 { 3218 zone_fsopt_t *this; 3219 3220 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 3221 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 3222 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 3223 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 3224 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 3225 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 3226 for (this = fstab->zone_fs_options; this != NULL; 3227 this = this->zone_fsopt_next) { 3228 if (strchr(this->zone_fsopt_opt, '=')) 3229 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 3230 else 3231 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 3232 if (this->zone_fsopt_next != NULL) 3233 (void) fprintf(fp, ","); 3234 } 3235 (void) fprintf(fp, "]\n"); 3236 } 3237 3238 static void 3239 output_ipd(FILE *fp, struct zone_fstab *ipdtab) 3240 { 3241 (void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD)); 3242 output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE); 3243 } 3244 3245 static void 3246 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3247 { 3248 struct zone_fstab lookup, user; 3249 bool output = FALSE; 3250 3251 if (zonecfg_setfsent(handle) != Z_OK) 3252 return; 3253 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 3254 if (cmd->cmd_prop_nv_pairs == 0) { 3255 output_fs(fp, &lookup); 3256 goto loopend; 3257 } 3258 if (fill_in_fstab(cmd, &user, TRUE) != Z_OK) 3259 goto loopend; 3260 if (strlen(user.zone_fs_dir) > 0 && 3261 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 3262 goto loopend; /* no match */ 3263 if (strlen(user.zone_fs_special) > 0 && 3264 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 3265 goto loopend; /* no match */ 3266 if (strlen(user.zone_fs_type) > 0 && 3267 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 3268 goto loopend; /* no match */ 3269 output_fs(fp, &lookup); 3270 output = TRUE; 3271 loopend: 3272 zonecfg_free_fs_option_list(lookup.zone_fs_options); 3273 } 3274 (void) zonecfg_endfsent(handle); 3275 /* 3276 * If a property n/v pair was specified, warn the user if there was 3277 * nothing to output. 3278 */ 3279 if (!output && cmd->cmd_prop_nv_pairs > 0) 3280 (void) printf(gettext("No such %s resource.\n"), 3281 rt_to_str(RT_FS)); 3282 } 3283 3284 static void 3285 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3286 { 3287 struct zone_fstab lookup, user; 3288 bool output = FALSE; 3289 3290 if (zonecfg_setipdent(handle) != Z_OK) 3291 return; 3292 while (zonecfg_getipdent(handle, &lookup) == Z_OK) { 3293 if (cmd->cmd_prop_nv_pairs == 0) { 3294 output_ipd(fp, &lookup); 3295 continue; 3296 } 3297 if (fill_in_ipdtab(cmd, &user, TRUE) != Z_OK) 3298 continue; 3299 if (strlen(user.zone_fs_dir) > 0 && 3300 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 3301 continue; /* no match */ 3302 output_ipd(fp, &lookup); 3303 output = TRUE; 3304 } 3305 (void) zonecfg_endipdent(handle); 3306 /* 3307 * If a property n/v pair was specified, warn the user if there was 3308 * nothing to output. 3309 */ 3310 if (!output && cmd->cmd_prop_nv_pairs > 0) 3311 (void) printf(gettext("No such %s resource.\n"), 3312 rt_to_str(RT_IPD)); 3313 } 3314 3315 static void 3316 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 3317 { 3318 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 3319 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 3320 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 3321 } 3322 3323 static void 3324 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3325 { 3326 struct zone_nwiftab lookup, user; 3327 bool output = FALSE; 3328 3329 if (zonecfg_setnwifent(handle) != Z_OK) 3330 return; 3331 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 3332 if (cmd->cmd_prop_nv_pairs == 0) { 3333 output_net(fp, &lookup); 3334 continue; 3335 } 3336 if (fill_in_nwiftab(cmd, &user, TRUE) != Z_OK) 3337 continue; 3338 if (strlen(user.zone_nwif_physical) > 0 && 3339 strcmp(user.zone_nwif_physical, 3340 lookup.zone_nwif_physical) != 0) 3341 continue; /* no match */ 3342 if (strlen(user.zone_nwif_address) > 0 && 3343 !zonecfg_same_net_address(user.zone_nwif_address, 3344 lookup.zone_nwif_address)) 3345 continue; /* no match */ 3346 output_net(fp, &lookup); 3347 output = TRUE; 3348 } 3349 (void) zonecfg_endnwifent(handle); 3350 /* 3351 * If a property n/v pair was specified, warn the user if there was 3352 * nothing to output. 3353 */ 3354 if (!output && cmd->cmd_prop_nv_pairs > 0) 3355 (void) printf(gettext("No such %s resource.\n"), 3356 rt_to_str(RT_NET)); 3357 } 3358 3359 static void 3360 output_dev(FILE *fp, struct zone_devtab *devtab) 3361 { 3362 (void) fprintf(fp, "%s\n", rt_to_str(RT_DEVICE)); 3363 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 3364 } 3365 3366 static void 3367 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3368 { 3369 struct zone_devtab lookup, user; 3370 bool output = FALSE; 3371 3372 if (zonecfg_setdevent(handle) != Z_OK) 3373 return; 3374 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 3375 if (cmd->cmd_prop_nv_pairs == 0) { 3376 output_dev(fp, &lookup); 3377 continue; 3378 } 3379 if (fill_in_devtab(cmd, &user, TRUE) != Z_OK) 3380 continue; 3381 if (strlen(user.zone_dev_match) > 0 && 3382 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 3383 continue; /* no match */ 3384 output_dev(fp, &lookup); 3385 output = TRUE; 3386 } 3387 (void) zonecfg_enddevent(handle); 3388 /* 3389 * If a property n/v pair was specified, warn the user if there was 3390 * nothing to output. 3391 */ 3392 if (!output && cmd->cmd_prop_nv_pairs > 0) 3393 (void) printf(gettext("No such %s resource.\n"), 3394 rt_to_str(RT_DEVICE)); 3395 } 3396 3397 static void 3398 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 3399 { 3400 struct zone_rctlvaltab *valptr; 3401 3402 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 3403 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 3404 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 3405 valptr = valptr->zone_rctlval_next) { 3406 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 3407 pt_to_str(PT_VALUE), 3408 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 3409 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 3410 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 3411 } 3412 } 3413 3414 static void 3415 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3416 { 3417 struct zone_rctltab lookup, user; 3418 bool output = FALSE; 3419 3420 if (zonecfg_setrctlent(handle) != Z_OK) 3421 return; 3422 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 3423 if (cmd->cmd_prop_nv_pairs == 0) { 3424 output_rctl(fp, &lookup); 3425 } else if (fill_in_rctltab(cmd, &user, TRUE) == Z_OK && 3426 (strlen(user.zone_rctl_name) == 0 || 3427 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 3428 output_rctl(fp, &lookup); 3429 output = TRUE; 3430 } 3431 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 3432 } 3433 (void) zonecfg_endrctlent(handle); 3434 /* 3435 * If a property n/v pair was specified, warn the user if there was 3436 * nothing to output. 3437 */ 3438 if (!output && cmd->cmd_prop_nv_pairs > 0) 3439 (void) printf(gettext("No such %s resource.\n"), 3440 rt_to_str(RT_RCTL)); 3441 } 3442 3443 static void 3444 output_attr(FILE *fp, struct zone_attrtab *attrtab) 3445 { 3446 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 3447 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 3448 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 3449 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 3450 } 3451 3452 static void 3453 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3454 { 3455 struct zone_attrtab lookup, user; 3456 bool output = FALSE; 3457 3458 if (zonecfg_setattrent(handle) != Z_OK) 3459 return; 3460 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 3461 if (cmd->cmd_prop_nv_pairs == 0) { 3462 output_attr(fp, &lookup); 3463 continue; 3464 } 3465 if (fill_in_attrtab(cmd, &user, TRUE) != Z_OK) 3466 continue; 3467 if (strlen(user.zone_attr_name) > 0 && 3468 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 3469 continue; /* no match */ 3470 if (strlen(user.zone_attr_type) > 0 && 3471 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 3472 continue; /* no match */ 3473 if (strlen(user.zone_attr_value) > 0 && 3474 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 3475 continue; /* no match */ 3476 output_attr(fp, &lookup); 3477 output = TRUE; 3478 } 3479 (void) zonecfg_endattrent(handle); 3480 /* 3481 * If a property n/v pair was specified, warn the user if there was 3482 * nothing to output. 3483 */ 3484 if (!output && cmd->cmd_prop_nv_pairs > 0) 3485 (void) printf(gettext("No such %s resource.\n"), 3486 rt_to_str(RT_ATTR)); 3487 } 3488 3489 static void 3490 output_ds(FILE *fp, struct zone_dstab *dstab) 3491 { 3492 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 3493 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 3494 } 3495 3496 static void 3497 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3498 { 3499 struct zone_dstab lookup, user; 3500 bool output = FALSE; 3501 3502 if (zonecfg_setdevent(handle) != Z_OK) 3503 return; 3504 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 3505 if (cmd->cmd_prop_nv_pairs == 0) { 3506 output_ds(fp, &lookup); 3507 continue; 3508 } 3509 if (fill_in_dstab(cmd, &user, TRUE) != Z_OK) 3510 continue; 3511 if (strlen(user.zone_dataset_name) > 0 && 3512 strcmp(user.zone_dataset_name, 3513 lookup.zone_dataset_name) != 0) 3514 continue; /* no match */ 3515 output_ds(fp, &lookup); 3516 output = TRUE; 3517 } 3518 (void) zonecfg_enddsent(handle); 3519 /* 3520 * If a property n/v pair was specified, warn the user if there was 3521 * nothing to output. 3522 */ 3523 if (!output && cmd->cmd_prop_nv_pairs > 0) 3524 (void) printf(gettext("No such %s resource.\n"), 3525 rt_to_str(RT_DATASET)); 3526 } 3527 3528 void 3529 info_func(cmd_t *cmd) 3530 { 3531 FILE *fp = stdout; 3532 bool need_to_close = FALSE; 3533 char *pager; 3534 3535 assert(cmd != NULL); 3536 3537 if (initialize(TRUE) != Z_OK) 3538 return; 3539 3540 /* don't page error output */ 3541 if (interactive_mode) { 3542 if ((pager = getenv("PAGER")) == NULL) 3543 pager = PAGER; 3544 if ((fp = popen(pager, "w")) != NULL) 3545 need_to_close = TRUE; 3546 setbuf(fp, NULL); 3547 } 3548 3549 if (!global_scope) { 3550 switch (resource_scope) { 3551 case RT_FS: 3552 output_fs(fp, &in_progress_fstab); 3553 break; 3554 case RT_IPD: 3555 output_ipd(fp, &in_progress_ipdtab); 3556 break; 3557 case RT_NET: 3558 output_net(fp, &in_progress_nwiftab); 3559 break; 3560 case RT_DEVICE: 3561 output_dev(fp, &in_progress_devtab); 3562 break; 3563 case RT_RCTL: 3564 output_rctl(fp, &in_progress_rctltab); 3565 break; 3566 case RT_ATTR: 3567 output_attr(fp, &in_progress_attrtab); 3568 break; 3569 case RT_DATASET: 3570 output_ds(fp, &in_progress_dstab); 3571 break; 3572 } 3573 goto cleanup; 3574 } 3575 3576 switch (cmd->cmd_res_type) { 3577 case RT_UNKNOWN: 3578 info_zonename(handle, fp); 3579 info_zonepath(handle, fp); 3580 info_brand(handle, fp); 3581 info_autoboot(handle, fp); 3582 info_bootargs(handle, fp); 3583 info_pool(handle, fp); 3584 info_limitpriv(handle, fp); 3585 info_ipd(handle, fp, cmd); 3586 info_fs(handle, fp, cmd); 3587 info_net(handle, fp, cmd); 3588 info_dev(handle, fp, cmd); 3589 info_rctl(handle, fp, cmd); 3590 info_attr(handle, fp, cmd); 3591 info_ds(handle, fp, cmd); 3592 break; 3593 case RT_ZONENAME: 3594 info_zonename(handle, fp); 3595 break; 3596 case RT_ZONEPATH: 3597 info_zonepath(handle, fp); 3598 break; 3599 case RT_BRAND: 3600 info_brand(handle, fp); 3601 break; 3602 case RT_AUTOBOOT: 3603 info_autoboot(handle, fp); 3604 break; 3605 case RT_POOL: 3606 info_pool(handle, fp); 3607 break; 3608 case RT_LIMITPRIV: 3609 info_limitpriv(handle, fp); 3610 break; 3611 case RT_BOOTARGS: 3612 info_bootargs(handle, fp); 3613 break; 3614 case RT_FS: 3615 info_fs(handle, fp, cmd); 3616 break; 3617 case RT_IPD: 3618 info_ipd(handle, fp, cmd); 3619 break; 3620 case RT_NET: 3621 info_net(handle, fp, cmd); 3622 break; 3623 case RT_DEVICE: 3624 info_dev(handle, fp, cmd); 3625 break; 3626 case RT_RCTL: 3627 info_rctl(handle, fp, cmd); 3628 break; 3629 case RT_ATTR: 3630 info_attr(handle, fp, cmd); 3631 break; 3632 case RT_DATASET: 3633 info_ds(handle, fp, cmd); 3634 break; 3635 default: 3636 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 3637 TRUE); 3638 } 3639 3640 cleanup: 3641 if (need_to_close) 3642 (void) pclose(fp); 3643 } 3644 3645 /* 3646 * Helper function for verify-- checks that a required string property 3647 * exists. 3648 */ 3649 static void 3650 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 3651 { 3652 if (strlen(attr) == 0) { 3653 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 3654 pt_to_str(pt)); 3655 saw_error = TRUE; 3656 if (*ret_val == Z_OK) 3657 *ret_val = Z_REQD_PROPERTY_MISSING; 3658 } 3659 } 3660 3661 static int 3662 do_subproc(char *cmdbuf) 3663 { 3664 char inbuf[MAX_CMD_LEN]; 3665 FILE *file; 3666 int status; 3667 3668 file = popen(cmdbuf, "r"); 3669 if (file == NULL) { 3670 zerr(gettext("Could not launch: %s"), cmdbuf); 3671 return (-1); 3672 } 3673 3674 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 3675 fprintf(stderr, "%s", inbuf); 3676 status = pclose(file); 3677 3678 if (WIFSIGNALED(status)) { 3679 zerr(gettext("%s unexpectedly terminated due to signal %d"), 3680 cmdbuf, WTERMSIG(status)); 3681 return (-1); 3682 } 3683 assert(WIFEXITED(status)); 3684 return (WEXITSTATUS(status)); 3685 } 3686 3687 static int 3688 brand_verify(zone_dochandle_t handle) 3689 { 3690 char xml_file[32]; 3691 char cmdbuf[MAX_CMD_LEN]; 3692 brand_handle_t bh; 3693 char brand[MAXNAMELEN]; 3694 int err; 3695 3696 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 3697 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 3698 return (Z_INVALID_DOCUMENT); 3699 } 3700 if ((bh = brand_open(brand)) == NULL) { 3701 zerr("%s: %s\n", zone, gettext("unknown brand.")); 3702 return (Z_INVALID_DOCUMENT); 3703 } 3704 3705 /* 3706 * Fetch the verify command, if any, from the brand configuration 3707 * and build the command line to execute it. 3708 */ 3709 strcpy(cmdbuf, EXEC_PREFIX); 3710 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN, 3711 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 3712 brand_close(bh); 3713 if (err != Z_OK) { 3714 zerr("%s: %s\n", zone, 3715 gettext("could not get brand verification command")); 3716 return (Z_INVALID_DOCUMENT); 3717 } 3718 3719 /* 3720 * If the brand doesn't provide a verification routine, we just 3721 * return success. 3722 */ 3723 if (strlen(cmdbuf) == EXEC_LEN) 3724 return (Z_OK); 3725 3726 /* 3727 * Dump the current config information for this zone to a file. 3728 */ 3729 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX"); 3730 if (mkstemp(xml_file) == NULL) 3731 return (Z_TEMP_FILE); 3732 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 3733 (void) unlink(xml_file); 3734 return (err); 3735 } 3736 3737 /* 3738 * Execute the verification command. 3739 */ 3740 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 3741 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 3742 err = Z_BRAND_ERROR; 3743 } else { 3744 err = do_subproc(cmdbuf); 3745 } 3746 3747 (void) unlink(xml_file); 3748 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 3749 } 3750 3751 /* 3752 * See the DTD for which attributes are required for which resources. 3753 * 3754 * This function can be called by commit_func(), which needs to save things, 3755 * in addition to the general call from parse_and_run(), which doesn't need 3756 * things saved. Since the parameters are standardized, we distinguish by 3757 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 3758 * that a save is needed. 3759 */ 3760 void 3761 verify_func(cmd_t *cmd) 3762 { 3763 struct zone_nwiftab nwiftab; 3764 struct zone_fstab fstab; 3765 struct zone_attrtab attrtab; 3766 struct zone_rctltab rctltab; 3767 struct zone_dstab dstab; 3768 char zonepath[MAXPATHLEN]; 3769 char brand[MAXNAMELEN]; 3770 int err, ret_val = Z_OK, arg; 3771 bool save = FALSE; 3772 3773 optind = 0; 3774 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3775 switch (arg) { 3776 case '?': 3777 longer_usage(CMD_VERIFY); 3778 return; 3779 default: 3780 short_usage(CMD_VERIFY); 3781 return; 3782 } 3783 } 3784 if (optind > cmd->cmd_argc) { 3785 short_usage(CMD_VERIFY); 3786 return; 3787 } 3788 3789 if (zone_is_read_only(CMD_VERIFY)) 3790 return; 3791 3792 assert(cmd != NULL); 3793 3794 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 3795 save = TRUE; 3796 if (initialize(TRUE) != Z_OK) 3797 return; 3798 3799 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK) { 3800 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 3801 ret_val = Z_REQD_RESOURCE_MISSING; 3802 saw_error = TRUE; 3803 } 3804 if (strlen(zonepath) == 0) { 3805 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 3806 ret_val = Z_REQD_RESOURCE_MISSING; 3807 saw_error = TRUE; 3808 } 3809 3810 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 3811 zone_perror(zone, err, TRUE); 3812 return; 3813 } 3814 if (strcmp(brand, NATIVE_BRAND_NAME) != 0) { 3815 if ((err = brand_verify(handle)) != Z_OK) { 3816 zone_perror(zone, err, TRUE); 3817 return; 3818 } 3819 } 3820 3821 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 3822 zone_perror(zone, err, TRUE); 3823 return; 3824 } 3825 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 3826 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 3827 } 3828 (void) zonecfg_endipdent(handle); 3829 3830 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 3831 zone_perror(zone, err, TRUE); 3832 return; 3833 } 3834 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 3835 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 3836 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 3837 &ret_val); 3838 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 3839 3840 zonecfg_free_fs_option_list(fstab.zone_fs_options); 3841 } 3842 (void) zonecfg_endfsent(handle); 3843 3844 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 3845 zone_perror(zone, err, TRUE); 3846 return; 3847 } 3848 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 3849 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 3850 PT_ADDRESS, &ret_val); 3851 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 3852 PT_PHYSICAL, &ret_val); 3853 } 3854 (void) zonecfg_endnwifent(handle); 3855 3856 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 3857 zone_perror(zone, err, TRUE); 3858 return; 3859 } 3860 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 3861 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 3862 &ret_val); 3863 3864 if (rctltab.zone_rctl_valptr == NULL) { 3865 zerr(gettext("%s: no %s specified"), 3866 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 3867 saw_error = TRUE; 3868 if (ret_val == Z_OK) 3869 ret_val = Z_REQD_PROPERTY_MISSING; 3870 } else { 3871 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 3872 } 3873 } 3874 (void) zonecfg_endrctlent(handle); 3875 3876 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 3877 zone_perror(zone, err, TRUE); 3878 return; 3879 } 3880 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 3881 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 3882 &ret_val); 3883 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 3884 &ret_val); 3885 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 3886 &ret_val); 3887 } 3888 (void) zonecfg_endattrent(handle); 3889 3890 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 3891 zone_perror(zone, err, TRUE); 3892 return; 3893 } 3894 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 3895 if (strlen(dstab.zone_dataset_name) == 0) { 3896 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3897 pt_to_str(PT_NAME), gettext("not specified")); 3898 saw_error = TRUE; 3899 if (ret_val == Z_OK) 3900 ret_val = Z_REQD_PROPERTY_MISSING; 3901 } else if (!zfs_name_valid(dstab.zone_dataset_name, 3902 ZFS_TYPE_FILESYSTEM)) { 3903 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3904 pt_to_str(PT_NAME), gettext("invalid")); 3905 saw_error = TRUE; 3906 if (ret_val == Z_OK) 3907 ret_val = Z_BAD_PROPERTY; 3908 } 3909 3910 } 3911 (void) zonecfg_enddsent(handle); 3912 3913 if (!global_scope) { 3914 zerr(gettext("resource specification incomplete")); 3915 saw_error = TRUE; 3916 if (ret_val == Z_OK) 3917 ret_val = Z_INSUFFICIENT_SPEC; 3918 } 3919 3920 if (save) { 3921 if (ret_val == Z_OK) { 3922 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 3923 need_to_commit = FALSE; 3924 (void) strlcpy(revert_zone, zone, 3925 sizeof (revert_zone)); 3926 } 3927 } else { 3928 zerr(gettext("Zone %s failed to verify"), zone); 3929 } 3930 } 3931 if (ret_val != Z_OK) 3932 zone_perror(zone, ret_val, TRUE); 3933 } 3934 3935 void 3936 cancel_func(cmd_t *cmd) 3937 { 3938 int arg; 3939 3940 assert(cmd != NULL); 3941 3942 optind = 0; 3943 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3944 switch (arg) { 3945 case '?': 3946 longer_usage(CMD_CANCEL); 3947 return; 3948 default: 3949 short_usage(CMD_CANCEL); 3950 return; 3951 } 3952 } 3953 if (optind != cmd->cmd_argc) { 3954 short_usage(CMD_CANCEL); 3955 return; 3956 } 3957 3958 if (global_scope) 3959 scope_usage(CMD_CANCEL); 3960 global_scope = TRUE; 3961 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 3962 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 3963 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 3964 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 3965 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 3966 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 3967 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 3968 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 3969 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 3970 } 3971 3972 static int 3973 validate_attr_name(char *name) 3974 { 3975 int i; 3976 3977 if (!isalnum(name[0])) { 3978 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 3979 "numeric character."), rt_to_str(RT_ATTR), 3980 pt_to_str(PT_NAME), name); 3981 return (Z_INVAL); 3982 } 3983 for (i = 1; name[i]; i++) 3984 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 3985 zerr(gettext("Invalid %s %s %s: can only contain " 3986 "alpha-numeric characters, plus '-' and '.'."), 3987 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 3988 return (Z_INVAL); 3989 } 3990 return (Z_OK); 3991 } 3992 3993 static int 3994 validate_attr_type_val(struct zone_attrtab *attrtab) 3995 { 3996 boolean_t boolval; 3997 int64_t intval; 3998 char strval[MAXNAMELEN]; 3999 uint64_t uintval; 4000 4001 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 4002 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 4003 return (Z_OK); 4004 zerr(gettext("invalid %s value for %s=%s"), 4005 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 4006 return (Z_ERR); 4007 } 4008 4009 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 4010 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 4011 return (Z_OK); 4012 zerr(gettext("invalid %s value for %s=%s"), 4013 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 4014 return (Z_ERR); 4015 } 4016 4017 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 4018 if (zonecfg_get_attr_string(attrtab, strval, 4019 sizeof (strval)) == Z_OK) 4020 return (Z_OK); 4021 zerr(gettext("invalid %s value for %s=%s"), 4022 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 4023 return (Z_ERR); 4024 } 4025 4026 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 4027 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 4028 return (Z_OK); 4029 zerr(gettext("invalid %s value for %s=%s"), 4030 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 4031 return (Z_ERR); 4032 } 4033 4034 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 4035 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 4036 return (Z_ERR); 4037 } 4038 4039 /* 4040 * Helper function for end_func-- checks the existence of a given property 4041 * and emits a message if not specified. 4042 */ 4043 static int 4044 end_check_reqd(char *attr, int pt, bool *validation_failed) 4045 { 4046 if (strlen(attr) == 0) { 4047 *validation_failed = TRUE; 4048 zerr(gettext("%s not specified"), pt_to_str(pt)); 4049 return (Z_ERR); 4050 } 4051 return (Z_OK); 4052 } 4053 4054 void 4055 end_func(cmd_t *cmd) 4056 { 4057 bool validation_failed = FALSE; 4058 struct zone_fstab tmp_fstab; 4059 struct zone_nwiftab tmp_nwiftab; 4060 struct zone_devtab tmp_devtab; 4061 struct zone_rctltab tmp_rctltab; 4062 struct zone_attrtab tmp_attrtab; 4063 struct zone_dstab tmp_dstab; 4064 int err, arg; 4065 4066 assert(cmd != NULL); 4067 4068 optind = 0; 4069 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 4070 switch (arg) { 4071 case '?': 4072 longer_usage(CMD_END); 4073 return; 4074 default: 4075 short_usage(CMD_END); 4076 return; 4077 } 4078 } 4079 if (optind != cmd->cmd_argc) { 4080 short_usage(CMD_END); 4081 return; 4082 } 4083 4084 if (global_scope) { 4085 scope_usage(CMD_END); 4086 return; 4087 } 4088 4089 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 4090 4091 switch (resource_scope) { 4092 case RT_FS: 4093 /* First make sure everything was filled in. */ 4094 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 4095 PT_DIR, &validation_failed) == Z_OK) { 4096 if (in_progress_fstab.zone_fs_dir[0] != '/') { 4097 zerr(gettext("%s %s is not an absolute path."), 4098 pt_to_str(PT_DIR), 4099 in_progress_fstab.zone_fs_dir); 4100 validation_failed = TRUE; 4101 } 4102 } 4103 4104 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 4105 PT_SPECIAL, &validation_failed); 4106 4107 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 4108 in_progress_fstab.zone_fs_raw[0] != '/') { 4109 zerr(gettext("%s %s is not an absolute path."), 4110 pt_to_str(PT_RAW), 4111 in_progress_fstab.zone_fs_raw); 4112 validation_failed = TRUE; 4113 } 4114 4115 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 4116 &validation_failed); 4117 4118 if (validation_failed) { 4119 saw_error = TRUE; 4120 return; 4121 } 4122 4123 if (end_op == CMD_ADD) { 4124 /* Make sure there isn't already one like this. */ 4125 bzero(&tmp_fstab, sizeof (tmp_fstab)); 4126 (void) strlcpy(tmp_fstab.zone_fs_dir, 4127 in_progress_fstab.zone_fs_dir, 4128 sizeof (tmp_fstab.zone_fs_dir)); 4129 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 4130 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 4131 if (err == Z_OK) { 4132 zerr(gettext("A %s resource " 4133 "with the %s '%s' already exists."), 4134 rt_to_str(RT_FS), pt_to_str(PT_DIR), 4135 in_progress_fstab.zone_fs_dir); 4136 saw_error = TRUE; 4137 return; 4138 } 4139 err = zonecfg_add_filesystem(handle, 4140 &in_progress_fstab); 4141 } else { 4142 err = zonecfg_modify_filesystem(handle, &old_fstab, 4143 &in_progress_fstab); 4144 } 4145 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 4146 in_progress_fstab.zone_fs_options = NULL; 4147 break; 4148 4149 case RT_IPD: 4150 /* First make sure everything was filled in. */ 4151 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 4152 &validation_failed) == Z_OK) { 4153 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 4154 zerr(gettext("%s %s is not an absolute path."), 4155 pt_to_str(PT_DIR), 4156 in_progress_ipdtab.zone_fs_dir); 4157 validation_failed = TRUE; 4158 } 4159 } 4160 if (validation_failed) { 4161 saw_error = TRUE; 4162 return; 4163 } 4164 4165 if (end_op == CMD_ADD) { 4166 /* Make sure there isn't already one like this. */ 4167 bzero(&tmp_fstab, sizeof (tmp_fstab)); 4168 (void) strlcpy(tmp_fstab.zone_fs_dir, 4169 in_progress_ipdtab.zone_fs_dir, 4170 sizeof (tmp_fstab.zone_fs_dir)); 4171 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 4172 if (err == Z_OK) { 4173 zerr(gettext("An %s resource " 4174 "with the %s '%s' already exists."), 4175 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 4176 in_progress_ipdtab.zone_fs_dir); 4177 saw_error = TRUE; 4178 return; 4179 } 4180 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 4181 } else { 4182 err = zonecfg_modify_ipd(handle, &old_ipdtab, 4183 &in_progress_ipdtab); 4184 } 4185 break; 4186 case RT_NET: 4187 /* First make sure everything was filled in. */ 4188 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 4189 PT_PHYSICAL, &validation_failed); 4190 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_address, 4191 PT_ADDRESS, &validation_failed); 4192 4193 if (validation_failed) { 4194 saw_error = TRUE; 4195 return; 4196 } 4197 4198 if (end_op == CMD_ADD) { 4199 /* Make sure there isn't already one like this. */ 4200 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 4201 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 4202 in_progress_nwiftab.zone_nwif_address, 4203 sizeof (tmp_nwiftab.zone_nwif_address)); 4204 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 4205 zerr(gettext("A %s resource " 4206 "with the %s '%s' already exists."), 4207 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS), 4208 in_progress_nwiftab.zone_nwif_address); 4209 saw_error = TRUE; 4210 return; 4211 } 4212 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 4213 } else { 4214 err = zonecfg_modify_nwif(handle, &old_nwiftab, 4215 &in_progress_nwiftab); 4216 } 4217 break; 4218 4219 case RT_DEVICE: 4220 /* First make sure everything was filled in. */ 4221 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 4222 PT_MATCH, &validation_failed); 4223 4224 if (validation_failed) { 4225 saw_error = TRUE; 4226 return; 4227 } 4228 4229 if (end_op == CMD_ADD) { 4230 /* Make sure there isn't already one like this. */ 4231 (void) strlcpy(tmp_devtab.zone_dev_match, 4232 in_progress_devtab.zone_dev_match, 4233 sizeof (tmp_devtab.zone_dev_match)); 4234 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 4235 zerr(gettext("A %s resource with the %s '%s' " 4236 "already exists."), rt_to_str(RT_DEVICE), 4237 pt_to_str(PT_MATCH), 4238 in_progress_devtab.zone_dev_match); 4239 saw_error = TRUE; 4240 return; 4241 } 4242 err = zonecfg_add_dev(handle, &in_progress_devtab); 4243 } else { 4244 err = zonecfg_modify_dev(handle, &old_devtab, 4245 &in_progress_devtab); 4246 } 4247 break; 4248 4249 case RT_RCTL: 4250 /* First make sure everything was filled in. */ 4251 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 4252 PT_NAME, &validation_failed); 4253 4254 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 4255 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 4256 validation_failed = TRUE; 4257 } 4258 4259 if (validation_failed) { 4260 saw_error = TRUE; 4261 return; 4262 } 4263 4264 if (end_op == CMD_ADD) { 4265 /* Make sure there isn't already one like this. */ 4266 (void) strlcpy(tmp_rctltab.zone_rctl_name, 4267 in_progress_rctltab.zone_rctl_name, 4268 sizeof (tmp_rctltab.zone_rctl_name)); 4269 tmp_rctltab.zone_rctl_valptr = NULL; 4270 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 4271 zonecfg_free_rctl_value_list( 4272 tmp_rctltab.zone_rctl_valptr); 4273 if (err == Z_OK) { 4274 zerr(gettext("A %s resource " 4275 "with the %s '%s' already exists."), 4276 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 4277 in_progress_rctltab.zone_rctl_name); 4278 saw_error = TRUE; 4279 return; 4280 } 4281 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 4282 } else { 4283 err = zonecfg_modify_rctl(handle, &old_rctltab, 4284 &in_progress_rctltab); 4285 } 4286 if (err == Z_OK) { 4287 zonecfg_free_rctl_value_list( 4288 in_progress_rctltab.zone_rctl_valptr); 4289 in_progress_rctltab.zone_rctl_valptr = NULL; 4290 } 4291 break; 4292 4293 case RT_ATTR: 4294 /* First make sure everything was filled in. */ 4295 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 4296 PT_NAME, &validation_failed); 4297 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 4298 PT_TYPE, &validation_failed); 4299 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 4300 PT_VALUE, &validation_failed); 4301 4302 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 4303 Z_OK) 4304 validation_failed = TRUE; 4305 4306 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 4307 validation_failed = TRUE; 4308 4309 if (validation_failed) { 4310 saw_error = TRUE; 4311 return; 4312 } 4313 if (end_op == CMD_ADD) { 4314 /* Make sure there isn't already one like this. */ 4315 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 4316 (void) strlcpy(tmp_attrtab.zone_attr_name, 4317 in_progress_attrtab.zone_attr_name, 4318 sizeof (tmp_attrtab.zone_attr_name)); 4319 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 4320 zerr(gettext("An %s resource " 4321 "with the %s '%s' already exists."), 4322 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 4323 in_progress_attrtab.zone_attr_name); 4324 saw_error = TRUE; 4325 return; 4326 } 4327 err = zonecfg_add_attr(handle, &in_progress_attrtab); 4328 } else { 4329 err = zonecfg_modify_attr(handle, &old_attrtab, 4330 &in_progress_attrtab); 4331 } 4332 break; 4333 case RT_DATASET: 4334 /* First make sure everything was filled in. */ 4335 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 4336 zerr("%s %s", pt_to_str(PT_NAME), 4337 gettext("not specified")); 4338 saw_error = TRUE; 4339 validation_failed = TRUE; 4340 } 4341 if (validation_failed) 4342 return; 4343 if (end_op == CMD_ADD) { 4344 /* Make sure there isn't already one like this. */ 4345 bzero(&tmp_dstab, sizeof (tmp_dstab)); 4346 (void) strlcpy(tmp_dstab.zone_dataset_name, 4347 in_progress_dstab.zone_dataset_name, 4348 sizeof (tmp_dstab.zone_dataset_name)); 4349 err = zonecfg_lookup_ds(handle, &tmp_dstab); 4350 if (err == Z_OK) { 4351 zerr(gettext("A %s resource " 4352 "with the %s '%s' already exists."), 4353 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 4354 in_progress_dstab.zone_dataset_name); 4355 saw_error = TRUE; 4356 return; 4357 } 4358 err = zonecfg_add_ds(handle, &in_progress_dstab); 4359 } else { 4360 err = zonecfg_modify_ds(handle, &old_dstab, 4361 &in_progress_dstab); 4362 } 4363 break; 4364 default: 4365 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 4366 TRUE); 4367 saw_error = TRUE; 4368 return; 4369 } 4370 4371 if (err != Z_OK) { 4372 zone_perror(zone, err, TRUE); 4373 } else { 4374 need_to_commit = TRUE; 4375 global_scope = TRUE; 4376 end_op = -1; 4377 } 4378 } 4379 4380 void 4381 commit_func(cmd_t *cmd) 4382 { 4383 int arg; 4384 4385 optind = 0; 4386 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 4387 switch (arg) { 4388 case '?': 4389 longer_usage(CMD_COMMIT); 4390 return; 4391 default: 4392 short_usage(CMD_COMMIT); 4393 return; 4394 } 4395 } 4396 if (optind != cmd->cmd_argc) { 4397 short_usage(CMD_COMMIT); 4398 return; 4399 } 4400 4401 if (zone_is_read_only(CMD_COMMIT)) 4402 return; 4403 4404 assert(cmd != NULL); 4405 4406 cmd->cmd_argc = 1; 4407 /* 4408 * cmd_arg normally comes from a strdup() in the lexer, and the 4409 * whole cmd structure and its (char *) attributes are freed at 4410 * the completion of each command, so the strdup() below is needed 4411 * to match this and prevent a core dump from trying to free() 4412 * something that can't be. 4413 */ 4414 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 4415 zone_perror(zone, Z_NOMEM, TRUE); 4416 exit(Z_ERR); 4417 } 4418 cmd->cmd_argv[1] = NULL; 4419 verify_func(cmd); 4420 } 4421 4422 void 4423 revert_func(cmd_t *cmd) 4424 { 4425 char line[128]; /* enough to ask a question */ 4426 bool force = FALSE; 4427 int err, arg, answer; 4428 4429 optind = 0; 4430 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 4431 switch (arg) { 4432 case '?': 4433 longer_usage(CMD_REVERT); 4434 return; 4435 case 'F': 4436 force = TRUE; 4437 break; 4438 default: 4439 short_usage(CMD_REVERT); 4440 return; 4441 } 4442 } 4443 if (optind != cmd->cmd_argc) { 4444 short_usage(CMD_REVERT); 4445 return; 4446 } 4447 4448 if (zone_is_read_only(CMD_REVERT)) 4449 return; 4450 4451 if (zonecfg_check_handle(handle) != Z_OK) { 4452 zerr(gettext("No changes to revert.")); 4453 saw_error = TRUE; 4454 return; 4455 } 4456 4457 if (!force) { 4458 (void) snprintf(line, sizeof (line), 4459 gettext("Are you sure you want to revert")); 4460 if ((answer = ask_yesno(FALSE, line)) == -1) { 4461 zerr(gettext("Input not from terminal and -F not " 4462 "specified:\n%s command ignored, exiting."), 4463 cmd_to_str(CMD_REVERT)); 4464 exit(Z_ERR); 4465 } 4466 if (answer != 1) 4467 return; 4468 } 4469 4470 /* 4471 * Time for a new handle: finish the old one off first 4472 * then get a new one properly to avoid leaks. 4473 */ 4474 zonecfg_fini_handle(handle); 4475 if ((handle = zonecfg_init_handle()) == NULL) { 4476 zone_perror(execname, Z_NOMEM, TRUE); 4477 exit(Z_ERR); 4478 } 4479 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 4480 saw_error = TRUE; 4481 got_handle = FALSE; 4482 if (err == Z_NO_ZONE) 4483 zerr(gettext("%s: no such saved zone to revert to."), 4484 revert_zone); 4485 else 4486 zone_perror(zone, err, TRUE); 4487 } 4488 (void) strlcpy(zone, revert_zone, sizeof (zone)); 4489 } 4490 4491 void 4492 help_func(cmd_t *cmd) 4493 { 4494 int i; 4495 4496 assert(cmd != NULL); 4497 4498 if (cmd->cmd_argc == 0) { 4499 usage(TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 4500 return; 4501 } 4502 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 4503 usage(TRUE, HELP_USAGE); 4504 return; 4505 } 4506 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 4507 usage(TRUE, HELP_SUBCMDS); 4508 return; 4509 } 4510 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 4511 usage(TRUE, HELP_SYNTAX | HELP_RES_PROPS); 4512 return; 4513 } 4514 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 4515 longer_usage(CMD_HELP); 4516 return; 4517 } 4518 4519 for (i = 0; i <= CMD_MAX; i++) { 4520 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 4521 longer_usage(i); 4522 return; 4523 } 4524 } 4525 /* We do not use zerr() here because we do not want its extra \n. */ 4526 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 4527 cmd->cmd_argv[0]); 4528 usage(FALSE, HELP_META); 4529 } 4530 4531 static int 4532 string_to_yyin(char *string) 4533 { 4534 if ((yyin = tmpfile()) == NULL) { 4535 zone_perror(execname, Z_TEMP_FILE, TRUE); 4536 return (Z_ERR); 4537 } 4538 if (fwrite(string, strlen(string), 1, yyin) != 1) { 4539 zone_perror(execname, Z_TEMP_FILE, TRUE); 4540 return (Z_ERR); 4541 } 4542 if (fseek(yyin, 0, SEEK_SET) != 0) { 4543 zone_perror(execname, Z_TEMP_FILE, TRUE); 4544 return (Z_ERR); 4545 } 4546 return (Z_OK); 4547 } 4548 4549 /* This is the back-end helper function for read_input() below. */ 4550 4551 static int 4552 cleanup() 4553 { 4554 int answer; 4555 cmd_t *cmd; 4556 4557 if (!interactive_mode && !cmd_file_mode) { 4558 /* 4559 * If we're not in interactive mode, and we're not in command 4560 * file mode, then we must be in commands-from-the-command-line 4561 * mode. As such, we can't loop back and ask for more input. 4562 * It was OK to prompt for such things as whether or not to 4563 * really delete a zone in the command handler called from 4564 * yyparse() above, but "really quit?" makes no sense in this 4565 * context. So disable prompting. 4566 */ 4567 ok_to_prompt = FALSE; 4568 } 4569 if (!global_scope) { 4570 if (!time_to_exit) { 4571 /* 4572 * Just print a simple error message in the -1 case, 4573 * since exit_func() already handles that case, and 4574 * EOF means we are finished anyway. 4575 */ 4576 answer = ask_yesno(FALSE, 4577 gettext("Resource incomplete; really quit")); 4578 if (answer == -1) { 4579 zerr(gettext("Resource incomplete.")); 4580 return (Z_ERR); 4581 } 4582 if (answer != 1) { 4583 yyin = stdin; 4584 return (Z_REPEAT); 4585 } 4586 } else { 4587 saw_error = TRUE; 4588 } 4589 } 4590 /* 4591 * Make sure we tried something and that the handle checks 4592 * out, or we would get a false error trying to commit. 4593 */ 4594 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 4595 if ((cmd = alloc_cmd()) == NULL) { 4596 zone_perror(zone, Z_NOMEM, TRUE); 4597 return (Z_ERR); 4598 } 4599 cmd->cmd_argc = 0; 4600 cmd->cmd_argv[0] = NULL; 4601 commit_func(cmd); 4602 free_cmd(cmd); 4603 /* 4604 * need_to_commit will get set back to FALSE if the 4605 * configuration is saved successfully. 4606 */ 4607 if (need_to_commit) { 4608 if (force_exit) { 4609 zerr(gettext("Configuration not saved.")); 4610 return (Z_ERR); 4611 } 4612 answer = ask_yesno(FALSE, 4613 gettext("Configuration not saved; really quit")); 4614 if (answer == -1) { 4615 zerr(gettext("Configuration not saved.")); 4616 return (Z_ERR); 4617 } 4618 if (answer != 1) { 4619 time_to_exit = FALSE; 4620 yyin = stdin; 4621 return (Z_REPEAT); 4622 } 4623 } 4624 } 4625 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 4626 } 4627 4628 /* 4629 * read_input() is the driver of this program. It is a wrapper around 4630 * yyparse(), printing appropriate prompts when needed, checking for 4631 * exit conditions and reacting appropriately [the latter in its cleanup() 4632 * helper function]. 4633 * 4634 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 4635 * so do_interactive() knows that we are not really done (i.e, we asked 4636 * the user if we should really quit and the user said no). 4637 */ 4638 static int 4639 read_input() 4640 { 4641 bool yyin_is_a_tty = isatty(fileno(yyin)); 4642 /* 4643 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 4644 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 4645 */ 4646 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 4647 4648 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 4649 newline_terminated = TRUE; 4650 for (;;) { 4651 if (yyin_is_a_tty) { 4652 if (newline_terminated) { 4653 if (global_scope) 4654 (void) snprintf(prompt, sizeof (prompt), 4655 "%s:%s> ", execname, zone); 4656 else 4657 (void) snprintf(prompt, sizeof (prompt), 4658 "%s:%s:%s> ", execname, zone, 4659 rt_to_str(resource_scope)); 4660 } 4661 /* 4662 * If the user hits ^C then we want to catch it and 4663 * start over. If the user hits EOF then we want to 4664 * bail out. 4665 */ 4666 line = gl_get_line(gl, prompt, NULL, -1); 4667 if (gl_return_status(gl) == GLR_SIGNAL) { 4668 gl_abandon_line(gl); 4669 continue; 4670 } 4671 if (line == NULL) 4672 break; 4673 (void) string_to_yyin(line); 4674 while (!feof(yyin)) 4675 yyparse(); 4676 } else { 4677 yyparse(); 4678 } 4679 /* Bail out on an error in command file mode. */ 4680 if (saw_error && cmd_file_mode && !interactive_mode) 4681 time_to_exit = TRUE; 4682 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 4683 break; 4684 } 4685 return (cleanup()); 4686 } 4687 4688 /* 4689 * This function is used in the zonecfg-interactive-mode scenario: it just 4690 * calls read_input() until we are done. 4691 */ 4692 4693 static int 4694 do_interactive(void) 4695 { 4696 int err; 4697 4698 interactive_mode = TRUE; 4699 if (!read_only_mode) { 4700 /* 4701 * Try to set things up proactively in interactive mode, so 4702 * that if the zone in question does not exist yet, we can 4703 * provide the user with a clue. 4704 */ 4705 (void) initialize(FALSE); 4706 } 4707 do { 4708 err = read_input(); 4709 } while (err == Z_REPEAT); 4710 return (err); 4711 } 4712 4713 /* 4714 * cmd_file is slightly more complicated, as it has to open the command file 4715 * and set yyin appropriately. Once that is done, though, it just calls 4716 * read_input(), and only once, since prompting is not possible. 4717 */ 4718 4719 static int 4720 cmd_file(char *file) 4721 { 4722 FILE *infile; 4723 int err; 4724 struct stat statbuf; 4725 bool using_real_file = (strcmp(file, "-") != 0); 4726 4727 if (using_real_file) { 4728 /* 4729 * zerr() prints a line number in cmd_file_mode, which we do 4730 * not want here, so temporarily unset it. 4731 */ 4732 cmd_file_mode = FALSE; 4733 if ((infile = fopen(file, "r")) == NULL) { 4734 zerr(gettext("could not open file %s: %s"), 4735 file, strerror(errno)); 4736 return (Z_ERR); 4737 } 4738 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 4739 zerr(gettext("could not stat file %s: %s"), 4740 file, strerror(errno)); 4741 err = Z_ERR; 4742 goto done; 4743 } 4744 if (!S_ISREG(statbuf.st_mode)) { 4745 zerr(gettext("%s is not a regular file."), file); 4746 err = Z_ERR; 4747 goto done; 4748 } 4749 yyin = infile; 4750 cmd_file_mode = TRUE; 4751 ok_to_prompt = FALSE; 4752 } else { 4753 /* 4754 * "-f -" is essentially the same as interactive mode, 4755 * so treat it that way. 4756 */ 4757 interactive_mode = TRUE; 4758 } 4759 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 4760 if ((err = read_input()) == Z_REPEAT) 4761 err = Z_ERR; 4762 done: 4763 if (using_real_file) 4764 (void) fclose(infile); 4765 return (err); 4766 } 4767 4768 /* 4769 * Since yacc is based on reading from a (FILE *) whereas what we get from 4770 * the command line is in argv format, we need to convert when the user 4771 * gives us commands directly from the command line. That is done here by 4772 * concatenating the argv list into a space-separated string, writing it 4773 * to a temp file, and rewinding the file so yyin can be set to it. Then 4774 * we call read_input(), and only once, since prompting about whether to 4775 * continue or quit would make no sense in this context. 4776 */ 4777 4778 static int 4779 one_command_at_a_time(int argc, char *argv[]) 4780 { 4781 char *command; 4782 size_t len = 2; /* terminal \n\0 */ 4783 int i, err; 4784 4785 for (i = 0; i < argc; i++) 4786 len += strlen(argv[i]) + 1; 4787 if ((command = malloc(len)) == NULL) { 4788 zone_perror(execname, Z_NOMEM, TRUE); 4789 return (Z_ERR); 4790 } 4791 (void) strlcpy(command, argv[0], len); 4792 for (i = 1; i < argc; i++) { 4793 (void) strlcat(command, " ", len); 4794 (void) strlcat(command, argv[i], len); 4795 } 4796 (void) strlcat(command, "\n", len); 4797 err = string_to_yyin(command); 4798 free(command); 4799 if (err != Z_OK) 4800 return (err); 4801 while (!feof(yyin)) 4802 yyparse(); 4803 return (cleanup()); 4804 } 4805 4806 static char * 4807 get_execbasename(char *execfullname) 4808 { 4809 char *last_slash, *execbasename; 4810 4811 /* guard against '/' at end of command invocation */ 4812 for (;;) { 4813 last_slash = strrchr(execfullname, '/'); 4814 if (last_slash == NULL) { 4815 execbasename = execfullname; 4816 break; 4817 } else { 4818 execbasename = last_slash + 1; 4819 if (*execbasename == '\0') { 4820 *last_slash = '\0'; 4821 continue; 4822 } 4823 break; 4824 } 4825 } 4826 return (execbasename); 4827 } 4828 4829 int 4830 main(int argc, char *argv[]) 4831 { 4832 int err, arg; 4833 struct stat st; 4834 4835 /* This must be before anything goes to stdout. */ 4836 setbuf(stdout, NULL); 4837 4838 saw_error = FALSE; 4839 cmd_file_mode = FALSE; 4840 execname = get_execbasename(argv[0]); 4841 4842 (void) setlocale(LC_ALL, ""); 4843 (void) textdomain(TEXT_DOMAIN); 4844 4845 if (getzoneid() != GLOBAL_ZONEID) { 4846 zerr(gettext("%s can only be run from the global zone."), 4847 execname); 4848 exit(Z_ERR); 4849 } 4850 4851 if (argc < 2) { 4852 usage(FALSE, HELP_USAGE | HELP_SUBCMDS); 4853 exit(Z_USAGE); 4854 } 4855 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 4856 (void) one_command_at_a_time(argc - 1, &(argv[1])); 4857 exit(Z_OK); 4858 } 4859 4860 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 4861 switch (arg) { 4862 case '?': 4863 if (optopt == '?') 4864 usage(TRUE, HELP_USAGE | HELP_SUBCMDS); 4865 else 4866 usage(FALSE, HELP_USAGE); 4867 exit(Z_USAGE); 4868 /* NOTREACHED */ 4869 case 'f': 4870 cmd_file_name = optarg; 4871 cmd_file_mode = TRUE; 4872 break; 4873 case 'R': 4874 if (*optarg != '/') { 4875 zerr(gettext("root path must be absolute: %s"), 4876 optarg); 4877 exit(Z_USAGE); 4878 } 4879 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 4880 zerr(gettext( 4881 "root path must be a directory: %s"), 4882 optarg); 4883 exit(Z_USAGE); 4884 } 4885 zonecfg_set_root(optarg); 4886 break; 4887 case 'z': 4888 if (zonecfg_validate_zonename(optarg) != Z_OK) { 4889 zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE); 4890 usage(FALSE, HELP_SYNTAX); 4891 exit(Z_USAGE); 4892 } 4893 (void) strlcpy(zone, optarg, sizeof (zone)); 4894 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 4895 break; 4896 default: 4897 usage(FALSE, HELP_USAGE); 4898 exit(Z_USAGE); 4899 } 4900 } 4901 4902 if (optind > argc || strcmp(zone, "") == 0) { 4903 usage(FALSE, HELP_USAGE); 4904 exit(Z_USAGE); 4905 } 4906 4907 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 4908 read_only_mode = FALSE; 4909 } else if (err == Z_ACCES) { 4910 read_only_mode = TRUE; 4911 /* skip this message in one-off from command line mode */ 4912 if (optind == argc) 4913 (void) fprintf(stderr, gettext("WARNING: you do not " 4914 "have write access to this zone's configuration " 4915 "file;\ngoing into read-only mode.\n")); 4916 } else { 4917 fprintf(stderr, "%s: Could not access zone configuration " 4918 "store: %s\n", execname, zonecfg_strerror(err)); 4919 exit(Z_ERR); 4920 } 4921 4922 if ((handle = zonecfg_init_handle()) == NULL) { 4923 zone_perror(execname, Z_NOMEM, TRUE); 4924 exit(Z_ERR); 4925 } 4926 4927 /* 4928 * This may get set back to FALSE again in cmd_file() if cmd_file_name 4929 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 4930 */ 4931 if (isatty(STDIN_FILENO)) 4932 ok_to_prompt = TRUE; 4933 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 4934 exit(Z_ERR); 4935 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 4936 exit(Z_ERR); 4937 (void) sigset(SIGINT, SIG_IGN); 4938 if (optind == argc) { 4939 if (!cmd_file_mode) 4940 err = do_interactive(); 4941 else 4942 err = cmd_file(cmd_file_name); 4943 } else { 4944 err = one_command_at_a_time(argc - optind, &(argv[optind])); 4945 } 4946 zonecfg_fini_handle(handle); 4947 if (brand != NULL) 4948 brand_close(brand); 4949 (void) del_GetLine(gl); 4950 return (err); 4951 } 4952