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