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