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