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