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