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