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