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