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 bzero(fstab, sizeof (*fstab)); 1900 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 1901 pp = cmd->cmd_property_ptr[i]; 1902 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 1903 zerr(gettext("A simple value was expected here.")); 1904 saw_error = TRUE; 1905 return (Z_INSUFFICIENT_SPEC); 1906 } 1907 switch (cmd->cmd_prop_name[i]) { 1908 case PT_DIR: 1909 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 1910 sizeof (fstab->zone_fs_dir)); 1911 break; 1912 case PT_SPECIAL: 1913 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 1914 sizeof (fstab->zone_fs_special)); 1915 break; 1916 case PT_RAW: 1917 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 1918 sizeof (fstab->zone_fs_raw)); 1919 break; 1920 case PT_TYPE: 1921 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 1922 sizeof (fstab->zone_fs_type)); 1923 break; 1924 default: 1925 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 1926 Z_NO_PROPERTY_TYPE, TRUE); 1927 return (Z_INSUFFICIENT_SPEC); 1928 } 1929 } 1930 if (fill_in_only) 1931 return (Z_OK); 1932 return (zonecfg_lookup_filesystem(handle, fstab)); 1933 } 1934 1935 static int 1936 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, bool fill_in_only) 1937 { 1938 int err, i; 1939 property_value_ptr_t pp; 1940 1941 if ((err = initialize(TRUE)) != Z_OK) 1942 return (err); 1943 1944 bzero(ipdtab, sizeof (*ipdtab)); 1945 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 1946 pp = cmd->cmd_property_ptr[i]; 1947 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 1948 zerr(gettext("A simple value was expected here.")); 1949 saw_error = TRUE; 1950 return (Z_INSUFFICIENT_SPEC); 1951 } 1952 switch (cmd->cmd_prop_name[i]) { 1953 case PT_DIR: 1954 (void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple, 1955 sizeof (ipdtab->zone_fs_dir)); 1956 break; 1957 default: 1958 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 1959 Z_NO_PROPERTY_TYPE, TRUE); 1960 return (Z_INSUFFICIENT_SPEC); 1961 } 1962 } 1963 if (fill_in_only) 1964 return (Z_OK); 1965 return (zonecfg_lookup_ipd(handle, ipdtab)); 1966 } 1967 1968 static int 1969 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, bool fill_in_only) 1970 { 1971 int err, i; 1972 property_value_ptr_t pp; 1973 1974 if ((err = initialize(TRUE)) != Z_OK) 1975 return (err); 1976 1977 bzero(nwiftab, sizeof (*nwiftab)); 1978 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 1979 pp = cmd->cmd_property_ptr[i]; 1980 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 1981 zerr(gettext("A simple value was expected here.")); 1982 saw_error = TRUE; 1983 return (Z_INSUFFICIENT_SPEC); 1984 } 1985 switch (cmd->cmd_prop_name[i]) { 1986 case PT_ADDRESS: 1987 (void) strlcpy(nwiftab->zone_nwif_address, 1988 pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 1989 break; 1990 case PT_PHYSICAL: 1991 (void) strlcpy(nwiftab->zone_nwif_physical, 1992 pp->pv_simple, 1993 sizeof (nwiftab->zone_nwif_physical)); 1994 break; 1995 default: 1996 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 1997 Z_NO_PROPERTY_TYPE, TRUE); 1998 return (Z_INSUFFICIENT_SPEC); 1999 } 2000 } 2001 if (fill_in_only) 2002 return (Z_OK); 2003 err = zonecfg_lookup_nwif(handle, nwiftab); 2004 return (err); 2005 } 2006 2007 static int 2008 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, bool fill_in_only) 2009 { 2010 int err, i; 2011 property_value_ptr_t pp; 2012 2013 if ((err = initialize(TRUE)) != Z_OK) 2014 return (err); 2015 2016 bzero(devtab, sizeof (*devtab)); 2017 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2018 pp = cmd->cmd_property_ptr[i]; 2019 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2020 zerr(gettext("A simple value was expected here.")); 2021 saw_error = TRUE; 2022 return (Z_INSUFFICIENT_SPEC); 2023 } 2024 switch (cmd->cmd_prop_name[i]) { 2025 case PT_MATCH: 2026 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2027 sizeof (devtab->zone_dev_match)); 2028 break; 2029 default: 2030 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2031 Z_NO_PROPERTY_TYPE, TRUE); 2032 return (Z_INSUFFICIENT_SPEC); 2033 } 2034 } 2035 if (fill_in_only) 2036 return (Z_OK); 2037 err = zonecfg_lookup_dev(handle, devtab); 2038 return (err); 2039 } 2040 2041 static int 2042 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, bool fill_in_only) 2043 { 2044 int err, i; 2045 property_value_ptr_t pp; 2046 2047 if ((err = initialize(TRUE)) != Z_OK) 2048 return (err); 2049 2050 bzero(rctltab, sizeof (*rctltab)); 2051 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2052 pp = cmd->cmd_property_ptr[i]; 2053 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2054 zerr(gettext("A simple value was expected here.")); 2055 saw_error = TRUE; 2056 return (Z_INSUFFICIENT_SPEC); 2057 } 2058 switch (cmd->cmd_prop_name[i]) { 2059 case PT_NAME: 2060 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2061 sizeof (rctltab->zone_rctl_name)); 2062 break; 2063 default: 2064 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2065 Z_NO_PROPERTY_TYPE, TRUE); 2066 return (Z_INSUFFICIENT_SPEC); 2067 } 2068 } 2069 if (fill_in_only) 2070 return (Z_OK); 2071 err = zonecfg_lookup_rctl(handle, rctltab); 2072 return (err); 2073 } 2074 2075 static int 2076 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, bool fill_in_only) 2077 { 2078 int err, i; 2079 property_value_ptr_t pp; 2080 2081 if ((err = initialize(TRUE)) != Z_OK) 2082 return (err); 2083 2084 bzero(attrtab, sizeof (*attrtab)); 2085 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2086 pp = cmd->cmd_property_ptr[i]; 2087 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2088 zerr(gettext("A simple value was expected here.")); 2089 saw_error = TRUE; 2090 return (Z_INSUFFICIENT_SPEC); 2091 } 2092 switch (cmd->cmd_prop_name[i]) { 2093 case PT_NAME: 2094 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2095 sizeof (attrtab->zone_attr_name)); 2096 break; 2097 case PT_TYPE: 2098 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2099 sizeof (attrtab->zone_attr_type)); 2100 break; 2101 case PT_VALUE: 2102 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2103 sizeof (attrtab->zone_attr_value)); 2104 break; 2105 default: 2106 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2107 Z_NO_PROPERTY_TYPE, TRUE); 2108 return (Z_INSUFFICIENT_SPEC); 2109 } 2110 } 2111 if (fill_in_only) 2112 return (Z_OK); 2113 err = zonecfg_lookup_attr(handle, attrtab); 2114 return (err); 2115 } 2116 2117 static int 2118 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, bool fill_in_only) 2119 { 2120 int err, i; 2121 property_value_ptr_t pp; 2122 2123 if ((err = initialize(TRUE)) != Z_OK) 2124 return (err); 2125 2126 dstab->zone_dataset_name[0] = '\0'; 2127 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2128 pp = cmd->cmd_property_ptr[i]; 2129 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2130 zerr(gettext("A simple value was expected here.")); 2131 saw_error = TRUE; 2132 return (Z_INSUFFICIENT_SPEC); 2133 } 2134 switch (cmd->cmd_prop_name[i]) { 2135 case PT_NAME: 2136 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2137 sizeof (dstab->zone_dataset_name)); 2138 break; 2139 default: 2140 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2141 Z_NO_PROPERTY_TYPE, TRUE); 2142 return (Z_INSUFFICIENT_SPEC); 2143 } 2144 } 2145 if (fill_in_only) 2146 return (Z_OK); 2147 return (zonecfg_lookup_ds(handle, dstab)); 2148 } 2149 2150 static void 2151 remove_resource(cmd_t *cmd) 2152 { 2153 int err, type; 2154 struct zone_fstab fstab; 2155 struct zone_nwiftab nwiftab; 2156 struct zone_devtab devtab; 2157 struct zone_attrtab attrtab; 2158 struct zone_rctltab rctltab; 2159 struct zone_dstab dstab; 2160 2161 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2162 long_usage(CMD_REMOVE, TRUE); 2163 return; 2164 } 2165 2166 if (initialize(TRUE) != Z_OK) 2167 return; 2168 2169 switch (type) { 2170 case RT_FS: 2171 if ((err = fill_in_fstab(cmd, &fstab, FALSE)) != Z_OK) { 2172 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2173 return; 2174 } 2175 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 2176 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2177 else 2178 need_to_commit = TRUE; 2179 zonecfg_free_fs_option_list(fstab.zone_fs_options); 2180 return; 2181 case RT_IPD: 2182 if (state_atleast(ZONE_STATE_INSTALLED)) { 2183 zerr(gettext("Zone %s already installed; %s %s not " 2184 "allowed."), zone, cmd_to_str(CMD_REMOVE), 2185 rt_to_str(RT_IPD)); 2186 return; 2187 } 2188 if ((err = fill_in_ipdtab(cmd, &fstab, FALSE)) != Z_OK) { 2189 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2190 return; 2191 } 2192 if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK) 2193 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2194 else 2195 need_to_commit = TRUE; 2196 return; 2197 case RT_NET: 2198 if ((err = fill_in_nwiftab(cmd, &nwiftab, FALSE)) != Z_OK) { 2199 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2200 return; 2201 } 2202 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 2203 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2204 else 2205 need_to_commit = TRUE; 2206 return; 2207 case RT_DEVICE: 2208 if ((err = fill_in_devtab(cmd, &devtab, FALSE)) != Z_OK) { 2209 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2210 return; 2211 } 2212 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 2213 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2214 else 2215 need_to_commit = TRUE; 2216 return; 2217 case RT_RCTL: 2218 if ((err = fill_in_rctltab(cmd, &rctltab, FALSE)) != Z_OK) { 2219 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2220 return; 2221 } 2222 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) 2223 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2224 else 2225 need_to_commit = TRUE; 2226 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 2227 return; 2228 case RT_ATTR: 2229 if ((err = fill_in_attrtab(cmd, &attrtab, FALSE)) != Z_OK) { 2230 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2231 return; 2232 } 2233 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 2234 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2235 else 2236 need_to_commit = TRUE; 2237 return; 2238 case RT_DATASET: 2239 if ((err = fill_in_dstab(cmd, &dstab, FALSE)) != Z_OK) { 2240 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2241 return; 2242 } 2243 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 2244 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2245 else 2246 need_to_commit = TRUE; 2247 return; 2248 default: 2249 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 2250 long_usage(CMD_REMOVE, TRUE); 2251 usage(FALSE, HELP_RESOURCES); 2252 return; 2253 } 2254 } 2255 2256 static void 2257 remove_property(cmd_t *cmd) 2258 { 2259 char *prop_id; 2260 int err, res_type, prop_type; 2261 property_value_ptr_t pp; 2262 struct zone_rctlvaltab *rctlvaltab; 2263 complex_property_ptr_t cx; 2264 2265 res_type = resource_scope; 2266 prop_type = cmd->cmd_prop_name[0]; 2267 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2268 long_usage(CMD_REMOVE, TRUE); 2269 return; 2270 } 2271 2272 if (cmd->cmd_prop_nv_pairs != 1) { 2273 long_usage(CMD_ADD, TRUE); 2274 return; 2275 } 2276 2277 if (initialize(TRUE) != Z_OK) 2278 return; 2279 2280 switch (res_type) { 2281 case RT_FS: 2282 if (prop_type != PT_OPTIONS) { 2283 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2284 TRUE); 2285 long_usage(CMD_REMOVE, TRUE); 2286 usage(FALSE, HELP_PROPS); 2287 return; 2288 } 2289 pp = cmd->cmd_property_ptr[0]; 2290 if (pp->pv_type == PROP_VAL_COMPLEX) { 2291 zerr(gettext("A %s or %s value was expected here."), 2292 pvt_to_str(PROP_VAL_SIMPLE), 2293 pvt_to_str(PROP_VAL_LIST)); 2294 saw_error = TRUE; 2295 return; 2296 } 2297 if (pp->pv_type == PROP_VAL_SIMPLE) { 2298 if (pp->pv_simple == NULL) { 2299 long_usage(CMD_ADD, TRUE); 2300 return; 2301 } 2302 prop_id = pp->pv_simple; 2303 err = zonecfg_remove_fs_option(&in_progress_fstab, 2304 prop_id); 2305 if (err != Z_OK) 2306 zone_perror(pt_to_str(prop_type), err, TRUE); 2307 } else { 2308 list_property_ptr_t list; 2309 2310 for (list = pp->pv_list; list != NULL; 2311 list = list->lp_next) { 2312 prop_id = list->lp_simple; 2313 if (prop_id == NULL) 2314 break; 2315 err = zonecfg_remove_fs_option( 2316 &in_progress_fstab, prop_id); 2317 if (err != Z_OK) 2318 zone_perror(pt_to_str(prop_type), err, 2319 TRUE); 2320 } 2321 } 2322 return; 2323 case RT_RCTL: 2324 if (prop_type != PT_VALUE) { 2325 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2326 TRUE); 2327 long_usage(CMD_REMOVE, TRUE); 2328 usage(FALSE, HELP_PROPS); 2329 return; 2330 } 2331 pp = cmd->cmd_property_ptr[0]; 2332 if (pp->pv_type != PROP_VAL_COMPLEX) { 2333 zerr(gettext("A %s value was expected here."), 2334 pvt_to_str(PROP_VAL_COMPLEX)); 2335 saw_error = TRUE; 2336 return; 2337 } 2338 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 2339 zone_perror(zone, Z_NOMEM, TRUE); 2340 exit(Z_ERR); 2341 } 2342 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) { 2343 switch (cx->cp_type) { 2344 case PT_PRIV: 2345 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2346 cx->cp_value, 2347 sizeof (rctlvaltab->zone_rctlval_priv)); 2348 break; 2349 case PT_LIMIT: 2350 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2351 cx->cp_value, 2352 sizeof (rctlvaltab->zone_rctlval_limit)); 2353 break; 2354 case PT_ACTION: 2355 (void) strlcpy(rctlvaltab->zone_rctlval_action, 2356 cx->cp_value, 2357 sizeof (rctlvaltab->zone_rctlval_action)); 2358 break; 2359 default: 2360 zone_perror(pt_to_str(prop_type), 2361 Z_NO_PROPERTY_TYPE, TRUE); 2362 long_usage(CMD_ADD, TRUE); 2363 usage(FALSE, HELP_PROPS); 2364 zonecfg_free_rctl_value_list(rctlvaltab); 2365 return; 2366 } 2367 } 2368 rctlvaltab->zone_rctlval_next = NULL; 2369 err = zonecfg_remove_rctl_value(&in_progress_rctltab, 2370 rctlvaltab); 2371 if (err != Z_OK) 2372 zone_perror(pt_to_str(prop_type), err, TRUE); 2373 zonecfg_free_rctl_value_list(rctlvaltab); 2374 return; 2375 default: 2376 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 2377 long_usage(CMD_REMOVE, TRUE); 2378 usage(FALSE, HELP_RESOURCES); 2379 return; 2380 } 2381 } 2382 2383 void 2384 remove_func(cmd_t *cmd) 2385 { 2386 if (zone_is_read_only(CMD_REMOVE)) 2387 return; 2388 2389 assert(cmd != NULL); 2390 2391 if (global_scope) 2392 remove_resource(cmd); 2393 else 2394 remove_property(cmd); 2395 } 2396 2397 void 2398 select_func(cmd_t *cmd) 2399 { 2400 int type, err; 2401 2402 if (zone_is_read_only(CMD_SELECT)) 2403 return; 2404 2405 assert(cmd != NULL); 2406 2407 if (global_scope) { 2408 global_scope = FALSE; 2409 resource_scope = cmd->cmd_res_type; 2410 end_op = CMD_SELECT; 2411 } else { 2412 scope_usage(CMD_SELECT); 2413 return; 2414 } 2415 2416 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2417 long_usage(CMD_SELECT, TRUE); 2418 return; 2419 } 2420 2421 if (initialize(TRUE) != Z_OK) 2422 return; 2423 2424 switch (type) { 2425 case RT_FS: 2426 if ((err = fill_in_fstab(cmd, &old_fstab, FALSE)) != Z_OK) { 2427 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, TRUE); 2428 global_scope = TRUE; 2429 } 2430 bcopy(&old_fstab, &in_progress_fstab, 2431 sizeof (struct zone_fstab)); 2432 return; 2433 case RT_IPD: 2434 if (state_atleast(ZONE_STATE_INCOMPLETE)) { 2435 zerr(gettext("Zone %s not in %s state; %s %s not " 2436 "allowed."), zone, 2437 zone_state_str(ZONE_STATE_CONFIGURED), 2438 cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD)); 2439 global_scope = TRUE; 2440 end_op = -1; 2441 return; 2442 } 2443 if ((err = fill_in_ipdtab(cmd, &old_ipdtab, FALSE)) != Z_OK) { 2444 z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, TRUE); 2445 global_scope = TRUE; 2446 } 2447 bcopy(&old_ipdtab, &in_progress_ipdtab, 2448 sizeof (struct zone_fstab)); 2449 return; 2450 case RT_NET: 2451 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, FALSE)) != Z_OK) { 2452 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, TRUE); 2453 global_scope = TRUE; 2454 } 2455 bcopy(&old_nwiftab, &in_progress_nwiftab, 2456 sizeof (struct zone_nwiftab)); 2457 return; 2458 case RT_DEVICE: 2459 if ((err = fill_in_devtab(cmd, &old_devtab, FALSE)) != Z_OK) { 2460 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, TRUE); 2461 global_scope = TRUE; 2462 } 2463 bcopy(&old_devtab, &in_progress_devtab, 2464 sizeof (struct zone_devtab)); 2465 return; 2466 case RT_RCTL: 2467 if ((err = fill_in_rctltab(cmd, &old_rctltab, FALSE)) != Z_OK) { 2468 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, TRUE); 2469 global_scope = TRUE; 2470 } 2471 bcopy(&old_rctltab, &in_progress_rctltab, 2472 sizeof (struct zone_rctltab)); 2473 return; 2474 case RT_ATTR: 2475 if ((err = fill_in_attrtab(cmd, &old_attrtab, FALSE)) != Z_OK) { 2476 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, TRUE); 2477 global_scope = TRUE; 2478 } 2479 bcopy(&old_attrtab, &in_progress_attrtab, 2480 sizeof (struct zone_attrtab)); 2481 return; 2482 case RT_DATASET: 2483 if ((err = fill_in_dstab(cmd, &old_dstab, FALSE)) != Z_OK) { 2484 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, TRUE); 2485 global_scope = TRUE; 2486 } 2487 bcopy(&old_dstab, &in_progress_dstab, 2488 sizeof (struct zone_dstab)); 2489 return; 2490 default: 2491 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 2492 long_usage(CMD_SELECT, TRUE); 2493 usage(FALSE, HELP_RESOURCES); 2494 return; 2495 } 2496 } 2497 2498 /* 2499 * Network "addresses" can be one of the following forms: 2500 * <IPv4 address> 2501 * <IPv4 address>/<prefix length> 2502 * <IPv6 address>/<prefix length> 2503 * <host name> 2504 * <host name>/<prefix length> 2505 * In other words, the "/" followed by a prefix length is allowed but not 2506 * required for IPv4 addresses and host names, and required for IPv6 addresses. 2507 * If a prefix length is given, it must be in the allowable range: 0 to 32 for 2508 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses. 2509 * Host names must start with an alpha-numeric character, and all subsequent 2510 * characters must be either alpha-numeric or "-". 2511 */ 2512 2513 static int 2514 validate_net_address_syntax(char *address) 2515 { 2516 char *slashp, part1[MAXHOSTNAMELEN]; 2517 struct in6_addr in6; 2518 struct in_addr in4; 2519 int prefixlen, i; 2520 2521 /* 2522 * Copy the part before any '/' into part1 or copy the whole 2523 * thing if there is no '/'. 2524 */ 2525 if ((slashp = strchr(address, '/')) != NULL) { 2526 *slashp = '\0'; 2527 (void) strlcpy(part1, address, sizeof (part1)); 2528 *slashp = '/'; 2529 prefixlen = atoi(++slashp); 2530 } else { 2531 (void) strlcpy(part1, address, sizeof (part1)); 2532 } 2533 2534 if (inet_pton(AF_INET6, part1, &in6) == 1) { 2535 if (slashp == NULL) { 2536 zerr(gettext("%s: IPv6 addresses " 2537 "require /prefix-length suffix."), address); 2538 return (Z_ERR); 2539 } 2540 if (prefixlen < 0 || prefixlen > 128) { 2541 zerr(gettext("%s: IPv6 address " 2542 "prefix lengths must be 0 - 128."), address); 2543 return (Z_ERR); 2544 } 2545 return (Z_OK); 2546 } 2547 2548 /* At this point, any /prefix must be for IPv4. */ 2549 if (slashp != NULL) { 2550 if (prefixlen < 0 || prefixlen > 32) { 2551 zerr(gettext("%s: IPv4 address " 2552 "prefix lengths must be 0 - 32."), address); 2553 return (Z_ERR); 2554 } 2555 } 2556 if (inet_pton(AF_INET, part1, &in4) == 1) 2557 return (Z_OK); 2558 2559 /* address may also be a host name */ 2560 if (!isalnum(part1[0])) { 2561 zerr(gettext("%s: bogus host name or network address syntax"), 2562 part1); 2563 saw_error = TRUE; 2564 usage(FALSE, HELP_NETADDR); 2565 return (Z_ERR); 2566 } 2567 for (i = 1; part1[i]; i++) 2568 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') { 2569 zerr(gettext("%s: bogus host name or " 2570 "network address syntax"), part1); 2571 saw_error = TRUE; 2572 usage(FALSE, HELP_NETADDR); 2573 return (Z_ERR); 2574 } 2575 return (Z_OK); 2576 } 2577 2578 static int 2579 validate_net_physical_syntax(char *ifname) 2580 { 2581 if (strchr(ifname, ':') == NULL) 2582 return (Z_OK); 2583 zerr(gettext("%s: physical interface name required; " 2584 "logical interface name not allowed"), ifname); 2585 return (Z_ERR); 2586 } 2587 2588 static boolean_t 2589 valid_fs_type(const char *type) 2590 { 2591 /* 2592 * Is this a valid path component? 2593 */ 2594 if (strlen(type) + 1 > MAXNAMELEN) 2595 return (B_FALSE); 2596 /* 2597 * Make sure a bad value for "type" doesn't make 2598 * /usr/lib/fs/<type>/mount turn into something else. 2599 */ 2600 if (strchr(type, '/') != NULL || type[0] == '\0' || 2601 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 2602 return (B_FALSE); 2603 /* 2604 * More detailed verification happens later by zoneadm(1m). 2605 */ 2606 return (B_TRUE); 2607 } 2608 2609 void 2610 set_func(cmd_t *cmd) 2611 { 2612 char *prop_id; 2613 int err, res_type, prop_type; 2614 property_value_ptr_t pp; 2615 boolean_t autoboot; 2616 2617 if (zone_is_read_only(CMD_SET)) 2618 return; 2619 2620 assert(cmd != NULL); 2621 2622 prop_type = cmd->cmd_prop_name[0]; 2623 if (global_scope) { 2624 if (prop_type == PT_ZONENAME) { 2625 res_type = RT_ZONENAME; 2626 } else if (prop_type == PT_ZONEPATH) { 2627 res_type = RT_ZONEPATH; 2628 } else if (prop_type == PT_AUTOBOOT) { 2629 res_type = RT_AUTOBOOT; 2630 } else if (prop_type == PT_POOL) { 2631 res_type = RT_POOL; 2632 } else { 2633 zerr(gettext("Cannot set a resource-specific property " 2634 "from the global scope.")); 2635 saw_error = TRUE; 2636 return; 2637 } 2638 } else { 2639 res_type = resource_scope; 2640 } 2641 2642 pp = cmd->cmd_property_ptr[0]; 2643 /* 2644 * A nasty expression but not that complicated: 2645 * 1. fs options are simple or list (tested below) 2646 * 2. rctl value's are complex or list (tested below) 2647 * Anything else should be simple. 2648 */ 2649 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 2650 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 2651 (pp->pv_type != PROP_VAL_SIMPLE || 2652 (prop_id = pp->pv_simple) == NULL)) { 2653 zerr(gettext("A %s value was expected here."), 2654 pvt_to_str(PROP_VAL_SIMPLE)); 2655 saw_error = TRUE; 2656 return; 2657 } 2658 if (prop_type == PT_UNKNOWN) { 2659 long_usage(CMD_SET, TRUE); 2660 return; 2661 } 2662 2663 /* 2664 * Special case: the user can change the zone name prior to 'create'; 2665 * if the zone already exists, we fall through letting initialize() 2666 * and the rest of the logic run. 2667 */ 2668 if (res_type == RT_ZONENAME && got_handle == FALSE && 2669 !state_atleast(ZONE_STATE_CONFIGURED)) { 2670 (void) strlcpy(zone, prop_id, sizeof (zone)); 2671 return; 2672 } 2673 2674 if (initialize(TRUE) != Z_OK) 2675 return; 2676 2677 switch (res_type) { 2678 case RT_ZONENAME: 2679 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 2680 /* 2681 * Use prop_id instead of 'zone' here, since we're 2682 * reporting a problem about the *new* zonename. 2683 */ 2684 zone_perror(prop_id, err, TRUE); 2685 } else { 2686 need_to_commit = TRUE; 2687 (void) strlcpy(zone, prop_id, sizeof (zone)); 2688 } 2689 return; 2690 case RT_ZONEPATH: 2691 if (state_atleast(ZONE_STATE_INSTALLED)) { 2692 zerr(gettext("Zone %s already installed; %s %s not " 2693 "allowed."), zone, cmd_to_str(CMD_SET), 2694 rt_to_str(RT_ZONEPATH)); 2695 return; 2696 } 2697 if (validate_zonepath_syntax(prop_id) != Z_OK) { 2698 saw_error = TRUE; 2699 return; 2700 } 2701 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 2702 zone_perror(zone, err, TRUE); 2703 else 2704 need_to_commit = TRUE; 2705 return; 2706 case RT_AUTOBOOT: 2707 if (strcmp(prop_id, "true") == 0) { 2708 autoboot = B_TRUE; 2709 } else if (strcmp(prop_id, "false") == 0) { 2710 autoboot = B_FALSE; 2711 } else { 2712 zerr(gettext("%s value must be '%s' or '%s'."), 2713 pt_to_str(PT_AUTOBOOT), "true", "false"); 2714 saw_error = TRUE; 2715 return; 2716 } 2717 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 2718 zone_perror(zone, err, TRUE); 2719 else 2720 need_to_commit = TRUE; 2721 return; 2722 case RT_POOL: 2723 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 2724 zone_perror(zone, err, TRUE); 2725 else 2726 need_to_commit = TRUE; 2727 return; 2728 case RT_FS: 2729 switch (prop_type) { 2730 case PT_DIR: 2731 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 2732 sizeof (in_progress_fstab.zone_fs_dir)); 2733 return; 2734 case PT_SPECIAL: 2735 (void) strlcpy(in_progress_fstab.zone_fs_special, 2736 prop_id, 2737 sizeof (in_progress_fstab.zone_fs_special)); 2738 return; 2739 case PT_RAW: 2740 (void) strlcpy(in_progress_fstab.zone_fs_raw, 2741 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 2742 return; 2743 case PT_TYPE: 2744 if (!valid_fs_type(prop_id)) { 2745 zerr(gettext("\"%s\" is not a valid %s."), 2746 prop_id, pt_to_str(PT_TYPE)); 2747 saw_error = TRUE; 2748 return; 2749 } 2750 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 2751 sizeof (in_progress_fstab.zone_fs_type)); 2752 return; 2753 case PT_OPTIONS: 2754 if (pp->pv_type != PROP_VAL_SIMPLE && 2755 pp->pv_type != PROP_VAL_LIST) { 2756 zerr(gettext("A %s or %s value was expected " 2757 "here."), pvt_to_str(PROP_VAL_SIMPLE), 2758 pvt_to_str(PROP_VAL_LIST)); 2759 saw_error = TRUE; 2760 return; 2761 } 2762 zonecfg_free_fs_option_list( 2763 in_progress_fstab.zone_fs_options); 2764 in_progress_fstab.zone_fs_options = NULL; 2765 if (!(pp->pv_type == PROP_VAL_LIST && 2766 pp->pv_list == NULL)) 2767 add_property(cmd); 2768 return; 2769 default: 2770 break; 2771 } 2772 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 2773 long_usage(CMD_SET, TRUE); 2774 usage(FALSE, HELP_PROPS); 2775 return; 2776 case RT_IPD: 2777 switch (prop_type) { 2778 case PT_DIR: 2779 (void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id, 2780 sizeof (in_progress_ipdtab.zone_fs_dir)); 2781 return; 2782 default: 2783 break; 2784 } 2785 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 2786 long_usage(CMD_SET, TRUE); 2787 usage(FALSE, HELP_PROPS); 2788 return; 2789 case RT_NET: 2790 switch (prop_type) { 2791 case PT_ADDRESS: 2792 if (validate_net_address_syntax(prop_id) != Z_OK) { 2793 saw_error = TRUE; 2794 return; 2795 } 2796 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, 2797 prop_id, 2798 sizeof (in_progress_nwiftab.zone_nwif_address)); 2799 break; 2800 case PT_PHYSICAL: 2801 if (validate_net_physical_syntax(prop_id) != Z_OK) { 2802 saw_error = TRUE; 2803 return; 2804 } 2805 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 2806 prop_id, 2807 sizeof (in_progress_nwiftab.zone_nwif_physical)); 2808 break; 2809 default: 2810 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2811 TRUE); 2812 long_usage(CMD_SET, TRUE); 2813 usage(FALSE, HELP_PROPS); 2814 return; 2815 } 2816 return; 2817 case RT_DEVICE: 2818 switch (prop_type) { 2819 case PT_MATCH: 2820 (void) strlcpy(in_progress_devtab.zone_dev_match, 2821 prop_id, 2822 sizeof (in_progress_devtab.zone_dev_match)); 2823 break; 2824 default: 2825 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2826 TRUE); 2827 long_usage(CMD_SET, TRUE); 2828 usage(FALSE, HELP_PROPS); 2829 return; 2830 } 2831 return; 2832 case RT_RCTL: 2833 switch (prop_type) { 2834 case PT_NAME: 2835 if (!zonecfg_valid_rctlname(prop_id)) { 2836 zerr(gettext("'%s' is not a valid zone %s " 2837 "name."), prop_id, rt_to_str(RT_RCTL)); 2838 return; 2839 } 2840 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 2841 prop_id, 2842 sizeof (in_progress_rctltab.zone_rctl_name)); 2843 break; 2844 case PT_VALUE: 2845 if (pp->pv_type != PROP_VAL_COMPLEX && 2846 pp->pv_type != PROP_VAL_LIST) { 2847 zerr(gettext("A %s or %s value was expected " 2848 "here."), pvt_to_str(PROP_VAL_COMPLEX), 2849 pvt_to_str(PROP_VAL_LIST)); 2850 saw_error = TRUE; 2851 return; 2852 } 2853 zonecfg_free_rctl_value_list( 2854 in_progress_rctltab.zone_rctl_valptr); 2855 in_progress_rctltab.zone_rctl_valptr = NULL; 2856 if (!(pp->pv_type == PROP_VAL_LIST && 2857 pp->pv_list == NULL)) 2858 add_property(cmd); 2859 break; 2860 default: 2861 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2862 TRUE); 2863 long_usage(CMD_SET, TRUE); 2864 usage(FALSE, HELP_PROPS); 2865 return; 2866 } 2867 return; 2868 case RT_ATTR: 2869 switch (prop_type) { 2870 case PT_NAME: 2871 (void) strlcpy(in_progress_attrtab.zone_attr_name, 2872 prop_id, 2873 sizeof (in_progress_attrtab.zone_attr_name)); 2874 break; 2875 case PT_TYPE: 2876 (void) strlcpy(in_progress_attrtab.zone_attr_type, 2877 prop_id, 2878 sizeof (in_progress_attrtab.zone_attr_type)); 2879 break; 2880 case PT_VALUE: 2881 (void) strlcpy(in_progress_attrtab.zone_attr_value, 2882 prop_id, 2883 sizeof (in_progress_attrtab.zone_attr_value)); 2884 break; 2885 default: 2886 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2887 TRUE); 2888 long_usage(CMD_SET, TRUE); 2889 usage(FALSE, HELP_PROPS); 2890 return; 2891 } 2892 return; 2893 case RT_DATASET: 2894 switch (prop_type) { 2895 case PT_NAME: 2896 (void) strlcpy(in_progress_dstab.zone_dataset_name, 2897 prop_id, 2898 sizeof (in_progress_dstab.zone_dataset_name)); 2899 return; 2900 default: 2901 break; 2902 } 2903 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 2904 long_usage(CMD_SET, TRUE); 2905 usage(FALSE, HELP_PROPS); 2906 return; 2907 default: 2908 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 2909 long_usage(CMD_SET, TRUE); 2910 usage(FALSE, HELP_RESOURCES); 2911 return; 2912 } 2913 } 2914 2915 static void 2916 output_prop(FILE *fp, int pnum, char *pval, bool print_notspec) 2917 { 2918 char *qstr; 2919 2920 if (*pval != '\0') { 2921 qstr = quoteit(pval); 2922 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 2923 free(qstr); 2924 } else if (print_notspec) 2925 (void) fprintf(fp, gettext("\t%s not specified\n"), 2926 pt_to_str(pnum)); 2927 } 2928 2929 static void 2930 info_zonename(zone_dochandle_t handle, FILE *fp) 2931 { 2932 char zonename[ZONENAME_MAX]; 2933 2934 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 2935 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 2936 zonename); 2937 else 2938 (void) fprintf(fp, gettext("%s not specified\n"), 2939 pt_to_str(PT_ZONENAME)); 2940 } 2941 2942 static void 2943 info_zonepath(zone_dochandle_t handle, FILE *fp) 2944 { 2945 char zonepath[MAXPATHLEN]; 2946 2947 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 2948 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 2949 zonepath); 2950 else { 2951 (void) fprintf(fp, gettext("%s not specified\n"), 2952 pt_to_str(PT_ZONEPATH)); 2953 } 2954 } 2955 2956 static void 2957 info_autoboot(zone_dochandle_t handle, FILE *fp) 2958 { 2959 boolean_t autoboot; 2960 int err; 2961 2962 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 2963 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 2964 autoboot ? "true" : "false"); 2965 else 2966 zone_perror(zone, err, TRUE); 2967 } 2968 2969 static void 2970 info_pool(zone_dochandle_t handle, FILE *fp) 2971 { 2972 char pool[MAXNAMELEN]; 2973 int err; 2974 2975 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 2976 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 2977 else 2978 zone_perror(zone, err, TRUE); 2979 } 2980 2981 static void 2982 output_fs(FILE *fp, struct zone_fstab *fstab) 2983 { 2984 zone_fsopt_t *this; 2985 2986 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 2987 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 2988 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 2989 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 2990 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 2991 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 2992 for (this = fstab->zone_fs_options; this != NULL; 2993 this = this->zone_fsopt_next) { 2994 if (strchr(this->zone_fsopt_opt, '=')) 2995 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 2996 else 2997 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 2998 if (this->zone_fsopt_next != NULL) 2999 (void) fprintf(fp, ","); 3000 } 3001 (void) fprintf(fp, "]\n"); 3002 } 3003 3004 static void 3005 output_ipd(FILE *fp, struct zone_fstab *ipdtab) 3006 { 3007 (void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD)); 3008 output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE); 3009 } 3010 3011 static void 3012 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3013 { 3014 struct zone_fstab lookup, user; 3015 bool output = FALSE; 3016 3017 if (zonecfg_setfsent(handle) != Z_OK) 3018 return; 3019 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 3020 if (cmd->cmd_prop_nv_pairs == 0) { 3021 output_fs(fp, &lookup); 3022 goto loopend; 3023 } 3024 if (fill_in_fstab(cmd, &user, TRUE) != Z_OK) 3025 goto loopend; 3026 if (strlen(user.zone_fs_dir) > 0 && 3027 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 3028 goto loopend; /* no match */ 3029 if (strlen(user.zone_fs_special) > 0 && 3030 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 3031 goto loopend; /* no match */ 3032 if (strlen(user.zone_fs_type) > 0 && 3033 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 3034 goto loopend; /* no match */ 3035 output_fs(fp, &lookup); 3036 output = TRUE; 3037 loopend: 3038 zonecfg_free_fs_option_list(lookup.zone_fs_options); 3039 } 3040 (void) zonecfg_endfsent(handle); 3041 /* 3042 * If a property n/v pair was specified, warn the user if there was 3043 * nothing to output. 3044 */ 3045 if (!output && cmd->cmd_prop_nv_pairs > 0) 3046 (void) printf(gettext("No such %s resource.\n"), 3047 rt_to_str(RT_FS)); 3048 } 3049 3050 static void 3051 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3052 { 3053 struct zone_fstab lookup, user; 3054 bool output = FALSE; 3055 3056 if (zonecfg_setipdent(handle) != Z_OK) 3057 return; 3058 while (zonecfg_getipdent(handle, &lookup) == Z_OK) { 3059 if (cmd->cmd_prop_nv_pairs == 0) { 3060 output_ipd(fp, &lookup); 3061 continue; 3062 } 3063 if (fill_in_ipdtab(cmd, &user, TRUE) != Z_OK) 3064 continue; 3065 if (strlen(user.zone_fs_dir) > 0 && 3066 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 3067 continue; /* no match */ 3068 output_ipd(fp, &lookup); 3069 output = TRUE; 3070 } 3071 (void) zonecfg_endipdent(handle); 3072 /* 3073 * If a property n/v pair was specified, warn the user if there was 3074 * nothing to output. 3075 */ 3076 if (!output && cmd->cmd_prop_nv_pairs > 0) 3077 (void) printf(gettext("No such %s resource.\n"), 3078 rt_to_str(RT_IPD)); 3079 } 3080 3081 static void 3082 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 3083 { 3084 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 3085 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 3086 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 3087 } 3088 3089 static void 3090 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3091 { 3092 struct zone_nwiftab lookup, user; 3093 bool output = FALSE; 3094 3095 if (zonecfg_setnwifent(handle) != Z_OK) 3096 return; 3097 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 3098 if (cmd->cmd_prop_nv_pairs == 0) { 3099 output_net(fp, &lookup); 3100 continue; 3101 } 3102 if (fill_in_nwiftab(cmd, &user, TRUE) != Z_OK) 3103 continue; 3104 if (strlen(user.zone_nwif_physical) > 0 && 3105 strcmp(user.zone_nwif_physical, 3106 lookup.zone_nwif_physical) != 0) 3107 continue; /* no match */ 3108 if (strlen(user.zone_nwif_address) > 0 && 3109 !zonecfg_same_net_address(user.zone_nwif_address, 3110 lookup.zone_nwif_address)) 3111 continue; /* no match */ 3112 output_net(fp, &lookup); 3113 output = TRUE; 3114 } 3115 (void) zonecfg_endnwifent(handle); 3116 /* 3117 * If a property n/v pair was specified, warn the user if there was 3118 * nothing to output. 3119 */ 3120 if (!output && cmd->cmd_prop_nv_pairs > 0) 3121 (void) printf(gettext("No such %s resource.\n"), 3122 rt_to_str(RT_NET)); 3123 } 3124 3125 static void 3126 output_dev(FILE *fp, struct zone_devtab *devtab) 3127 { 3128 (void) fprintf(fp, "%s\n", rt_to_str(RT_DEVICE)); 3129 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 3130 } 3131 3132 static void 3133 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3134 { 3135 struct zone_devtab lookup, user; 3136 bool output = FALSE; 3137 3138 if (zonecfg_setdevent(handle) != Z_OK) 3139 return; 3140 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 3141 if (cmd->cmd_prop_nv_pairs == 0) { 3142 output_dev(fp, &lookup); 3143 continue; 3144 } 3145 if (fill_in_devtab(cmd, &user, TRUE) != Z_OK) 3146 continue; 3147 if (strlen(user.zone_dev_match) > 0 && 3148 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 3149 continue; /* no match */ 3150 output_dev(fp, &lookup); 3151 output = TRUE; 3152 } 3153 (void) zonecfg_enddevent(handle); 3154 /* 3155 * If a property n/v pair was specified, warn the user if there was 3156 * nothing to output. 3157 */ 3158 if (!output && cmd->cmd_prop_nv_pairs > 0) 3159 (void) printf(gettext("No such %s resource.\n"), 3160 rt_to_str(RT_DEVICE)); 3161 } 3162 3163 static void 3164 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 3165 { 3166 struct zone_rctlvaltab *valptr; 3167 3168 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 3169 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 3170 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 3171 valptr = valptr->zone_rctlval_next) { 3172 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 3173 pt_to_str(PT_VALUE), 3174 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 3175 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 3176 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 3177 } 3178 } 3179 3180 static void 3181 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3182 { 3183 struct zone_rctltab lookup, user; 3184 bool output = FALSE; 3185 3186 if (zonecfg_setrctlent(handle) != Z_OK) 3187 return; 3188 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 3189 if (cmd->cmd_prop_nv_pairs == 0) { 3190 output_rctl(fp, &lookup); 3191 } else if (fill_in_rctltab(cmd, &user, TRUE) == Z_OK && 3192 (strlen(user.zone_rctl_name) == 0 || 3193 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 3194 output_rctl(fp, &lookup); 3195 output = TRUE; 3196 } 3197 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 3198 } 3199 (void) zonecfg_endrctlent(handle); 3200 /* 3201 * If a property n/v pair was specified, warn the user if there was 3202 * nothing to output. 3203 */ 3204 if (!output && cmd->cmd_prop_nv_pairs > 0) 3205 (void) printf(gettext("No such %s resource.\n"), 3206 rt_to_str(RT_RCTL)); 3207 } 3208 3209 static void 3210 output_attr(FILE *fp, struct zone_attrtab *attrtab) 3211 { 3212 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 3213 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 3214 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 3215 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 3216 } 3217 3218 static void 3219 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3220 { 3221 struct zone_attrtab lookup, user; 3222 bool output = FALSE; 3223 3224 if (zonecfg_setattrent(handle) != Z_OK) 3225 return; 3226 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 3227 if (cmd->cmd_prop_nv_pairs == 0) { 3228 output_attr(fp, &lookup); 3229 continue; 3230 } 3231 if (fill_in_attrtab(cmd, &user, TRUE) != Z_OK) 3232 continue; 3233 if (strlen(user.zone_attr_name) > 0 && 3234 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 3235 continue; /* no match */ 3236 if (strlen(user.zone_attr_type) > 0 && 3237 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 3238 continue; /* no match */ 3239 if (strlen(user.zone_attr_value) > 0 && 3240 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 3241 continue; /* no match */ 3242 output_attr(fp, &lookup); 3243 output = TRUE; 3244 } 3245 (void) zonecfg_endattrent(handle); 3246 /* 3247 * If a property n/v pair was specified, warn the user if there was 3248 * nothing to output. 3249 */ 3250 if (!output && cmd->cmd_prop_nv_pairs > 0) 3251 (void) printf(gettext("No such %s resource.\n"), 3252 rt_to_str(RT_ATTR)); 3253 } 3254 3255 static void 3256 output_ds(FILE *fp, struct zone_dstab *dstab) 3257 { 3258 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 3259 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 3260 } 3261 3262 static void 3263 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 3264 { 3265 struct zone_dstab lookup, user; 3266 bool output = FALSE; 3267 3268 if (zonecfg_setdevent(handle) != Z_OK) 3269 return; 3270 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 3271 if (cmd->cmd_prop_nv_pairs == 0) { 3272 output_ds(fp, &lookup); 3273 continue; 3274 } 3275 if (fill_in_dstab(cmd, &user, TRUE) != Z_OK) 3276 continue; 3277 if (strlen(user.zone_dataset_name) > 0 && 3278 strcmp(user.zone_dataset_name, 3279 lookup.zone_dataset_name) != 0) 3280 continue; /* no match */ 3281 output_ds(fp, &lookup); 3282 output = TRUE; 3283 } 3284 (void) zonecfg_enddsent(handle); 3285 /* 3286 * If a property n/v pair was specified, warn the user if there was 3287 * nothing to output. 3288 */ 3289 if (!output && cmd->cmd_prop_nv_pairs > 0) 3290 (void) printf(gettext("No such %s resource.\n"), 3291 rt_to_str(RT_DATASET)); 3292 } 3293 3294 3295 void 3296 info_func(cmd_t *cmd) 3297 { 3298 FILE *fp = stdout; 3299 bool need_to_close = FALSE; 3300 char *pager; 3301 3302 assert(cmd != NULL); 3303 3304 if (initialize(TRUE) != Z_OK) 3305 return; 3306 3307 /* don't page error output */ 3308 if (interactive_mode) { 3309 if ((pager = getenv("PAGER")) == NULL) 3310 pager = PAGER; 3311 if ((fp = popen(pager, "w")) != NULL) 3312 need_to_close = TRUE; 3313 else 3314 fp = stdout; 3315 setbuf(fp, NULL); 3316 } 3317 3318 if (!global_scope) { 3319 switch (resource_scope) { 3320 case RT_FS: 3321 output_fs(fp, &in_progress_fstab); 3322 break; 3323 case RT_IPD: 3324 output_ipd(fp, &in_progress_ipdtab); 3325 break; 3326 case RT_NET: 3327 output_net(fp, &in_progress_nwiftab); 3328 break; 3329 case RT_DEVICE: 3330 output_dev(fp, &in_progress_devtab); 3331 break; 3332 case RT_RCTL: 3333 output_rctl(fp, &in_progress_rctltab); 3334 break; 3335 case RT_ATTR: 3336 output_attr(fp, &in_progress_attrtab); 3337 break; 3338 case RT_DATASET: 3339 output_ds(fp, &in_progress_dstab); 3340 break; 3341 } 3342 goto cleanup; 3343 } 3344 3345 switch (cmd->cmd_res_type) { 3346 case RT_UNKNOWN: 3347 info_zonename(handle, fp); 3348 info_zonepath(handle, fp); 3349 info_autoboot(handle, fp); 3350 info_pool(handle, fp); 3351 info_ipd(handle, fp, cmd); 3352 info_fs(handle, fp, cmd); 3353 info_net(handle, fp, cmd); 3354 info_dev(handle, fp, cmd); 3355 info_rctl(handle, fp, cmd); 3356 info_attr(handle, fp, cmd); 3357 info_ds(handle, fp, cmd); 3358 break; 3359 case RT_ZONENAME: 3360 info_zonename(handle, fp); 3361 break; 3362 case RT_ZONEPATH: 3363 info_zonepath(handle, fp); 3364 break; 3365 case RT_AUTOBOOT: 3366 info_autoboot(handle, fp); 3367 break; 3368 case RT_POOL: 3369 info_pool(handle, fp); 3370 break; 3371 case RT_FS: 3372 info_fs(handle, fp, cmd); 3373 break; 3374 case RT_IPD: 3375 info_ipd(handle, fp, cmd); 3376 break; 3377 case RT_NET: 3378 info_net(handle, fp, cmd); 3379 break; 3380 case RT_DEVICE: 3381 info_dev(handle, fp, cmd); 3382 break; 3383 case RT_RCTL: 3384 info_rctl(handle, fp, cmd); 3385 break; 3386 case RT_ATTR: 3387 info_attr(handle, fp, cmd); 3388 break; 3389 case RT_DATASET: 3390 info_ds(handle, fp, cmd); 3391 break; 3392 default: 3393 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 3394 TRUE); 3395 } 3396 3397 cleanup: 3398 if (need_to_close) 3399 (void) pclose(fp); 3400 } 3401 3402 /* 3403 * Helper function for verify-- checks that a required string property 3404 * exists. 3405 */ 3406 static void 3407 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 3408 { 3409 if (strlen(attr) == 0) { 3410 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 3411 pt_to_str(pt)); 3412 saw_error = TRUE; 3413 if (*ret_val == Z_OK) 3414 *ret_val = Z_REQD_PROPERTY_MISSING; 3415 } 3416 } 3417 3418 /* 3419 * See the DTD for which attributes are required for which resources. 3420 * 3421 * This function can be called by commit_func(), which needs to save things, 3422 * in addition to the general call from parse_and_run(), which doesn't need 3423 * things saved. Since the parameters are standardized, we distinguish by 3424 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 3425 * that a save is needed. 3426 */ 3427 void 3428 verify_func(cmd_t *cmd) 3429 { 3430 struct zone_nwiftab nwiftab; 3431 struct zone_fstab fstab; 3432 struct zone_attrtab attrtab; 3433 struct zone_rctltab rctltab; 3434 struct zone_dstab dstab; 3435 char zonepath[MAXPATHLEN]; 3436 int err, ret_val = Z_OK, arg; 3437 bool save = FALSE; 3438 3439 optind = 0; 3440 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3441 switch (arg) { 3442 case '?': 3443 longer_usage(CMD_VERIFY); 3444 return; 3445 default: 3446 short_usage(CMD_VERIFY); 3447 return; 3448 } 3449 } 3450 if (optind > cmd->cmd_argc) { 3451 short_usage(CMD_VERIFY); 3452 return; 3453 } 3454 3455 if (zone_is_read_only(CMD_VERIFY)) 3456 return; 3457 3458 assert(cmd != NULL); 3459 3460 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 3461 save = TRUE; 3462 if (initialize(TRUE) != Z_OK) 3463 return; 3464 3465 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK) { 3466 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 3467 ret_val = Z_REQD_RESOURCE_MISSING; 3468 saw_error = TRUE; 3469 } 3470 if (strlen(zonepath) == 0) { 3471 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 3472 ret_val = Z_REQD_RESOURCE_MISSING; 3473 saw_error = TRUE; 3474 } 3475 3476 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 3477 zone_perror(zone, err, TRUE); 3478 return; 3479 } 3480 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 3481 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 3482 } 3483 (void) zonecfg_endipdent(handle); 3484 3485 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 3486 zone_perror(zone, err, TRUE); 3487 return; 3488 } 3489 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 3490 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 3491 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 3492 &ret_val); 3493 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 3494 3495 zonecfg_free_fs_option_list(fstab.zone_fs_options); 3496 } 3497 (void) zonecfg_endfsent(handle); 3498 3499 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 3500 zone_perror(zone, err, TRUE); 3501 return; 3502 } 3503 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 3504 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 3505 PT_ADDRESS, &ret_val); 3506 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 3507 PT_PHYSICAL, &ret_val); 3508 } 3509 (void) zonecfg_endnwifent(handle); 3510 3511 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 3512 zone_perror(zone, err, TRUE); 3513 return; 3514 } 3515 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 3516 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 3517 &ret_val); 3518 3519 if (rctltab.zone_rctl_valptr == NULL) { 3520 zerr(gettext("%s: no %s specified"), 3521 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 3522 saw_error = TRUE; 3523 if (ret_val == Z_OK) 3524 ret_val = Z_REQD_PROPERTY_MISSING; 3525 } else { 3526 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 3527 } 3528 } 3529 (void) zonecfg_endrctlent(handle); 3530 3531 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 3532 zone_perror(zone, err, TRUE); 3533 return; 3534 } 3535 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 3536 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 3537 &ret_val); 3538 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 3539 &ret_val); 3540 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 3541 &ret_val); 3542 } 3543 (void) zonecfg_endattrent(handle); 3544 3545 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 3546 zone_perror(zone, err, TRUE); 3547 return; 3548 } 3549 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 3550 if (strlen(dstab.zone_dataset_name) == 0) { 3551 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3552 pt_to_str(PT_NAME), gettext("not specified")); 3553 saw_error = TRUE; 3554 if (ret_val == Z_OK) 3555 ret_val = Z_REQD_PROPERTY_MISSING; 3556 } else if (!zfs_name_valid(dstab.zone_dataset_name, 3557 ZFS_TYPE_FILESYSTEM)) { 3558 zerr("%s: %s %s", rt_to_str(RT_DATASET), 3559 pt_to_str(PT_NAME), gettext("invalid")); 3560 saw_error = TRUE; 3561 if (ret_val == Z_OK) 3562 ret_val = Z_BAD_PROPERTY; 3563 } 3564 3565 } 3566 (void) zonecfg_enddsent(handle); 3567 3568 if (!global_scope) { 3569 zerr(gettext("resource specification incomplete")); 3570 saw_error = TRUE; 3571 if (ret_val == Z_OK) 3572 ret_val = Z_INSUFFICIENT_SPEC; 3573 } 3574 3575 if (save) { 3576 if (ret_val == Z_OK) { 3577 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 3578 need_to_commit = FALSE; 3579 (void) strlcpy(revert_zone, zone, 3580 sizeof (revert_zone)); 3581 } 3582 } else { 3583 zerr(gettext("Zone %s failed to verify"), zone); 3584 } 3585 } 3586 if (ret_val != Z_OK) 3587 zone_perror(zone, ret_val, TRUE); 3588 } 3589 3590 void 3591 cancel_func(cmd_t *cmd) 3592 { 3593 int arg; 3594 3595 assert(cmd != NULL); 3596 3597 optind = 0; 3598 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3599 switch (arg) { 3600 case '?': 3601 longer_usage(CMD_CANCEL); 3602 return; 3603 default: 3604 short_usage(CMD_CANCEL); 3605 return; 3606 } 3607 } 3608 if (optind != cmd->cmd_argc) { 3609 short_usage(CMD_CANCEL); 3610 return; 3611 } 3612 3613 if (global_scope) 3614 scope_usage(CMD_CANCEL); 3615 global_scope = TRUE; 3616 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 3617 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 3618 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 3619 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 3620 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 3621 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 3622 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 3623 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 3624 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 3625 } 3626 3627 static int 3628 validate_attr_name(char *name) 3629 { 3630 int i; 3631 3632 if (!isalnum(name[0])) { 3633 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 3634 "numeric character."), rt_to_str(RT_ATTR), 3635 pt_to_str(PT_NAME), name); 3636 return (Z_INVAL); 3637 } 3638 for (i = 1; name[i]; i++) 3639 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 3640 zerr(gettext("Invalid %s %s %s: can only contain " 3641 "alpha-numeric characters, plus '-' and '.'."), 3642 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 3643 return (Z_INVAL); 3644 } 3645 return (Z_OK); 3646 } 3647 3648 static int 3649 validate_attr_type_val(struct zone_attrtab *attrtab) 3650 { 3651 boolean_t boolval; 3652 int64_t intval; 3653 char strval[MAXNAMELEN]; 3654 uint64_t uintval; 3655 3656 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 3657 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 3658 return (Z_OK); 3659 zerr(gettext("invalid %s value for %s=%s"), 3660 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 3661 return (Z_ERR); 3662 } 3663 3664 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 3665 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 3666 return (Z_OK); 3667 zerr(gettext("invalid %s value for %s=%s"), 3668 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 3669 return (Z_ERR); 3670 } 3671 3672 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 3673 if (zonecfg_get_attr_string(attrtab, strval, 3674 sizeof (strval)) == Z_OK) 3675 return (Z_OK); 3676 zerr(gettext("invalid %s value for %s=%s"), 3677 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 3678 return (Z_ERR); 3679 } 3680 3681 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 3682 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 3683 return (Z_OK); 3684 zerr(gettext("invalid %s value for %s=%s"), 3685 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 3686 return (Z_ERR); 3687 } 3688 3689 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 3690 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 3691 return (Z_ERR); 3692 } 3693 3694 /* 3695 * Helper function for end_func-- checks the existence of a given property 3696 * and emits a message if not specified. 3697 */ 3698 static int 3699 end_check_reqd(char *attr, int pt, bool *validation_failed) 3700 { 3701 if (strlen(attr) == 0) { 3702 *validation_failed = TRUE; 3703 zerr(gettext("%s not specified"), pt_to_str(pt)); 3704 return (Z_ERR); 3705 } 3706 return (Z_OK); 3707 } 3708 3709 void 3710 end_func(cmd_t *cmd) 3711 { 3712 bool validation_failed = FALSE; 3713 struct zone_fstab tmp_fstab; 3714 struct zone_nwiftab tmp_nwiftab; 3715 struct zone_devtab tmp_devtab; 3716 struct zone_rctltab tmp_rctltab; 3717 struct zone_attrtab tmp_attrtab; 3718 struct zone_dstab tmp_dstab; 3719 int err, arg; 3720 3721 assert(cmd != NULL); 3722 3723 optind = 0; 3724 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 3725 switch (arg) { 3726 case '?': 3727 longer_usage(CMD_END); 3728 return; 3729 default: 3730 short_usage(CMD_END); 3731 return; 3732 } 3733 } 3734 if (optind != cmd->cmd_argc) { 3735 short_usage(CMD_END); 3736 return; 3737 } 3738 3739 if (global_scope) { 3740 scope_usage(CMD_END); 3741 return; 3742 } 3743 3744 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 3745 3746 switch (resource_scope) { 3747 case RT_FS: 3748 /* First make sure everything was filled in. */ 3749 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 3750 PT_DIR, &validation_failed) == Z_OK) { 3751 if (in_progress_fstab.zone_fs_dir[0] != '/') { 3752 zerr(gettext("%s %s is not an absolute path."), 3753 pt_to_str(PT_DIR), 3754 in_progress_fstab.zone_fs_dir); 3755 validation_failed = TRUE; 3756 } 3757 } 3758 3759 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 3760 PT_SPECIAL, &validation_failed); 3761 3762 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 3763 in_progress_fstab.zone_fs_raw[0] != '/') { 3764 zerr(gettext("%s %s is not an absolute path."), 3765 pt_to_str(PT_RAW), 3766 in_progress_fstab.zone_fs_raw); 3767 validation_failed = TRUE; 3768 } 3769 3770 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 3771 &validation_failed); 3772 3773 if (validation_failed) { 3774 saw_error = TRUE; 3775 return; 3776 } 3777 3778 if (end_op == CMD_ADD) { 3779 /* Make sure there isn't already one like this. */ 3780 bzero(&tmp_fstab, sizeof (tmp_fstab)); 3781 (void) strlcpy(tmp_fstab.zone_fs_dir, 3782 in_progress_fstab.zone_fs_dir, 3783 sizeof (tmp_fstab.zone_fs_dir)); 3784 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 3785 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 3786 if (err == Z_OK) { 3787 zerr(gettext("A %s resource " 3788 "with the %s '%s' already exists."), 3789 rt_to_str(RT_FS), pt_to_str(PT_DIR), 3790 in_progress_fstab.zone_fs_dir); 3791 saw_error = TRUE; 3792 return; 3793 } 3794 err = zonecfg_add_filesystem(handle, 3795 &in_progress_fstab); 3796 } else { 3797 err = zonecfg_modify_filesystem(handle, &old_fstab, 3798 &in_progress_fstab); 3799 } 3800 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 3801 in_progress_fstab.zone_fs_options = NULL; 3802 break; 3803 3804 case RT_IPD: 3805 /* First make sure everything was filled in. */ 3806 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 3807 &validation_failed) == Z_OK) { 3808 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 3809 zerr(gettext("%s %s is not an absolute path."), 3810 pt_to_str(PT_DIR), 3811 in_progress_ipdtab.zone_fs_dir); 3812 validation_failed = TRUE; 3813 } 3814 } 3815 if (validation_failed) { 3816 saw_error = TRUE; 3817 return; 3818 } 3819 3820 if (end_op == CMD_ADD) { 3821 /* Make sure there isn't already one like this. */ 3822 bzero(&tmp_fstab, sizeof (tmp_fstab)); 3823 (void) strlcpy(tmp_fstab.zone_fs_dir, 3824 in_progress_ipdtab.zone_fs_dir, 3825 sizeof (tmp_fstab.zone_fs_dir)); 3826 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 3827 if (err == Z_OK) { 3828 zerr(gettext("An %s resource " 3829 "with the %s '%s' already exists."), 3830 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 3831 in_progress_ipdtab.zone_fs_dir); 3832 saw_error = TRUE; 3833 return; 3834 } 3835 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 3836 } else { 3837 err = zonecfg_modify_ipd(handle, &old_ipdtab, 3838 &in_progress_ipdtab); 3839 } 3840 break; 3841 case RT_NET: 3842 /* First make sure everything was filled in. */ 3843 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 3844 PT_PHYSICAL, &validation_failed); 3845 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_address, 3846 PT_ADDRESS, &validation_failed); 3847 3848 if (validation_failed) { 3849 saw_error = TRUE; 3850 return; 3851 } 3852 3853 if (end_op == CMD_ADD) { 3854 /* Make sure there isn't already one like this. */ 3855 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 3856 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 3857 in_progress_nwiftab.zone_nwif_address, 3858 sizeof (tmp_nwiftab.zone_nwif_address)); 3859 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 3860 zerr(gettext("A %s resource " 3861 "with the %s '%s' already exists."), 3862 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS), 3863 in_progress_nwiftab.zone_nwif_address); 3864 saw_error = TRUE; 3865 return; 3866 } 3867 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 3868 } else { 3869 err = zonecfg_modify_nwif(handle, &old_nwiftab, 3870 &in_progress_nwiftab); 3871 } 3872 break; 3873 3874 case RT_DEVICE: 3875 /* First make sure everything was filled in. */ 3876 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 3877 PT_MATCH, &validation_failed); 3878 3879 if (validation_failed) { 3880 saw_error = TRUE; 3881 return; 3882 } 3883 3884 if (end_op == CMD_ADD) { 3885 /* Make sure there isn't already one like this. */ 3886 (void) strlcpy(tmp_devtab.zone_dev_match, 3887 in_progress_devtab.zone_dev_match, 3888 sizeof (tmp_devtab.zone_dev_match)); 3889 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 3890 zerr(gettext("A %s resource with the %s '%s' " 3891 "already exists."), rt_to_str(RT_DEVICE), 3892 pt_to_str(PT_MATCH), 3893 in_progress_devtab.zone_dev_match); 3894 saw_error = TRUE; 3895 return; 3896 } 3897 err = zonecfg_add_dev(handle, &in_progress_devtab); 3898 } else { 3899 err = zonecfg_modify_dev(handle, &old_devtab, 3900 &in_progress_devtab); 3901 } 3902 break; 3903 3904 case RT_RCTL: 3905 /* First make sure everything was filled in. */ 3906 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 3907 PT_NAME, &validation_failed); 3908 3909 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 3910 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 3911 validation_failed = TRUE; 3912 } 3913 3914 if (validation_failed) { 3915 saw_error = TRUE; 3916 return; 3917 } 3918 3919 if (end_op == CMD_ADD) { 3920 /* Make sure there isn't already one like this. */ 3921 (void) strlcpy(tmp_rctltab.zone_rctl_name, 3922 in_progress_rctltab.zone_rctl_name, 3923 sizeof (tmp_rctltab.zone_rctl_name)); 3924 tmp_rctltab.zone_rctl_valptr = NULL; 3925 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 3926 zonecfg_free_rctl_value_list( 3927 tmp_rctltab.zone_rctl_valptr); 3928 if (err == Z_OK) { 3929 zerr(gettext("A %s resource " 3930 "with the %s '%s' already exists."), 3931 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 3932 in_progress_rctltab.zone_rctl_name); 3933 saw_error = TRUE; 3934 return; 3935 } 3936 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 3937 } else { 3938 err = zonecfg_modify_rctl(handle, &old_rctltab, 3939 &in_progress_rctltab); 3940 } 3941 if (err == Z_OK) { 3942 zonecfg_free_rctl_value_list( 3943 in_progress_rctltab.zone_rctl_valptr); 3944 in_progress_rctltab.zone_rctl_valptr = NULL; 3945 } 3946 break; 3947 3948 case RT_ATTR: 3949 /* First make sure everything was filled in. */ 3950 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 3951 PT_NAME, &validation_failed); 3952 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 3953 PT_TYPE, &validation_failed); 3954 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 3955 PT_VALUE, &validation_failed); 3956 3957 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 3958 Z_OK) 3959 validation_failed = TRUE; 3960 3961 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 3962 validation_failed = TRUE; 3963 3964 if (validation_failed) { 3965 saw_error = TRUE; 3966 return; 3967 } 3968 if (end_op == CMD_ADD) { 3969 /* Make sure there isn't already one like this. */ 3970 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 3971 (void) strlcpy(tmp_attrtab.zone_attr_name, 3972 in_progress_attrtab.zone_attr_name, 3973 sizeof (tmp_attrtab.zone_attr_name)); 3974 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 3975 zerr(gettext("An %s resource " 3976 "with the %s '%s' already exists."), 3977 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 3978 in_progress_attrtab.zone_attr_name); 3979 saw_error = TRUE; 3980 return; 3981 } 3982 err = zonecfg_add_attr(handle, &in_progress_attrtab); 3983 } else { 3984 err = zonecfg_modify_attr(handle, &old_attrtab, 3985 &in_progress_attrtab); 3986 } 3987 break; 3988 case RT_DATASET: 3989 /* First make sure everything was filled in. */ 3990 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 3991 zerr("%s %s", pt_to_str(PT_NAME), 3992 gettext("not specified")); 3993 saw_error = TRUE; 3994 validation_failed = TRUE; 3995 } 3996 if (validation_failed) 3997 return; 3998 if (end_op == CMD_ADD) { 3999 /* Make sure there isn't already one like this. */ 4000 bzero(&tmp_dstab, sizeof (tmp_dstab)); 4001 (void) strlcpy(tmp_dstab.zone_dataset_name, 4002 in_progress_dstab.zone_dataset_name, 4003 sizeof (tmp_dstab.zone_dataset_name)); 4004 err = zonecfg_lookup_ds(handle, &tmp_dstab); 4005 if (err == Z_OK) { 4006 zerr(gettext("A %s resource " 4007 "with the %s '%s' already exists."), 4008 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 4009 in_progress_dstab.zone_dataset_name); 4010 saw_error = TRUE; 4011 return; 4012 } 4013 err = zonecfg_add_ds(handle, &in_progress_dstab); 4014 } else { 4015 err = zonecfg_modify_ds(handle, &old_dstab, 4016 &in_progress_dstab); 4017 } 4018 break; 4019 default: 4020 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 4021 TRUE); 4022 saw_error = TRUE; 4023 return; 4024 } 4025 4026 if (err != Z_OK) { 4027 zone_perror(zone, err, TRUE); 4028 } else { 4029 need_to_commit = TRUE; 4030 global_scope = TRUE; 4031 end_op = -1; 4032 } 4033 } 4034 4035 void 4036 commit_func(cmd_t *cmd) 4037 { 4038 int arg; 4039 4040 optind = 0; 4041 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 4042 switch (arg) { 4043 case '?': 4044 longer_usage(CMD_COMMIT); 4045 return; 4046 default: 4047 short_usage(CMD_COMMIT); 4048 return; 4049 } 4050 } 4051 if (optind != cmd->cmd_argc) { 4052 short_usage(CMD_COMMIT); 4053 return; 4054 } 4055 4056 if (zone_is_read_only(CMD_COMMIT)) 4057 return; 4058 4059 assert(cmd != NULL); 4060 4061 cmd->cmd_argc = 1; 4062 /* 4063 * cmd_arg normally comes from a strdup() in the lexer, and the 4064 * whole cmd structure and its (char *) attributes are freed at 4065 * the completion of each command, so the strdup() below is needed 4066 * to match this and prevent a core dump from trying to free() 4067 * something that can't be. 4068 */ 4069 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 4070 zone_perror(zone, Z_NOMEM, TRUE); 4071 exit(Z_ERR); 4072 } 4073 cmd->cmd_argv[1] = NULL; 4074 verify_func(cmd); 4075 } 4076 4077 void 4078 revert_func(cmd_t *cmd) 4079 { 4080 char line[128]; /* enough to ask a question */ 4081 bool force = FALSE; 4082 int err, arg, answer; 4083 4084 optind = 0; 4085 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 4086 switch (arg) { 4087 case '?': 4088 longer_usage(CMD_REVERT); 4089 return; 4090 case 'F': 4091 force = TRUE; 4092 break; 4093 default: 4094 short_usage(CMD_REVERT); 4095 return; 4096 } 4097 } 4098 if (optind != cmd->cmd_argc) { 4099 short_usage(CMD_REVERT); 4100 return; 4101 } 4102 4103 if (zone_is_read_only(CMD_REVERT)) 4104 return; 4105 4106 if (zonecfg_check_handle(handle) != Z_OK) { 4107 zerr(gettext("No changes to revert.")); 4108 saw_error = TRUE; 4109 return; 4110 } 4111 4112 if (!force) { 4113 (void) snprintf(line, sizeof (line), 4114 gettext("Are you sure you want to revert")); 4115 if ((answer = ask_yesno(FALSE, line)) == -1) { 4116 zerr(gettext("Input not from terminal and -F not " 4117 "specified:\n%s command ignored, exiting."), 4118 cmd_to_str(CMD_REVERT)); 4119 exit(Z_ERR); 4120 } 4121 if (answer != 1) 4122 return; 4123 } 4124 4125 /* 4126 * Time for a new handle: finish the old one off first 4127 * then get a new one properly to avoid leaks. 4128 */ 4129 zonecfg_fini_handle(handle); 4130 if ((handle = zonecfg_init_handle()) == NULL) { 4131 zone_perror(execname, Z_NOMEM, TRUE); 4132 exit(Z_ERR); 4133 } 4134 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 4135 saw_error = TRUE; 4136 got_handle = FALSE; 4137 if (err == Z_NO_ZONE) 4138 zerr(gettext("%s: no such saved zone to revert to."), 4139 revert_zone); 4140 else 4141 zone_perror(zone, err, TRUE); 4142 } 4143 (void) strlcpy(zone, revert_zone, sizeof (zone)); 4144 } 4145 4146 void 4147 help_func(cmd_t *cmd) 4148 { 4149 int i; 4150 4151 assert(cmd != NULL); 4152 4153 if (cmd->cmd_argc == 0) { 4154 usage(TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 4155 return; 4156 } 4157 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 4158 usage(TRUE, HELP_USAGE); 4159 return; 4160 } 4161 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 4162 usage(TRUE, HELP_SUBCMDS); 4163 return; 4164 } 4165 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 4166 usage(TRUE, HELP_SYNTAX | HELP_RES_PROPS); 4167 return; 4168 } 4169 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 4170 longer_usage(CMD_HELP); 4171 return; 4172 } 4173 4174 for (i = 0; i <= CMD_MAX; i++) { 4175 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 4176 longer_usage(i); 4177 return; 4178 } 4179 } 4180 /* We do not use zerr() here because we do not want its extra \n. */ 4181 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 4182 cmd->cmd_argv[0]); 4183 usage(FALSE, HELP_META); 4184 } 4185 4186 static int 4187 string_to_yyin(char *string) 4188 { 4189 if ((yyin = tmpfile()) == NULL) { 4190 zone_perror(execname, Z_TEMP_FILE, TRUE); 4191 return (Z_ERR); 4192 } 4193 if (fwrite(string, strlen(string), 1, yyin) != 1) { 4194 zone_perror(execname, Z_TEMP_FILE, TRUE); 4195 return (Z_ERR); 4196 } 4197 if (fseek(yyin, 0, SEEK_SET) != 0) { 4198 zone_perror(execname, Z_TEMP_FILE, TRUE); 4199 return (Z_ERR); 4200 } 4201 return (Z_OK); 4202 } 4203 4204 /* This is the back-end helper function for read_input() below. */ 4205 4206 static int 4207 cleanup() 4208 { 4209 int answer; 4210 cmd_t *cmd; 4211 4212 if (!interactive_mode && !cmd_file_mode) { 4213 /* 4214 * If we're not in interactive mode, and we're not in command 4215 * file mode, then we must be in commands-from-the-command-line 4216 * mode. As such, we can't loop back and ask for more input. 4217 * It was OK to prompt for such things as whether or not to 4218 * really delete a zone in the command handler called from 4219 * yyparse() above, but "really quit?" makes no sense in this 4220 * context. So disable prompting. 4221 */ 4222 ok_to_prompt = FALSE; 4223 } 4224 if (!global_scope) { 4225 if (!time_to_exit) { 4226 /* 4227 * Just print a simple error message in the -1 case, 4228 * since exit_func() already handles that case, and 4229 * EOF means we are finished anyway. 4230 */ 4231 answer = ask_yesno(FALSE, 4232 gettext("Resource incomplete; really quit")); 4233 if (answer == -1) { 4234 zerr(gettext("Resource incomplete.")); 4235 return (Z_ERR); 4236 } 4237 if (answer != 1) { 4238 yyin = stdin; 4239 return (Z_REPEAT); 4240 } 4241 } else { 4242 saw_error = TRUE; 4243 } 4244 } 4245 /* 4246 * Make sure we tried something and that the handle checks 4247 * out, or we would get a false error trying to commit. 4248 */ 4249 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 4250 if ((cmd = alloc_cmd()) == NULL) { 4251 zone_perror(zone, Z_NOMEM, TRUE); 4252 return (Z_ERR); 4253 } 4254 cmd->cmd_argc = 0; 4255 cmd->cmd_argv[0] = NULL; 4256 commit_func(cmd); 4257 free_cmd(cmd); 4258 /* 4259 * need_to_commit will get set back to FALSE if the 4260 * configuration is saved successfully. 4261 */ 4262 if (need_to_commit) { 4263 if (force_exit) { 4264 zerr(gettext("Configuration not saved.")); 4265 return (Z_ERR); 4266 } 4267 answer = ask_yesno(FALSE, 4268 gettext("Configuration not saved; really quit")); 4269 if (answer == -1) { 4270 zerr(gettext("Configuration not saved.")); 4271 return (Z_ERR); 4272 } 4273 if (answer != 1) { 4274 time_to_exit = FALSE; 4275 yyin = stdin; 4276 return (Z_REPEAT); 4277 } 4278 } 4279 } 4280 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 4281 } 4282 4283 /* 4284 * read_input() is the driver of this program. It is a wrapper around 4285 * yyparse(), printing appropriate prompts when needed, checking for 4286 * exit conditions and reacting appropriately [the latter in its cleanup() 4287 * helper function]. 4288 * 4289 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 4290 * so do_interactive() knows that we are not really done (i.e, we asked 4291 * the user if we should really quit and the user said no). 4292 */ 4293 static int 4294 read_input() 4295 { 4296 bool yyin_is_a_tty = isatty(fileno(yyin)); 4297 /* 4298 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 4299 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 4300 */ 4301 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 4302 4303 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 4304 newline_terminated = TRUE; 4305 for (;;) { 4306 if (yyin_is_a_tty) { 4307 if (newline_terminated) { 4308 if (global_scope) 4309 (void) snprintf(prompt, sizeof (prompt), 4310 "%s:%s> ", execname, zone); 4311 else 4312 (void) snprintf(prompt, sizeof (prompt), 4313 "%s:%s:%s> ", execname, zone, 4314 rt_to_str(resource_scope)); 4315 } 4316 /* 4317 * If the user hits ^C then we want to catch it and 4318 * start over. If the user hits EOF then we want to 4319 * bail out. 4320 */ 4321 line = gl_get_line(gl, prompt, NULL, -1); 4322 if (gl_return_status(gl) == GLR_SIGNAL) { 4323 gl_abandon_line(gl); 4324 continue; 4325 } 4326 if (line == NULL) 4327 break; 4328 (void) string_to_yyin(line); 4329 while (!feof(yyin)) 4330 yyparse(); 4331 } else { 4332 yyparse(); 4333 } 4334 /* Bail out on an error in command file mode. */ 4335 if (saw_error && cmd_file_mode && !interactive_mode) 4336 time_to_exit = TRUE; 4337 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 4338 break; 4339 } 4340 return (cleanup()); 4341 } 4342 4343 /* 4344 * This function is used in the zonecfg-interactive-mode scenario: it just 4345 * calls read_input() until we are done. 4346 */ 4347 4348 static int 4349 do_interactive(void) 4350 { 4351 int err; 4352 4353 interactive_mode = TRUE; 4354 if (!read_only_mode) { 4355 /* 4356 * Try to set things up proactively in interactive mode, so 4357 * that if the zone in question does not exist yet, we can 4358 * provide the user with a clue. 4359 */ 4360 (void) initialize(FALSE); 4361 } 4362 do { 4363 err = read_input(); 4364 } while (err == Z_REPEAT); 4365 return (err); 4366 } 4367 4368 /* 4369 * cmd_file is slightly more complicated, as it has to open the command file 4370 * and set yyin appropriately. Once that is done, though, it just calls 4371 * read_input(), and only once, since prompting is not possible. 4372 */ 4373 4374 static int 4375 cmd_file(char *file) 4376 { 4377 FILE *infile; 4378 int err; 4379 struct stat statbuf; 4380 bool using_real_file = (strcmp(file, "-") != 0); 4381 4382 if (using_real_file) { 4383 /* 4384 * zerr() prints a line number in cmd_file_mode, which we do 4385 * not want here, so temporarily unset it. 4386 */ 4387 cmd_file_mode = FALSE; 4388 if ((infile = fopen(file, "r")) == NULL) { 4389 zerr(gettext("could not open file %s: %s"), 4390 file, strerror(errno)); 4391 return (Z_ERR); 4392 } 4393 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 4394 zerr(gettext("could not stat file %s: %s"), 4395 file, strerror(errno)); 4396 err = Z_ERR; 4397 goto done; 4398 } 4399 if (!S_ISREG(statbuf.st_mode)) { 4400 zerr(gettext("%s is not a regular file."), file); 4401 err = Z_ERR; 4402 goto done; 4403 } 4404 yyin = infile; 4405 cmd_file_mode = TRUE; 4406 ok_to_prompt = FALSE; 4407 } else { 4408 /* 4409 * "-f -" is essentially the same as interactive mode, 4410 * so treat it that way. 4411 */ 4412 interactive_mode = TRUE; 4413 } 4414 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 4415 if ((err = read_input()) == Z_REPEAT) 4416 err = Z_ERR; 4417 done: 4418 if (using_real_file) 4419 (void) fclose(infile); 4420 return (err); 4421 } 4422 4423 /* 4424 * Since yacc is based on reading from a (FILE *) whereas what we get from 4425 * the command line is in argv format, we need to convert when the user 4426 * gives us commands directly from the command line. That is done here by 4427 * concatenating the argv list into a space-separated string, writing it 4428 * to a temp file, and rewinding the file so yyin can be set to it. Then 4429 * we call read_input(), and only once, since prompting about whether to 4430 * continue or quit would make no sense in this context. 4431 */ 4432 4433 static int 4434 one_command_at_a_time(int argc, char *argv[]) 4435 { 4436 char *command; 4437 size_t len = 2; /* terminal \n\0 */ 4438 int i, err; 4439 4440 for (i = 0; i < argc; i++) 4441 len += strlen(argv[i]) + 1; 4442 if ((command = malloc(len)) == NULL) { 4443 zone_perror(execname, Z_NOMEM, TRUE); 4444 return (Z_ERR); 4445 } 4446 (void) strlcpy(command, argv[0], len); 4447 for (i = 1; i < argc; i++) { 4448 (void) strlcat(command, " ", len); 4449 (void) strlcat(command, argv[i], len); 4450 } 4451 (void) strlcat(command, "\n", len); 4452 err = string_to_yyin(command); 4453 free(command); 4454 if (err != Z_OK) 4455 return (err); 4456 while (!feof(yyin)) 4457 yyparse(); 4458 return (cleanup()); 4459 } 4460 4461 static char * 4462 get_execbasename(char *execfullname) 4463 { 4464 char *last_slash, *execbasename; 4465 4466 /* guard against '/' at end of command invocation */ 4467 for (;;) { 4468 last_slash = strrchr(execfullname, '/'); 4469 if (last_slash == NULL) { 4470 execbasename = execfullname; 4471 break; 4472 } else { 4473 execbasename = last_slash + 1; 4474 if (*execbasename == '\0') { 4475 *last_slash = '\0'; 4476 continue; 4477 } 4478 break; 4479 } 4480 } 4481 return (execbasename); 4482 } 4483 4484 int 4485 main(int argc, char *argv[]) 4486 { 4487 int err, arg; 4488 4489 /* This must be before anything goes to stdout. */ 4490 setbuf(stdout, NULL); 4491 4492 saw_error = FALSE; 4493 cmd_file_mode = FALSE; 4494 execname = get_execbasename(argv[0]); 4495 4496 (void) setlocale(LC_ALL, ""); 4497 (void) textdomain(TEXT_DOMAIN); 4498 4499 if (getzoneid() != GLOBAL_ZONEID) { 4500 zerr(gettext("%s can only be run from the global zone."), 4501 execname); 4502 exit(Z_ERR); 4503 } 4504 4505 if (argc < 2) { 4506 usage(FALSE, HELP_USAGE | HELP_SUBCMDS); 4507 exit(Z_USAGE); 4508 } 4509 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 4510 (void) one_command_at_a_time(argc - 1, &(argv[1])); 4511 exit(Z_OK); 4512 } 4513 4514 while ((arg = getopt(argc, argv, "?f:z:")) != EOF) { 4515 switch (arg) { 4516 case '?': 4517 if (optopt == '?') 4518 usage(TRUE, HELP_USAGE | HELP_SUBCMDS); 4519 else 4520 usage(FALSE, HELP_USAGE); 4521 exit(Z_USAGE); 4522 /* NOTREACHED */ 4523 case 'f': 4524 cmd_file_name = optarg; 4525 cmd_file_mode = TRUE; 4526 break; 4527 case 'z': 4528 if (zonecfg_validate_zonename(optarg) != Z_OK) { 4529 zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE); 4530 usage(FALSE, HELP_SYNTAX); 4531 exit(Z_USAGE); 4532 } 4533 (void) strlcpy(zone, optarg, sizeof (zone)); 4534 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 4535 break; 4536 default: 4537 usage(FALSE, HELP_USAGE); 4538 exit(Z_USAGE); 4539 } 4540 } 4541 4542 if (optind > argc || strcmp(zone, "") == 0) { 4543 usage(FALSE, HELP_USAGE); 4544 exit(Z_USAGE); 4545 } 4546 4547 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 4548 read_only_mode = FALSE; 4549 } else if (err == Z_ACCES) { 4550 read_only_mode = TRUE; 4551 /* skip this message in one-off from command line mode */ 4552 if (optind == argc) 4553 (void) fprintf(stderr, gettext("WARNING: you do not " 4554 "have write access to this zone's configuration " 4555 "file;\ngoing into read-only mode.\n")); 4556 } else { 4557 fprintf(stderr, "%s: Could not access zone configuration " 4558 "store: %s\n", execname, zonecfg_strerror(err)); 4559 exit(Z_ERR); 4560 } 4561 4562 if ((handle = zonecfg_init_handle()) == NULL) { 4563 zone_perror(execname, Z_NOMEM, TRUE); 4564 exit(Z_ERR); 4565 } 4566 4567 /* 4568 * This may get set back to FALSE again in cmd_file() if cmd_file_name 4569 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 4570 */ 4571 if (isatty(STDIN_FILENO)) 4572 ok_to_prompt = TRUE; 4573 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 4574 exit(Z_ERR); 4575 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 4576 exit(Z_ERR); 4577 (void) sigset(SIGINT, SIG_IGN); 4578 if (optind == argc) { 4579 if (!cmd_file_mode) 4580 err = do_interactive(); 4581 else 4582 err = cmd_file(cmd_file_name); 4583 } else { 4584 err = one_command_at_a_time(argc - optind, &(argv[optind])); 4585 } 4586 zonecfg_fini_handle(handle); 4587 (void) del_GetLine(gl); 4588 return (err); 4589 } 4590