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