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 = "/tmp/zonecfg_verify.XXXXXX"; 3691 char cmdbuf[MAX_CMD_LEN]; 3692 brand_handle_t *bhp; 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 ((bhp = 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(bhp, cmdbuf + EXEC_LEN, 3711 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 3712 brand_close(bhp); 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 if (mkstemp(xml_file) == NULL) 3730 return (Z_TEMP_FILE); 3731 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 3732 (void) unlink(xml_file); 3733 return (err); 3734 } 3735 3736 /* 3737 * Execute the verification command. 3738 */ 3739 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 3740 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 3741 err = Z_BRAND_ERROR; 3742 } else { 3743 err = do_subproc(cmdbuf); 3744 } 3745 3746 (void) unlink(xml_file); 3747 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 3748 } 3749 3750 /* 3751 * See the DTD for which attributes are required for which resources. 3752 * 3753 * This function can be called by commit_func(), which needs to save things, 3754 * in addition to the general call from parse_and_run(), which doesn't need 3755 * things saved. Since the parameters are standardized, we distinguish by 3756 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 3757 * that a save is needed. 3758 */ 3759 void 3760 verify_func(cmd_t *cmd) 3761 { 3762 struct zone_nwiftab nwiftab; 3763 struct zone_fstab fstab; 3764 struct zone_attrtab attrtab; 3765 struct zone_rctltab rctltab; 3766 struct zone_dstab dstab; 3767 char zonepath[MAXPATHLEN]; 3768 char brand[MAXNAMELEN]; 3769 int err, ret_val = Z_OK, arg; 3770 bool save = FALSE; 3771 3772 optind = 0; 3773 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3774 switch (arg) { 3775 case '?': 3776 longer_usage(CMD_VERIFY); 3777 return; 3778 default: 3779 short_usage(CMD_VERIFY); 3780 return; 3781 } 3782 } 3783 if (optind > cmd->cmd_argc) { 3784 short_usage(CMD_VERIFY); 3785 return; 3786 } 3787 3788 if (zone_is_read_only(CMD_VERIFY)) 3789 return; 3790 3791 assert(cmd != NULL); 3792 3793 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 3794 save = TRUE; 3795 if (initialize(TRUE) != Z_OK) 3796 return; 3797 3798 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK) { 3799 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 3800 ret_val = Z_REQD_RESOURCE_MISSING; 3801 saw_error = TRUE; 3802 } 3803 if (strlen(zonepath) == 0) { 3804 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 3805 ret_val = Z_REQD_RESOURCE_MISSING; 3806 saw_error = TRUE; 3807 } 3808 3809 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 3810 zone_perror(zone, err, TRUE); 3811 return; 3812 } 3813 if (strcmp(brand, NATIVE_BRAND_NAME) != 0) { 3814 if ((err = brand_verify(handle)) != Z_OK) { 3815 zone_perror(zone, err, TRUE); 3816 return; 3817 } 3818 } 3819 3820 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 3821 zone_perror(zone, err, TRUE); 3822 return; 3823 } 3824 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 3825 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 3826 } 3827 (void) zonecfg_endipdent(handle); 3828 3829 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 3830 zone_perror(zone, err, TRUE); 3831 return; 3832 } 3833 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 3834 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 3835 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 3836 &ret_val); 3837 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 3838 3839 zonecfg_free_fs_option_list(fstab.zone_fs_options); 3840 } 3841 (void) zonecfg_endfsent(handle); 3842 3843 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 3844 zone_perror(zone, err, TRUE); 3845 return; 3846 } 3847 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 3848 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 3849 PT_ADDRESS, &ret_val); 3850 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 3851 PT_PHYSICAL, &ret_val); 3852 } 3853 (void) zonecfg_endnwifent(handle); 3854 3855 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 3856 zone_perror(zone, err, TRUE); 3857 return; 3858 } 3859 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 3860 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 3861 &ret_val); 3862 3863 if (rctltab.zone_rctl_valptr == NULL) { 3864 zerr(gettext("%s: no %s specified"), 3865 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 3866 saw_error = TRUE; 3867 if (ret_val == Z_OK) 3868 ret_val = Z_REQD_PROPERTY_MISSING; 3869 } else { 3870 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 3871 } 3872 } 3873 (void) zonecfg_endrctlent(handle); 3874 3875 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 3876 zone_perror(zone, err, TRUE); 3877 return; 3878 } 3879 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 3880 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 3881 &ret_val); 3882 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 3883 &ret_val); 3884 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 3885 &ret_val); 3886 } 3887 (void) zonecfg_endattrent(handle); 3888 3889 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 3890 zone_perror(zone, err, TRUE); 3891 return; 3892 } 3893 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 3894 if (strlen(dstab.zone_dataset_name) == 0) { 3895 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3896 pt_to_str(PT_NAME), gettext("not specified")); 3897 saw_error = TRUE; 3898 if (ret_val == Z_OK) 3899 ret_val = Z_REQD_PROPERTY_MISSING; 3900 } else if (!zfs_name_valid(dstab.zone_dataset_name, 3901 ZFS_TYPE_FILESYSTEM)) { 3902 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3903 pt_to_str(PT_NAME), gettext("invalid")); 3904 saw_error = TRUE; 3905 if (ret_val == Z_OK) 3906 ret_val = Z_BAD_PROPERTY; 3907 } 3908 3909 } 3910 (void) zonecfg_enddsent(handle); 3911 3912 if (!global_scope) { 3913 zerr(gettext("resource specification incomplete")); 3914 saw_error = TRUE; 3915 if (ret_val == Z_OK) 3916 ret_val = Z_INSUFFICIENT_SPEC; 3917 } 3918 3919 if (save) { 3920 if (ret_val == Z_OK) { 3921 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 3922 need_to_commit = FALSE; 3923 (void) strlcpy(revert_zone, zone, 3924 sizeof (revert_zone)); 3925 } 3926 } else { 3927 zerr(gettext("Zone %s failed to verify"), zone); 3928 } 3929 } 3930 if (ret_val != Z_OK) 3931 zone_perror(zone, ret_val, TRUE); 3932 } 3933 3934 void 3935 cancel_func(cmd_t *cmd) 3936 { 3937 int arg; 3938 3939 assert(cmd != NULL); 3940 3941 optind = 0; 3942 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3943 switch (arg) { 3944 case '?': 3945 longer_usage(CMD_CANCEL); 3946 return; 3947 default: 3948 short_usage(CMD_CANCEL); 3949 return; 3950 } 3951 } 3952 if (optind != cmd->cmd_argc) { 3953 short_usage(CMD_CANCEL); 3954 return; 3955 } 3956 3957 if (global_scope) 3958 scope_usage(CMD_CANCEL); 3959 global_scope = TRUE; 3960 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 3961 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 3962 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 3963 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 3964 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 3965 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 3966 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 3967 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 3968 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 3969 } 3970 3971 static int 3972 validate_attr_name(char *name) 3973 { 3974 int i; 3975 3976 if (!isalnum(name[0])) { 3977 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 3978 "numeric character."), rt_to_str(RT_ATTR), 3979 pt_to_str(PT_NAME), name); 3980 return (Z_INVAL); 3981 } 3982 for (i = 1; name[i]; i++) 3983 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 3984 zerr(gettext("Invalid %s %s %s: can only contain " 3985 "alpha-numeric characters, plus '-' and '.'."), 3986 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 3987 return (Z_INVAL); 3988 } 3989 return (Z_OK); 3990 } 3991 3992 static int 3993 validate_attr_type_val(struct zone_attrtab *attrtab) 3994 { 3995 boolean_t boolval; 3996 int64_t intval; 3997 char strval[MAXNAMELEN]; 3998 uint64_t uintval; 3999 4000 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 4001 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 4002 return (Z_OK); 4003 zerr(gettext("invalid %s value for %s=%s"), 4004 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 4005 return (Z_ERR); 4006 } 4007 4008 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 4009 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 4010 return (Z_OK); 4011 zerr(gettext("invalid %s value for %s=%s"), 4012 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 4013 return (Z_ERR); 4014 } 4015 4016 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 4017 if (zonecfg_get_attr_string(attrtab, strval, 4018 sizeof (strval)) == Z_OK) 4019 return (Z_OK); 4020 zerr(gettext("invalid %s value for %s=%s"), 4021 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 4022 return (Z_ERR); 4023 } 4024 4025 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 4026 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 4027 return (Z_OK); 4028 zerr(gettext("invalid %s value for %s=%s"), 4029 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 4030 return (Z_ERR); 4031 } 4032 4033 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 4034 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 4035 return (Z_ERR); 4036 } 4037 4038 /* 4039 * Helper function for end_func-- checks the existence of a given property 4040 * and emits a message if not specified. 4041 */ 4042 static int 4043 end_check_reqd(char *attr, int pt, bool *validation_failed) 4044 { 4045 if (strlen(attr) == 0) { 4046 *validation_failed = TRUE; 4047 zerr(gettext("%s not specified"), pt_to_str(pt)); 4048 return (Z_ERR); 4049 } 4050 return (Z_OK); 4051 } 4052 4053 void 4054 end_func(cmd_t *cmd) 4055 { 4056 bool validation_failed = FALSE; 4057 struct zone_fstab tmp_fstab; 4058 struct zone_nwiftab tmp_nwiftab; 4059 struct zone_devtab tmp_devtab; 4060 struct zone_rctltab tmp_rctltab; 4061 struct zone_attrtab tmp_attrtab; 4062 struct zone_dstab tmp_dstab; 4063 int err, arg; 4064 4065 assert(cmd != NULL); 4066 4067 optind = 0; 4068 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 4069 switch (arg) { 4070 case '?': 4071 longer_usage(CMD_END); 4072 return; 4073 default: 4074 short_usage(CMD_END); 4075 return; 4076 } 4077 } 4078 if (optind != cmd->cmd_argc) { 4079 short_usage(CMD_END); 4080 return; 4081 } 4082 4083 if (global_scope) { 4084 scope_usage(CMD_END); 4085 return; 4086 } 4087 4088 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 4089 4090 switch (resource_scope) { 4091 case RT_FS: 4092 /* First make sure everything was filled in. */ 4093 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 4094 PT_DIR, &validation_failed) == Z_OK) { 4095 if (in_progress_fstab.zone_fs_dir[0] != '/') { 4096 zerr(gettext("%s %s is not an absolute path."), 4097 pt_to_str(PT_DIR), 4098 in_progress_fstab.zone_fs_dir); 4099 validation_failed = TRUE; 4100 } 4101 } 4102 4103 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 4104 PT_SPECIAL, &validation_failed); 4105 4106 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 4107 in_progress_fstab.zone_fs_raw[0] != '/') { 4108 zerr(gettext("%s %s is not an absolute path."), 4109 pt_to_str(PT_RAW), 4110 in_progress_fstab.zone_fs_raw); 4111 validation_failed = TRUE; 4112 } 4113 4114 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 4115 &validation_failed); 4116 4117 if (validation_failed) { 4118 saw_error = TRUE; 4119 return; 4120 } 4121 4122 if (end_op == CMD_ADD) { 4123 /* Make sure there isn't already one like this. */ 4124 bzero(&tmp_fstab, sizeof (tmp_fstab)); 4125 (void) strlcpy(tmp_fstab.zone_fs_dir, 4126 in_progress_fstab.zone_fs_dir, 4127 sizeof (tmp_fstab.zone_fs_dir)); 4128 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 4129 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 4130 if (err == Z_OK) { 4131 zerr(gettext("A %s resource " 4132 "with the %s '%s' already exists."), 4133 rt_to_str(RT_FS), pt_to_str(PT_DIR), 4134 in_progress_fstab.zone_fs_dir); 4135 saw_error = TRUE; 4136 return; 4137 } 4138 err = zonecfg_add_filesystem(handle, 4139 &in_progress_fstab); 4140 } else { 4141 err = zonecfg_modify_filesystem(handle, &old_fstab, 4142 &in_progress_fstab); 4143 } 4144 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 4145 in_progress_fstab.zone_fs_options = NULL; 4146 break; 4147 4148 case RT_IPD: 4149 /* First make sure everything was filled in. */ 4150 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 4151 &validation_failed) == Z_OK) { 4152 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 4153 zerr(gettext("%s %s is not an absolute path."), 4154 pt_to_str(PT_DIR), 4155 in_progress_ipdtab.zone_fs_dir); 4156 validation_failed = TRUE; 4157 } 4158 } 4159 if (validation_failed) { 4160 saw_error = TRUE; 4161 return; 4162 } 4163 4164 if (end_op == CMD_ADD) { 4165 /* Make sure there isn't already one like this. */ 4166 bzero(&tmp_fstab, sizeof (tmp_fstab)); 4167 (void) strlcpy(tmp_fstab.zone_fs_dir, 4168 in_progress_ipdtab.zone_fs_dir, 4169 sizeof (tmp_fstab.zone_fs_dir)); 4170 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 4171 if (err == Z_OK) { 4172 zerr(gettext("An %s resource " 4173 "with the %s '%s' already exists."), 4174 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 4175 in_progress_ipdtab.zone_fs_dir); 4176 saw_error = TRUE; 4177 return; 4178 } 4179 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 4180 } else { 4181 err = zonecfg_modify_ipd(handle, &old_ipdtab, 4182 &in_progress_ipdtab); 4183 } 4184 break; 4185 case RT_NET: 4186 /* First make sure everything was filled in. */ 4187 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 4188 PT_PHYSICAL, &validation_failed); 4189 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_address, 4190 PT_ADDRESS, &validation_failed); 4191 4192 if (validation_failed) { 4193 saw_error = TRUE; 4194 return; 4195 } 4196 4197 if (end_op == CMD_ADD) { 4198 /* Make sure there isn't already one like this. */ 4199 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 4200 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 4201 in_progress_nwiftab.zone_nwif_address, 4202 sizeof (tmp_nwiftab.zone_nwif_address)); 4203 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 4204 zerr(gettext("A %s resource " 4205 "with the %s '%s' already exists."), 4206 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS), 4207 in_progress_nwiftab.zone_nwif_address); 4208 saw_error = TRUE; 4209 return; 4210 } 4211 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 4212 } else { 4213 err = zonecfg_modify_nwif(handle, &old_nwiftab, 4214 &in_progress_nwiftab); 4215 } 4216 break; 4217 4218 case RT_DEVICE: 4219 /* First make sure everything was filled in. */ 4220 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 4221 PT_MATCH, &validation_failed); 4222 4223 if (validation_failed) { 4224 saw_error = TRUE; 4225 return; 4226 } 4227 4228 if (end_op == CMD_ADD) { 4229 /* Make sure there isn't already one like this. */ 4230 (void) strlcpy(tmp_devtab.zone_dev_match, 4231 in_progress_devtab.zone_dev_match, 4232 sizeof (tmp_devtab.zone_dev_match)); 4233 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 4234 zerr(gettext("A %s resource with the %s '%s' " 4235 "already exists."), rt_to_str(RT_DEVICE), 4236 pt_to_str(PT_MATCH), 4237 in_progress_devtab.zone_dev_match); 4238 saw_error = TRUE; 4239 return; 4240 } 4241 err = zonecfg_add_dev(handle, &in_progress_devtab); 4242 } else { 4243 err = zonecfg_modify_dev(handle, &old_devtab, 4244 &in_progress_devtab); 4245 } 4246 break; 4247 4248 case RT_RCTL: 4249 /* First make sure everything was filled in. */ 4250 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 4251 PT_NAME, &validation_failed); 4252 4253 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 4254 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 4255 validation_failed = TRUE; 4256 } 4257 4258 if (validation_failed) { 4259 saw_error = TRUE; 4260 return; 4261 } 4262 4263 if (end_op == CMD_ADD) { 4264 /* Make sure there isn't already one like this. */ 4265 (void) strlcpy(tmp_rctltab.zone_rctl_name, 4266 in_progress_rctltab.zone_rctl_name, 4267 sizeof (tmp_rctltab.zone_rctl_name)); 4268 tmp_rctltab.zone_rctl_valptr = NULL; 4269 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 4270 zonecfg_free_rctl_value_list( 4271 tmp_rctltab.zone_rctl_valptr); 4272 if (err == Z_OK) { 4273 zerr(gettext("A %s resource " 4274 "with the %s '%s' already exists."), 4275 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 4276 in_progress_rctltab.zone_rctl_name); 4277 saw_error = TRUE; 4278 return; 4279 } 4280 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 4281 } else { 4282 err = zonecfg_modify_rctl(handle, &old_rctltab, 4283 &in_progress_rctltab); 4284 } 4285 if (err == Z_OK) { 4286 zonecfg_free_rctl_value_list( 4287 in_progress_rctltab.zone_rctl_valptr); 4288 in_progress_rctltab.zone_rctl_valptr = NULL; 4289 } 4290 break; 4291 4292 case RT_ATTR: 4293 /* First make sure everything was filled in. */ 4294 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 4295 PT_NAME, &validation_failed); 4296 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 4297 PT_TYPE, &validation_failed); 4298 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 4299 PT_VALUE, &validation_failed); 4300 4301 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 4302 Z_OK) 4303 validation_failed = TRUE; 4304 4305 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 4306 validation_failed = TRUE; 4307 4308 if (validation_failed) { 4309 saw_error = TRUE; 4310 return; 4311 } 4312 if (end_op == CMD_ADD) { 4313 /* Make sure there isn't already one like this. */ 4314 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 4315 (void) strlcpy(tmp_attrtab.zone_attr_name, 4316 in_progress_attrtab.zone_attr_name, 4317 sizeof (tmp_attrtab.zone_attr_name)); 4318 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 4319 zerr(gettext("An %s resource " 4320 "with the %s '%s' already exists."), 4321 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 4322 in_progress_attrtab.zone_attr_name); 4323 saw_error = TRUE; 4324 return; 4325 } 4326 err = zonecfg_add_attr(handle, &in_progress_attrtab); 4327 } else { 4328 err = zonecfg_modify_attr(handle, &old_attrtab, 4329 &in_progress_attrtab); 4330 } 4331 break; 4332 case RT_DATASET: 4333 /* First make sure everything was filled in. */ 4334 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 4335 zerr("%s %s", pt_to_str(PT_NAME), 4336 gettext("not specified")); 4337 saw_error = TRUE; 4338 validation_failed = TRUE; 4339 } 4340 if (validation_failed) 4341 return; 4342 if (end_op == CMD_ADD) { 4343 /* Make sure there isn't already one like this. */ 4344 bzero(&tmp_dstab, sizeof (tmp_dstab)); 4345 (void) strlcpy(tmp_dstab.zone_dataset_name, 4346 in_progress_dstab.zone_dataset_name, 4347 sizeof (tmp_dstab.zone_dataset_name)); 4348 err = zonecfg_lookup_ds(handle, &tmp_dstab); 4349 if (err == Z_OK) { 4350 zerr(gettext("A %s resource " 4351 "with the %s '%s' already exists."), 4352 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 4353 in_progress_dstab.zone_dataset_name); 4354 saw_error = TRUE; 4355 return; 4356 } 4357 err = zonecfg_add_ds(handle, &in_progress_dstab); 4358 } else { 4359 err = zonecfg_modify_ds(handle, &old_dstab, 4360 &in_progress_dstab); 4361 } 4362 break; 4363 default: 4364 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 4365 TRUE); 4366 saw_error = TRUE; 4367 return; 4368 } 4369 4370 if (err != Z_OK) { 4371 zone_perror(zone, err, TRUE); 4372 } else { 4373 need_to_commit = TRUE; 4374 global_scope = TRUE; 4375 end_op = -1; 4376 } 4377 } 4378 4379 void 4380 commit_func(cmd_t *cmd) 4381 { 4382 int arg; 4383 4384 optind = 0; 4385 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 4386 switch (arg) { 4387 case '?': 4388 longer_usage(CMD_COMMIT); 4389 return; 4390 default: 4391 short_usage(CMD_COMMIT); 4392 return; 4393 } 4394 } 4395 if (optind != cmd->cmd_argc) { 4396 short_usage(CMD_COMMIT); 4397 return; 4398 } 4399 4400 if (zone_is_read_only(CMD_COMMIT)) 4401 return; 4402 4403 assert(cmd != NULL); 4404 4405 cmd->cmd_argc = 1; 4406 /* 4407 * cmd_arg normally comes from a strdup() in the lexer, and the 4408 * whole cmd structure and its (char *) attributes are freed at 4409 * the completion of each command, so the strdup() below is needed 4410 * to match this and prevent a core dump from trying to free() 4411 * something that can't be. 4412 */ 4413 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 4414 zone_perror(zone, Z_NOMEM, TRUE); 4415 exit(Z_ERR); 4416 } 4417 cmd->cmd_argv[1] = NULL; 4418 verify_func(cmd); 4419 } 4420 4421 void 4422 revert_func(cmd_t *cmd) 4423 { 4424 char line[128]; /* enough to ask a question */ 4425 bool force = FALSE; 4426 int err, arg, answer; 4427 4428 optind = 0; 4429 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 4430 switch (arg) { 4431 case '?': 4432 longer_usage(CMD_REVERT); 4433 return; 4434 case 'F': 4435 force = TRUE; 4436 break; 4437 default: 4438 short_usage(CMD_REVERT); 4439 return; 4440 } 4441 } 4442 if (optind != cmd->cmd_argc) { 4443 short_usage(CMD_REVERT); 4444 return; 4445 } 4446 4447 if (zone_is_read_only(CMD_REVERT)) 4448 return; 4449 4450 if (zonecfg_check_handle(handle) != Z_OK) { 4451 zerr(gettext("No changes to revert.")); 4452 saw_error = TRUE; 4453 return; 4454 } 4455 4456 if (!force) { 4457 (void) snprintf(line, sizeof (line), 4458 gettext("Are you sure you want to revert")); 4459 if ((answer = ask_yesno(FALSE, line)) == -1) { 4460 zerr(gettext("Input not from terminal and -F not " 4461 "specified:\n%s command ignored, exiting."), 4462 cmd_to_str(CMD_REVERT)); 4463 exit(Z_ERR); 4464 } 4465 if (answer != 1) 4466 return; 4467 } 4468 4469 /* 4470 * Time for a new handle: finish the old one off first 4471 * then get a new one properly to avoid leaks. 4472 */ 4473 zonecfg_fini_handle(handle); 4474 if ((handle = zonecfg_init_handle()) == NULL) { 4475 zone_perror(execname, Z_NOMEM, TRUE); 4476 exit(Z_ERR); 4477 } 4478 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 4479 saw_error = TRUE; 4480 got_handle = FALSE; 4481 if (err == Z_NO_ZONE) 4482 zerr(gettext("%s: no such saved zone to revert to."), 4483 revert_zone); 4484 else 4485 zone_perror(zone, err, TRUE); 4486 } 4487 (void) strlcpy(zone, revert_zone, sizeof (zone)); 4488 } 4489 4490 void 4491 help_func(cmd_t *cmd) 4492 { 4493 int i; 4494 4495 assert(cmd != NULL); 4496 4497 if (cmd->cmd_argc == 0) { 4498 usage(TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 4499 return; 4500 } 4501 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 4502 usage(TRUE, HELP_USAGE); 4503 return; 4504 } 4505 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 4506 usage(TRUE, HELP_SUBCMDS); 4507 return; 4508 } 4509 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 4510 usage(TRUE, HELP_SYNTAX | HELP_RES_PROPS); 4511 return; 4512 } 4513 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 4514 longer_usage(CMD_HELP); 4515 return; 4516 } 4517 4518 for (i = 0; i <= CMD_MAX; i++) { 4519 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 4520 longer_usage(i); 4521 return; 4522 } 4523 } 4524 /* We do not use zerr() here because we do not want its extra \n. */ 4525 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 4526 cmd->cmd_argv[0]); 4527 usage(FALSE, HELP_META); 4528 } 4529 4530 static int 4531 string_to_yyin(char *string) 4532 { 4533 if ((yyin = tmpfile()) == NULL) { 4534 zone_perror(execname, Z_TEMP_FILE, TRUE); 4535 return (Z_ERR); 4536 } 4537 if (fwrite(string, strlen(string), 1, yyin) != 1) { 4538 zone_perror(execname, Z_TEMP_FILE, TRUE); 4539 return (Z_ERR); 4540 } 4541 if (fseek(yyin, 0, SEEK_SET) != 0) { 4542 zone_perror(execname, Z_TEMP_FILE, TRUE); 4543 return (Z_ERR); 4544 } 4545 return (Z_OK); 4546 } 4547 4548 /* This is the back-end helper function for read_input() below. */ 4549 4550 static int 4551 cleanup() 4552 { 4553 int answer; 4554 cmd_t *cmd; 4555 4556 if (!interactive_mode && !cmd_file_mode) { 4557 /* 4558 * If we're not in interactive mode, and we're not in command 4559 * file mode, then we must be in commands-from-the-command-line 4560 * mode. As such, we can't loop back and ask for more input. 4561 * It was OK to prompt for such things as whether or not to 4562 * really delete a zone in the command handler called from 4563 * yyparse() above, but "really quit?" makes no sense in this 4564 * context. So disable prompting. 4565 */ 4566 ok_to_prompt = FALSE; 4567 } 4568 if (!global_scope) { 4569 if (!time_to_exit) { 4570 /* 4571 * Just print a simple error message in the -1 case, 4572 * since exit_func() already handles that case, and 4573 * EOF means we are finished anyway. 4574 */ 4575 answer = ask_yesno(FALSE, 4576 gettext("Resource incomplete; really quit")); 4577 if (answer == -1) { 4578 zerr(gettext("Resource incomplete.")); 4579 return (Z_ERR); 4580 } 4581 if (answer != 1) { 4582 yyin = stdin; 4583 return (Z_REPEAT); 4584 } 4585 } else { 4586 saw_error = TRUE; 4587 } 4588 } 4589 /* 4590 * Make sure we tried something and that the handle checks 4591 * out, or we would get a false error trying to commit. 4592 */ 4593 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 4594 if ((cmd = alloc_cmd()) == NULL) { 4595 zone_perror(zone, Z_NOMEM, TRUE); 4596 return (Z_ERR); 4597 } 4598 cmd->cmd_argc = 0; 4599 cmd->cmd_argv[0] = NULL; 4600 commit_func(cmd); 4601 free_cmd(cmd); 4602 /* 4603 * need_to_commit will get set back to FALSE if the 4604 * configuration is saved successfully. 4605 */ 4606 if (need_to_commit) { 4607 if (force_exit) { 4608 zerr(gettext("Configuration not saved.")); 4609 return (Z_ERR); 4610 } 4611 answer = ask_yesno(FALSE, 4612 gettext("Configuration not saved; really quit")); 4613 if (answer == -1) { 4614 zerr(gettext("Configuration not saved.")); 4615 return (Z_ERR); 4616 } 4617 if (answer != 1) { 4618 time_to_exit = FALSE; 4619 yyin = stdin; 4620 return (Z_REPEAT); 4621 } 4622 } 4623 } 4624 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 4625 } 4626 4627 /* 4628 * read_input() is the driver of this program. It is a wrapper around 4629 * yyparse(), printing appropriate prompts when needed, checking for 4630 * exit conditions and reacting appropriately [the latter in its cleanup() 4631 * helper function]. 4632 * 4633 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 4634 * so do_interactive() knows that we are not really done (i.e, we asked 4635 * the user if we should really quit and the user said no). 4636 */ 4637 static int 4638 read_input() 4639 { 4640 bool yyin_is_a_tty = isatty(fileno(yyin)); 4641 /* 4642 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 4643 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 4644 */ 4645 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 4646 4647 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 4648 newline_terminated = TRUE; 4649 for (;;) { 4650 if (yyin_is_a_tty) { 4651 if (newline_terminated) { 4652 if (global_scope) 4653 (void) snprintf(prompt, sizeof (prompt), 4654 "%s:%s> ", execname, zone); 4655 else 4656 (void) snprintf(prompt, sizeof (prompt), 4657 "%s:%s:%s> ", execname, zone, 4658 rt_to_str(resource_scope)); 4659 } 4660 /* 4661 * If the user hits ^C then we want to catch it and 4662 * start over. If the user hits EOF then we want to 4663 * bail out. 4664 */ 4665 line = gl_get_line(gl, prompt, NULL, -1); 4666 if (gl_return_status(gl) == GLR_SIGNAL) { 4667 gl_abandon_line(gl); 4668 continue; 4669 } 4670 if (line == NULL) 4671 break; 4672 (void) string_to_yyin(line); 4673 while (!feof(yyin)) 4674 yyparse(); 4675 } else { 4676 yyparse(); 4677 } 4678 /* Bail out on an error in command file mode. */ 4679 if (saw_error && cmd_file_mode && !interactive_mode) 4680 time_to_exit = TRUE; 4681 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 4682 break; 4683 } 4684 return (cleanup()); 4685 } 4686 4687 /* 4688 * This function is used in the zonecfg-interactive-mode scenario: it just 4689 * calls read_input() until we are done. 4690 */ 4691 4692 static int 4693 do_interactive(void) 4694 { 4695 int err; 4696 4697 interactive_mode = TRUE; 4698 if (!read_only_mode) { 4699 /* 4700 * Try to set things up proactively in interactive mode, so 4701 * that if the zone in question does not exist yet, we can 4702 * provide the user with a clue. 4703 */ 4704 (void) initialize(FALSE); 4705 } 4706 do { 4707 err = read_input(); 4708 } while (err == Z_REPEAT); 4709 return (err); 4710 } 4711 4712 /* 4713 * cmd_file is slightly more complicated, as it has to open the command file 4714 * and set yyin appropriately. Once that is done, though, it just calls 4715 * read_input(), and only once, since prompting is not possible. 4716 */ 4717 4718 static int 4719 cmd_file(char *file) 4720 { 4721 FILE *infile; 4722 int err; 4723 struct stat statbuf; 4724 bool using_real_file = (strcmp(file, "-") != 0); 4725 4726 if (using_real_file) { 4727 /* 4728 * zerr() prints a line number in cmd_file_mode, which we do 4729 * not want here, so temporarily unset it. 4730 */ 4731 cmd_file_mode = FALSE; 4732 if ((infile = fopen(file, "r")) == NULL) { 4733 zerr(gettext("could not open file %s: %s"), 4734 file, strerror(errno)); 4735 return (Z_ERR); 4736 } 4737 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 4738 zerr(gettext("could not stat file %s: %s"), 4739 file, strerror(errno)); 4740 err = Z_ERR; 4741 goto done; 4742 } 4743 if (!S_ISREG(statbuf.st_mode)) { 4744 zerr(gettext("%s is not a regular file."), file); 4745 err = Z_ERR; 4746 goto done; 4747 } 4748 yyin = infile; 4749 cmd_file_mode = TRUE; 4750 ok_to_prompt = FALSE; 4751 } else { 4752 /* 4753 * "-f -" is essentially the same as interactive mode, 4754 * so treat it that way. 4755 */ 4756 interactive_mode = TRUE; 4757 } 4758 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 4759 if ((err = read_input()) == Z_REPEAT) 4760 err = Z_ERR; 4761 done: 4762 if (using_real_file) 4763 (void) fclose(infile); 4764 return (err); 4765 } 4766 4767 /* 4768 * Since yacc is based on reading from a (FILE *) whereas what we get from 4769 * the command line is in argv format, we need to convert when the user 4770 * gives us commands directly from the command line. That is done here by 4771 * concatenating the argv list into a space-separated string, writing it 4772 * to a temp file, and rewinding the file so yyin can be set to it. Then 4773 * we call read_input(), and only once, since prompting about whether to 4774 * continue or quit would make no sense in this context. 4775 */ 4776 4777 static int 4778 one_command_at_a_time(int argc, char *argv[]) 4779 { 4780 char *command; 4781 size_t len = 2; /* terminal \n\0 */ 4782 int i, err; 4783 4784 for (i = 0; i < argc; i++) 4785 len += strlen(argv[i]) + 1; 4786 if ((command = malloc(len)) == NULL) { 4787 zone_perror(execname, Z_NOMEM, TRUE); 4788 return (Z_ERR); 4789 } 4790 (void) strlcpy(command, argv[0], len); 4791 for (i = 1; i < argc; i++) { 4792 (void) strlcat(command, " ", len); 4793 (void) strlcat(command, argv[i], len); 4794 } 4795 (void) strlcat(command, "\n", len); 4796 err = string_to_yyin(command); 4797 free(command); 4798 if (err != Z_OK) 4799 return (err); 4800 while (!feof(yyin)) 4801 yyparse(); 4802 return (cleanup()); 4803 } 4804 4805 static char * 4806 get_execbasename(char *execfullname) 4807 { 4808 char *last_slash, *execbasename; 4809 4810 /* guard against '/' at end of command invocation */ 4811 for (;;) { 4812 last_slash = strrchr(execfullname, '/'); 4813 if (last_slash == NULL) { 4814 execbasename = execfullname; 4815 break; 4816 } else { 4817 execbasename = last_slash + 1; 4818 if (*execbasename == '\0') { 4819 *last_slash = '\0'; 4820 continue; 4821 } 4822 break; 4823 } 4824 } 4825 return (execbasename); 4826 } 4827 4828 int 4829 main(int argc, char *argv[]) 4830 { 4831 int err, arg; 4832 struct stat st; 4833 4834 /* This must be before anything goes to stdout. */ 4835 setbuf(stdout, NULL); 4836 4837 saw_error = FALSE; 4838 cmd_file_mode = FALSE; 4839 execname = get_execbasename(argv[0]); 4840 4841 (void) setlocale(LC_ALL, ""); 4842 (void) textdomain(TEXT_DOMAIN); 4843 4844 if (getzoneid() != GLOBAL_ZONEID) { 4845 zerr(gettext("%s can only be run from the global zone."), 4846 execname); 4847 exit(Z_ERR); 4848 } 4849 4850 if (argc < 2) { 4851 usage(FALSE, HELP_USAGE | HELP_SUBCMDS); 4852 exit(Z_USAGE); 4853 } 4854 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 4855 (void) one_command_at_a_time(argc - 1, &(argv[1])); 4856 exit(Z_OK); 4857 } 4858 4859 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 4860 switch (arg) { 4861 case '?': 4862 if (optopt == '?') 4863 usage(TRUE, HELP_USAGE | HELP_SUBCMDS); 4864 else 4865 usage(FALSE, HELP_USAGE); 4866 exit(Z_USAGE); 4867 /* NOTREACHED */ 4868 case 'f': 4869 cmd_file_name = optarg; 4870 cmd_file_mode = TRUE; 4871 break; 4872 case 'R': 4873 if (*optarg != '/') { 4874 zerr(gettext("root path must be absolute: %s"), 4875 optarg); 4876 exit(Z_USAGE); 4877 } 4878 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 4879 zerr(gettext( 4880 "root path must be a directory: %s"), 4881 optarg); 4882 exit(Z_USAGE); 4883 } 4884 zonecfg_set_root(optarg); 4885 break; 4886 case 'z': 4887 if (zonecfg_validate_zonename(optarg) != Z_OK) { 4888 zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE); 4889 usage(FALSE, HELP_SYNTAX); 4890 exit(Z_USAGE); 4891 } 4892 (void) strlcpy(zone, optarg, sizeof (zone)); 4893 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 4894 break; 4895 default: 4896 usage(FALSE, HELP_USAGE); 4897 exit(Z_USAGE); 4898 } 4899 } 4900 4901 if (optind > argc || strcmp(zone, "") == 0) { 4902 usage(FALSE, HELP_USAGE); 4903 exit(Z_USAGE); 4904 } 4905 4906 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 4907 read_only_mode = FALSE; 4908 } else if (err == Z_ACCES) { 4909 read_only_mode = TRUE; 4910 /* skip this message in one-off from command line mode */ 4911 if (optind == argc) 4912 (void) fprintf(stderr, gettext("WARNING: you do not " 4913 "have write access to this zone's configuration " 4914 "file;\ngoing into read-only mode.\n")); 4915 } else { 4916 fprintf(stderr, "%s: Could not access zone configuration " 4917 "store: %s\n", execname, zonecfg_strerror(err)); 4918 exit(Z_ERR); 4919 } 4920 4921 if ((handle = zonecfg_init_handle()) == NULL) { 4922 zone_perror(execname, Z_NOMEM, TRUE); 4923 exit(Z_ERR); 4924 } 4925 4926 /* 4927 * This may get set back to FALSE again in cmd_file() if cmd_file_name 4928 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 4929 */ 4930 if (isatty(STDIN_FILENO)) 4931 ok_to_prompt = TRUE; 4932 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 4933 exit(Z_ERR); 4934 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 4935 exit(Z_ERR); 4936 (void) sigset(SIGINT, SIG_IGN); 4937 if (optind == argc) { 4938 if (!cmd_file_mode) 4939 err = do_interactive(); 4940 else 4941 err = cmd_file(cmd_file_name); 4942 } else { 4943 err = one_command_at_a_time(argc - optind, &(argv[optind])); 4944 } 4945 zonecfg_fini_handle(handle); 4946 if (brand != NULL) 4947 brand_close(brand); 4948 (void) del_GetLine(gl); 4949 return (err); 4950 } 4951