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