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