1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * zonecfg is a lex/yacc based command interpreter used to manage zone 31 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which 32 * the grammar (see zonecfg_grammar.y) builds up into commands, some of 33 * which takes resources and/or properties as arguments. See the block 34 * comments near the end of zonecfg_grammar.y for how the data structures 35 * which keep track of these resources and properties are built up. 36 * 37 * The resource/property data structures are inserted into a command 38 * structure (see zonecfg.h), which also keeps track of command names, 39 * miscellaneous arguments, and function handlers. The grammar selects 40 * the appropriate function handler, each of which takes a pointer to a 41 * command structure as its sole argument, and invokes it. The grammar 42 * itself is "entered" (a la the Matrix) by yyparse(), which is called 43 * from read_input(), our main driving function. That in turn is called 44 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each 45 * of which is called from main() depending on how the program was invoked. 46 * 47 * The rest of this module consists of the various function handlers and 48 * their helper functions. Some of these functions, particularly the 49 * X_to_str() functions, which maps command, resource and property numbers 50 * to strings, are used quite liberally, as doing so results in a better 51 * program w/rt I18N, reducing the need for translation notes. 52 */ 53 54 #include <sys/mntent.h> 55 #include <sys/varargs.h> 56 #include <sys/sysmacros.h> 57 58 #include <errno.h> 59 #include <fcntl.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 <signal.h> 73 #include <wait.h> 74 #include <libtecla.h> 75 #include <libzfs.h> 76 #include <sys/brand.h> 77 #include <libbrand.h> 78 79 #include <libzonecfg.h> 80 #include "zonecfg.h" 81 82 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 83 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 84 #endif 85 86 #define PAGER "/usr/bin/more" 87 #define EXEC_PREFIX "exec " 88 #define EXEC_LEN (strlen(EXEC_PREFIX)) 89 90 struct help { 91 uint_t cmd_num; 92 char *cmd_name; 93 uint_t flags; 94 char *short_usage; 95 }; 96 97 extern int yyparse(void); 98 extern int lex_lineno; 99 100 #define MAX_LINE_LEN 1024 101 #define MAX_CMD_HIST 1024 102 #define MAX_CMD_LEN 1024 103 104 #define ONE_MB 1048576 105 106 /* 107 * Each SHELP_ should be a simple string. 108 */ 109 110 #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \ 111 "add <property-name> <property-value>\n\t(resource scope)" 112 #define SHELP_CANCEL "cancel" 113 #define SHELP_CLEAR "clear <property-name>" 114 #define SHELP_COMMIT "commit" 115 #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]" 116 #define SHELP_DELETE "delete [-F]" 117 #define SHELP_END "end" 118 #define SHELP_EXIT "exit [-F]" 119 #define SHELP_EXPORT "export [-f output-file]" 120 #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]" 121 #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]" 122 #define SHELP_REMOVE "remove [-F] <resource-type> " \ 123 "[ <property-name>=<property-value> ]*\n" \ 124 "\t(global scope)\n" \ 125 "remove <property-name> <property-value>\n" \ 126 "\t(resource scope)" 127 #define SHELP_REVERT "revert [-F]" 128 #define SHELP_SELECT "select <resource-type> { <property-name>=" \ 129 "<property-value> }" 130 #define SHELP_SET "set <property-name>=<property-value>" 131 #define SHELP_VERIFY "verify" 132 133 static struct help helptab[] = { 134 { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, }, 135 { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, }, 136 { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, }, 137 { CMD_COMMIT, "commit", 0, SHELP_COMMIT, }, 138 { CMD_CREATE, "create", 0, SHELP_CREATE, }, 139 { CMD_DELETE, "delete", 0, SHELP_DELETE, }, 140 { CMD_END, "end", 0, SHELP_END, }, 141 { CMD_EXIT, "exit", 0, SHELP_EXIT, }, 142 { CMD_EXPORT, "export", 0, SHELP_EXPORT, }, 143 { CMD_HELP, "help", 0, SHELP_HELP }, 144 { CMD_INFO, "info", HELP_RES_PROPS, SHELP_INFO, }, 145 { CMD_REMOVE, "remove", HELP_RES_PROPS, SHELP_REMOVE, }, 146 { CMD_REVERT, "revert", 0, SHELP_REVERT, }, 147 { CMD_SELECT, "select", HELP_RES_PROPS, SHELP_SELECT, }, 148 { CMD_SET, "set", HELP_PROPS, SHELP_SET, }, 149 { CMD_VERIFY, "verify", 0, SHELP_VERIFY, }, 150 { 0 }, 151 }; 152 153 #define MAX_RT_STRLEN 16 154 155 /* These *must* match the order of the RT_ define's from zonecfg.h */ 156 static char *res_types[] = { 157 "unknown", 158 "zonename", 159 "zonepath", 160 "autoboot", 161 "pool", 162 "fs", 163 "inherit-pkg-dir", 164 "net", 165 "device", 166 "rctl", 167 "attr", 168 "dataset", 169 "limitpriv", 170 "bootargs", 171 "brand", 172 "dedicated-cpu", 173 "capped-memory", 174 ALIAS_MAXLWPS, 175 ALIAS_MAXSHMMEM, 176 ALIAS_MAXSHMIDS, 177 ALIAS_MAXMSGIDS, 178 ALIAS_MAXSEMIDS, 179 ALIAS_SHARES, 180 "scheduling-class", 181 "ip-type", 182 NULL 183 }; 184 185 /* These *must* match the order of the PT_ define's from zonecfg.h */ 186 static char *prop_types[] = { 187 "unknown", 188 "zonename", 189 "zonepath", 190 "autoboot", 191 "pool", 192 "dir", 193 "special", 194 "type", 195 "options", 196 "address", 197 "physical", 198 "name", 199 "value", 200 "match", 201 "priv", 202 "limit", 203 "action", 204 "raw", 205 "limitpriv", 206 "bootargs", 207 "brand", 208 "ncpus", 209 "importance", 210 "swap", 211 "locked", 212 ALIAS_SHARES, 213 ALIAS_MAXLWPS, 214 ALIAS_MAXSHMMEM, 215 ALIAS_MAXSHMIDS, 216 ALIAS_MAXMSGIDS, 217 ALIAS_MAXSEMIDS, 218 ALIAS_MAXLOCKEDMEM, 219 ALIAS_MAXSWAP, 220 "scheduling-class", 221 "ip-type", 222 NULL 223 }; 224 225 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */ 226 static char *prop_val_types[] = { 227 "simple", 228 "complex", 229 "list", 230 }; 231 232 /* 233 * The various _cmds[] lists below are for command tab-completion. 234 */ 235 236 /* 237 * remove has a space afterwards because it has qualifiers; the other commands 238 * that have qualifiers (add, select, etc.) don't need a space here because 239 * they have their own _cmds[] lists below. 240 */ 241 static const char *global_scope_cmds[] = { 242 "add", 243 "clear", 244 "commit", 245 "create", 246 "delete", 247 "exit", 248 "export", 249 "help", 250 "info", 251 "remove ", 252 "revert", 253 "select", 254 "set", 255 "verify", 256 NULL 257 }; 258 259 static const char *add_cmds[] = { 260 "add fs", 261 "add inherit-pkg-dir", 262 "add net", 263 "add device", 264 "add rctl", 265 "add attr", 266 "add dataset", 267 "add dedicated-cpu", 268 "add capped-memory", 269 NULL 270 }; 271 272 static const char *clear_cmds[] = { 273 "clear autoboot", 274 "clear pool", 275 "clear limitpriv", 276 "clear bootargs", 277 "clear scheduling-class", 278 "clear ip-type", 279 "clear " ALIAS_MAXLWPS, 280 "clear " ALIAS_MAXSHMMEM, 281 "clear " ALIAS_MAXSHMIDS, 282 "clear " ALIAS_MAXMSGIDS, 283 "clear " ALIAS_MAXSEMIDS, 284 "clear " ALIAS_SHARES, 285 NULL 286 }; 287 288 static const char *remove_cmds[] = { 289 "remove fs ", 290 "remove inherit-pkg-dir ", 291 "remove net ", 292 "remove device ", 293 "remove rctl ", 294 "remove attr ", 295 "remove dataset ", 296 "remove dedicated-cpu ", 297 "remove capped-memory ", 298 NULL 299 }; 300 301 static const char *select_cmds[] = { 302 "select fs ", 303 "select inherit-pkg-dir ", 304 "select net ", 305 "select device ", 306 "select rctl ", 307 "select attr ", 308 "select dataset ", 309 "select dedicated-cpu", 310 "select capped-memory", 311 NULL 312 }; 313 314 static const char *set_cmds[] = { 315 "set zonename=", 316 "set zonepath=", 317 "set brand=", 318 "set autoboot=", 319 "set pool=", 320 "set limitpriv=", 321 "set bootargs=", 322 "set scheduling-class=", 323 "set ip-type=", 324 "set " ALIAS_MAXLWPS "=", 325 "set " ALIAS_MAXSHMMEM "=", 326 "set " ALIAS_MAXSHMIDS "=", 327 "set " ALIAS_MAXMSGIDS "=", 328 "set " ALIAS_MAXSEMIDS "=", 329 "set " ALIAS_SHARES "=", 330 NULL 331 }; 332 333 static const char *info_cmds[] = { 334 "info fs ", 335 "info inherit-pkg-dir ", 336 "info net ", 337 "info device ", 338 "info rctl ", 339 "info attr ", 340 "info dataset ", 341 "info capped-memory", 342 "info dedicated-cpu", 343 "info zonename", 344 "info zonepath", 345 "info autoboot", 346 "info pool", 347 "info limitpriv", 348 "info bootargs", 349 "info brand", 350 "info scheduling-class", 351 "info ip-type", 352 "info max-lwps", 353 "info max-shm-memory", 354 "info max-shm-ids", 355 "info max-msg-ids", 356 "info max-sem-ids", 357 "info cpu-shares", 358 NULL 359 }; 360 361 static const char *fs_res_scope_cmds[] = { 362 "add options ", 363 "cancel", 364 "end", 365 "exit", 366 "help", 367 "info", 368 "remove options ", 369 "set dir=", 370 "set raw=", 371 "set special=", 372 "set type=", 373 "clear raw", 374 NULL 375 }; 376 377 static const char *net_res_scope_cmds[] = { 378 "cancel", 379 "end", 380 "exit", 381 "help", 382 "info", 383 "set address=", 384 "set physical=", 385 NULL 386 }; 387 388 static const char *ipd_res_scope_cmds[] = { 389 "cancel", 390 "end", 391 "exit", 392 "help", 393 "info", 394 "set dir=", 395 NULL 396 }; 397 398 static const char *device_res_scope_cmds[] = { 399 "cancel", 400 "end", 401 "exit", 402 "help", 403 "info", 404 "set match=", 405 NULL 406 }; 407 408 static const char *attr_res_scope_cmds[] = { 409 "cancel", 410 "end", 411 "exit", 412 "help", 413 "info", 414 "set name=", 415 "set type=", 416 "set value=", 417 NULL 418 }; 419 420 static const char *rctl_res_scope_cmds[] = { 421 "add value ", 422 "cancel", 423 "end", 424 "exit", 425 "help", 426 "info", 427 "remove value ", 428 "set name=", 429 NULL 430 }; 431 432 static const char *dataset_res_scope_cmds[] = { 433 "cancel", 434 "end", 435 "exit", 436 "help", 437 "info", 438 "set name=", 439 NULL 440 }; 441 442 static const char *pset_res_scope_cmds[] = { 443 "cancel", 444 "end", 445 "exit", 446 "help", 447 "info", 448 "set ncpus=", 449 "set importance=", 450 "clear importance", 451 NULL 452 }; 453 454 static const char *mcap_res_scope_cmds[] = { 455 "cancel", 456 "end", 457 "exit", 458 "help", 459 "info", 460 "set physical=", 461 "set swap=", 462 "set locked=", 463 "clear physical", 464 "clear swap", 465 "clear locked", 466 NULL 467 }; 468 469 /* Global variables */ 470 471 /* set early in main(), never modified thereafter, used all over the place */ 472 static char *execname; 473 474 /* set in main(), used all over the place */ 475 static zone_dochandle_t handle; 476 477 /* used all over the place */ 478 static char zone[ZONENAME_MAX]; 479 static char revert_zone[ZONENAME_MAX]; 480 481 /* global brand operations */ 482 static brand_handle_t brand; 483 484 /* set in modifying functions, checked in read_input() */ 485 static bool need_to_commit = FALSE; 486 bool saw_error; 487 488 /* set in yacc parser, checked in read_input() */ 489 bool newline_terminated; 490 491 /* set in main(), checked in lex error handler */ 492 bool cmd_file_mode; 493 494 /* set in exit_func(), checked in read_input() */ 495 static bool time_to_exit = FALSE, force_exit = FALSE; 496 497 /* used in short_usage() and zerr() */ 498 static char *cmd_file_name = NULL; 499 500 /* checked in read_input() and other places */ 501 static bool ok_to_prompt = FALSE; 502 503 /* set and checked in initialize() */ 504 static bool got_handle = FALSE; 505 506 /* initialized in do_interactive(), checked in initialize() */ 507 static bool interactive_mode; 508 509 /* set if configuring the global zone */ 510 static bool global_zone = FALSE; 511 512 /* set in main(), checked in multiple places */ 513 static bool read_only_mode; 514 515 static bool global_scope = TRUE; /* scope is outer/global or inner/resource */ 516 static int resource_scope; /* should be in the RT_ list from zonecfg.h */ 517 static int end_op = -1; /* operation on end is either add or modify */ 518 519 int num_prop_vals; /* for grammar */ 520 521 /* 522 * These are for keeping track of resources as they are specified as part of 523 * the multi-step process. They should be initialized by add_resource() or 524 * select_func() and filled in by add_property() or set_func(). 525 */ 526 static struct zone_fstab old_fstab, in_progress_fstab; 527 static struct zone_fstab old_ipdtab, in_progress_ipdtab; 528 static struct zone_nwiftab old_nwiftab, in_progress_nwiftab; 529 static struct zone_devtab old_devtab, in_progress_devtab; 530 static struct zone_rctltab old_rctltab, in_progress_rctltab; 531 static struct zone_attrtab old_attrtab, in_progress_attrtab; 532 static struct zone_dstab old_dstab, in_progress_dstab; 533 static struct zone_psettab old_psettab, in_progress_psettab; 534 static struct zone_mcaptab old_mcaptab, in_progress_mcaptab; 535 536 static GetLine *gl; /* The gl_get_line() resource object */ 537 538 static void bytes_to_units(char *str, char *buf, int bufsize); 539 540 /* Functions begin here */ 541 542 static bool 543 initial_match(const char *line1, const char *line2, int word_end) 544 { 545 if (word_end <= 0) 546 return (TRUE); 547 return (strncmp(line1, line2, word_end) == 0); 548 } 549 550 static int 551 add_stuff(WordCompletion *cpl, const char *line1, const char **list, 552 int word_end) 553 { 554 int i, err; 555 556 for (i = 0; list[i] != NULL; i++) { 557 if (initial_match(line1, list[i], word_end)) { 558 err = cpl_add_completion(cpl, line1, 0, word_end, 559 list[i] + word_end, "", ""); 560 if (err != 0) 561 return (err); 562 } 563 } 564 return (0); 565 } 566 567 static 568 /* ARGSUSED */ 569 CPL_MATCH_FN(cmd_cpl_fn) 570 { 571 if (global_scope) { 572 /* 573 * The MAX/MIN tests below are to make sure we have at least 574 * enough characters to distinguish from other prefixes (MAX) 575 * but only check MIN(what we have, what we're checking). 576 */ 577 if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0) 578 return (add_stuff(cpl, line, add_cmds, word_end)); 579 if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0) 580 return (add_stuff(cpl, line, clear_cmds, word_end)); 581 if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0) 582 return (add_stuff(cpl, line, select_cmds, word_end)); 583 if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0) 584 return (add_stuff(cpl, line, set_cmds, word_end)); 585 if (strncmp(line, "remove ", MAX(MIN(word_end, 7), 1)) == 0) 586 return (add_stuff(cpl, line, remove_cmds, word_end)); 587 if (strncmp(line, "info ", MAX(MIN(word_end, 5), 1)) == 0) 588 return (add_stuff(cpl, line, info_cmds, word_end)); 589 return (add_stuff(cpl, line, global_scope_cmds, word_end)); 590 } 591 switch (resource_scope) { 592 case RT_FS: 593 return (add_stuff(cpl, line, fs_res_scope_cmds, word_end)); 594 case RT_IPD: 595 return (add_stuff(cpl, line, ipd_res_scope_cmds, word_end)); 596 case RT_NET: 597 return (add_stuff(cpl, line, net_res_scope_cmds, word_end)); 598 case RT_DEVICE: 599 return (add_stuff(cpl, line, device_res_scope_cmds, word_end)); 600 case RT_RCTL: 601 return (add_stuff(cpl, line, rctl_res_scope_cmds, word_end)); 602 case RT_ATTR: 603 return (add_stuff(cpl, line, attr_res_scope_cmds, word_end)); 604 case RT_DATASET: 605 return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end)); 606 case RT_DCPU: 607 return (add_stuff(cpl, line, pset_res_scope_cmds, word_end)); 608 case RT_MCAP: 609 return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end)); 610 } 611 return (0); 612 } 613 614 /* 615 * For the main CMD_func() functions below, several of them call getopt() 616 * then check optind against argc to make sure an extra parameter was not 617 * passed in. The reason this is not caught in the grammar is that the 618 * grammar just checks for a miscellaneous TOKEN, which is *expected* to 619 * be "-F" (for example), but could be anything. So (for example) this 620 * check will prevent "create bogus". 621 */ 622 623 cmd_t * 624 alloc_cmd(void) 625 { 626 return (calloc(1, sizeof (cmd_t))); 627 } 628 629 void 630 free_cmd(cmd_t *cmd) 631 { 632 int i; 633 634 for (i = 0; i < MAX_EQ_PROP_PAIRS; i++) 635 if (cmd->cmd_property_ptr[i] != NULL) { 636 property_value_ptr_t pp = cmd->cmd_property_ptr[i]; 637 638 switch (pp->pv_type) { 639 case PROP_VAL_SIMPLE: 640 free(pp->pv_simple); 641 break; 642 case PROP_VAL_COMPLEX: 643 free_complex(pp->pv_complex); 644 break; 645 case PROP_VAL_LIST: 646 free_list(pp->pv_list); 647 break; 648 } 649 } 650 for (i = 0; i < cmd->cmd_argc; i++) 651 free(cmd->cmd_argv[i]); 652 free(cmd); 653 } 654 655 complex_property_ptr_t 656 alloc_complex(void) 657 { 658 return (calloc(1, sizeof (complex_property_t))); 659 } 660 661 void 662 free_complex(complex_property_ptr_t complex) 663 { 664 if (complex == NULL) 665 return; 666 free_complex(complex->cp_next); 667 if (complex->cp_value != NULL) 668 free(complex->cp_value); 669 free(complex); 670 } 671 672 list_property_ptr_t 673 alloc_list(void) 674 { 675 return (calloc(1, sizeof (list_property_t))); 676 } 677 678 void 679 free_list(list_property_ptr_t list) 680 { 681 if (list == NULL) 682 return; 683 if (list->lp_simple != NULL) 684 free(list->lp_simple); 685 free_complex(list->lp_complex); 686 free_list(list->lp_next); 687 free(list); 688 } 689 690 void 691 free_outer_list(list_property_ptr_t list) 692 { 693 if (list == NULL) 694 return; 695 free_outer_list(list->lp_next); 696 free(list); 697 } 698 699 static struct zone_rctlvaltab * 700 alloc_rctlvaltab(void) 701 { 702 return (calloc(1, sizeof (struct zone_rctlvaltab))); 703 } 704 705 static char * 706 rt_to_str(int res_type) 707 { 708 assert(res_type >= RT_MIN && res_type <= RT_MAX); 709 return (res_types[res_type]); 710 } 711 712 static char * 713 pt_to_str(int prop_type) 714 { 715 assert(prop_type >= PT_MIN && prop_type <= PT_MAX); 716 return (prop_types[prop_type]); 717 } 718 719 static char * 720 pvt_to_str(int pv_type) 721 { 722 assert(pv_type >= PROP_VAL_MIN && pv_type <= PROP_VAL_MAX); 723 return (prop_val_types[pv_type]); 724 } 725 726 static char * 727 cmd_to_str(int cmd_num) 728 { 729 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 730 return (helptab[cmd_num].cmd_name); 731 } 732 733 /* 734 * This is a separate function rather than a set of define's because of the 735 * gettext() wrapping. 736 */ 737 738 /* 739 * TRANSLATION_NOTE 740 * Each string below should have \t follow \n whenever needed; the 741 * initial \t and the terminal \n will be provided by the calling function. 742 */ 743 744 static char * 745 long_help(int cmd_num) 746 { 747 static char line[1024]; /* arbitrary large amount */ 748 749 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 750 switch (cmd_num) { 751 case CMD_HELP: 752 return (gettext("Prints help message.")); 753 case CMD_CREATE: 754 (void) snprintf(line, sizeof (line), 755 gettext("Creates a configuration for the " 756 "specified zone. %s should be\n\tused to " 757 "begin configuring a new zone. If overwriting an " 758 "existing\n\tconfiguration, the -F flag can be " 759 "used to force the action. If\n\t-t template is " 760 "given, creates a configuration identical to the\n" 761 "\tspecified template, except that the zone name " 762 "is changed from\n\ttemplate to zonename. '%s -a' " 763 "creates a configuration from a\n\tdetached " 764 "zonepath. '%s -b' results in a blank " 765 "configuration.\n\t'%s' with no arguments applies " 766 "the Sun default settings."), 767 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE), 768 cmd_to_str(CMD_CREATE), cmd_to_str(CMD_CREATE)); 769 return (line); 770 case CMD_EXIT: 771 return (gettext("Exits the program. The -F flag can " 772 "be used to force the action.")); 773 case CMD_EXPORT: 774 return (gettext("Prints configuration to standard " 775 "output, or to output-file if\n\tspecified, in " 776 "a form suitable for use in a command-file.")); 777 case CMD_ADD: 778 return (gettext("Add specified resource to " 779 "configuration.")); 780 case CMD_DELETE: 781 return (gettext("Deletes the specified zone. The -F " 782 "flag can be used to force the\n\taction.")); 783 case CMD_REMOVE: 784 return (gettext("Remove specified resource from " 785 "configuration. The -F flag can be used\n\tto " 786 "force the action.")); 787 case CMD_SELECT: 788 (void) snprintf(line, sizeof (line), 789 gettext("Selects a resource to modify. " 790 "Resource modification is completed\n\twith the " 791 "command \"%s\". The property name/value pairs " 792 "must uniquely\n\tidentify a resource. Note that " 793 "the curly braces ('{', '}') mean one\n\tor more " 794 "of whatever is between them."), 795 cmd_to_str(CMD_END)); 796 return (line); 797 case CMD_SET: 798 return (gettext("Sets property values.")); 799 case CMD_CLEAR: 800 return (gettext("Clears property values.")); 801 case CMD_INFO: 802 return (gettext("Displays information about the " 803 "current configuration. If resource\n\ttype is " 804 "specified, displays only information about " 805 "resources of\n\tthe relevant type. If resource " 806 "id is specified, displays only\n\tinformation " 807 "about that resource.")); 808 case CMD_VERIFY: 809 return (gettext("Verifies current configuration " 810 "for correctness (some resource types\n\thave " 811 "required properties).")); 812 case CMD_COMMIT: 813 (void) snprintf(line, sizeof (line), 814 gettext("Commits current configuration. " 815 "Configuration must be committed to\n\tbe used by " 816 "%s. Until the configuration is committed, " 817 "changes \n\tcan be removed with the %s " 818 "command. This operation is\n\tattempted " 819 "automatically upon completion of a %s " 820 "session."), "zoneadm", cmd_to_str(CMD_REVERT), 821 "zonecfg"); 822 return (line); 823 case CMD_REVERT: 824 return (gettext("Reverts configuration back to the " 825 "last committed state. The -F flag\n\tcan be " 826 "used to force the action.")); 827 case CMD_CANCEL: 828 return (gettext("Cancels resource/property " 829 "specification.")); 830 case CMD_END: 831 return (gettext("Ends resource/property " 832 "specification.")); 833 } 834 /* NOTREACHED */ 835 return (NULL); 836 } 837 838 /* 839 * Called with verbose TRUE when help is explicitly requested, FALSE for 840 * unexpected errors. 841 */ 842 843 void 844 usage(bool verbose, uint_t flags) 845 { 846 FILE *fp = verbose ? stdout : stderr, *newfp; 847 bool need_to_close = FALSE; 848 char *pager; 849 int i; 850 851 /* don't page error output */ 852 if (verbose && interactive_mode) { 853 if ((pager = getenv("PAGER")) == NULL) 854 pager = PAGER; 855 if ((newfp = popen(pager, "w")) != NULL) { 856 need_to_close = TRUE; 857 fp = newfp; 858 } 859 } 860 if (flags & HELP_META) { 861 (void) fprintf(fp, gettext("More help is available for the " 862 "following:\n")); 863 (void) fprintf(fp, "\n\tcommands ('%s commands')\n", 864 cmd_to_str(CMD_HELP)); 865 (void) fprintf(fp, "\tsyntax ('%s syntax')\n", 866 cmd_to_str(CMD_HELP)); 867 (void) fprintf(fp, "\tusage ('%s usage')\n\n", 868 cmd_to_str(CMD_HELP)); 869 (void) fprintf(fp, gettext("You may also obtain help on any " 870 "command by typing '%s <command-name>.'\n"), 871 cmd_to_str(CMD_HELP)); 872 } 873 if (flags & HELP_RES_SCOPE) { 874 switch (resource_scope) { 875 case RT_FS: 876 (void) fprintf(fp, gettext("The '%s' resource scope is " 877 "used to configure a file-system.\n"), 878 rt_to_str(resource_scope)); 879 (void) fprintf(fp, gettext("Valid commands:\n")); 880 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 881 pt_to_str(PT_DIR), gettext("<path>")); 882 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 883 pt_to_str(PT_SPECIAL), gettext("<path>")); 884 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 885 pt_to_str(PT_RAW), gettext("<raw-device>")); 886 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 887 pt_to_str(PT_TYPE), gettext("<file-system type>")); 888 (void) fprintf(fp, "\t%s %s %s\n", cmd_to_str(CMD_ADD), 889 pt_to_str(PT_OPTIONS), 890 gettext("<file-system options>")); 891 (void) fprintf(fp, "\t%s %s %s\n", 892 cmd_to_str(CMD_REMOVE), pt_to_str(PT_OPTIONS), 893 gettext("<file-system options>")); 894 (void) fprintf(fp, gettext("Consult the file-system " 895 "specific manual page, such as mount_ufs(1M), " 896 "for\ndetails about file-system options. Note " 897 "that any file-system options with an\nembedded " 898 "'=' character must be enclosed in double quotes, " 899 /*CSTYLED*/ 900 "such as \"%s=5\".\n"), MNTOPT_RETRY); 901 break; 902 case RT_IPD: 903 (void) fprintf(fp, gettext("The '%s' resource scope is " 904 "used to configure a directory\ninherited from the " 905 "global zone into a non-global zone in read-only " 906 "mode.\n"), rt_to_str(resource_scope)); 907 (void) fprintf(fp, gettext("Valid commands:\n")); 908 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 909 pt_to_str(PT_DIR), gettext("<path>")); 910 break; 911 case RT_NET: 912 (void) fprintf(fp, gettext("The '%s' resource scope is " 913 "used to configure a network interface.\n"), 914 rt_to_str(resource_scope)); 915 (void) fprintf(fp, gettext("Valid commands:\n")); 916 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 917 pt_to_str(PT_ADDRESS), gettext("<IP-address>")); 918 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 919 pt_to_str(PT_PHYSICAL), gettext("<interface>")); 920 (void) fprintf(fp, gettext("See ifconfig(1M) for " 921 "details of the <interface> string.\n")); 922 (void) fprintf(fp, gettext("%s %s is valid if the %s " 923 "property is set to %s, otherwise it must not be " 924 "set.\n"), 925 cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS), 926 pt_to_str(PT_IPTYPE), "shared"); 927 break; 928 case RT_DEVICE: 929 (void) fprintf(fp, gettext("The '%s' resource scope is " 930 "used to configure a device node.\n"), 931 rt_to_str(resource_scope)); 932 (void) fprintf(fp, gettext("Valid commands:\n")); 933 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 934 pt_to_str(PT_MATCH), gettext("<device-path>")); 935 break; 936 case RT_RCTL: 937 (void) fprintf(fp, gettext("The '%s' resource scope is " 938 "used to configure a resource control.\n"), 939 rt_to_str(resource_scope)); 940 (void) fprintf(fp, gettext("Valid commands:\n")); 941 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 942 pt_to_str(PT_NAME), gettext("<string>")); 943 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 944 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 945 pt_to_str(PT_PRIV), gettext("<priv-value>"), 946 pt_to_str(PT_LIMIT), gettext("<number>"), 947 pt_to_str(PT_ACTION), gettext("<action-value>")); 948 (void) fprintf(fp, "\t%s %s (%s=%s,%s=%s,%s=%s)\n", 949 cmd_to_str(CMD_REMOVE), pt_to_str(PT_VALUE), 950 pt_to_str(PT_PRIV), gettext("<priv-value>"), 951 pt_to_str(PT_LIMIT), gettext("<number>"), 952 pt_to_str(PT_ACTION), gettext("<action-value>")); 953 (void) fprintf(fp, "%s\n\t%s := privileged\n" 954 "\t%s := none | deny\n", gettext("Where"), 955 gettext("<priv-value>"), gettext("<action-value>")); 956 break; 957 case RT_ATTR: 958 (void) fprintf(fp, gettext("The '%s' resource scope is " 959 "used to configure a generic attribute.\n"), 960 rt_to_str(resource_scope)); 961 (void) fprintf(fp, gettext("Valid commands:\n")); 962 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 963 pt_to_str(PT_NAME), gettext("<name>")); 964 (void) fprintf(fp, "\t%s %s=boolean\n", 965 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 966 (void) fprintf(fp, "\t%s %s=true | false\n", 967 cmd_to_str(CMD_SET), pt_to_str(PT_VALUE)); 968 (void) fprintf(fp, gettext("or\n")); 969 (void) fprintf(fp, "\t%s %s=int\n", cmd_to_str(CMD_SET), 970 pt_to_str(PT_TYPE)); 971 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 972 pt_to_str(PT_VALUE), gettext("<integer>")); 973 (void) fprintf(fp, gettext("or\n")); 974 (void) fprintf(fp, "\t%s %s=string\n", 975 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 976 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 977 pt_to_str(PT_VALUE), gettext("<string>")); 978 (void) fprintf(fp, gettext("or\n")); 979 (void) fprintf(fp, "\t%s %s=uint\n", 980 cmd_to_str(CMD_SET), pt_to_str(PT_TYPE)); 981 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 982 pt_to_str(PT_VALUE), gettext("<unsigned integer>")); 983 break; 984 case RT_DATASET: 985 (void) fprintf(fp, gettext("The '%s' resource scope is " 986 "used to export ZFS datasets.\n"), 987 rt_to_str(resource_scope)); 988 (void) fprintf(fp, gettext("Valid commands:\n")); 989 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 990 pt_to_str(PT_NAME), gettext("<name>")); 991 break; 992 case RT_DCPU: 993 (void) fprintf(fp, gettext("The '%s' resource scope " 994 "configures the 'pools' facility to dedicate\na " 995 "subset of the system's processors to this zone " 996 "while it is running.\n"), 997 rt_to_str(resource_scope)); 998 (void) fprintf(fp, gettext("Valid commands:\n")); 999 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1000 pt_to_str(PT_NCPUS), 1001 gettext("<unsigned integer | range>")); 1002 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1003 pt_to_str(PT_IMPORTANCE), 1004 gettext("<unsigned integer>")); 1005 break; 1006 case RT_MCAP: 1007 (void) fprintf(fp, gettext("The '%s' resource scope is " 1008 "used to set an upper limit (a cap) on the\n" 1009 "amount of physical memory, swap space and locked " 1010 "memory that can be used by\nthis zone.\n"), 1011 rt_to_str(resource_scope)); 1012 (void) fprintf(fp, gettext("Valid commands:\n")); 1013 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1014 pt_to_str(PT_PHYSICAL), 1015 gettext("<qualified unsigned decimal>")); 1016 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1017 pt_to_str(PT_SWAP), 1018 gettext("<qualified unsigned decimal>")); 1019 (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), 1020 pt_to_str(PT_LOCKED), 1021 gettext("<qualified unsigned decimal>")); 1022 break; 1023 } 1024 (void) fprintf(fp, gettext("And from any resource scope, you " 1025 "can:\n")); 1026 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_END), 1027 gettext("(to conclude this operation)")); 1028 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_CANCEL), 1029 gettext("(to cancel this operation)")); 1030 (void) fprintf(fp, "\t%s\t%s\n", cmd_to_str(CMD_EXIT), 1031 gettext("(to exit the zonecfg utility)")); 1032 } 1033 if (flags & HELP_USAGE) { 1034 (void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"), 1035 execname, cmd_to_str(CMD_HELP)); 1036 (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n", 1037 execname, gettext("interactive")); 1038 (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname); 1039 (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n", 1040 execname); 1041 } 1042 if (flags & HELP_SUBCMDS) { 1043 (void) fprintf(fp, "%s:\n\n", gettext("Commands")); 1044 for (i = 0; i <= CMD_MAX; i++) { 1045 (void) fprintf(fp, "%s\n", helptab[i].short_usage); 1046 if (verbose) 1047 (void) fprintf(fp, "\t%s\n\n", long_help(i)); 1048 } 1049 } 1050 if (flags & HELP_SYNTAX) { 1051 if (!verbose) 1052 (void) fprintf(fp, "\n"); 1053 (void) fprintf(fp, "<zone> := [A-Za-z0-9][A-Za-z0-9_.-]*\n"); 1054 (void) fprintf(fp, gettext("\t(except the reserved words " 1055 "'%s' and anything starting with '%s')\n"), "global", 1056 "SUNW"); 1057 (void) fprintf(fp, 1058 gettext("\tName must be less than %d characters.\n"), 1059 ZONENAME_MAX); 1060 if (verbose) 1061 (void) fprintf(fp, "\n"); 1062 } 1063 if (flags & HELP_NETADDR) { 1064 (void) fprintf(fp, gettext("\n<net-addr> :=")); 1065 (void) fprintf(fp, 1066 gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n")); 1067 (void) fprintf(fp, 1068 gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n")); 1069 (void) fprintf(fp, 1070 gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n")); 1071 (void) fprintf(fp, gettext("See inet(3SOCKET) for IPv4 and " 1072 "IPv6 address syntax.\n")); 1073 (void) fprintf(fp, gettext("<IPv4-prefix-length> := [0-32]\n")); 1074 (void) fprintf(fp, 1075 gettext("<IPv6-prefix-length> := [0-128]\n")); 1076 (void) fprintf(fp, 1077 gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n")); 1078 } 1079 if (flags & HELP_RESOURCES) { 1080 (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t" 1081 "%s | %s | %s\n\n", 1082 gettext("resource type"), rt_to_str(RT_FS), 1083 rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE), 1084 rt_to_str(RT_RCTL), rt_to_str(RT_ATTR), 1085 rt_to_str(RT_DATASET), rt_to_str(RT_DCPU), 1086 rt_to_str(RT_MCAP)); 1087 } 1088 if (flags & HELP_PROPS) { 1089 (void) fprintf(fp, gettext("For resource type ... there are " 1090 "property types ...:\n")); 1091 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1092 pt_to_str(PT_ZONENAME)); 1093 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1094 pt_to_str(PT_ZONEPATH)); 1095 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1096 pt_to_str(PT_BRAND)); 1097 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1098 pt_to_str(PT_AUTOBOOT)); 1099 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1100 pt_to_str(PT_BOOTARGS)); 1101 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1102 pt_to_str(PT_POOL)); 1103 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1104 pt_to_str(PT_LIMITPRIV)); 1105 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1106 pt_to_str(PT_SCHED)); 1107 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1108 pt_to_str(PT_IPTYPE)); 1109 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1110 pt_to_str(PT_MAXLWPS)); 1111 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1112 pt_to_str(PT_MAXSHMMEM)); 1113 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1114 pt_to_str(PT_MAXSHMIDS)); 1115 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1116 pt_to_str(PT_MAXMSGIDS)); 1117 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1118 pt_to_str(PT_MAXSEMIDS)); 1119 (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), 1120 pt_to_str(PT_SHARES)); 1121 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s\n", rt_to_str(RT_FS), 1122 pt_to_str(PT_DIR), pt_to_str(PT_SPECIAL), 1123 pt_to_str(PT_RAW), pt_to_str(PT_TYPE), 1124 pt_to_str(PT_OPTIONS)); 1125 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_IPD), 1126 pt_to_str(PT_DIR)); 1127 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_NET), 1128 pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL)); 1129 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE), 1130 pt_to_str(PT_MATCH)); 1131 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL), 1132 pt_to_str(PT_NAME), pt_to_str(PT_VALUE)); 1133 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR), 1134 pt_to_str(PT_NAME), pt_to_str(PT_TYPE), 1135 pt_to_str(PT_VALUE)); 1136 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET), 1137 pt_to_str(PT_NAME)); 1138 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU), 1139 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE)); 1140 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP), 1141 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP), 1142 pt_to_str(PT_LOCKED)); 1143 } 1144 if (need_to_close) 1145 (void) pclose(fp); 1146 } 1147 1148 /* PRINTFLIKE1 */ 1149 static void 1150 zerr(const char *fmt, ...) 1151 { 1152 va_list alist; 1153 static int last_lineno; 1154 1155 /* lex_lineno has already been incremented in the lexer; compensate */ 1156 if (cmd_file_mode && lex_lineno > last_lineno) { 1157 if (strcmp(cmd_file_name, "-") == 0) 1158 (void) fprintf(stderr, gettext("On line %d:\n"), 1159 lex_lineno - 1); 1160 else 1161 (void) fprintf(stderr, gettext("On line %d of %s:\n"), 1162 lex_lineno - 1, cmd_file_name); 1163 last_lineno = lex_lineno; 1164 } 1165 va_start(alist, fmt); 1166 (void) vfprintf(stderr, fmt, alist); 1167 (void) fprintf(stderr, "\n"); 1168 va_end(alist); 1169 } 1170 1171 static void 1172 zone_perror(char *prefix, int err, bool set_saw) 1173 { 1174 zerr("%s: %s", prefix, zonecfg_strerror(err)); 1175 if (set_saw) 1176 saw_error = TRUE; 1177 } 1178 1179 /* 1180 * zone_perror() expects a single string, but for remove and select 1181 * we have both the command and the resource type, so this wrapper 1182 * function serves the same purpose in a slightly different way. 1183 */ 1184 1185 static void 1186 z_cmd_rt_perror(int cmd_num, int res_num, int err, bool set_saw) 1187 { 1188 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num), 1189 zonecfg_strerror(err)); 1190 if (set_saw) 1191 saw_error = TRUE; 1192 } 1193 1194 /* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */ 1195 static int 1196 initialize(bool handle_expected) 1197 { 1198 int err; 1199 char brandname[MAXNAMELEN]; 1200 1201 if (zonecfg_check_handle(handle) != Z_OK) { 1202 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) { 1203 got_handle = TRUE; 1204 if (zonecfg_get_brand(handle, brandname, 1205 sizeof (brandname)) != Z_OK) { 1206 zerr("Zone %s is inconsistent: missing " 1207 "brand attribute", zone); 1208 exit(Z_ERR); 1209 } 1210 if ((brand = brand_open(brandname)) == NULL) { 1211 zerr("Zone %s uses non-existent brand \"%s\"." 1212 " Unable to continue", zone, brandname); 1213 exit(Z_ERR); 1214 } 1215 } else if (global_zone && err == Z_NO_ZONE && !got_handle && 1216 !read_only_mode) { 1217 /* 1218 * We implicitly create the global zone config if it 1219 * doesn't exist. 1220 */ 1221 zone_dochandle_t tmphandle; 1222 1223 if ((tmphandle = zonecfg_init_handle()) == NULL) { 1224 zone_perror(execname, Z_NOMEM, TRUE); 1225 exit(Z_ERR); 1226 } 1227 1228 err = zonecfg_get_template_handle("SUNWblank", zone, 1229 tmphandle); 1230 1231 if (err != Z_OK) { 1232 zonecfg_fini_handle(tmphandle); 1233 zone_perror("SUNWblank", err, TRUE); 1234 return (err); 1235 } 1236 1237 need_to_commit = TRUE; 1238 zonecfg_fini_handle(handle); 1239 handle = tmphandle; 1240 got_handle = TRUE; 1241 1242 } else { 1243 zone_perror(zone, err, handle_expected || got_handle); 1244 if (err == Z_NO_ZONE && !got_handle && 1245 interactive_mode && !read_only_mode) 1246 (void) printf(gettext("Use '%s' to begin " 1247 "configuring a new zone.\n"), 1248 cmd_to_str(CMD_CREATE)); 1249 return (err); 1250 } 1251 } 1252 return (Z_OK); 1253 } 1254 1255 static bool 1256 state_atleast(zone_state_t state) 1257 { 1258 zone_state_t state_num; 1259 int err; 1260 1261 if ((err = zone_get_state(zone, &state_num)) != Z_OK) { 1262 /* all states are greater than "non-existent" */ 1263 if (err == Z_NO_ZONE) 1264 return (B_FALSE); 1265 zerr(gettext("Unexpectedly failed to determine state " 1266 "of zone %s: %s"), zone, zonecfg_strerror(err)); 1267 exit(Z_ERR); 1268 } 1269 return (state_num >= state); 1270 } 1271 1272 /* 1273 * short_usage() is for bad syntax: getopt() issues, too many arguments, etc. 1274 */ 1275 1276 void 1277 short_usage(int command) 1278 { 1279 /* lex_lineno has already been incremented in the lexer; compensate */ 1280 if (cmd_file_mode) { 1281 if (strcmp(cmd_file_name, "-") == 0) 1282 (void) fprintf(stderr, 1283 gettext("syntax error on line %d\n"), 1284 lex_lineno - 1); 1285 else 1286 (void) fprintf(stderr, 1287 gettext("syntax error on line %d of %s\n"), 1288 lex_lineno - 1, cmd_file_name); 1289 } 1290 (void) fprintf(stderr, "%s:\n%s\n", gettext("usage"), 1291 helptab[command].short_usage); 1292 saw_error = TRUE; 1293 } 1294 1295 /* 1296 * long_usage() is for bad semantics: e.g., wrong property type for a given 1297 * resource type. It is also used by longer_usage() below. 1298 */ 1299 1300 void 1301 long_usage(uint_t cmd_num, bool set_saw) 1302 { 1303 (void) fprintf(set_saw ? stderr : stdout, "%s:\n%s\n", gettext("usage"), 1304 helptab[cmd_num].short_usage); 1305 (void) fprintf(set_saw ? stderr : stdout, "\t%s\n", long_help(cmd_num)); 1306 if (set_saw) 1307 saw_error = TRUE; 1308 } 1309 1310 /* 1311 * longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also 1312 * any extra usage() flags as appropriate for whatever command. 1313 */ 1314 1315 void 1316 longer_usage(uint_t cmd_num) 1317 { 1318 long_usage(cmd_num, FALSE); 1319 if (helptab[cmd_num].flags != 0) { 1320 (void) printf("\n"); 1321 usage(TRUE, helptab[cmd_num].flags); 1322 } 1323 } 1324 1325 /* 1326 * scope_usage() is simply used when a command is called from the wrong scope. 1327 */ 1328 1329 static void 1330 scope_usage(uint_t cmd_num) 1331 { 1332 zerr(gettext("The %s command only makes sense in the %s scope."), 1333 cmd_to_str(cmd_num), 1334 global_scope ? gettext("resource") : gettext("global")); 1335 saw_error = TRUE; 1336 } 1337 1338 /* 1339 * On input, TRUE => yes, FALSE => no. 1340 * On return, TRUE => 1, FALSE => no, could not ask => -1. 1341 */ 1342 1343 static int 1344 ask_yesno(bool default_answer, const char *question) 1345 { 1346 char line[64]; /* should be enough to answer yes or no */ 1347 1348 if (!ok_to_prompt) { 1349 saw_error = TRUE; 1350 return (-1); 1351 } 1352 for (;;) { 1353 if (printf("%s (%s)? ", question, 1354 default_answer ? "[y]/n" : "y/[n]") < 0) 1355 return (-1); 1356 if (fgets(line, sizeof (line), stdin) == NULL) 1357 return (-1); 1358 1359 if (line[0] == '\n') 1360 return (default_answer ? 1 : 0); 1361 if (tolower(line[0]) == 'y') 1362 return (1); 1363 if (tolower(line[0]) == 'n') 1364 return (0); 1365 } 1366 } 1367 1368 /* 1369 * Prints warning if zone already exists. 1370 * In interactive mode, prompts if we should continue anyway and returns Z_OK 1371 * if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR. 1372 * 1373 * Note that if a zone exists and its state is >= INSTALLED, an error message 1374 * will be printed and this function will return Z_ERR regardless of mode. 1375 */ 1376 1377 static int 1378 check_if_zone_already_exists(bool force) 1379 { 1380 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 1381 zone_dochandle_t tmphandle; 1382 int res, answer; 1383 1384 if ((tmphandle = zonecfg_init_handle()) == NULL) { 1385 zone_perror(execname, Z_NOMEM, TRUE); 1386 exit(Z_ERR); 1387 } 1388 res = zonecfg_get_handle(zone, tmphandle); 1389 zonecfg_fini_handle(tmphandle); 1390 if (res != Z_OK) 1391 return (Z_OK); 1392 1393 if (state_atleast(ZONE_STATE_INSTALLED)) { 1394 zerr(gettext("Zone %s already installed; %s not allowed."), 1395 zone, cmd_to_str(CMD_CREATE)); 1396 return (Z_ERR); 1397 } 1398 1399 if (force) { 1400 (void) printf(gettext("Zone %s already exists; overwriting.\n"), 1401 zone); 1402 return (Z_OK); 1403 } 1404 (void) snprintf(line, sizeof (line), 1405 gettext("Zone %s already exists; %s anyway"), zone, 1406 cmd_to_str(CMD_CREATE)); 1407 if ((answer = ask_yesno(FALSE, line)) == -1) { 1408 zerr(gettext("Zone exists, input not from terminal and -F not " 1409 "specified:\n%s command ignored, exiting."), 1410 cmd_to_str(CMD_CREATE)); 1411 exit(Z_ERR); 1412 } 1413 return (answer == 1 ? Z_OK : Z_ERR); 1414 } 1415 1416 static bool 1417 zone_is_read_only(int cmd_num) 1418 { 1419 if (strncmp(zone, "SUNW", 4) == 0) { 1420 zerr(gettext("%s: zones beginning with SUNW are read-only."), 1421 zone); 1422 saw_error = TRUE; 1423 return (TRUE); 1424 } 1425 if (read_only_mode) { 1426 zerr(gettext("%s: cannot %s in read-only mode."), zone, 1427 cmd_to_str(cmd_num)); 1428 saw_error = TRUE; 1429 return (TRUE); 1430 } 1431 return (FALSE); 1432 } 1433 1434 /* 1435 * Create a new configuration. 1436 */ 1437 void 1438 create_func(cmd_t *cmd) 1439 { 1440 int err, arg; 1441 char zone_template[ZONENAME_MAX]; 1442 char attach_path[MAXPATHLEN]; 1443 zone_dochandle_t tmphandle; 1444 bool force = FALSE; 1445 bool attach = FALSE; 1446 1447 assert(cmd != NULL); 1448 1449 /* This is the default if no arguments are given. */ 1450 (void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template)); 1451 1452 optind = 0; 1453 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:")) 1454 != EOF) { 1455 switch (arg) { 1456 case '?': 1457 if (optopt == '?') 1458 longer_usage(CMD_CREATE); 1459 else 1460 short_usage(CMD_CREATE); 1461 return; 1462 case 'a': 1463 (void) strlcpy(attach_path, optarg, 1464 sizeof (attach_path)); 1465 attach = TRUE; 1466 break; 1467 case 'b': 1468 (void) strlcpy(zone_template, "SUNWblank", 1469 sizeof (zone_template)); 1470 break; 1471 case 'F': 1472 force = TRUE; 1473 break; 1474 case 't': 1475 (void) strlcpy(zone_template, optarg, 1476 sizeof (zone_template)); 1477 break; 1478 default: 1479 short_usage(CMD_CREATE); 1480 return; 1481 } 1482 } 1483 if (optind != cmd->cmd_argc) { 1484 short_usage(CMD_CREATE); 1485 return; 1486 } 1487 1488 if (zone_is_read_only(CMD_CREATE)) 1489 return; 1490 1491 if (check_if_zone_already_exists(force) != Z_OK) 1492 return; 1493 1494 /* 1495 * Get a temporary handle first. If that fails, the old handle 1496 * will not be lost. Then finish whichever one we don't need, 1497 * to avoid leaks. Then get the handle for zone_template, and 1498 * set the name to zone: this "copy, rename" method is how 1499 * create -[b|t] works. 1500 */ 1501 if ((tmphandle = zonecfg_init_handle()) == NULL) { 1502 zone_perror(execname, Z_NOMEM, TRUE); 1503 exit(Z_ERR); 1504 } 1505 1506 if (attach) 1507 err = zonecfg_get_attach_handle(attach_path, zone, B_FALSE, 1508 tmphandle); 1509 else 1510 err = zonecfg_get_template_handle(zone_template, zone, 1511 tmphandle); 1512 1513 if (err != Z_OK) { 1514 zonecfg_fini_handle(tmphandle); 1515 if (attach && err == Z_NO_ZONE) 1516 (void) fprintf(stderr, gettext("invalid path to " 1517 "detached zone\n")); 1518 else if (attach && err == Z_INVALID_DOCUMENT) 1519 (void) fprintf(stderr, gettext("Cannot attach to an " 1520 "earlier release of the operating system\n")); 1521 else 1522 zone_perror(zone_template, err, TRUE); 1523 return; 1524 } 1525 1526 need_to_commit = TRUE; 1527 zonecfg_fini_handle(handle); 1528 handle = tmphandle; 1529 got_handle = TRUE; 1530 } 1531 1532 /* 1533 * This malloc()'s memory, which must be freed by the caller. 1534 */ 1535 static char * 1536 quoteit(char *instr) 1537 { 1538 char *outstr; 1539 size_t outstrsize = strlen(instr) + 3; /* 2 quotes + '\0' */ 1540 1541 if ((outstr = malloc(outstrsize)) == NULL) { 1542 zone_perror(zone, Z_NOMEM, FALSE); 1543 exit(Z_ERR); 1544 } 1545 if (strchr(instr, ' ') == NULL) { 1546 (void) strlcpy(outstr, instr, outstrsize); 1547 return (outstr); 1548 } 1549 (void) snprintf(outstr, outstrsize, "\"%s\"", instr); 1550 return (outstr); 1551 } 1552 1553 static void 1554 export_prop(FILE *of, int prop_num, char *prop_id) 1555 { 1556 char *quote_str; 1557 1558 if (strlen(prop_id) == 0) 1559 return; 1560 quote_str = quoteit(prop_id); 1561 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1562 pt_to_str(prop_num), quote_str); 1563 free(quote_str); 1564 } 1565 1566 void 1567 export_func(cmd_t *cmd) 1568 { 1569 struct zone_nwiftab nwiftab; 1570 struct zone_fstab fstab; 1571 struct zone_devtab devtab; 1572 struct zone_attrtab attrtab; 1573 struct zone_rctltab rctltab; 1574 struct zone_dstab dstab; 1575 struct zone_psettab psettab; 1576 struct zone_mcaptab mcaptab; 1577 struct zone_rctlvaltab *valptr; 1578 int err, arg; 1579 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN]; 1580 char bootargs[BOOTARGS_MAX]; 1581 char sched[MAXNAMELEN]; 1582 char brand[MAXNAMELEN]; 1583 char *limitpriv; 1584 FILE *of; 1585 boolean_t autoboot; 1586 zone_iptype_t iptype; 1587 bool need_to_close = FALSE; 1588 1589 assert(cmd != NULL); 1590 1591 outfile[0] = '\0'; 1592 optind = 0; 1593 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) { 1594 switch (arg) { 1595 case '?': 1596 if (optopt == '?') 1597 longer_usage(CMD_EXPORT); 1598 else 1599 short_usage(CMD_EXPORT); 1600 return; 1601 case 'f': 1602 (void) strlcpy(outfile, optarg, sizeof (outfile)); 1603 break; 1604 default: 1605 short_usage(CMD_EXPORT); 1606 return; 1607 } 1608 } 1609 if (optind != cmd->cmd_argc) { 1610 short_usage(CMD_EXPORT); 1611 return; 1612 } 1613 if (strlen(outfile) == 0) { 1614 of = stdout; 1615 } else { 1616 if ((of = fopen(outfile, "w")) == NULL) { 1617 zerr(gettext("opening file %s: %s"), 1618 outfile, strerror(errno)); 1619 goto done; 1620 } 1621 setbuf(of, NULL); 1622 need_to_close = TRUE; 1623 } 1624 1625 if ((err = initialize(TRUE)) != Z_OK) 1626 goto done; 1627 1628 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE)); 1629 1630 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK && 1631 strlen(zonepath) > 0) 1632 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1633 pt_to_str(PT_ZONEPATH), zonepath); 1634 1635 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) && 1636 (strcmp(brand, NATIVE_BRAND_NAME) != 0)) 1637 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1638 pt_to_str(PT_BRAND), brand); 1639 1640 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK) 1641 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1642 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false"); 1643 1644 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK && 1645 strlen(bootargs) > 0) { 1646 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1647 pt_to_str(PT_BOOTARGS), bootargs); 1648 } 1649 1650 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 1651 strlen(pool) > 0) 1652 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1653 pt_to_str(PT_POOL), pool); 1654 1655 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK && 1656 strlen(limitpriv) > 0) { 1657 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1658 pt_to_str(PT_LIMITPRIV), limitpriv); 1659 free(limitpriv); 1660 } 1661 1662 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK && 1663 strlen(sched) > 0) 1664 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1665 pt_to_str(PT_SCHED), sched); 1666 1667 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) { 1668 switch (iptype) { 1669 case ZS_SHARED: 1670 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1671 pt_to_str(PT_IPTYPE), "shared"); 1672 break; 1673 case ZS_EXCLUSIVE: 1674 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1675 pt_to_str(PT_IPTYPE), "exclusive"); 1676 break; 1677 } 1678 } 1679 1680 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 1681 zone_perror(zone, err, FALSE); 1682 goto done; 1683 } 1684 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 1685 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1686 rt_to_str(RT_IPD)); 1687 export_prop(of, PT_DIR, fstab.zone_fs_dir); 1688 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1689 } 1690 (void) zonecfg_endipdent(handle); 1691 1692 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 1693 zone_perror(zone, err, FALSE); 1694 goto done; 1695 } 1696 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 1697 zone_fsopt_t *optptr; 1698 1699 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1700 rt_to_str(RT_FS)); 1701 export_prop(of, PT_DIR, fstab.zone_fs_dir); 1702 export_prop(of, PT_SPECIAL, fstab.zone_fs_special); 1703 export_prop(of, PT_RAW, fstab.zone_fs_raw); 1704 export_prop(of, PT_TYPE, fstab.zone_fs_type); 1705 for (optptr = fstab.zone_fs_options; optptr != NULL; 1706 optptr = optptr->zone_fsopt_next) { 1707 /* 1708 * Simple property values with embedded equal signs 1709 * need to be quoted to prevent the lexer from 1710 * mis-parsing them as complex name=value pairs. 1711 */ 1712 if (strchr(optptr->zone_fsopt_opt, '=')) 1713 (void) fprintf(of, "%s %s \"%s\"\n", 1714 cmd_to_str(CMD_ADD), 1715 pt_to_str(PT_OPTIONS), 1716 optptr->zone_fsopt_opt); 1717 else 1718 (void) fprintf(of, "%s %s %s\n", 1719 cmd_to_str(CMD_ADD), 1720 pt_to_str(PT_OPTIONS), 1721 optptr->zone_fsopt_opt); 1722 } 1723 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1724 zonecfg_free_fs_option_list(fstab.zone_fs_options); 1725 } 1726 (void) zonecfg_endfsent(handle); 1727 1728 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 1729 zone_perror(zone, err, FALSE); 1730 goto done; 1731 } 1732 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 1733 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1734 rt_to_str(RT_NET)); 1735 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address); 1736 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical); 1737 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1738 } 1739 (void) zonecfg_endnwifent(handle); 1740 1741 if ((err = zonecfg_setdevent(handle)) != Z_OK) { 1742 zone_perror(zone, err, FALSE); 1743 goto done; 1744 } 1745 while (zonecfg_getdevent(handle, &devtab) == Z_OK) { 1746 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1747 rt_to_str(RT_DEVICE)); 1748 export_prop(of, PT_MATCH, devtab.zone_dev_match); 1749 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1750 } 1751 (void) zonecfg_enddevent(handle); 1752 1753 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 1754 zone_perror(zone, err, FALSE); 1755 goto done; 1756 } 1757 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 1758 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD)); 1759 export_prop(of, PT_NAME, rctltab.zone_rctl_name); 1760 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL; 1761 valptr = valptr->zone_rctlval_next) { 1762 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n", 1763 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 1764 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 1765 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 1766 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 1767 } 1768 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1769 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 1770 } 1771 (void) zonecfg_endrctlent(handle); 1772 1773 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 1774 zone_perror(zone, err, FALSE); 1775 goto done; 1776 } 1777 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 1778 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1779 rt_to_str(RT_ATTR)); 1780 export_prop(of, PT_NAME, attrtab.zone_attr_name); 1781 export_prop(of, PT_TYPE, attrtab.zone_attr_type); 1782 export_prop(of, PT_VALUE, attrtab.zone_attr_value); 1783 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1784 } 1785 (void) zonecfg_endattrent(handle); 1786 1787 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 1788 zone_perror(zone, err, FALSE); 1789 goto done; 1790 } 1791 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 1792 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1793 rt_to_str(RT_DATASET)); 1794 export_prop(of, PT_NAME, dstab.zone_dataset_name); 1795 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1796 } 1797 (void) zonecfg_enddsent(handle); 1798 1799 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) { 1800 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1801 rt_to_str(RT_DCPU)); 1802 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0) 1803 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1804 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max); 1805 else 1806 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET), 1807 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min, 1808 psettab.zone_ncpu_max); 1809 if (psettab.zone_importance[0] != '\0') 1810 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1811 pt_to_str(PT_IMPORTANCE), psettab.zone_importance); 1812 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1813 } 1814 1815 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) { 1816 char buf[128]; 1817 1818 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1819 rt_to_str(RT_MCAP)); 1820 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf)); 1821 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1822 pt_to_str(PT_PHYSICAL), buf); 1823 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 1824 } 1825 1826 done: 1827 if (need_to_close) 1828 (void) fclose(of); 1829 } 1830 1831 void 1832 exit_func(cmd_t *cmd) 1833 { 1834 int arg, answer; 1835 1836 optind = 0; 1837 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 1838 switch (arg) { 1839 case '?': 1840 longer_usage(CMD_EXIT); 1841 return; 1842 case 'F': 1843 force_exit = TRUE; 1844 break; 1845 default: 1846 short_usage(CMD_EXIT); 1847 return; 1848 } 1849 } 1850 if (optind < cmd->cmd_argc) { 1851 short_usage(CMD_EXIT); 1852 return; 1853 } 1854 1855 if (global_scope || force_exit) { 1856 time_to_exit = TRUE; 1857 return; 1858 } 1859 1860 answer = ask_yesno(FALSE, "Resource incomplete; really quit"); 1861 if (answer == -1) { 1862 zerr(gettext("Resource incomplete, input " 1863 "not from terminal and -F not specified:\n%s command " 1864 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT)); 1865 exit(Z_ERR); 1866 } else if (answer == 1) { 1867 time_to_exit = TRUE; 1868 } 1869 /* (answer == 0) => just return */ 1870 } 1871 1872 static int 1873 validate_zonepath_syntax(char *path) 1874 { 1875 if (path[0] != '/') { 1876 zerr(gettext("%s is not an absolute path."), path); 1877 return (Z_ERR); 1878 } 1879 if (strcmp(path, "/") == 0) { 1880 zerr(gettext("/ is not allowed as a %s."), 1881 pt_to_str(PT_ZONEPATH)); 1882 return (Z_ERR); 1883 } 1884 return (Z_OK); 1885 } 1886 1887 static void 1888 add_resource(cmd_t *cmd) 1889 { 1890 int type; 1891 struct zone_psettab tmp_psettab; 1892 struct zone_mcaptab tmp_mcaptab; 1893 uint64_t tmp_mcap; 1894 char pool[MAXNAMELEN]; 1895 1896 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 1897 long_usage(CMD_ADD, TRUE); 1898 goto bad; 1899 } 1900 1901 switch (type) { 1902 case RT_FS: 1903 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 1904 return; 1905 case RT_IPD: 1906 if (state_atleast(ZONE_STATE_INSTALLED)) { 1907 zerr(gettext("Zone %s already installed; %s %s not " 1908 "allowed."), zone, cmd_to_str(CMD_ADD), 1909 rt_to_str(RT_IPD)); 1910 goto bad; 1911 } 1912 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 1913 return; 1914 case RT_NET: 1915 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 1916 return; 1917 case RT_DEVICE: 1918 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 1919 return; 1920 case RT_RCTL: 1921 if (global_zone) 1922 zerr(gettext("WARNING: Setting a global zone resource " 1923 "control too low could deny\nservice " 1924 "to even the root user; " 1925 "this could render the system impossible\n" 1926 "to administer. Please use caution.")); 1927 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 1928 return; 1929 case RT_ATTR: 1930 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 1931 return; 1932 case RT_DATASET: 1933 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 1934 return; 1935 case RT_DCPU: 1936 /* Make sure there isn't already a cpu-set entry. */ 1937 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 1938 zerr(gettext("The %s resource already exists."), 1939 rt_to_str(RT_DCPU)); 1940 goto bad; 1941 } 1942 1943 /* Make sure the pool property isn't set. */ 1944 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 1945 strlen(pool) > 0) { 1946 zerr(gettext("The %s property is already set. " 1947 "A persistent pool is incompatible with\nthe %s " 1948 "resource."), 1949 pt_to_str(PT_POOL), rt_to_str(RT_DCPU)); 1950 goto bad; 1951 } 1952 1953 bzero(&in_progress_psettab, sizeof (in_progress_psettab)); 1954 return; 1955 case RT_MCAP: 1956 /* 1957 * Make sure there isn't already a mem-cap entry or max-swap 1958 * or max-locked rctl. 1959 */ 1960 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK || 1961 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap) 1962 == Z_OK || 1963 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 1964 &tmp_mcap) == Z_OK) { 1965 zerr(gettext("The %s resource or a related resource " 1966 "control already exists."), rt_to_str(RT_MCAP)); 1967 goto bad; 1968 } 1969 if (global_zone) 1970 zerr(gettext("WARNING: Setting a global zone memory " 1971 "cap too low could deny\nservice " 1972 "to even the root user; " 1973 "this could render the system impossible\n" 1974 "to administer. Please use caution.")); 1975 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab)); 1976 return; 1977 default: 1978 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 1979 long_usage(CMD_ADD, TRUE); 1980 usage(FALSE, HELP_RESOURCES); 1981 } 1982 bad: 1983 global_scope = TRUE; 1984 end_op = -1; 1985 } 1986 1987 static void 1988 do_complex_rctl_val(complex_property_ptr_t cp) 1989 { 1990 struct zone_rctlvaltab *rctlvaltab; 1991 complex_property_ptr_t cx; 1992 bool seen_priv = FALSE, seen_limit = FALSE, seen_action = FALSE; 1993 rctlblk_t *rctlblk; 1994 int err; 1995 1996 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 1997 zone_perror(zone, Z_NOMEM, TRUE); 1998 exit(Z_ERR); 1999 } 2000 for (cx = cp; cx != NULL; cx = cx->cp_next) { 2001 switch (cx->cp_type) { 2002 case PT_PRIV: 2003 if (seen_priv) { 2004 zerr(gettext("%s already specified"), 2005 pt_to_str(PT_PRIV)); 2006 goto bad; 2007 } 2008 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2009 cx->cp_value, 2010 sizeof (rctlvaltab->zone_rctlval_priv)); 2011 seen_priv = TRUE; 2012 break; 2013 case PT_LIMIT: 2014 if (seen_limit) { 2015 zerr(gettext("%s already specified"), 2016 pt_to_str(PT_LIMIT)); 2017 goto bad; 2018 } 2019 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2020 cx->cp_value, 2021 sizeof (rctlvaltab->zone_rctlval_limit)); 2022 seen_limit = TRUE; 2023 break; 2024 case PT_ACTION: 2025 if (seen_action) { 2026 zerr(gettext("%s already specified"), 2027 pt_to_str(PT_ACTION)); 2028 goto bad; 2029 } 2030 (void) strlcpy(rctlvaltab->zone_rctlval_action, 2031 cx->cp_value, 2032 sizeof (rctlvaltab->zone_rctlval_action)); 2033 seen_action = TRUE; 2034 break; 2035 default: 2036 zone_perror(pt_to_str(PT_VALUE), 2037 Z_NO_PROPERTY_TYPE, TRUE); 2038 long_usage(CMD_ADD, TRUE); 2039 usage(FALSE, HELP_PROPS); 2040 zonecfg_free_rctl_value_list(rctlvaltab); 2041 return; 2042 } 2043 } 2044 if (!seen_priv) 2045 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV)); 2046 if (!seen_limit) 2047 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT)); 2048 if (!seen_action) 2049 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION)); 2050 if (!seen_priv || !seen_limit || !seen_action) 2051 goto bad; 2052 rctlvaltab->zone_rctlval_next = NULL; 2053 rctlblk = alloca(rctlblk_size()); 2054 /* 2055 * Make sure the rctl value looks roughly correct; we won't know if 2056 * it's truly OK until we verify the configuration on the target 2057 * system. 2058 */ 2059 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK || 2060 !zonecfg_valid_rctlblk(rctlblk)) { 2061 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL), 2062 pt_to_str(PT_VALUE)); 2063 goto bad; 2064 } 2065 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab); 2066 if (err != Z_OK) 2067 zone_perror(pt_to_str(PT_VALUE), err, TRUE); 2068 return; 2069 2070 bad: 2071 zonecfg_free_rctl_value_list(rctlvaltab); 2072 } 2073 2074 static void 2075 add_property(cmd_t *cmd) 2076 { 2077 char *prop_id; 2078 int err, res_type, prop_type; 2079 property_value_ptr_t pp; 2080 list_property_ptr_t l; 2081 2082 res_type = resource_scope; 2083 prop_type = cmd->cmd_prop_name[0]; 2084 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2085 long_usage(CMD_ADD, TRUE); 2086 return; 2087 } 2088 2089 if (cmd->cmd_prop_nv_pairs != 1) { 2090 long_usage(CMD_ADD, TRUE); 2091 return; 2092 } 2093 2094 if (initialize(TRUE) != Z_OK) 2095 return; 2096 2097 switch (res_type) { 2098 case RT_FS: 2099 if (prop_type != PT_OPTIONS) { 2100 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2101 TRUE); 2102 long_usage(CMD_ADD, TRUE); 2103 usage(FALSE, HELP_PROPS); 2104 return; 2105 } 2106 pp = cmd->cmd_property_ptr[0]; 2107 if (pp->pv_type != PROP_VAL_SIMPLE && 2108 pp->pv_type != PROP_VAL_LIST) { 2109 zerr(gettext("A %s or %s value was expected here."), 2110 pvt_to_str(PROP_VAL_SIMPLE), 2111 pvt_to_str(PROP_VAL_LIST)); 2112 saw_error = TRUE; 2113 return; 2114 } 2115 if (pp->pv_type == PROP_VAL_SIMPLE) { 2116 if (pp->pv_simple == NULL) { 2117 long_usage(CMD_ADD, TRUE); 2118 return; 2119 } 2120 prop_id = pp->pv_simple; 2121 err = zonecfg_add_fs_option(&in_progress_fstab, 2122 prop_id); 2123 if (err != Z_OK) 2124 zone_perror(pt_to_str(prop_type), err, TRUE); 2125 } else { 2126 list_property_ptr_t list; 2127 2128 for (list = pp->pv_list; list != NULL; 2129 list = list->lp_next) { 2130 prop_id = list->lp_simple; 2131 if (prop_id == NULL) 2132 break; 2133 err = zonecfg_add_fs_option( 2134 &in_progress_fstab, prop_id); 2135 if (err != Z_OK) 2136 zone_perror(pt_to_str(prop_type), err, 2137 TRUE); 2138 } 2139 } 2140 return; 2141 case RT_RCTL: 2142 if (prop_type != PT_VALUE) { 2143 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2144 TRUE); 2145 long_usage(CMD_ADD, TRUE); 2146 usage(FALSE, HELP_PROPS); 2147 return; 2148 } 2149 pp = cmd->cmd_property_ptr[0]; 2150 if (pp->pv_type != PROP_VAL_COMPLEX && 2151 pp->pv_type != PROP_VAL_LIST) { 2152 zerr(gettext("A %s or %s value was expected here."), 2153 pvt_to_str(PROP_VAL_COMPLEX), 2154 pvt_to_str(PROP_VAL_LIST)); 2155 saw_error = TRUE; 2156 return; 2157 } 2158 if (pp->pv_type == PROP_VAL_COMPLEX) { 2159 do_complex_rctl_val(pp->pv_complex); 2160 return; 2161 } 2162 for (l = pp->pv_list; l != NULL; l = l->lp_next) 2163 do_complex_rctl_val(l->lp_complex); 2164 return; 2165 default: 2166 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 2167 long_usage(CMD_ADD, TRUE); 2168 usage(FALSE, HELP_RESOURCES); 2169 return; 2170 } 2171 } 2172 2173 static boolean_t 2174 gz_invalid_resource(int type) 2175 { 2176 return (global_zone && (type == RT_FS || type == RT_IPD || 2177 type == RT_NET || type == RT_DEVICE || type == RT_ATTR || 2178 type == RT_DATASET)); 2179 } 2180 2181 static boolean_t 2182 gz_invalid_rt_property(int type) 2183 { 2184 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH || 2185 type == RT_AUTOBOOT || type == RT_LIMITPRIV || 2186 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED || 2187 type == RT_IPTYPE)); 2188 } 2189 2190 static boolean_t 2191 gz_invalid_property(int type) 2192 { 2193 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH || 2194 type == PT_AUTOBOOT || type == PT_LIMITPRIV || 2195 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED || 2196 type == PT_IPTYPE)); 2197 } 2198 2199 void 2200 add_func(cmd_t *cmd) 2201 { 2202 int arg; 2203 2204 assert(cmd != NULL); 2205 2206 optind = 0; 2207 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 2208 switch (arg) { 2209 case '?': 2210 longer_usage(CMD_ADD); 2211 return; 2212 default: 2213 short_usage(CMD_ADD); 2214 return; 2215 } 2216 } 2217 if (optind != cmd->cmd_argc) { 2218 short_usage(CMD_ADD); 2219 return; 2220 } 2221 2222 if (zone_is_read_only(CMD_ADD)) 2223 return; 2224 2225 if (initialize(TRUE) != Z_OK) 2226 return; 2227 if (global_scope) { 2228 if (gz_invalid_resource(cmd->cmd_res_type)) { 2229 zerr(gettext("Cannot add a %s resource to the " 2230 "global zone."), rt_to_str(cmd->cmd_res_type)); 2231 saw_error = TRUE; 2232 return; 2233 } 2234 2235 global_scope = FALSE; 2236 resource_scope = cmd->cmd_res_type; 2237 end_op = CMD_ADD; 2238 add_resource(cmd); 2239 } else 2240 add_property(cmd); 2241 } 2242 2243 /* 2244 * This routine has an unusual implementation, because it tries very 2245 * hard to succeed in the face of a variety of failure modes. 2246 * The most common and most vexing occurs when the index file and 2247 * the /etc/zones/<zonename.xml> file are not both present. In 2248 * this case, delete must eradicate as much of the zone state as is left 2249 * so that the user can later create a new zone with the same name. 2250 */ 2251 void 2252 delete_func(cmd_t *cmd) 2253 { 2254 int err, arg, answer; 2255 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 2256 bool force = FALSE; 2257 2258 optind = 0; 2259 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2260 switch (arg) { 2261 case '?': 2262 longer_usage(CMD_DELETE); 2263 return; 2264 case 'F': 2265 force = TRUE; 2266 break; 2267 default: 2268 short_usage(CMD_DELETE); 2269 return; 2270 } 2271 } 2272 if (optind != cmd->cmd_argc) { 2273 short_usage(CMD_DELETE); 2274 return; 2275 } 2276 2277 if (zone_is_read_only(CMD_DELETE)) 2278 return; 2279 2280 if (!force) { 2281 /* 2282 * Initialize sets up the global called "handle" and warns the 2283 * user if the zone is not configured. In force mode, we don't 2284 * trust that evaluation, and hence skip it. (We don't need the 2285 * handle to be loaded anyway, since zonecfg_destroy is done by 2286 * zonename). However, we also have to take care to emulate the 2287 * messages spit out by initialize; see below. 2288 */ 2289 if (initialize(TRUE) != Z_OK) 2290 return; 2291 2292 (void) snprintf(line, sizeof (line), 2293 gettext("Are you sure you want to delete zone %s"), zone); 2294 if ((answer = ask_yesno(FALSE, line)) == -1) { 2295 zerr(gettext("Input not from terminal and -F not " 2296 "specified:\n%s command ignored, exiting."), 2297 cmd_to_str(CMD_DELETE)); 2298 exit(Z_ERR); 2299 } 2300 if (answer != 1) 2301 return; 2302 } 2303 2304 if ((err = zonecfg_destroy(zone, force)) != Z_OK) { 2305 if ((err == Z_BAD_ZONE_STATE) && !force) { 2306 zerr(gettext("Zone %s not in %s state; %s not " 2307 "allowed. Use -F to force %s."), 2308 zone, zone_state_str(ZONE_STATE_CONFIGURED), 2309 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE)); 2310 } else { 2311 zone_perror(zone, err, TRUE); 2312 } 2313 } 2314 need_to_commit = FALSE; 2315 2316 /* 2317 * Emulate initialize's messaging; if there wasn't a valid handle to 2318 * begin with, then user had typed delete (or delete -F) multiple 2319 * times. So we emit a message. 2320 * 2321 * We only do this in the 'force' case because normally, initialize() 2322 * takes care of this for us. 2323 */ 2324 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode) 2325 (void) printf(gettext("Use '%s' to begin " 2326 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE)); 2327 2328 /* 2329 * Time for a new handle: finish the old one off first 2330 * then get a new one properly to avoid leaks. 2331 */ 2332 if (got_handle) { 2333 zonecfg_fini_handle(handle); 2334 if ((handle = zonecfg_init_handle()) == NULL) { 2335 zone_perror(execname, Z_NOMEM, TRUE); 2336 exit(Z_ERR); 2337 } 2338 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) { 2339 /* If there was no zone before, that's OK */ 2340 if (err != Z_NO_ZONE) 2341 zone_perror(zone, err, TRUE); 2342 got_handle = FALSE; 2343 } 2344 } 2345 } 2346 2347 static int 2348 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, bool fill_in_only) 2349 { 2350 int err, i; 2351 property_value_ptr_t pp; 2352 2353 if ((err = initialize(TRUE)) != Z_OK) 2354 return (err); 2355 2356 bzero(fstab, sizeof (*fstab)); 2357 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2358 pp = cmd->cmd_property_ptr[i]; 2359 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2360 zerr(gettext("A simple value was expected here.")); 2361 saw_error = TRUE; 2362 return (Z_INSUFFICIENT_SPEC); 2363 } 2364 switch (cmd->cmd_prop_name[i]) { 2365 case PT_DIR: 2366 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 2367 sizeof (fstab->zone_fs_dir)); 2368 break; 2369 case PT_SPECIAL: 2370 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 2371 sizeof (fstab->zone_fs_special)); 2372 break; 2373 case PT_RAW: 2374 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 2375 sizeof (fstab->zone_fs_raw)); 2376 break; 2377 case PT_TYPE: 2378 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 2379 sizeof (fstab->zone_fs_type)); 2380 break; 2381 default: 2382 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2383 Z_NO_PROPERTY_TYPE, TRUE); 2384 return (Z_INSUFFICIENT_SPEC); 2385 } 2386 } 2387 if (fill_in_only) 2388 return (Z_OK); 2389 return (zonecfg_lookup_filesystem(handle, fstab)); 2390 } 2391 2392 static int 2393 fill_in_ipdtab(cmd_t *cmd, struct zone_fstab *ipdtab, bool fill_in_only) 2394 { 2395 int err, i; 2396 property_value_ptr_t pp; 2397 2398 if ((err = initialize(TRUE)) != Z_OK) 2399 return (err); 2400 2401 bzero(ipdtab, sizeof (*ipdtab)); 2402 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2403 pp = cmd->cmd_property_ptr[i]; 2404 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2405 zerr(gettext("A simple value was expected here.")); 2406 saw_error = TRUE; 2407 return (Z_INSUFFICIENT_SPEC); 2408 } 2409 switch (cmd->cmd_prop_name[i]) { 2410 case PT_DIR: 2411 (void) strlcpy(ipdtab->zone_fs_dir, pp->pv_simple, 2412 sizeof (ipdtab->zone_fs_dir)); 2413 break; 2414 default: 2415 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2416 Z_NO_PROPERTY_TYPE, TRUE); 2417 return (Z_INSUFFICIENT_SPEC); 2418 } 2419 } 2420 if (fill_in_only) 2421 return (Z_OK); 2422 return (zonecfg_lookup_ipd(handle, ipdtab)); 2423 } 2424 2425 static int 2426 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, bool fill_in_only) 2427 { 2428 int err, i; 2429 property_value_ptr_t pp; 2430 2431 if ((err = initialize(TRUE)) != Z_OK) 2432 return (err); 2433 2434 bzero(nwiftab, sizeof (*nwiftab)); 2435 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2436 pp = cmd->cmd_property_ptr[i]; 2437 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2438 zerr(gettext("A simple value was expected here.")); 2439 saw_error = TRUE; 2440 return (Z_INSUFFICIENT_SPEC); 2441 } 2442 switch (cmd->cmd_prop_name[i]) { 2443 case PT_ADDRESS: 2444 (void) strlcpy(nwiftab->zone_nwif_address, 2445 pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 2446 break; 2447 case PT_PHYSICAL: 2448 (void) strlcpy(nwiftab->zone_nwif_physical, 2449 pp->pv_simple, 2450 sizeof (nwiftab->zone_nwif_physical)); 2451 break; 2452 default: 2453 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2454 Z_NO_PROPERTY_TYPE, TRUE); 2455 return (Z_INSUFFICIENT_SPEC); 2456 } 2457 } 2458 if (fill_in_only) 2459 return (Z_OK); 2460 err = zonecfg_lookup_nwif(handle, nwiftab); 2461 return (err); 2462 } 2463 2464 static int 2465 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, bool fill_in_only) 2466 { 2467 int err, i; 2468 property_value_ptr_t pp; 2469 2470 if ((err = initialize(TRUE)) != Z_OK) 2471 return (err); 2472 2473 bzero(devtab, sizeof (*devtab)); 2474 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2475 pp = cmd->cmd_property_ptr[i]; 2476 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2477 zerr(gettext("A simple value was expected here.")); 2478 saw_error = TRUE; 2479 return (Z_INSUFFICIENT_SPEC); 2480 } 2481 switch (cmd->cmd_prop_name[i]) { 2482 case PT_MATCH: 2483 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2484 sizeof (devtab->zone_dev_match)); 2485 break; 2486 default: 2487 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2488 Z_NO_PROPERTY_TYPE, TRUE); 2489 return (Z_INSUFFICIENT_SPEC); 2490 } 2491 } 2492 if (fill_in_only) 2493 return (Z_OK); 2494 err = zonecfg_lookup_dev(handle, devtab); 2495 return (err); 2496 } 2497 2498 static int 2499 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, bool fill_in_only) 2500 { 2501 int err, i; 2502 property_value_ptr_t pp; 2503 2504 if ((err = initialize(TRUE)) != Z_OK) 2505 return (err); 2506 2507 bzero(rctltab, sizeof (*rctltab)); 2508 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2509 pp = cmd->cmd_property_ptr[i]; 2510 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2511 zerr(gettext("A simple value was expected here.")); 2512 saw_error = TRUE; 2513 return (Z_INSUFFICIENT_SPEC); 2514 } 2515 switch (cmd->cmd_prop_name[i]) { 2516 case PT_NAME: 2517 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2518 sizeof (rctltab->zone_rctl_name)); 2519 break; 2520 default: 2521 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2522 Z_NO_PROPERTY_TYPE, TRUE); 2523 return (Z_INSUFFICIENT_SPEC); 2524 } 2525 } 2526 if (fill_in_only) 2527 return (Z_OK); 2528 err = zonecfg_lookup_rctl(handle, rctltab); 2529 return (err); 2530 } 2531 2532 static int 2533 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, bool fill_in_only) 2534 { 2535 int err, i; 2536 property_value_ptr_t pp; 2537 2538 if ((err = initialize(TRUE)) != Z_OK) 2539 return (err); 2540 2541 bzero(attrtab, sizeof (*attrtab)); 2542 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2543 pp = cmd->cmd_property_ptr[i]; 2544 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2545 zerr(gettext("A simple value was expected here.")); 2546 saw_error = TRUE; 2547 return (Z_INSUFFICIENT_SPEC); 2548 } 2549 switch (cmd->cmd_prop_name[i]) { 2550 case PT_NAME: 2551 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2552 sizeof (attrtab->zone_attr_name)); 2553 break; 2554 case PT_TYPE: 2555 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2556 sizeof (attrtab->zone_attr_type)); 2557 break; 2558 case PT_VALUE: 2559 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2560 sizeof (attrtab->zone_attr_value)); 2561 break; 2562 default: 2563 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2564 Z_NO_PROPERTY_TYPE, TRUE); 2565 return (Z_INSUFFICIENT_SPEC); 2566 } 2567 } 2568 if (fill_in_only) 2569 return (Z_OK); 2570 err = zonecfg_lookup_attr(handle, attrtab); 2571 return (err); 2572 } 2573 2574 static int 2575 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, bool fill_in_only) 2576 { 2577 int err, i; 2578 property_value_ptr_t pp; 2579 2580 if ((err = initialize(TRUE)) != Z_OK) 2581 return (err); 2582 2583 dstab->zone_dataset_name[0] = '\0'; 2584 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2585 pp = cmd->cmd_property_ptr[i]; 2586 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2587 zerr(gettext("A simple value was expected here.")); 2588 saw_error = TRUE; 2589 return (Z_INSUFFICIENT_SPEC); 2590 } 2591 switch (cmd->cmd_prop_name[i]) { 2592 case PT_NAME: 2593 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2594 sizeof (dstab->zone_dataset_name)); 2595 break; 2596 default: 2597 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2598 Z_NO_PROPERTY_TYPE, TRUE); 2599 return (Z_INSUFFICIENT_SPEC); 2600 } 2601 } 2602 if (fill_in_only) 2603 return (Z_OK); 2604 return (zonecfg_lookup_ds(handle, dstab)); 2605 } 2606 2607 static void 2608 remove_aliased_rctl(int type, char *name) 2609 { 2610 int err; 2611 uint64_t tmp; 2612 2613 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) { 2614 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2615 zonecfg_strerror(err)); 2616 saw_error = TRUE; 2617 return; 2618 } 2619 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) { 2620 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 2621 zonecfg_strerror(err)); 2622 saw_error = TRUE; 2623 } else { 2624 need_to_commit = TRUE; 2625 } 2626 } 2627 2628 static boolean_t 2629 prompt_remove_resource(cmd_t *cmd, char *rsrc) 2630 { 2631 int num; 2632 int answer; 2633 int arg; 2634 boolean_t force = B_FALSE; 2635 char prompt[128]; 2636 2637 optind = 0; 2638 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 2639 switch (arg) { 2640 case 'F': 2641 force = B_TRUE; 2642 break; 2643 default: 2644 return (B_FALSE); 2645 } 2646 } 2647 2648 num = zonecfg_num_resources(handle, rsrc); 2649 2650 if (num == 0) { 2651 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY, 2652 TRUE); 2653 return (B_FALSE); 2654 } 2655 if (num > 1 && !force) { 2656 if (!interactive_mode) { 2657 zerr(gettext("There are multiple instances of this " 2658 "resource. Either qualify the resource to\n" 2659 "remove a single instance or use the -F option to " 2660 "remove all instances.")); 2661 saw_error = TRUE; 2662 return (B_FALSE); 2663 } 2664 (void) snprintf(prompt, sizeof (prompt), gettext( 2665 "Are you sure you want to remove ALL '%s' resources"), 2666 rsrc); 2667 answer = ask_yesno(FALSE, prompt); 2668 if (answer == -1) { 2669 zerr(gettext("Resource incomplete.")); 2670 return (B_FALSE); 2671 } 2672 if (answer != 1) 2673 return (B_FALSE); 2674 } 2675 return (B_TRUE); 2676 } 2677 2678 static void 2679 remove_fs(cmd_t *cmd) 2680 { 2681 int err; 2682 2683 /* traditional, qualified fs removal */ 2684 if (cmd->cmd_prop_nv_pairs > 0) { 2685 struct zone_fstab fstab; 2686 2687 if ((err = fill_in_fstab(cmd, &fstab, FALSE)) != Z_OK) { 2688 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2689 return; 2690 } 2691 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 2692 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2693 else 2694 need_to_commit = TRUE; 2695 zonecfg_free_fs_option_list(fstab.zone_fs_options); 2696 return; 2697 } 2698 2699 /* 2700 * unqualified fs removal. remove all fs's but prompt if more 2701 * than one. 2702 */ 2703 if (!prompt_remove_resource(cmd, "fs")) 2704 return; 2705 2706 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK) 2707 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); 2708 else 2709 need_to_commit = TRUE; 2710 } 2711 2712 static void 2713 remove_ipd(cmd_t *cmd) 2714 { 2715 int err; 2716 2717 if (state_atleast(ZONE_STATE_INSTALLED)) { 2718 zerr(gettext("Zone %s already installed; %s %s not allowed."), 2719 zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD)); 2720 return; 2721 } 2722 2723 /* traditional, qualified ipd removal */ 2724 if (cmd->cmd_prop_nv_pairs > 0) { 2725 struct zone_fstab fstab; 2726 2727 if ((err = fill_in_ipdtab(cmd, &fstab, FALSE)) != Z_OK) { 2728 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2729 return; 2730 } 2731 if ((err = zonecfg_delete_ipd(handle, &fstab)) != Z_OK) 2732 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2733 else 2734 need_to_commit = TRUE; 2735 return; 2736 } 2737 2738 /* 2739 * unqualified ipd removal. remove all ipds but prompt if more 2740 * than one. 2741 */ 2742 if (!prompt_remove_resource(cmd, "inherit-pkg-dir")) 2743 return; 2744 2745 if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir")) 2746 != Z_OK) 2747 z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); 2748 else 2749 need_to_commit = TRUE; 2750 } 2751 2752 static void 2753 remove_net(cmd_t *cmd) 2754 { 2755 int err; 2756 2757 /* traditional, qualified net removal */ 2758 if (cmd->cmd_prop_nv_pairs > 0) { 2759 struct zone_nwiftab nwiftab; 2760 2761 if ((err = fill_in_nwiftab(cmd, &nwiftab, FALSE)) != Z_OK) { 2762 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2763 return; 2764 } 2765 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 2766 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2767 else 2768 need_to_commit = TRUE; 2769 return; 2770 } 2771 2772 /* 2773 * unqualified net removal. remove all nets but prompt if more 2774 * than one. 2775 */ 2776 if (!prompt_remove_resource(cmd, "net")) 2777 return; 2778 2779 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK) 2780 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); 2781 else 2782 need_to_commit = TRUE; 2783 } 2784 2785 static void 2786 remove_device(cmd_t *cmd) 2787 { 2788 int err; 2789 2790 /* traditional, qualified device removal */ 2791 if (cmd->cmd_prop_nv_pairs > 0) { 2792 struct zone_devtab devtab; 2793 2794 if ((err = fill_in_devtab(cmd, &devtab, FALSE)) != Z_OK) { 2795 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2796 return; 2797 } 2798 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 2799 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2800 else 2801 need_to_commit = TRUE; 2802 return; 2803 } 2804 2805 /* 2806 * unqualified device removal. remove all devices but prompt if more 2807 * than one. 2808 */ 2809 if (!prompt_remove_resource(cmd, "device")) 2810 return; 2811 2812 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK) 2813 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); 2814 else 2815 need_to_commit = TRUE; 2816 } 2817 2818 static void 2819 remove_attr(cmd_t *cmd) 2820 { 2821 int err; 2822 2823 /* traditional, qualified attr removal */ 2824 if (cmd->cmd_prop_nv_pairs > 0) { 2825 struct zone_attrtab attrtab; 2826 2827 if ((err = fill_in_attrtab(cmd, &attrtab, FALSE)) != Z_OK) { 2828 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2829 return; 2830 } 2831 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 2832 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2833 else 2834 need_to_commit = TRUE; 2835 return; 2836 } 2837 2838 /* 2839 * unqualified attr removal. remove all attrs but prompt if more 2840 * than one. 2841 */ 2842 if (!prompt_remove_resource(cmd, "attr")) 2843 return; 2844 2845 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK) 2846 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); 2847 else 2848 need_to_commit = TRUE; 2849 } 2850 2851 static void 2852 remove_dataset(cmd_t *cmd) 2853 { 2854 int err; 2855 2856 /* traditional, qualified dataset removal */ 2857 if (cmd->cmd_prop_nv_pairs > 0) { 2858 struct zone_dstab dstab; 2859 2860 if ((err = fill_in_dstab(cmd, &dstab, FALSE)) != Z_OK) { 2861 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2862 return; 2863 } 2864 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 2865 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2866 else 2867 need_to_commit = TRUE; 2868 return; 2869 } 2870 2871 /* 2872 * unqualified dataset removal. remove all datasets but prompt if more 2873 * than one. 2874 */ 2875 if (!prompt_remove_resource(cmd, "dataset")) 2876 return; 2877 2878 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK) 2879 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); 2880 else 2881 need_to_commit = TRUE; 2882 } 2883 2884 static void 2885 remove_rctl(cmd_t *cmd) 2886 { 2887 int err; 2888 2889 /* traditional, qualified rctl removal */ 2890 if (cmd->cmd_prop_nv_pairs > 0) { 2891 struct zone_rctltab rctltab; 2892 2893 if ((err = fill_in_rctltab(cmd, &rctltab, FALSE)) != Z_OK) { 2894 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2895 return; 2896 } 2897 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) 2898 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2899 else 2900 need_to_commit = TRUE; 2901 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 2902 return; 2903 } 2904 2905 /* 2906 * unqualified rctl removal. remove all rctls but prompt if more 2907 * than one. 2908 */ 2909 if (!prompt_remove_resource(cmd, "rctl")) 2910 return; 2911 2912 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK) 2913 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); 2914 else 2915 need_to_commit = TRUE; 2916 } 2917 2918 static void 2919 remove_pset() 2920 { 2921 int err; 2922 struct zone_psettab psettab; 2923 2924 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) { 2925 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, TRUE); 2926 return; 2927 } 2928 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 2929 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, TRUE); 2930 else 2931 need_to_commit = TRUE; 2932 } 2933 2934 static void 2935 remove_mcap() 2936 { 2937 int err, res1, res2, res3; 2938 uint64_t tmp; 2939 struct zone_mcaptab mcaptab; 2940 boolean_t revert = B_FALSE; 2941 2942 res1 = zonecfg_lookup_mcap(handle, &mcaptab); 2943 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp); 2944 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp); 2945 2946 /* if none of these exist, there is no resource to remove */ 2947 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 2948 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP), 2949 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 2950 saw_error = TRUE; 2951 return; 2952 } 2953 if (res1 == Z_OK) { 2954 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) { 2955 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); 2956 revert = B_TRUE; 2957 } else { 2958 need_to_commit = TRUE; 2959 } 2960 } 2961 if (res2 == Z_OK) { 2962 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP)) 2963 != Z_OK) { 2964 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); 2965 revert = B_TRUE; 2966 } else { 2967 need_to_commit = TRUE; 2968 } 2969 } 2970 if (res3 == Z_OK) { 2971 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM)) 2972 != Z_OK) { 2973 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); 2974 revert = B_TRUE; 2975 } else { 2976 need_to_commit = TRUE; 2977 } 2978 } 2979 2980 if (revert) 2981 need_to_commit = FALSE; 2982 } 2983 2984 static void 2985 remove_resource(cmd_t *cmd) 2986 { 2987 int type; 2988 int arg; 2989 2990 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2991 long_usage(CMD_REMOVE, TRUE); 2992 return; 2993 } 2994 2995 optind = 0; 2996 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2997 switch (arg) { 2998 case '?': 2999 longer_usage(CMD_REMOVE); 3000 return; 3001 case 'F': 3002 break; 3003 default: 3004 short_usage(CMD_REMOVE); 3005 return; 3006 } 3007 } 3008 3009 if (initialize(TRUE) != Z_OK) 3010 return; 3011 3012 switch (type) { 3013 case RT_FS: 3014 remove_fs(cmd); 3015 return; 3016 case RT_IPD: 3017 remove_ipd(cmd); 3018 return; 3019 case RT_NET: 3020 remove_net(cmd); 3021 return; 3022 case RT_DEVICE: 3023 remove_device(cmd); 3024 return; 3025 case RT_RCTL: 3026 remove_rctl(cmd); 3027 return; 3028 case RT_ATTR: 3029 remove_attr(cmd); 3030 return; 3031 case RT_DATASET: 3032 remove_dataset(cmd); 3033 return; 3034 case RT_DCPU: 3035 remove_pset(); 3036 return; 3037 case RT_MCAP: 3038 remove_mcap(); 3039 return; 3040 default: 3041 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 3042 long_usage(CMD_REMOVE, TRUE); 3043 usage(FALSE, HELP_RESOURCES); 3044 return; 3045 } 3046 } 3047 3048 static void 3049 remove_property(cmd_t *cmd) 3050 { 3051 char *prop_id; 3052 int err, res_type, prop_type; 3053 property_value_ptr_t pp; 3054 struct zone_rctlvaltab *rctlvaltab; 3055 complex_property_ptr_t cx; 3056 3057 res_type = resource_scope; 3058 prop_type = cmd->cmd_prop_name[0]; 3059 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3060 long_usage(CMD_REMOVE, TRUE); 3061 return; 3062 } 3063 3064 if (cmd->cmd_prop_nv_pairs != 1) { 3065 long_usage(CMD_ADD, TRUE); 3066 return; 3067 } 3068 3069 if (initialize(TRUE) != Z_OK) 3070 return; 3071 3072 switch (res_type) { 3073 case RT_FS: 3074 if (prop_type != PT_OPTIONS) { 3075 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3076 TRUE); 3077 long_usage(CMD_REMOVE, TRUE); 3078 usage(FALSE, HELP_PROPS); 3079 return; 3080 } 3081 pp = cmd->cmd_property_ptr[0]; 3082 if (pp->pv_type == PROP_VAL_COMPLEX) { 3083 zerr(gettext("A %s or %s value was expected here."), 3084 pvt_to_str(PROP_VAL_SIMPLE), 3085 pvt_to_str(PROP_VAL_LIST)); 3086 saw_error = TRUE; 3087 return; 3088 } 3089 if (pp->pv_type == PROP_VAL_SIMPLE) { 3090 if (pp->pv_simple == NULL) { 3091 long_usage(CMD_ADD, TRUE); 3092 return; 3093 } 3094 prop_id = pp->pv_simple; 3095 err = zonecfg_remove_fs_option(&in_progress_fstab, 3096 prop_id); 3097 if (err != Z_OK) 3098 zone_perror(pt_to_str(prop_type), err, TRUE); 3099 } else { 3100 list_property_ptr_t list; 3101 3102 for (list = pp->pv_list; list != NULL; 3103 list = list->lp_next) { 3104 prop_id = list->lp_simple; 3105 if (prop_id == NULL) 3106 break; 3107 err = zonecfg_remove_fs_option( 3108 &in_progress_fstab, prop_id); 3109 if (err != Z_OK) 3110 zone_perror(pt_to_str(prop_type), err, 3111 TRUE); 3112 } 3113 } 3114 return; 3115 case RT_RCTL: 3116 if (prop_type != PT_VALUE) { 3117 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3118 TRUE); 3119 long_usage(CMD_REMOVE, TRUE); 3120 usage(FALSE, HELP_PROPS); 3121 return; 3122 } 3123 pp = cmd->cmd_property_ptr[0]; 3124 if (pp->pv_type != PROP_VAL_COMPLEX) { 3125 zerr(gettext("A %s value was expected here."), 3126 pvt_to_str(PROP_VAL_COMPLEX)); 3127 saw_error = TRUE; 3128 return; 3129 } 3130 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 3131 zone_perror(zone, Z_NOMEM, TRUE); 3132 exit(Z_ERR); 3133 } 3134 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) { 3135 switch (cx->cp_type) { 3136 case PT_PRIV: 3137 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 3138 cx->cp_value, 3139 sizeof (rctlvaltab->zone_rctlval_priv)); 3140 break; 3141 case PT_LIMIT: 3142 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 3143 cx->cp_value, 3144 sizeof (rctlvaltab->zone_rctlval_limit)); 3145 break; 3146 case PT_ACTION: 3147 (void) strlcpy(rctlvaltab->zone_rctlval_action, 3148 cx->cp_value, 3149 sizeof (rctlvaltab->zone_rctlval_action)); 3150 break; 3151 default: 3152 zone_perror(pt_to_str(prop_type), 3153 Z_NO_PROPERTY_TYPE, TRUE); 3154 long_usage(CMD_ADD, TRUE); 3155 usage(FALSE, HELP_PROPS); 3156 zonecfg_free_rctl_value_list(rctlvaltab); 3157 return; 3158 } 3159 } 3160 rctlvaltab->zone_rctlval_next = NULL; 3161 err = zonecfg_remove_rctl_value(&in_progress_rctltab, 3162 rctlvaltab); 3163 if (err != Z_OK) 3164 zone_perror(pt_to_str(prop_type), err, TRUE); 3165 zonecfg_free_rctl_value_list(rctlvaltab); 3166 return; 3167 default: 3168 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 3169 long_usage(CMD_REMOVE, TRUE); 3170 usage(FALSE, HELP_RESOURCES); 3171 return; 3172 } 3173 } 3174 3175 void 3176 remove_func(cmd_t *cmd) 3177 { 3178 if (zone_is_read_only(CMD_REMOVE)) 3179 return; 3180 3181 assert(cmd != NULL); 3182 3183 if (global_scope) { 3184 if (gz_invalid_resource(cmd->cmd_res_type)) { 3185 zerr(gettext("%s is not a valid resource for the " 3186 "global zone."), rt_to_str(cmd->cmd_res_type)); 3187 saw_error = TRUE; 3188 return; 3189 } 3190 remove_resource(cmd); 3191 } else { 3192 remove_property(cmd); 3193 } 3194 } 3195 3196 static void 3197 clear_property(cmd_t *cmd) 3198 { 3199 int res_type, prop_type; 3200 3201 res_type = resource_scope; 3202 prop_type = cmd->cmd_res_type; 3203 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3204 long_usage(CMD_CLEAR, TRUE); 3205 return; 3206 } 3207 3208 if (initialize(TRUE) != Z_OK) 3209 return; 3210 3211 switch (res_type) { 3212 case RT_FS: 3213 if (prop_type == PT_RAW) { 3214 in_progress_fstab.zone_fs_raw[0] = '\0'; 3215 need_to_commit = TRUE; 3216 return; 3217 } 3218 break; 3219 case RT_DCPU: 3220 if (prop_type == PT_IMPORTANCE) { 3221 in_progress_psettab.zone_importance[0] = '\0'; 3222 need_to_commit = TRUE; 3223 return; 3224 } 3225 break; 3226 case RT_MCAP: 3227 switch (prop_type) { 3228 case PT_PHYSICAL: 3229 in_progress_mcaptab.zone_physmem_cap[0] = '\0'; 3230 need_to_commit = TRUE; 3231 return; 3232 case PT_SWAP: 3233 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP); 3234 return; 3235 case PT_LOCKED: 3236 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM); 3237 return; 3238 } 3239 break; 3240 default: 3241 break; 3242 } 3243 3244 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, TRUE); 3245 } 3246 3247 static void 3248 clear_global(cmd_t *cmd) 3249 { 3250 int err, type; 3251 3252 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3253 long_usage(CMD_CLEAR, TRUE); 3254 return; 3255 } 3256 3257 if (initialize(TRUE) != Z_OK) 3258 return; 3259 3260 switch (type) { 3261 case PT_ZONENAME: 3262 /* FALLTHRU */ 3263 case PT_ZONEPATH: 3264 /* FALLTHRU */ 3265 case PT_BRAND: 3266 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, TRUE); 3267 return; 3268 case PT_AUTOBOOT: 3269 /* false is default; we'll treat as equivalent to clearing */ 3270 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK) 3271 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, TRUE); 3272 else 3273 need_to_commit = TRUE; 3274 return; 3275 case PT_POOL: 3276 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK) 3277 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, TRUE); 3278 else 3279 need_to_commit = TRUE; 3280 return; 3281 case PT_LIMITPRIV: 3282 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK) 3283 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, TRUE); 3284 else 3285 need_to_commit = TRUE; 3286 return; 3287 case PT_BOOTARGS: 3288 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK) 3289 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, TRUE); 3290 else 3291 need_to_commit = TRUE; 3292 return; 3293 case PT_SCHED: 3294 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK) 3295 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, TRUE); 3296 else 3297 need_to_commit = TRUE; 3298 return; 3299 case PT_IPTYPE: 3300 /* shared is default; we'll treat as equivalent to clearing */ 3301 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK) 3302 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, TRUE); 3303 else 3304 need_to_commit = TRUE; 3305 return; 3306 case PT_MAXLWPS: 3307 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS); 3308 return; 3309 case PT_MAXSHMMEM: 3310 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM); 3311 return; 3312 case PT_MAXSHMIDS: 3313 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS); 3314 return; 3315 case PT_MAXMSGIDS: 3316 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS); 3317 return; 3318 case PT_MAXSEMIDS: 3319 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS); 3320 return; 3321 case PT_SHARES: 3322 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES); 3323 return; 3324 default: 3325 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, TRUE); 3326 long_usage(CMD_CLEAR, TRUE); 3327 usage(FALSE, HELP_PROPS); 3328 return; 3329 } 3330 } 3331 3332 void 3333 clear_func(cmd_t *cmd) 3334 { 3335 if (zone_is_read_only(CMD_CLEAR)) 3336 return; 3337 3338 assert(cmd != NULL); 3339 3340 if (global_scope) { 3341 if (gz_invalid_property(cmd->cmd_res_type)) { 3342 zerr(gettext("%s is not a valid property for the " 3343 "global zone."), pt_to_str(cmd->cmd_res_type)); 3344 saw_error = TRUE; 3345 return; 3346 } 3347 3348 clear_global(cmd); 3349 } else { 3350 clear_property(cmd); 3351 } 3352 } 3353 3354 void 3355 select_func(cmd_t *cmd) 3356 { 3357 int type, err, res; 3358 uint64_t limit; 3359 3360 if (zone_is_read_only(CMD_SELECT)) 3361 return; 3362 3363 assert(cmd != NULL); 3364 3365 if (global_scope) { 3366 global_scope = FALSE; 3367 resource_scope = cmd->cmd_res_type; 3368 end_op = CMD_SELECT; 3369 } else { 3370 scope_usage(CMD_SELECT); 3371 return; 3372 } 3373 3374 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3375 long_usage(CMD_SELECT, TRUE); 3376 return; 3377 } 3378 3379 if (initialize(TRUE) != Z_OK) 3380 return; 3381 3382 switch (type) { 3383 case RT_FS: 3384 if ((err = fill_in_fstab(cmd, &old_fstab, FALSE)) != Z_OK) { 3385 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, TRUE); 3386 global_scope = TRUE; 3387 } 3388 bcopy(&old_fstab, &in_progress_fstab, 3389 sizeof (struct zone_fstab)); 3390 return; 3391 case RT_IPD: 3392 if (state_atleast(ZONE_STATE_INCOMPLETE)) { 3393 zerr(gettext("Zone %s not in %s state; %s %s not " 3394 "allowed."), zone, 3395 zone_state_str(ZONE_STATE_CONFIGURED), 3396 cmd_to_str(CMD_SELECT), rt_to_str(RT_IPD)); 3397 global_scope = TRUE; 3398 end_op = -1; 3399 return; 3400 } 3401 if ((err = fill_in_ipdtab(cmd, &old_ipdtab, FALSE)) != Z_OK) { 3402 z_cmd_rt_perror(CMD_SELECT, RT_IPD, err, TRUE); 3403 global_scope = TRUE; 3404 } 3405 bcopy(&old_ipdtab, &in_progress_ipdtab, 3406 sizeof (struct zone_fstab)); 3407 return; 3408 case RT_NET: 3409 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, FALSE)) != Z_OK) { 3410 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, TRUE); 3411 global_scope = TRUE; 3412 } 3413 bcopy(&old_nwiftab, &in_progress_nwiftab, 3414 sizeof (struct zone_nwiftab)); 3415 return; 3416 case RT_DEVICE: 3417 if ((err = fill_in_devtab(cmd, &old_devtab, FALSE)) != Z_OK) { 3418 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, TRUE); 3419 global_scope = TRUE; 3420 } 3421 bcopy(&old_devtab, &in_progress_devtab, 3422 sizeof (struct zone_devtab)); 3423 return; 3424 case RT_RCTL: 3425 if ((err = fill_in_rctltab(cmd, &old_rctltab, FALSE)) != Z_OK) { 3426 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, TRUE); 3427 global_scope = TRUE; 3428 } 3429 bcopy(&old_rctltab, &in_progress_rctltab, 3430 sizeof (struct zone_rctltab)); 3431 return; 3432 case RT_ATTR: 3433 if ((err = fill_in_attrtab(cmd, &old_attrtab, FALSE)) != Z_OK) { 3434 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, TRUE); 3435 global_scope = TRUE; 3436 } 3437 bcopy(&old_attrtab, &in_progress_attrtab, 3438 sizeof (struct zone_attrtab)); 3439 return; 3440 case RT_DATASET: 3441 if ((err = fill_in_dstab(cmd, &old_dstab, FALSE)) != Z_OK) { 3442 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, TRUE); 3443 global_scope = TRUE; 3444 } 3445 bcopy(&old_dstab, &in_progress_dstab, 3446 sizeof (struct zone_dstab)); 3447 return; 3448 case RT_DCPU: 3449 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) { 3450 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, TRUE); 3451 global_scope = TRUE; 3452 } 3453 bcopy(&old_psettab, &in_progress_psettab, 3454 sizeof (struct zone_psettab)); 3455 return; 3456 case RT_MCAP: 3457 /* if none of these exist, there is no resource to select */ 3458 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK && 3459 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit) 3460 != Z_OK && 3461 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit) 3462 != Z_OK) { 3463 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE, 3464 TRUE); 3465 global_scope = TRUE; 3466 } 3467 if (res == Z_OK) 3468 bcopy(&old_mcaptab, &in_progress_mcaptab, 3469 sizeof (struct zone_mcaptab)); 3470 else 3471 bzero(&in_progress_mcaptab, 3472 sizeof (in_progress_mcaptab)); 3473 return; 3474 default: 3475 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); 3476 long_usage(CMD_SELECT, TRUE); 3477 usage(FALSE, HELP_RESOURCES); 3478 return; 3479 } 3480 } 3481 3482 /* 3483 * Network "addresses" can be one of the following forms: 3484 * <IPv4 address> 3485 * <IPv4 address>/<prefix length> 3486 * <IPv6 address>/<prefix length> 3487 * <host name> 3488 * <host name>/<prefix length> 3489 * In other words, the "/" followed by a prefix length is allowed but not 3490 * required for IPv4 addresses and host names, and required for IPv6 addresses. 3491 * If a prefix length is given, it must be in the allowable range: 0 to 32 for 3492 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses. 3493 * Host names must start with an alpha-numeric character, and all subsequent 3494 * characters must be either alpha-numeric or "-". 3495 */ 3496 3497 static int 3498 validate_net_address_syntax(char *address) 3499 { 3500 char *slashp, part1[MAXHOSTNAMELEN]; 3501 struct in6_addr in6; 3502 struct in_addr in4; 3503 int prefixlen, i; 3504 3505 /* 3506 * Copy the part before any '/' into part1 or copy the whole 3507 * thing if there is no '/'. 3508 */ 3509 if ((slashp = strchr(address, '/')) != NULL) { 3510 *slashp = '\0'; 3511 (void) strlcpy(part1, address, sizeof (part1)); 3512 *slashp = '/'; 3513 prefixlen = atoi(++slashp); 3514 } else { 3515 (void) strlcpy(part1, address, sizeof (part1)); 3516 } 3517 3518 if (inet_pton(AF_INET6, part1, &in6) == 1) { 3519 if (slashp == NULL) { 3520 zerr(gettext("%s: IPv6 addresses " 3521 "require /prefix-length suffix."), address); 3522 return (Z_ERR); 3523 } 3524 if (prefixlen < 0 || prefixlen > 128) { 3525 zerr(gettext("%s: IPv6 address " 3526 "prefix lengths must be 0 - 128."), address); 3527 return (Z_ERR); 3528 } 3529 return (Z_OK); 3530 } 3531 3532 /* At this point, any /prefix must be for IPv4. */ 3533 if (slashp != NULL) { 3534 if (prefixlen < 0 || prefixlen > 32) { 3535 zerr(gettext("%s: IPv4 address " 3536 "prefix lengths must be 0 - 32."), address); 3537 return (Z_ERR); 3538 } 3539 } 3540 if (inet_pton(AF_INET, part1, &in4) == 1) 3541 return (Z_OK); 3542 3543 /* address may also be a host name */ 3544 if (!isalnum(part1[0])) { 3545 zerr(gettext("%s: bogus host name or network address syntax"), 3546 part1); 3547 saw_error = TRUE; 3548 usage(FALSE, HELP_NETADDR); 3549 return (Z_ERR); 3550 } 3551 for (i = 1; part1[i]; i++) 3552 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') { 3553 zerr(gettext("%s: bogus host name or " 3554 "network address syntax"), part1); 3555 saw_error = TRUE; 3556 usage(FALSE, HELP_NETADDR); 3557 return (Z_ERR); 3558 } 3559 return (Z_OK); 3560 } 3561 3562 static int 3563 validate_net_physical_syntax(char *ifname) 3564 { 3565 if (strchr(ifname, ':') == NULL) 3566 return (Z_OK); 3567 zerr(gettext("%s: physical interface name required; " 3568 "logical interface name not allowed"), ifname); 3569 return (Z_ERR); 3570 } 3571 3572 static boolean_t 3573 valid_fs_type(const char *type) 3574 { 3575 /* 3576 * Is this a valid path component? 3577 */ 3578 if (strlen(type) + 1 > MAXNAMELEN) 3579 return (B_FALSE); 3580 /* 3581 * Make sure a bad value for "type" doesn't make 3582 * /usr/lib/fs/<type>/mount turn into something else. 3583 */ 3584 if (strchr(type, '/') != NULL || type[0] == '\0' || 3585 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 3586 return (B_FALSE); 3587 /* 3588 * More detailed verification happens later by zoneadm(1m). 3589 */ 3590 return (B_TRUE); 3591 } 3592 3593 static boolean_t 3594 allow_exclusive() 3595 { 3596 brand_handle_t bh; 3597 char brand[MAXNAMELEN]; 3598 boolean_t ret; 3599 3600 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 3601 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 3602 return (B_FALSE); 3603 } 3604 if ((bh = brand_open(brand)) == NULL) { 3605 zerr("%s: %s\n", zone, gettext("unknown brand.")); 3606 return (B_FALSE); 3607 } 3608 ret = brand_allow_exclusive_ip(bh); 3609 brand_close(bh); 3610 if (!ret) 3611 zerr(gettext("%s cannot be '%s' when %s is '%s'."), 3612 pt_to_str(PT_IPTYPE), "exclusive", 3613 pt_to_str(PT_BRAND), brand); 3614 return (ret); 3615 } 3616 3617 static void 3618 set_aliased_rctl(char *alias, int prop_type, char *s) 3619 { 3620 uint64_t limit; 3621 int err; 3622 char tmp[128]; 3623 3624 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0) 3625 zerr(gettext("WARNING: Setting a global zone resource " 3626 "control too low could deny\nservice " 3627 "to even the root user; " 3628 "this could render the system impossible\n" 3629 "to administer. Please use caution.")); 3630 3631 /* convert memory based properties */ 3632 if (prop_type == PT_MAXSHMMEM) { 3633 if (!zonecfg_valid_memlimit(s, &limit)) { 3634 zerr(gettext("A non-negative number with a required " 3635 "scale suffix (K, M, G or T) was expected\nhere.")); 3636 saw_error = TRUE; 3637 return; 3638 } 3639 3640 (void) snprintf(tmp, sizeof (tmp), "%llu", limit); 3641 s = tmp; 3642 } 3643 3644 if (!zonecfg_aliased_rctl_ok(handle, alias)) { 3645 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, FALSE); 3646 saw_error = TRUE; 3647 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) { 3648 zerr(gettext("%s property is out of range."), 3649 pt_to_str(prop_type)); 3650 saw_error = TRUE; 3651 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit)) 3652 != Z_OK) { 3653 zone_perror(zone, err, TRUE); 3654 saw_error = TRUE; 3655 } else { 3656 need_to_commit = TRUE; 3657 } 3658 } 3659 3660 void 3661 set_func(cmd_t *cmd) 3662 { 3663 char *prop_id; 3664 int arg, err, res_type, prop_type; 3665 property_value_ptr_t pp; 3666 boolean_t autoboot; 3667 zone_iptype_t iptype; 3668 boolean_t force_set = FALSE; 3669 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap); 3670 uint64_t mem_cap, mem_limit; 3671 struct zone_psettab tmp_psettab; 3672 3673 if (zone_is_read_only(CMD_SET)) 3674 return; 3675 3676 assert(cmd != NULL); 3677 3678 optind = opterr = 0; 3679 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 3680 switch (arg) { 3681 case 'F': 3682 force_set = TRUE; 3683 break; 3684 default: 3685 if (optopt == '?') 3686 longer_usage(CMD_SET); 3687 else 3688 short_usage(CMD_SET); 3689 return; 3690 } 3691 } 3692 3693 prop_type = cmd->cmd_prop_name[0]; 3694 if (global_scope) { 3695 if (gz_invalid_property(prop_type)) { 3696 zerr(gettext("%s is not a valid property for the " 3697 "global zone."), pt_to_str(prop_type)); 3698 saw_error = TRUE; 3699 return; 3700 } 3701 3702 if (prop_type == PT_ZONENAME) { 3703 res_type = RT_ZONENAME; 3704 } else if (prop_type == PT_ZONEPATH) { 3705 res_type = RT_ZONEPATH; 3706 } else if (prop_type == PT_AUTOBOOT) { 3707 res_type = RT_AUTOBOOT; 3708 } else if (prop_type == PT_BRAND) { 3709 res_type = RT_BRAND; 3710 } else if (prop_type == PT_POOL) { 3711 res_type = RT_POOL; 3712 } else if (prop_type == PT_LIMITPRIV) { 3713 res_type = RT_LIMITPRIV; 3714 } else if (prop_type == PT_BOOTARGS) { 3715 res_type = RT_BOOTARGS; 3716 } else if (prop_type == PT_SCHED) { 3717 res_type = RT_SCHED; 3718 } else if (prop_type == PT_IPTYPE) { 3719 res_type = RT_IPTYPE; 3720 } else if (prop_type == PT_MAXLWPS) { 3721 res_type = RT_MAXLWPS; 3722 } else if (prop_type == PT_MAXSHMMEM) { 3723 res_type = RT_MAXSHMMEM; 3724 } else if (prop_type == PT_MAXSHMIDS) { 3725 res_type = RT_MAXSHMIDS; 3726 } else if (prop_type == PT_MAXMSGIDS) { 3727 res_type = RT_MAXMSGIDS; 3728 } else if (prop_type == PT_MAXSEMIDS) { 3729 res_type = RT_MAXSEMIDS; 3730 } else if (prop_type == PT_SHARES) { 3731 res_type = RT_SHARES; 3732 } else { 3733 zerr(gettext("Cannot set a resource-specific property " 3734 "from the global scope.")); 3735 saw_error = TRUE; 3736 return; 3737 } 3738 } else { 3739 res_type = resource_scope; 3740 } 3741 3742 if (force_set) { 3743 if (res_type != RT_ZONEPATH) { 3744 zerr(gettext("Only zonepath setting can be forced.")); 3745 saw_error = TRUE; 3746 return; 3747 } 3748 if (!zonecfg_in_alt_root()) { 3749 zerr(gettext("Zonepath is changeable only in an " 3750 "alternate root.")); 3751 saw_error = TRUE; 3752 return; 3753 } 3754 } 3755 3756 pp = cmd->cmd_property_ptr[0]; 3757 /* 3758 * A nasty expression but not that complicated: 3759 * 1. fs options are simple or list (tested below) 3760 * 2. rctl value's are complex or list (tested below) 3761 * Anything else should be simple. 3762 */ 3763 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 3764 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 3765 (pp->pv_type != PROP_VAL_SIMPLE || 3766 (prop_id = pp->pv_simple) == NULL)) { 3767 zerr(gettext("A %s value was expected here."), 3768 pvt_to_str(PROP_VAL_SIMPLE)); 3769 saw_error = TRUE; 3770 return; 3771 } 3772 if (prop_type == PT_UNKNOWN) { 3773 long_usage(CMD_SET, TRUE); 3774 return; 3775 } 3776 3777 /* 3778 * Special case: the user can change the zone name prior to 'create'; 3779 * if the zone already exists, we fall through letting initialize() 3780 * and the rest of the logic run. 3781 */ 3782 if (res_type == RT_ZONENAME && got_handle == FALSE && 3783 !state_atleast(ZONE_STATE_CONFIGURED)) { 3784 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) { 3785 zone_perror(prop_id, err, TRUE); 3786 usage(FALSE, HELP_SYNTAX); 3787 return; 3788 } 3789 (void) strlcpy(zone, prop_id, sizeof (zone)); 3790 return; 3791 } 3792 3793 if (initialize(TRUE) != Z_OK) 3794 return; 3795 3796 switch (res_type) { 3797 case RT_ZONENAME: 3798 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 3799 /* 3800 * Use prop_id instead of 'zone' here, since we're 3801 * reporting a problem about the *new* zonename. 3802 */ 3803 zone_perror(prop_id, err, TRUE); 3804 usage(FALSE, HELP_SYNTAX); 3805 } else { 3806 need_to_commit = TRUE; 3807 (void) strlcpy(zone, prop_id, sizeof (zone)); 3808 } 3809 return; 3810 case RT_ZONEPATH: 3811 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) { 3812 zerr(gettext("Zone %s already installed; %s %s not " 3813 "allowed."), zone, cmd_to_str(CMD_SET), 3814 rt_to_str(RT_ZONEPATH)); 3815 return; 3816 } 3817 if (validate_zonepath_syntax(prop_id) != Z_OK) { 3818 saw_error = TRUE; 3819 return; 3820 } 3821 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 3822 zone_perror(zone, err, TRUE); 3823 else 3824 need_to_commit = TRUE; 3825 return; 3826 case RT_BRAND: 3827 if (state_atleast(ZONE_STATE_INSTALLED)) { 3828 zerr(gettext("Zone %s already installed; %s %s not " 3829 "allowed."), zone, cmd_to_str(CMD_SET), 3830 rt_to_str(RT_BRAND)); 3831 return; 3832 } 3833 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK) 3834 zone_perror(zone, err, TRUE); 3835 else 3836 need_to_commit = TRUE; 3837 return; 3838 case RT_AUTOBOOT: 3839 if (strcmp(prop_id, "true") == 0) { 3840 autoboot = B_TRUE; 3841 } else if (strcmp(prop_id, "false") == 0) { 3842 autoboot = B_FALSE; 3843 } else { 3844 zerr(gettext("%s value must be '%s' or '%s'."), 3845 pt_to_str(PT_AUTOBOOT), "true", "false"); 3846 saw_error = TRUE; 3847 return; 3848 } 3849 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 3850 zone_perror(zone, err, TRUE); 3851 else 3852 need_to_commit = TRUE; 3853 return; 3854 case RT_POOL: 3855 /* don't allow use of the reserved temporary pool names */ 3856 if (strncmp("SUNW", prop_id, 4) == 0) { 3857 zerr(gettext("pool names starting with SUNW are " 3858 "reserved.")); 3859 saw_error = TRUE; 3860 return; 3861 } 3862 3863 /* can't set pool if dedicated-cpu exists */ 3864 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 3865 zerr(gettext("The %s resource already exists. " 3866 "A persistent pool is incompatible\nwith the %s " 3867 "resource."), rt_to_str(RT_DCPU), 3868 rt_to_str(RT_DCPU)); 3869 saw_error = TRUE; 3870 return; 3871 } 3872 3873 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 3874 zone_perror(zone, err, TRUE); 3875 else 3876 need_to_commit = TRUE; 3877 return; 3878 case RT_LIMITPRIV: 3879 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK) 3880 zone_perror(zone, err, TRUE); 3881 else 3882 need_to_commit = TRUE; 3883 return; 3884 case RT_BOOTARGS: 3885 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK) 3886 zone_perror(zone, err, TRUE); 3887 else 3888 need_to_commit = TRUE; 3889 return; 3890 case RT_SCHED: 3891 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK) 3892 zone_perror(zone, err, TRUE); 3893 else 3894 need_to_commit = TRUE; 3895 return; 3896 case RT_IPTYPE: 3897 if (strcmp(prop_id, "shared") == 0) { 3898 iptype = ZS_SHARED; 3899 } else if (strcmp(prop_id, "exclusive") == 0) { 3900 iptype = ZS_EXCLUSIVE; 3901 } else { 3902 zerr(gettext("%s value must be '%s' or '%s'."), 3903 pt_to_str(PT_IPTYPE), "shared", "exclusive"); 3904 saw_error = TRUE; 3905 return; 3906 } 3907 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) { 3908 saw_error = TRUE; 3909 return; 3910 } 3911 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK) 3912 zone_perror(zone, err, TRUE); 3913 else 3914 need_to_commit = TRUE; 3915 return; 3916 case RT_MAXLWPS: 3917 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id); 3918 return; 3919 case RT_MAXSHMMEM: 3920 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id); 3921 return; 3922 case RT_MAXSHMIDS: 3923 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id); 3924 return; 3925 case RT_MAXMSGIDS: 3926 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id); 3927 return; 3928 case RT_MAXSEMIDS: 3929 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id); 3930 return; 3931 case RT_SHARES: 3932 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id); 3933 return; 3934 case RT_FS: 3935 switch (prop_type) { 3936 case PT_DIR: 3937 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 3938 sizeof (in_progress_fstab.zone_fs_dir)); 3939 return; 3940 case PT_SPECIAL: 3941 (void) strlcpy(in_progress_fstab.zone_fs_special, 3942 prop_id, 3943 sizeof (in_progress_fstab.zone_fs_special)); 3944 return; 3945 case PT_RAW: 3946 (void) strlcpy(in_progress_fstab.zone_fs_raw, 3947 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 3948 return; 3949 case PT_TYPE: 3950 if (!valid_fs_type(prop_id)) { 3951 zerr(gettext("\"%s\" is not a valid %s."), 3952 prop_id, pt_to_str(PT_TYPE)); 3953 saw_error = TRUE; 3954 return; 3955 } 3956 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 3957 sizeof (in_progress_fstab.zone_fs_type)); 3958 return; 3959 case PT_OPTIONS: 3960 if (pp->pv_type != PROP_VAL_SIMPLE && 3961 pp->pv_type != PROP_VAL_LIST) { 3962 zerr(gettext("A %s or %s value was expected " 3963 "here."), pvt_to_str(PROP_VAL_SIMPLE), 3964 pvt_to_str(PROP_VAL_LIST)); 3965 saw_error = TRUE; 3966 return; 3967 } 3968 zonecfg_free_fs_option_list( 3969 in_progress_fstab.zone_fs_options); 3970 in_progress_fstab.zone_fs_options = NULL; 3971 if (!(pp->pv_type == PROP_VAL_LIST && 3972 pp->pv_list == NULL)) 3973 add_property(cmd); 3974 return; 3975 default: 3976 break; 3977 } 3978 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 3979 long_usage(CMD_SET, TRUE); 3980 usage(FALSE, HELP_PROPS); 3981 return; 3982 case RT_IPD: 3983 switch (prop_type) { 3984 case PT_DIR: 3985 (void) strlcpy(in_progress_ipdtab.zone_fs_dir, prop_id, 3986 sizeof (in_progress_ipdtab.zone_fs_dir)); 3987 return; 3988 default: 3989 break; 3990 } 3991 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 3992 long_usage(CMD_SET, TRUE); 3993 usage(FALSE, HELP_PROPS); 3994 return; 3995 case RT_NET: 3996 switch (prop_type) { 3997 case PT_ADDRESS: 3998 if (validate_net_address_syntax(prop_id) != Z_OK) { 3999 saw_error = TRUE; 4000 return; 4001 } 4002 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, 4003 prop_id, 4004 sizeof (in_progress_nwiftab.zone_nwif_address)); 4005 break; 4006 case PT_PHYSICAL: 4007 if (validate_net_physical_syntax(prop_id) != Z_OK) { 4008 saw_error = TRUE; 4009 return; 4010 } 4011 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 4012 prop_id, 4013 sizeof (in_progress_nwiftab.zone_nwif_physical)); 4014 break; 4015 default: 4016 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4017 TRUE); 4018 long_usage(CMD_SET, TRUE); 4019 usage(FALSE, HELP_PROPS); 4020 return; 4021 } 4022 return; 4023 case RT_DEVICE: 4024 switch (prop_type) { 4025 case PT_MATCH: 4026 (void) strlcpy(in_progress_devtab.zone_dev_match, 4027 prop_id, 4028 sizeof (in_progress_devtab.zone_dev_match)); 4029 break; 4030 default: 4031 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4032 TRUE); 4033 long_usage(CMD_SET, TRUE); 4034 usage(FALSE, HELP_PROPS); 4035 return; 4036 } 4037 return; 4038 case RT_RCTL: 4039 switch (prop_type) { 4040 case PT_NAME: 4041 if (!zonecfg_valid_rctlname(prop_id)) { 4042 zerr(gettext("'%s' is not a valid zone %s " 4043 "name."), prop_id, rt_to_str(RT_RCTL)); 4044 return; 4045 } 4046 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 4047 prop_id, 4048 sizeof (in_progress_rctltab.zone_rctl_name)); 4049 break; 4050 case PT_VALUE: 4051 if (pp->pv_type != PROP_VAL_COMPLEX && 4052 pp->pv_type != PROP_VAL_LIST) { 4053 zerr(gettext("A %s or %s value was expected " 4054 "here."), pvt_to_str(PROP_VAL_COMPLEX), 4055 pvt_to_str(PROP_VAL_LIST)); 4056 saw_error = TRUE; 4057 return; 4058 } 4059 zonecfg_free_rctl_value_list( 4060 in_progress_rctltab.zone_rctl_valptr); 4061 in_progress_rctltab.zone_rctl_valptr = NULL; 4062 if (!(pp->pv_type == PROP_VAL_LIST && 4063 pp->pv_list == NULL)) 4064 add_property(cmd); 4065 break; 4066 default: 4067 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4068 TRUE); 4069 long_usage(CMD_SET, TRUE); 4070 usage(FALSE, HELP_PROPS); 4071 return; 4072 } 4073 return; 4074 case RT_ATTR: 4075 switch (prop_type) { 4076 case PT_NAME: 4077 (void) strlcpy(in_progress_attrtab.zone_attr_name, 4078 prop_id, 4079 sizeof (in_progress_attrtab.zone_attr_name)); 4080 break; 4081 case PT_TYPE: 4082 (void) strlcpy(in_progress_attrtab.zone_attr_type, 4083 prop_id, 4084 sizeof (in_progress_attrtab.zone_attr_type)); 4085 break; 4086 case PT_VALUE: 4087 (void) strlcpy(in_progress_attrtab.zone_attr_value, 4088 prop_id, 4089 sizeof (in_progress_attrtab.zone_attr_value)); 4090 break; 4091 default: 4092 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4093 TRUE); 4094 long_usage(CMD_SET, TRUE); 4095 usage(FALSE, HELP_PROPS); 4096 return; 4097 } 4098 return; 4099 case RT_DATASET: 4100 switch (prop_type) { 4101 case PT_NAME: 4102 (void) strlcpy(in_progress_dstab.zone_dataset_name, 4103 prop_id, 4104 sizeof (in_progress_dstab.zone_dataset_name)); 4105 return; 4106 default: 4107 break; 4108 } 4109 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 4110 long_usage(CMD_SET, TRUE); 4111 usage(FALSE, HELP_PROPS); 4112 return; 4113 case RT_DCPU: 4114 switch (prop_type) { 4115 char *lowp, *highp; 4116 4117 case PT_NCPUS: 4118 lowp = prop_id; 4119 if ((highp = strchr(prop_id, '-')) != NULL) 4120 *highp++ = '\0'; 4121 else 4122 highp = lowp; 4123 4124 /* Make sure the input makes sense. */ 4125 if (!zonecfg_valid_ncpus(lowp, highp)) { 4126 zerr(gettext("%s property is out of range."), 4127 pt_to_str(PT_NCPUS)); 4128 saw_error = TRUE; 4129 return; 4130 } 4131 4132 (void) strlcpy( 4133 in_progress_psettab.zone_ncpu_min, lowp, 4134 sizeof (in_progress_psettab.zone_ncpu_min)); 4135 (void) strlcpy( 4136 in_progress_psettab.zone_ncpu_max, highp, 4137 sizeof (in_progress_psettab.zone_ncpu_max)); 4138 return; 4139 case PT_IMPORTANCE: 4140 /* Make sure the value makes sense. */ 4141 if (!zonecfg_valid_importance(prop_id)) { 4142 zerr(gettext("%s property is out of range."), 4143 pt_to_str(PT_IMPORTANCE)); 4144 saw_error = TRUE; 4145 return; 4146 } 4147 4148 (void) strlcpy(in_progress_psettab.zone_importance, 4149 prop_id, 4150 sizeof (in_progress_psettab.zone_importance)); 4151 return; 4152 default: 4153 break; 4154 } 4155 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); 4156 long_usage(CMD_SET, TRUE); 4157 usage(FALSE, HELP_PROPS); 4158 return; 4159 case RT_MCAP: 4160 switch (prop_type) { 4161 case PT_PHYSICAL: 4162 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4163 zerr(gettext("A positive number with a " 4164 "required scale suffix (K, M, G or T) was " 4165 "expected here.")); 4166 saw_error = TRUE; 4167 } else if (mem_cap < ONE_MB) { 4168 zerr(gettext("%s value is too small. It must " 4169 "be at least 1M."), pt_to_str(PT_PHYSICAL)); 4170 saw_error = TRUE; 4171 } else { 4172 snprintf(in_progress_mcaptab.zone_physmem_cap, 4173 physmem_size, "%llu", mem_cap); 4174 } 4175 break; 4176 case PT_SWAP: 4177 /* 4178 * We have to check if an rctl is allowed here since 4179 * there might already be a rctl defined that blocks 4180 * the alias. 4181 */ 4182 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) { 4183 zone_perror(pt_to_str(PT_MAXSWAP), 4184 Z_ALIAS_DISALLOW, FALSE); 4185 saw_error = TRUE; 4186 return; 4187 } 4188 4189 if (global_zone) 4190 mem_limit = ONE_MB * 100; 4191 else 4192 mem_limit = ONE_MB * 50; 4193 4194 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4195 zerr(gettext("A positive number with a " 4196 "required scale suffix (K, M, G or T) was " 4197 "expected here.")); 4198 saw_error = TRUE; 4199 } else if (mem_cap < mem_limit) { 4200 char buf[128]; 4201 4202 (void) snprintf(buf, sizeof (buf), "%llu", 4203 mem_limit); 4204 bytes_to_units(buf, buf, sizeof (buf)); 4205 zerr(gettext("%s value is too small. It must " 4206 "be at least %s."), pt_to_str(PT_SWAP), 4207 buf); 4208 saw_error = TRUE; 4209 } else { 4210 if ((err = zonecfg_set_aliased_rctl(handle, 4211 ALIAS_MAXSWAP, mem_cap)) != Z_OK) 4212 zone_perror(zone, err, TRUE); 4213 else 4214 need_to_commit = TRUE; 4215 } 4216 break; 4217 case PT_LOCKED: 4218 /* 4219 * We have to check if an rctl is allowed here since 4220 * there might already be a rctl defined that blocks 4221 * the alias. 4222 */ 4223 if (!zonecfg_aliased_rctl_ok(handle, 4224 ALIAS_MAXLOCKEDMEM)) { 4225 zone_perror(pt_to_str(PT_LOCKED), 4226 Z_ALIAS_DISALLOW, FALSE); 4227 saw_error = TRUE; 4228 return; 4229 } 4230 4231 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4232 zerr(gettext("A non-negative number with a " 4233 "required scale suffix (K, M, G or T) was " 4234 "expected\nhere.")); 4235 saw_error = TRUE; 4236 } else { 4237 if ((err = zonecfg_set_aliased_rctl(handle, 4238 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK) 4239 zone_perror(zone, err, TRUE); 4240 else 4241 need_to_commit = TRUE; 4242 } 4243 break; 4244 default: 4245 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4246 TRUE); 4247 long_usage(CMD_SET, TRUE); 4248 usage(FALSE, HELP_PROPS); 4249 return; 4250 } 4251 4252 return; 4253 default: 4254 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); 4255 long_usage(CMD_SET, TRUE); 4256 usage(FALSE, HELP_RESOURCES); 4257 return; 4258 } 4259 } 4260 4261 static void 4262 output_prop(FILE *fp, int pnum, char *pval, bool print_notspec) 4263 { 4264 char *qstr; 4265 4266 if (*pval != '\0') { 4267 qstr = quoteit(pval); 4268 if (pnum == PT_SWAP || pnum == PT_LOCKED) 4269 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum), 4270 qstr); 4271 else 4272 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 4273 free(qstr); 4274 } else if (print_notspec) 4275 (void) fprintf(fp, gettext("\t%s not specified\n"), 4276 pt_to_str(pnum)); 4277 } 4278 4279 static void 4280 info_zonename(zone_dochandle_t handle, FILE *fp) 4281 { 4282 char zonename[ZONENAME_MAX]; 4283 4284 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 4285 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 4286 zonename); 4287 else 4288 (void) fprintf(fp, gettext("%s not specified\n"), 4289 pt_to_str(PT_ZONENAME)); 4290 } 4291 4292 static void 4293 info_zonepath(zone_dochandle_t handle, FILE *fp) 4294 { 4295 char zonepath[MAXPATHLEN]; 4296 4297 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 4298 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 4299 zonepath); 4300 else { 4301 (void) fprintf(fp, gettext("%s not specified\n"), 4302 pt_to_str(PT_ZONEPATH)); 4303 } 4304 } 4305 4306 static void 4307 info_brand(zone_dochandle_t handle, FILE *fp) 4308 { 4309 char brand[MAXNAMELEN]; 4310 4311 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK) 4312 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND), 4313 brand); 4314 else 4315 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND), 4316 gettext("not specified")); 4317 } 4318 4319 static void 4320 info_autoboot(zone_dochandle_t handle, FILE *fp) 4321 { 4322 boolean_t autoboot; 4323 int err; 4324 4325 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 4326 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 4327 autoboot ? "true" : "false"); 4328 else 4329 zone_perror(zone, err, TRUE); 4330 } 4331 4332 static void 4333 info_pool(zone_dochandle_t handle, FILE *fp) 4334 { 4335 char pool[MAXNAMELEN]; 4336 int err; 4337 4338 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 4339 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 4340 else 4341 zone_perror(zone, err, TRUE); 4342 } 4343 4344 static void 4345 info_limitpriv(zone_dochandle_t handle, FILE *fp) 4346 { 4347 char *limitpriv; 4348 int err; 4349 4350 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) { 4351 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV), 4352 limitpriv); 4353 free(limitpriv); 4354 } else { 4355 zone_perror(zone, err, TRUE); 4356 } 4357 } 4358 4359 static void 4360 info_bootargs(zone_dochandle_t handle, FILE *fp) 4361 { 4362 char bootargs[BOOTARGS_MAX]; 4363 int err; 4364 4365 if ((err = zonecfg_get_bootargs(handle, bootargs, 4366 sizeof (bootargs))) == Z_OK) { 4367 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS), 4368 bootargs); 4369 } else { 4370 zone_perror(zone, err, TRUE); 4371 } 4372 } 4373 4374 static void 4375 info_sched(zone_dochandle_t handle, FILE *fp) 4376 { 4377 char sched[MAXNAMELEN]; 4378 int err; 4379 4380 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched))) 4381 == Z_OK) { 4382 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched); 4383 } else { 4384 zone_perror(zone, err, TRUE); 4385 } 4386 } 4387 4388 static void 4389 info_iptype(zone_dochandle_t handle, FILE *fp) 4390 { 4391 zone_iptype_t iptype; 4392 int err; 4393 4394 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) { 4395 switch (iptype) { 4396 case ZS_SHARED: 4397 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4398 "shared"); 4399 break; 4400 case ZS_EXCLUSIVE: 4401 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 4402 "exclusive"); 4403 break; 4404 } 4405 } else { 4406 zone_perror(zone, err, TRUE); 4407 } 4408 } 4409 4410 static void 4411 output_fs(FILE *fp, struct zone_fstab *fstab) 4412 { 4413 zone_fsopt_t *this; 4414 4415 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 4416 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 4417 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 4418 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 4419 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 4420 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 4421 for (this = fstab->zone_fs_options; this != NULL; 4422 this = this->zone_fsopt_next) { 4423 if (strchr(this->zone_fsopt_opt, '=')) 4424 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 4425 else 4426 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 4427 if (this->zone_fsopt_next != NULL) 4428 (void) fprintf(fp, ","); 4429 } 4430 (void) fprintf(fp, "]\n"); 4431 } 4432 4433 static void 4434 output_ipd(FILE *fp, struct zone_fstab *ipdtab) 4435 { 4436 (void) fprintf(fp, "%s:\n", rt_to_str(RT_IPD)); 4437 output_prop(fp, PT_DIR, ipdtab->zone_fs_dir, B_TRUE); 4438 } 4439 4440 static void 4441 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4442 { 4443 struct zone_fstab lookup, user; 4444 bool output = FALSE; 4445 4446 if (zonecfg_setfsent(handle) != Z_OK) 4447 return; 4448 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 4449 if (cmd->cmd_prop_nv_pairs == 0) { 4450 output_fs(fp, &lookup); 4451 goto loopend; 4452 } 4453 if (fill_in_fstab(cmd, &user, TRUE) != Z_OK) 4454 goto loopend; 4455 if (strlen(user.zone_fs_dir) > 0 && 4456 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 4457 goto loopend; /* no match */ 4458 if (strlen(user.zone_fs_special) > 0 && 4459 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 4460 goto loopend; /* no match */ 4461 if (strlen(user.zone_fs_type) > 0 && 4462 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 4463 goto loopend; /* no match */ 4464 output_fs(fp, &lookup); 4465 output = TRUE; 4466 loopend: 4467 zonecfg_free_fs_option_list(lookup.zone_fs_options); 4468 } 4469 (void) zonecfg_endfsent(handle); 4470 /* 4471 * If a property n/v pair was specified, warn the user if there was 4472 * nothing to output. 4473 */ 4474 if (!output && cmd->cmd_prop_nv_pairs > 0) 4475 (void) printf(gettext("No such %s resource.\n"), 4476 rt_to_str(RT_FS)); 4477 } 4478 4479 static void 4480 info_ipd(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4481 { 4482 struct zone_fstab lookup, user; 4483 bool output = FALSE; 4484 4485 if (zonecfg_setipdent(handle) != Z_OK) 4486 return; 4487 while (zonecfg_getipdent(handle, &lookup) == Z_OK) { 4488 if (cmd->cmd_prop_nv_pairs == 0) { 4489 output_ipd(fp, &lookup); 4490 continue; 4491 } 4492 if (fill_in_ipdtab(cmd, &user, TRUE) != Z_OK) 4493 continue; 4494 if (strlen(user.zone_fs_dir) > 0 && 4495 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 4496 continue; /* no match */ 4497 output_ipd(fp, &lookup); 4498 output = TRUE; 4499 } 4500 (void) zonecfg_endipdent(handle); 4501 /* 4502 * If a property n/v pair was specified, warn the user if there was 4503 * nothing to output. 4504 */ 4505 if (!output && cmd->cmd_prop_nv_pairs > 0) 4506 (void) printf(gettext("No such %s resource.\n"), 4507 rt_to_str(RT_IPD)); 4508 } 4509 4510 static void 4511 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 4512 { 4513 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 4514 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 4515 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 4516 } 4517 4518 static void 4519 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4520 { 4521 struct zone_nwiftab lookup, user; 4522 bool output = FALSE; 4523 4524 if (zonecfg_setnwifent(handle) != Z_OK) 4525 return; 4526 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 4527 if (cmd->cmd_prop_nv_pairs == 0) { 4528 output_net(fp, &lookup); 4529 continue; 4530 } 4531 if (fill_in_nwiftab(cmd, &user, TRUE) != Z_OK) 4532 continue; 4533 if (strlen(user.zone_nwif_physical) > 0 && 4534 strcmp(user.zone_nwif_physical, 4535 lookup.zone_nwif_physical) != 0) 4536 continue; /* no match */ 4537 /* If present make sure it matches */ 4538 if (strlen(user.zone_nwif_address) > 0 && 4539 !zonecfg_same_net_address(user.zone_nwif_address, 4540 lookup.zone_nwif_address)) 4541 continue; /* no match */ 4542 output_net(fp, &lookup); 4543 output = TRUE; 4544 } 4545 (void) zonecfg_endnwifent(handle); 4546 /* 4547 * If a property n/v pair was specified, warn the user if there was 4548 * nothing to output. 4549 */ 4550 if (!output && cmd->cmd_prop_nv_pairs > 0) 4551 (void) printf(gettext("No such %s resource.\n"), 4552 rt_to_str(RT_NET)); 4553 } 4554 4555 static void 4556 output_dev(FILE *fp, struct zone_devtab *devtab) 4557 { 4558 (void) fprintf(fp, "%s\n", rt_to_str(RT_DEVICE)); 4559 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 4560 } 4561 4562 static void 4563 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4564 { 4565 struct zone_devtab lookup, user; 4566 bool output = FALSE; 4567 4568 if (zonecfg_setdevent(handle) != Z_OK) 4569 return; 4570 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 4571 if (cmd->cmd_prop_nv_pairs == 0) { 4572 output_dev(fp, &lookup); 4573 continue; 4574 } 4575 if (fill_in_devtab(cmd, &user, TRUE) != Z_OK) 4576 continue; 4577 if (strlen(user.zone_dev_match) > 0 && 4578 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 4579 continue; /* no match */ 4580 output_dev(fp, &lookup); 4581 output = TRUE; 4582 } 4583 (void) zonecfg_enddevent(handle); 4584 /* 4585 * If a property n/v pair was specified, warn the user if there was 4586 * nothing to output. 4587 */ 4588 if (!output && cmd->cmd_prop_nv_pairs > 0) 4589 (void) printf(gettext("No such %s resource.\n"), 4590 rt_to_str(RT_DEVICE)); 4591 } 4592 4593 static void 4594 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 4595 { 4596 struct zone_rctlvaltab *valptr; 4597 4598 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 4599 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 4600 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 4601 valptr = valptr->zone_rctlval_next) { 4602 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 4603 pt_to_str(PT_VALUE), 4604 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 4605 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 4606 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 4607 } 4608 } 4609 4610 static void 4611 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4612 { 4613 struct zone_rctltab lookup, user; 4614 bool output = FALSE; 4615 4616 if (zonecfg_setrctlent(handle) != Z_OK) 4617 return; 4618 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 4619 if (cmd->cmd_prop_nv_pairs == 0) { 4620 output_rctl(fp, &lookup); 4621 } else if (fill_in_rctltab(cmd, &user, TRUE) == Z_OK && 4622 (strlen(user.zone_rctl_name) == 0 || 4623 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 4624 output_rctl(fp, &lookup); 4625 output = TRUE; 4626 } 4627 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 4628 } 4629 (void) zonecfg_endrctlent(handle); 4630 /* 4631 * If a property n/v pair was specified, warn the user if there was 4632 * nothing to output. 4633 */ 4634 if (!output && cmd->cmd_prop_nv_pairs > 0) 4635 (void) printf(gettext("No such %s resource.\n"), 4636 rt_to_str(RT_RCTL)); 4637 } 4638 4639 static void 4640 output_attr(FILE *fp, struct zone_attrtab *attrtab) 4641 { 4642 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 4643 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 4644 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 4645 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 4646 } 4647 4648 static void 4649 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4650 { 4651 struct zone_attrtab lookup, user; 4652 bool output = FALSE; 4653 4654 if (zonecfg_setattrent(handle) != Z_OK) 4655 return; 4656 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 4657 if (cmd->cmd_prop_nv_pairs == 0) { 4658 output_attr(fp, &lookup); 4659 continue; 4660 } 4661 if (fill_in_attrtab(cmd, &user, TRUE) != Z_OK) 4662 continue; 4663 if (strlen(user.zone_attr_name) > 0 && 4664 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 4665 continue; /* no match */ 4666 if (strlen(user.zone_attr_type) > 0 && 4667 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 4668 continue; /* no match */ 4669 if (strlen(user.zone_attr_value) > 0 && 4670 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 4671 continue; /* no match */ 4672 output_attr(fp, &lookup); 4673 output = TRUE; 4674 } 4675 (void) zonecfg_endattrent(handle); 4676 /* 4677 * If a property n/v pair was specified, warn the user if there was 4678 * nothing to output. 4679 */ 4680 if (!output && cmd->cmd_prop_nv_pairs > 0) 4681 (void) printf(gettext("No such %s resource.\n"), 4682 rt_to_str(RT_ATTR)); 4683 } 4684 4685 static void 4686 output_ds(FILE *fp, struct zone_dstab *dstab) 4687 { 4688 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 4689 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 4690 } 4691 4692 static void 4693 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 4694 { 4695 struct zone_dstab lookup, user; 4696 bool output = FALSE; 4697 4698 if (zonecfg_setdsent(handle) != Z_OK) 4699 return; 4700 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 4701 if (cmd->cmd_prop_nv_pairs == 0) { 4702 output_ds(fp, &lookup); 4703 continue; 4704 } 4705 if (fill_in_dstab(cmd, &user, TRUE) != Z_OK) 4706 continue; 4707 if (strlen(user.zone_dataset_name) > 0 && 4708 strcmp(user.zone_dataset_name, 4709 lookup.zone_dataset_name) != 0) 4710 continue; /* no match */ 4711 output_ds(fp, &lookup); 4712 output = TRUE; 4713 } 4714 (void) zonecfg_enddsent(handle); 4715 /* 4716 * If a property n/v pair was specified, warn the user if there was 4717 * nothing to output. 4718 */ 4719 if (!output && cmd->cmd_prop_nv_pairs > 0) 4720 (void) printf(gettext("No such %s resource.\n"), 4721 rt_to_str(RT_DATASET)); 4722 } 4723 4724 static void 4725 output_pset(FILE *fp, struct zone_psettab *psettab) 4726 { 4727 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU)); 4728 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0) 4729 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS), 4730 psettab->zone_ncpu_max); 4731 else 4732 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS), 4733 psettab->zone_ncpu_min, psettab->zone_ncpu_max); 4734 if (psettab->zone_importance[0] != '\0') 4735 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE), 4736 psettab->zone_importance); 4737 } 4738 4739 static void 4740 info_pset(zone_dochandle_t handle, FILE *fp) 4741 { 4742 struct zone_psettab lookup; 4743 4744 if (zonecfg_getpsetent(handle, &lookup) == Z_OK) 4745 output_pset(fp, &lookup); 4746 } 4747 4748 static void 4749 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias) 4750 { 4751 uint64_t limit; 4752 4753 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) { 4754 /* convert memory based properties */ 4755 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) { 4756 char buf[128]; 4757 4758 (void) snprintf(buf, sizeof (buf), "%llu", limit); 4759 bytes_to_units(buf, buf, sizeof (buf)); 4760 (void) fprintf(fp, "[%s: %s]\n", alias, buf); 4761 return; 4762 } 4763 4764 (void) fprintf(fp, "[%s: %llu]\n", alias, limit); 4765 } 4766 } 4767 4768 static void 4769 bytes_to_units(char *str, char *buf, int bufsize) 4770 { 4771 unsigned long long num; 4772 unsigned long long save = 0; 4773 char *units = "BKMGT"; 4774 char *up = units; 4775 4776 num = strtoll(str, NULL, 10); 4777 4778 if (num < 1024) { 4779 (void) snprintf(buf, bufsize, "%llu", num); 4780 return; 4781 } 4782 4783 while ((num >= 1024) && (*up != 'T')) { 4784 up++; /* next unit of measurement */ 4785 save = num; 4786 num = (num + 512) >> 10; 4787 } 4788 4789 /* check if we should output a fraction. snprintf will round for us */ 4790 if (save % 1024 != 0 && ((save >> 10) < 10)) 4791 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024), 4792 *up); 4793 else 4794 (void) snprintf(buf, bufsize, "%llu%c", num, *up); 4795 } 4796 4797 static void 4798 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap, 4799 uint64_t maxswap, int showlocked, uint64_t maxlocked) 4800 { 4801 char buf[128]; 4802 4803 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP)); 4804 if (mcaptab->zone_physmem_cap[0] != '\0') { 4805 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf)); 4806 output_prop(fp, PT_PHYSICAL, buf, B_TRUE); 4807 } 4808 4809 if (showswap == Z_OK) { 4810 (void) snprintf(buf, sizeof (buf), "%llu", maxswap); 4811 bytes_to_units(buf, buf, sizeof (buf)); 4812 output_prop(fp, PT_SWAP, buf, B_TRUE); 4813 } 4814 4815 if (showlocked == Z_OK) { 4816 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked); 4817 bytes_to_units(buf, buf, sizeof (buf)); 4818 output_prop(fp, PT_LOCKED, buf, B_TRUE); 4819 } 4820 } 4821 4822 static void 4823 info_mcap(zone_dochandle_t handle, FILE *fp) 4824 { 4825 int res1, res2, res3; 4826 uint64_t swap_limit; 4827 uint64_t locked_limit; 4828 struct zone_mcaptab lookup; 4829 4830 bzero(&lookup, sizeof (lookup)); 4831 res1 = zonecfg_getmcapent(handle, &lookup); 4832 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit); 4833 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 4834 &locked_limit); 4835 4836 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK) 4837 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit); 4838 } 4839 4840 void 4841 info_func(cmd_t *cmd) 4842 { 4843 FILE *fp = stdout; 4844 bool need_to_close = FALSE; 4845 char *pager; 4846 int type; 4847 int res1, res2; 4848 uint64_t swap_limit; 4849 uint64_t locked_limit; 4850 4851 assert(cmd != NULL); 4852 4853 if (initialize(TRUE) != Z_OK) 4854 return; 4855 4856 /* don't page error output */ 4857 if (interactive_mode) { 4858 if ((pager = getenv("PAGER")) == NULL) 4859 pager = PAGER; 4860 if ((fp = popen(pager, "w")) != NULL) 4861 need_to_close = TRUE; 4862 setbuf(fp, NULL); 4863 } 4864 4865 if (!global_scope) { 4866 switch (resource_scope) { 4867 case RT_FS: 4868 output_fs(fp, &in_progress_fstab); 4869 break; 4870 case RT_IPD: 4871 output_ipd(fp, &in_progress_ipdtab); 4872 break; 4873 case RT_NET: 4874 output_net(fp, &in_progress_nwiftab); 4875 break; 4876 case RT_DEVICE: 4877 output_dev(fp, &in_progress_devtab); 4878 break; 4879 case RT_RCTL: 4880 output_rctl(fp, &in_progress_rctltab); 4881 break; 4882 case RT_ATTR: 4883 output_attr(fp, &in_progress_attrtab); 4884 break; 4885 case RT_DATASET: 4886 output_ds(fp, &in_progress_dstab); 4887 break; 4888 case RT_DCPU: 4889 output_pset(fp, &in_progress_psettab); 4890 break; 4891 case RT_MCAP: 4892 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 4893 &swap_limit); 4894 res2 = zonecfg_get_aliased_rctl(handle, 4895 ALIAS_MAXLOCKEDMEM, &locked_limit); 4896 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit, 4897 res2, locked_limit); 4898 break; 4899 } 4900 goto cleanup; 4901 } 4902 4903 type = cmd->cmd_res_type; 4904 4905 if (gz_invalid_rt_property(type)) { 4906 zerr(gettext("%s is not a valid property for the global zone."), 4907 rt_to_str(type)); 4908 goto cleanup; 4909 } 4910 4911 if (gz_invalid_resource(type)) { 4912 zerr(gettext("%s is not a valid resource for the global zone."), 4913 rt_to_str(type)); 4914 goto cleanup; 4915 } 4916 4917 switch (cmd->cmd_res_type) { 4918 case RT_UNKNOWN: 4919 info_zonename(handle, fp); 4920 if (!global_zone) { 4921 info_zonepath(handle, fp); 4922 info_brand(handle, fp); 4923 info_autoboot(handle, fp); 4924 info_bootargs(handle, fp); 4925 } 4926 info_pool(handle, fp); 4927 if (!global_zone) { 4928 info_limitpriv(handle, fp); 4929 info_sched(handle, fp); 4930 info_iptype(handle, fp); 4931 } 4932 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 4933 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 4934 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 4935 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 4936 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 4937 info_aliased_rctl(handle, fp, ALIAS_SHARES); 4938 if (!global_zone) { 4939 info_ipd(handle, fp, cmd); 4940 info_fs(handle, fp, cmd); 4941 info_net(handle, fp, cmd); 4942 info_dev(handle, fp, cmd); 4943 } 4944 info_pset(handle, fp); 4945 info_mcap(handle, fp); 4946 if (!global_zone) { 4947 info_attr(handle, fp, cmd); 4948 info_ds(handle, fp, cmd); 4949 } 4950 info_rctl(handle, fp, cmd); 4951 break; 4952 case RT_ZONENAME: 4953 info_zonename(handle, fp); 4954 break; 4955 case RT_ZONEPATH: 4956 info_zonepath(handle, fp); 4957 break; 4958 case RT_BRAND: 4959 info_brand(handle, fp); 4960 break; 4961 case RT_AUTOBOOT: 4962 info_autoboot(handle, fp); 4963 break; 4964 case RT_POOL: 4965 info_pool(handle, fp); 4966 break; 4967 case RT_LIMITPRIV: 4968 info_limitpriv(handle, fp); 4969 break; 4970 case RT_BOOTARGS: 4971 info_bootargs(handle, fp); 4972 break; 4973 case RT_SCHED: 4974 info_sched(handle, fp); 4975 break; 4976 case RT_IPTYPE: 4977 info_iptype(handle, fp); 4978 break; 4979 case RT_MAXLWPS: 4980 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 4981 break; 4982 case RT_MAXSHMMEM: 4983 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 4984 break; 4985 case RT_MAXSHMIDS: 4986 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 4987 break; 4988 case RT_MAXMSGIDS: 4989 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 4990 break; 4991 case RT_MAXSEMIDS: 4992 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 4993 break; 4994 case RT_SHARES: 4995 info_aliased_rctl(handle, fp, ALIAS_SHARES); 4996 break; 4997 case RT_FS: 4998 info_fs(handle, fp, cmd); 4999 break; 5000 case RT_IPD: 5001 info_ipd(handle, fp, cmd); 5002 break; 5003 case RT_NET: 5004 info_net(handle, fp, cmd); 5005 break; 5006 case RT_DEVICE: 5007 info_dev(handle, fp, cmd); 5008 break; 5009 case RT_RCTL: 5010 info_rctl(handle, fp, cmd); 5011 break; 5012 case RT_ATTR: 5013 info_attr(handle, fp, cmd); 5014 break; 5015 case RT_DATASET: 5016 info_ds(handle, fp, cmd); 5017 break; 5018 case RT_DCPU: 5019 info_pset(handle, fp); 5020 break; 5021 case RT_MCAP: 5022 info_mcap(handle, fp); 5023 break; 5024 default: 5025 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 5026 TRUE); 5027 } 5028 5029 cleanup: 5030 if (need_to_close) 5031 (void) pclose(fp); 5032 } 5033 5034 /* 5035 * Helper function for verify-- checks that a required string property 5036 * exists. 5037 */ 5038 static void 5039 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 5040 { 5041 if (strlen(attr) == 0) { 5042 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 5043 pt_to_str(pt)); 5044 saw_error = TRUE; 5045 if (*ret_val == Z_OK) 5046 *ret_val = Z_REQD_PROPERTY_MISSING; 5047 } 5048 } 5049 5050 static int 5051 do_subproc(char *cmdbuf) 5052 { 5053 char inbuf[MAX_CMD_LEN]; 5054 FILE *file; 5055 int status; 5056 5057 file = popen(cmdbuf, "r"); 5058 if (file == NULL) { 5059 zerr(gettext("Could not launch: %s"), cmdbuf); 5060 return (-1); 5061 } 5062 5063 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 5064 fprintf(stderr, "%s", inbuf); 5065 status = pclose(file); 5066 5067 if (WIFSIGNALED(status)) { 5068 zerr(gettext("%s unexpectedly terminated due to signal %d"), 5069 cmdbuf, WTERMSIG(status)); 5070 return (-1); 5071 } 5072 assert(WIFEXITED(status)); 5073 return (WEXITSTATUS(status)); 5074 } 5075 5076 static int 5077 brand_verify(zone_dochandle_t handle) 5078 { 5079 char xml_file[32]; 5080 char cmdbuf[MAX_CMD_LEN]; 5081 brand_handle_t bh; 5082 char brand[MAXNAMELEN]; 5083 int err; 5084 5085 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 5086 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 5087 return (Z_INVALID_DOCUMENT); 5088 } 5089 if ((bh = brand_open(brand)) == NULL) { 5090 zerr("%s: %s\n", zone, gettext("unknown brand.")); 5091 return (Z_INVALID_DOCUMENT); 5092 } 5093 5094 /* 5095 * Fetch the verify command, if any, from the brand configuration 5096 * and build the command line to execute it. 5097 */ 5098 strcpy(cmdbuf, EXEC_PREFIX); 5099 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN, 5100 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 5101 brand_close(bh); 5102 if (err != Z_OK) { 5103 zerr("%s: %s\n", zone, 5104 gettext("could not get brand verification command")); 5105 return (Z_INVALID_DOCUMENT); 5106 } 5107 5108 /* 5109 * If the brand doesn't provide a verification routine, we just 5110 * return success. 5111 */ 5112 if (strlen(cmdbuf) == EXEC_LEN) 5113 return (Z_OK); 5114 5115 /* 5116 * Dump the current config information for this zone to a file. 5117 */ 5118 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX"); 5119 if (mkstemp(xml_file) == NULL) 5120 return (Z_TEMP_FILE); 5121 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 5122 (void) unlink(xml_file); 5123 return (err); 5124 } 5125 5126 /* 5127 * Execute the verification command. 5128 */ 5129 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 5130 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 5131 err = Z_BRAND_ERROR; 5132 } else { 5133 err = do_subproc(cmdbuf); 5134 } 5135 5136 (void) unlink(xml_file); 5137 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 5138 } 5139 5140 /* 5141 * See the DTD for which attributes are required for which resources. 5142 * 5143 * This function can be called by commit_func(), which needs to save things, 5144 * in addition to the general call from parse_and_run(), which doesn't need 5145 * things saved. Since the parameters are standardized, we distinguish by 5146 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 5147 * that a save is needed. 5148 */ 5149 void 5150 verify_func(cmd_t *cmd) 5151 { 5152 struct zone_nwiftab nwiftab; 5153 struct zone_fstab fstab; 5154 struct zone_attrtab attrtab; 5155 struct zone_rctltab rctltab; 5156 struct zone_dstab dstab; 5157 struct zone_psettab psettab; 5158 char zonepath[MAXPATHLEN]; 5159 char sched[MAXNAMELEN]; 5160 char brand[MAXNAMELEN]; 5161 int err, ret_val = Z_OK, arg; 5162 bool save = FALSE; 5163 zone_iptype_t iptype; 5164 boolean_t has_cpu_shares = B_FALSE; 5165 5166 optind = 0; 5167 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5168 switch (arg) { 5169 case '?': 5170 longer_usage(CMD_VERIFY); 5171 return; 5172 default: 5173 short_usage(CMD_VERIFY); 5174 return; 5175 } 5176 } 5177 if (optind > cmd->cmd_argc) { 5178 short_usage(CMD_VERIFY); 5179 return; 5180 } 5181 5182 if (zone_is_read_only(CMD_VERIFY)) 5183 return; 5184 5185 assert(cmd != NULL); 5186 5187 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 5188 save = TRUE; 5189 if (initialize(TRUE) != Z_OK) 5190 return; 5191 5192 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK && 5193 !global_zone) { 5194 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 5195 ret_val = Z_REQD_RESOURCE_MISSING; 5196 saw_error = TRUE; 5197 } 5198 if (strlen(zonepath) == 0 && !global_zone) { 5199 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 5200 ret_val = Z_REQD_RESOURCE_MISSING; 5201 saw_error = TRUE; 5202 } 5203 5204 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 5205 zone_perror(zone, err, TRUE); 5206 return; 5207 } 5208 if (strcmp(brand, NATIVE_BRAND_NAME) != 0) { 5209 if ((err = brand_verify(handle)) != Z_OK) { 5210 zone_perror(zone, err, TRUE); 5211 return; 5212 } 5213 } 5214 5215 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 5216 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE)); 5217 ret_val = Z_REQD_RESOURCE_MISSING; 5218 saw_error = TRUE; 5219 } 5220 if ((err = zonecfg_setipdent(handle)) != Z_OK) { 5221 zone_perror(zone, err, TRUE); 5222 return; 5223 } 5224 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5225 check_reqd_prop(fstab.zone_fs_dir, RT_IPD, PT_DIR, &ret_val); 5226 } 5227 (void) zonecfg_endipdent(handle); 5228 5229 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 5230 zone_perror(zone, err, TRUE); 5231 return; 5232 } 5233 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 5234 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 5235 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 5236 &ret_val); 5237 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 5238 5239 zonecfg_free_fs_option_list(fstab.zone_fs_options); 5240 } 5241 (void) zonecfg_endfsent(handle); 5242 5243 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 5244 zone_perror(zone, err, TRUE); 5245 return; 5246 } 5247 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 5248 /* 5249 * physical is required in all cases. 5250 * A shared IP requires an address, while 5251 * an exclusive IP must not have an address. 5252 */ 5253 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 5254 PT_PHYSICAL, &ret_val); 5255 5256 switch (iptype) { 5257 case ZS_SHARED: 5258 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 5259 PT_ADDRESS, &ret_val); 5260 break; 5261 case ZS_EXCLUSIVE: 5262 if (strlen(nwiftab.zone_nwif_address) > 0) { 5263 zerr(gettext("%s: %s cannot be specified " 5264 "for an exclusive IP type"), 5265 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS)); 5266 saw_error = TRUE; 5267 if (ret_val == Z_OK) 5268 ret_val = Z_INVAL; 5269 } 5270 break; 5271 } 5272 } 5273 (void) zonecfg_endnwifent(handle); 5274 5275 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 5276 zone_perror(zone, err, TRUE); 5277 return; 5278 } 5279 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 5280 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 5281 &ret_val); 5282 5283 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0) 5284 has_cpu_shares = B_TRUE; 5285 5286 if (rctltab.zone_rctl_valptr == NULL) { 5287 zerr(gettext("%s: no %s specified"), 5288 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 5289 saw_error = TRUE; 5290 if (ret_val == Z_OK) 5291 ret_val = Z_REQD_PROPERTY_MISSING; 5292 } else { 5293 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 5294 } 5295 } 5296 (void) zonecfg_endrctlent(handle); 5297 5298 if (zonecfg_lookup_pset(handle, &psettab) == Z_OK && has_cpu_shares) { 5299 zerr(gettext("%s zone.cpu-shares and %s are incompatible."), 5300 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 5301 saw_error = TRUE; 5302 if (ret_val == Z_OK) 5303 ret_val = Z_INCOMPATIBLE; 5304 } 5305 5306 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched, 5307 sizeof (sched)) == Z_OK && strlen(sched) > 0 && 5308 strcmp(sched, "FSS") != 0) { 5309 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are " 5310 "incompatible"), 5311 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched); 5312 saw_error = TRUE; 5313 if (ret_val == Z_OK) 5314 ret_val = Z_INCOMPATIBLE; 5315 } 5316 5317 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 5318 zone_perror(zone, err, TRUE); 5319 return; 5320 } 5321 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 5322 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 5323 &ret_val); 5324 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 5325 &ret_val); 5326 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 5327 &ret_val); 5328 } 5329 (void) zonecfg_endattrent(handle); 5330 5331 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 5332 zone_perror(zone, err, TRUE); 5333 return; 5334 } 5335 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 5336 if (strlen(dstab.zone_dataset_name) == 0) { 5337 zerr("%s: %s %s", rt_to_str(RT_DATASET), 5338 pt_to_str(PT_NAME), gettext("not specified")); 5339 saw_error = TRUE; 5340 if (ret_val == Z_OK) 5341 ret_val = Z_REQD_PROPERTY_MISSING; 5342 } else if (!zfs_name_valid(dstab.zone_dataset_name, 5343 ZFS_TYPE_FILESYSTEM)) { 5344 zerr("%s: %s %s", rt_to_str(RT_DATASET), 5345 pt_to_str(PT_NAME), gettext("invalid")); 5346 saw_error = TRUE; 5347 if (ret_val == Z_OK) 5348 ret_val = Z_BAD_PROPERTY; 5349 } 5350 5351 } 5352 (void) zonecfg_enddsent(handle); 5353 5354 if (!global_scope) { 5355 zerr(gettext("resource specification incomplete")); 5356 saw_error = TRUE; 5357 if (ret_val == Z_OK) 5358 ret_val = Z_INSUFFICIENT_SPEC; 5359 } 5360 5361 if (save) { 5362 if (ret_val == Z_OK) { 5363 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 5364 need_to_commit = FALSE; 5365 (void) strlcpy(revert_zone, zone, 5366 sizeof (revert_zone)); 5367 } 5368 } else { 5369 zerr(gettext("Zone %s failed to verify"), zone); 5370 } 5371 } 5372 if (ret_val != Z_OK) 5373 zone_perror(zone, ret_val, TRUE); 5374 } 5375 5376 void 5377 cancel_func(cmd_t *cmd) 5378 { 5379 int arg; 5380 5381 assert(cmd != NULL); 5382 5383 optind = 0; 5384 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5385 switch (arg) { 5386 case '?': 5387 longer_usage(CMD_CANCEL); 5388 return; 5389 default: 5390 short_usage(CMD_CANCEL); 5391 return; 5392 } 5393 } 5394 if (optind != cmd->cmd_argc) { 5395 short_usage(CMD_CANCEL); 5396 return; 5397 } 5398 5399 if (global_scope) 5400 scope_usage(CMD_CANCEL); 5401 global_scope = TRUE; 5402 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 5403 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 5404 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 5405 bzero(&in_progress_ipdtab, sizeof (in_progress_ipdtab)); 5406 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 5407 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 5408 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 5409 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 5410 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 5411 } 5412 5413 static int 5414 validate_attr_name(char *name) 5415 { 5416 int i; 5417 5418 if (!isalnum(name[0])) { 5419 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 5420 "numeric character."), rt_to_str(RT_ATTR), 5421 pt_to_str(PT_NAME), name); 5422 return (Z_INVAL); 5423 } 5424 for (i = 1; name[i]; i++) 5425 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 5426 zerr(gettext("Invalid %s %s %s: can only contain " 5427 "alpha-numeric characters, plus '-' and '.'."), 5428 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 5429 return (Z_INVAL); 5430 } 5431 return (Z_OK); 5432 } 5433 5434 static int 5435 validate_attr_type_val(struct zone_attrtab *attrtab) 5436 { 5437 boolean_t boolval; 5438 int64_t intval; 5439 char strval[MAXNAMELEN]; 5440 uint64_t uintval; 5441 5442 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 5443 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 5444 return (Z_OK); 5445 zerr(gettext("invalid %s value for %s=%s"), 5446 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 5447 return (Z_ERR); 5448 } 5449 5450 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 5451 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 5452 return (Z_OK); 5453 zerr(gettext("invalid %s value for %s=%s"), 5454 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 5455 return (Z_ERR); 5456 } 5457 5458 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 5459 if (zonecfg_get_attr_string(attrtab, strval, 5460 sizeof (strval)) == Z_OK) 5461 return (Z_OK); 5462 zerr(gettext("invalid %s value for %s=%s"), 5463 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 5464 return (Z_ERR); 5465 } 5466 5467 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 5468 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 5469 return (Z_OK); 5470 zerr(gettext("invalid %s value for %s=%s"), 5471 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 5472 return (Z_ERR); 5473 } 5474 5475 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 5476 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 5477 return (Z_ERR); 5478 } 5479 5480 /* 5481 * Helper function for end_func-- checks the existence of a given property 5482 * and emits a message if not specified. 5483 */ 5484 static int 5485 end_check_reqd(char *attr, int pt, bool *validation_failed) 5486 { 5487 if (strlen(attr) == 0) { 5488 *validation_failed = TRUE; 5489 zerr(gettext("%s not specified"), pt_to_str(pt)); 5490 return (Z_ERR); 5491 } 5492 return (Z_OK); 5493 } 5494 5495 void 5496 end_func(cmd_t *cmd) 5497 { 5498 bool validation_failed = FALSE; 5499 struct zone_fstab tmp_fstab; 5500 struct zone_nwiftab tmp_nwiftab; 5501 struct zone_devtab tmp_devtab; 5502 struct zone_rctltab tmp_rctltab; 5503 struct zone_attrtab tmp_attrtab; 5504 struct zone_dstab tmp_dstab; 5505 int err, arg, res1, res2, res3; 5506 uint64_t swap_limit; 5507 uint64_t locked_limit; 5508 5509 assert(cmd != NULL); 5510 5511 optind = 0; 5512 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5513 switch (arg) { 5514 case '?': 5515 longer_usage(CMD_END); 5516 return; 5517 default: 5518 short_usage(CMD_END); 5519 return; 5520 } 5521 } 5522 if (optind != cmd->cmd_argc) { 5523 short_usage(CMD_END); 5524 return; 5525 } 5526 5527 if (global_scope) { 5528 scope_usage(CMD_END); 5529 return; 5530 } 5531 5532 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 5533 5534 switch (resource_scope) { 5535 case RT_FS: 5536 /* First make sure everything was filled in. */ 5537 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 5538 PT_DIR, &validation_failed) == Z_OK) { 5539 if (in_progress_fstab.zone_fs_dir[0] != '/') { 5540 zerr(gettext("%s %s is not an absolute path."), 5541 pt_to_str(PT_DIR), 5542 in_progress_fstab.zone_fs_dir); 5543 validation_failed = TRUE; 5544 } 5545 } 5546 5547 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 5548 PT_SPECIAL, &validation_failed); 5549 5550 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 5551 in_progress_fstab.zone_fs_raw[0] != '/') { 5552 zerr(gettext("%s %s is not an absolute path."), 5553 pt_to_str(PT_RAW), 5554 in_progress_fstab.zone_fs_raw); 5555 validation_failed = TRUE; 5556 } 5557 5558 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 5559 &validation_failed); 5560 5561 if (validation_failed) { 5562 saw_error = TRUE; 5563 return; 5564 } 5565 5566 if (end_op == CMD_ADD) { 5567 /* Make sure there isn't already one like this. */ 5568 bzero(&tmp_fstab, sizeof (tmp_fstab)); 5569 (void) strlcpy(tmp_fstab.zone_fs_dir, 5570 in_progress_fstab.zone_fs_dir, 5571 sizeof (tmp_fstab.zone_fs_dir)); 5572 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 5573 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 5574 if (err == Z_OK) { 5575 zerr(gettext("A %s resource " 5576 "with the %s '%s' already exists."), 5577 rt_to_str(RT_FS), pt_to_str(PT_DIR), 5578 in_progress_fstab.zone_fs_dir); 5579 saw_error = TRUE; 5580 return; 5581 } 5582 err = zonecfg_add_filesystem(handle, 5583 &in_progress_fstab); 5584 } else { 5585 err = zonecfg_modify_filesystem(handle, &old_fstab, 5586 &in_progress_fstab); 5587 } 5588 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 5589 in_progress_fstab.zone_fs_options = NULL; 5590 break; 5591 5592 case RT_IPD: 5593 /* First make sure everything was filled in. */ 5594 if (end_check_reqd(in_progress_ipdtab.zone_fs_dir, PT_DIR, 5595 &validation_failed) == Z_OK) { 5596 if (in_progress_ipdtab.zone_fs_dir[0] != '/') { 5597 zerr(gettext("%s %s is not an absolute path."), 5598 pt_to_str(PT_DIR), 5599 in_progress_ipdtab.zone_fs_dir); 5600 validation_failed = TRUE; 5601 } 5602 } 5603 if (validation_failed) { 5604 saw_error = TRUE; 5605 return; 5606 } 5607 5608 if (end_op == CMD_ADD) { 5609 /* Make sure there isn't already one like this. */ 5610 bzero(&tmp_fstab, sizeof (tmp_fstab)); 5611 (void) strlcpy(tmp_fstab.zone_fs_dir, 5612 in_progress_ipdtab.zone_fs_dir, 5613 sizeof (tmp_fstab.zone_fs_dir)); 5614 err = zonecfg_lookup_ipd(handle, &tmp_fstab); 5615 if (err == Z_OK) { 5616 zerr(gettext("An %s resource " 5617 "with the %s '%s' already exists."), 5618 rt_to_str(RT_IPD), pt_to_str(PT_DIR), 5619 in_progress_ipdtab.zone_fs_dir); 5620 saw_error = TRUE; 5621 return; 5622 } 5623 err = zonecfg_add_ipd(handle, &in_progress_ipdtab); 5624 } else { 5625 err = zonecfg_modify_ipd(handle, &old_ipdtab, 5626 &in_progress_ipdtab); 5627 } 5628 break; 5629 case RT_NET: 5630 /* 5631 * First make sure everything was filled in. 5632 * Since we don't know whether IP will be shared 5633 * or exclusive here, some checks are deferred until 5634 * the verify command. 5635 */ 5636 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 5637 PT_PHYSICAL, &validation_failed); 5638 5639 if (validation_failed) { 5640 saw_error = TRUE; 5641 return; 5642 } 5643 if (end_op == CMD_ADD) { 5644 /* Make sure there isn't already one like this. */ 5645 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 5646 (void) strlcpy(tmp_nwiftab.zone_nwif_physical, 5647 in_progress_nwiftab.zone_nwif_physical, 5648 sizeof (tmp_nwiftab.zone_nwif_physical)); 5649 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 5650 in_progress_nwiftab.zone_nwif_address, 5651 sizeof (tmp_nwiftab.zone_nwif_address)); 5652 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 5653 zerr(gettext("A %s resource with the %s '%s', " 5654 "and %s '%s' already exists."), 5655 rt_to_str(RT_NET), 5656 pt_to_str(PT_PHYSICAL), 5657 in_progress_nwiftab.zone_nwif_physical, 5658 pt_to_str(PT_ADDRESS), 5659 in_progress_nwiftab.zone_nwif_address); 5660 saw_error = TRUE; 5661 return; 5662 } 5663 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 5664 } else { 5665 err = zonecfg_modify_nwif(handle, &old_nwiftab, 5666 &in_progress_nwiftab); 5667 } 5668 break; 5669 5670 case RT_DEVICE: 5671 /* First make sure everything was filled in. */ 5672 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 5673 PT_MATCH, &validation_failed); 5674 5675 if (validation_failed) { 5676 saw_error = TRUE; 5677 return; 5678 } 5679 5680 if (end_op == CMD_ADD) { 5681 /* Make sure there isn't already one like this. */ 5682 (void) strlcpy(tmp_devtab.zone_dev_match, 5683 in_progress_devtab.zone_dev_match, 5684 sizeof (tmp_devtab.zone_dev_match)); 5685 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 5686 zerr(gettext("A %s resource with the %s '%s' " 5687 "already exists."), rt_to_str(RT_DEVICE), 5688 pt_to_str(PT_MATCH), 5689 in_progress_devtab.zone_dev_match); 5690 saw_error = TRUE; 5691 return; 5692 } 5693 err = zonecfg_add_dev(handle, &in_progress_devtab); 5694 } else { 5695 err = zonecfg_modify_dev(handle, &old_devtab, 5696 &in_progress_devtab); 5697 } 5698 break; 5699 5700 case RT_RCTL: 5701 /* First make sure everything was filled in. */ 5702 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 5703 PT_NAME, &validation_failed); 5704 5705 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 5706 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 5707 validation_failed = TRUE; 5708 } 5709 5710 if (validation_failed) { 5711 saw_error = TRUE; 5712 return; 5713 } 5714 5715 if (end_op == CMD_ADD) { 5716 /* Make sure there isn't already one like this. */ 5717 (void) strlcpy(tmp_rctltab.zone_rctl_name, 5718 in_progress_rctltab.zone_rctl_name, 5719 sizeof (tmp_rctltab.zone_rctl_name)); 5720 tmp_rctltab.zone_rctl_valptr = NULL; 5721 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 5722 zonecfg_free_rctl_value_list( 5723 tmp_rctltab.zone_rctl_valptr); 5724 if (err == Z_OK) { 5725 zerr(gettext("A %s resource " 5726 "with the %s '%s' already exists."), 5727 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 5728 in_progress_rctltab.zone_rctl_name); 5729 saw_error = TRUE; 5730 return; 5731 } 5732 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 5733 } else { 5734 err = zonecfg_modify_rctl(handle, &old_rctltab, 5735 &in_progress_rctltab); 5736 } 5737 if (err == Z_OK) { 5738 zonecfg_free_rctl_value_list( 5739 in_progress_rctltab.zone_rctl_valptr); 5740 in_progress_rctltab.zone_rctl_valptr = NULL; 5741 } 5742 break; 5743 5744 case RT_ATTR: 5745 /* First make sure everything was filled in. */ 5746 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 5747 PT_NAME, &validation_failed); 5748 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 5749 PT_TYPE, &validation_failed); 5750 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 5751 PT_VALUE, &validation_failed); 5752 5753 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 5754 Z_OK) 5755 validation_failed = TRUE; 5756 5757 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 5758 validation_failed = TRUE; 5759 5760 if (validation_failed) { 5761 saw_error = TRUE; 5762 return; 5763 } 5764 if (end_op == CMD_ADD) { 5765 /* Make sure there isn't already one like this. */ 5766 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 5767 (void) strlcpy(tmp_attrtab.zone_attr_name, 5768 in_progress_attrtab.zone_attr_name, 5769 sizeof (tmp_attrtab.zone_attr_name)); 5770 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 5771 zerr(gettext("An %s resource " 5772 "with the %s '%s' already exists."), 5773 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 5774 in_progress_attrtab.zone_attr_name); 5775 saw_error = TRUE; 5776 return; 5777 } 5778 err = zonecfg_add_attr(handle, &in_progress_attrtab); 5779 } else { 5780 err = zonecfg_modify_attr(handle, &old_attrtab, 5781 &in_progress_attrtab); 5782 } 5783 break; 5784 case RT_DATASET: 5785 /* First make sure everything was filled in. */ 5786 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 5787 zerr("%s %s", pt_to_str(PT_NAME), 5788 gettext("not specified")); 5789 saw_error = TRUE; 5790 validation_failed = TRUE; 5791 } 5792 if (validation_failed) 5793 return; 5794 if (end_op == CMD_ADD) { 5795 /* Make sure there isn't already one like this. */ 5796 bzero(&tmp_dstab, sizeof (tmp_dstab)); 5797 (void) strlcpy(tmp_dstab.zone_dataset_name, 5798 in_progress_dstab.zone_dataset_name, 5799 sizeof (tmp_dstab.zone_dataset_name)); 5800 err = zonecfg_lookup_ds(handle, &tmp_dstab); 5801 if (err == Z_OK) { 5802 zerr(gettext("A %s resource " 5803 "with the %s '%s' already exists."), 5804 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 5805 in_progress_dstab.zone_dataset_name); 5806 saw_error = TRUE; 5807 return; 5808 } 5809 err = zonecfg_add_ds(handle, &in_progress_dstab); 5810 } else { 5811 err = zonecfg_modify_ds(handle, &old_dstab, 5812 &in_progress_dstab); 5813 } 5814 break; 5815 case RT_DCPU: 5816 /* Make sure everything was filled in. */ 5817 if (end_check_reqd(in_progress_psettab.zone_ncpu_min, 5818 PT_NCPUS, &validation_failed) != Z_OK) { 5819 saw_error = TRUE; 5820 return; 5821 } 5822 5823 if (end_op == CMD_ADD) { 5824 err = zonecfg_add_pset(handle, &in_progress_psettab); 5825 } else { 5826 err = zonecfg_modify_pset(handle, &in_progress_psettab); 5827 } 5828 break; 5829 case RT_MCAP: 5830 /* Make sure everything was filled in. */ 5831 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ? 5832 Z_ERR : Z_OK; 5833 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 5834 &swap_limit); 5835 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 5836 &locked_limit); 5837 5838 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 5839 zerr(gettext("No property was specified. One of %s, " 5840 "%s or %s is required."), pt_to_str(PT_PHYSICAL), 5841 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED)); 5842 saw_error = TRUE; 5843 return; 5844 } 5845 5846 /* if phys & locked are both set, verify locked <= phys */ 5847 if (res1 == Z_OK && res3 == Z_OK) { 5848 uint64_t phys_limit; 5849 char *endp; 5850 5851 phys_limit = strtoull( 5852 in_progress_mcaptab.zone_physmem_cap, &endp, 10); 5853 if (phys_limit < locked_limit) { 5854 zerr(gettext("The %s cap must be less than or " 5855 "equal to the %s cap."), 5856 pt_to_str(PT_LOCKED), 5857 pt_to_str(PT_PHYSICAL)); 5858 saw_error = TRUE; 5859 return; 5860 } 5861 } 5862 5863 err = Z_OK; 5864 if (res1 == Z_OK) { 5865 /* 5866 * We could be ending from either an add operation 5867 * or a select operation. Since all of the properties 5868 * within this resource are optional, we always use 5869 * modify on the mcap entry. zonecfg_modify_mcap() 5870 * will handle both adding and modifying a memory cap. 5871 */ 5872 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab); 5873 } else if (end_op == CMD_SELECT) { 5874 /* 5875 * If we're ending from a select and the physical 5876 * memory cap is empty then the user could have cleared 5877 * the physical cap value, so try to delete the entry. 5878 */ 5879 (void) zonecfg_delete_mcap(handle); 5880 } 5881 break; 5882 default: 5883 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 5884 TRUE); 5885 saw_error = TRUE; 5886 return; 5887 } 5888 5889 if (err != Z_OK) { 5890 zone_perror(zone, err, TRUE); 5891 } else { 5892 need_to_commit = TRUE; 5893 global_scope = TRUE; 5894 end_op = -1; 5895 } 5896 } 5897 5898 void 5899 commit_func(cmd_t *cmd) 5900 { 5901 int arg; 5902 5903 optind = 0; 5904 if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 5905 switch (arg) { 5906 case '?': 5907 longer_usage(CMD_COMMIT); 5908 return; 5909 default: 5910 short_usage(CMD_COMMIT); 5911 return; 5912 } 5913 } 5914 if (optind != cmd->cmd_argc) { 5915 short_usage(CMD_COMMIT); 5916 return; 5917 } 5918 5919 if (zone_is_read_only(CMD_COMMIT)) 5920 return; 5921 5922 assert(cmd != NULL); 5923 5924 cmd->cmd_argc = 1; 5925 /* 5926 * cmd_arg normally comes from a strdup() in the lexer, and the 5927 * whole cmd structure and its (char *) attributes are freed at 5928 * the completion of each command, so the strdup() below is needed 5929 * to match this and prevent a core dump from trying to free() 5930 * something that can't be. 5931 */ 5932 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 5933 zone_perror(zone, Z_NOMEM, TRUE); 5934 exit(Z_ERR); 5935 } 5936 cmd->cmd_argv[1] = NULL; 5937 verify_func(cmd); 5938 } 5939 5940 void 5941 revert_func(cmd_t *cmd) 5942 { 5943 char line[128]; /* enough to ask a question */ 5944 bool force = FALSE; 5945 int err, arg, answer; 5946 5947 optind = 0; 5948 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 5949 switch (arg) { 5950 case '?': 5951 longer_usage(CMD_REVERT); 5952 return; 5953 case 'F': 5954 force = TRUE; 5955 break; 5956 default: 5957 short_usage(CMD_REVERT); 5958 return; 5959 } 5960 } 5961 if (optind != cmd->cmd_argc) { 5962 short_usage(CMD_REVERT); 5963 return; 5964 } 5965 5966 if (zone_is_read_only(CMD_REVERT)) 5967 return; 5968 5969 if (zonecfg_check_handle(handle) != Z_OK) { 5970 zerr(gettext("No changes to revert.")); 5971 saw_error = TRUE; 5972 return; 5973 } 5974 5975 if (!force) { 5976 (void) snprintf(line, sizeof (line), 5977 gettext("Are you sure you want to revert")); 5978 if ((answer = ask_yesno(FALSE, line)) == -1) { 5979 zerr(gettext("Input not from terminal and -F not " 5980 "specified:\n%s command ignored, exiting."), 5981 cmd_to_str(CMD_REVERT)); 5982 exit(Z_ERR); 5983 } 5984 if (answer != 1) 5985 return; 5986 } 5987 5988 /* 5989 * Time for a new handle: finish the old one off first 5990 * then get a new one properly to avoid leaks. 5991 */ 5992 zonecfg_fini_handle(handle); 5993 if ((handle = zonecfg_init_handle()) == NULL) { 5994 zone_perror(execname, Z_NOMEM, TRUE); 5995 exit(Z_ERR); 5996 } 5997 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 5998 saw_error = TRUE; 5999 got_handle = FALSE; 6000 if (err == Z_NO_ZONE) 6001 zerr(gettext("%s: no such saved zone to revert to."), 6002 revert_zone); 6003 else 6004 zone_perror(zone, err, TRUE); 6005 } 6006 (void) strlcpy(zone, revert_zone, sizeof (zone)); 6007 } 6008 6009 void 6010 help_func(cmd_t *cmd) 6011 { 6012 int i; 6013 6014 assert(cmd != NULL); 6015 6016 if (cmd->cmd_argc == 0) { 6017 usage(TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 6018 return; 6019 } 6020 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 6021 usage(TRUE, HELP_USAGE); 6022 return; 6023 } 6024 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 6025 usage(TRUE, HELP_SUBCMDS); 6026 return; 6027 } 6028 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 6029 usage(TRUE, HELP_SYNTAX | HELP_RES_PROPS); 6030 return; 6031 } 6032 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 6033 longer_usage(CMD_HELP); 6034 return; 6035 } 6036 6037 for (i = 0; i <= CMD_MAX; i++) { 6038 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 6039 longer_usage(i); 6040 return; 6041 } 6042 } 6043 /* We do not use zerr() here because we do not want its extra \n. */ 6044 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 6045 cmd->cmd_argv[0]); 6046 usage(FALSE, HELP_META); 6047 } 6048 6049 static int 6050 string_to_yyin(char *string) 6051 { 6052 if ((yyin = tmpfile()) == NULL) { 6053 zone_perror(execname, Z_TEMP_FILE, TRUE); 6054 return (Z_ERR); 6055 } 6056 if (fwrite(string, strlen(string), 1, yyin) != 1) { 6057 zone_perror(execname, Z_TEMP_FILE, TRUE); 6058 return (Z_ERR); 6059 } 6060 if (fseek(yyin, 0, SEEK_SET) != 0) { 6061 zone_perror(execname, Z_TEMP_FILE, TRUE); 6062 return (Z_ERR); 6063 } 6064 return (Z_OK); 6065 } 6066 6067 /* This is the back-end helper function for read_input() below. */ 6068 6069 static int 6070 cleanup() 6071 { 6072 int answer; 6073 cmd_t *cmd; 6074 6075 if (!interactive_mode && !cmd_file_mode) { 6076 /* 6077 * If we're not in interactive mode, and we're not in command 6078 * file mode, then we must be in commands-from-the-command-line 6079 * mode. As such, we can't loop back and ask for more input. 6080 * It was OK to prompt for such things as whether or not to 6081 * really delete a zone in the command handler called from 6082 * yyparse() above, but "really quit?" makes no sense in this 6083 * context. So disable prompting. 6084 */ 6085 ok_to_prompt = FALSE; 6086 } 6087 if (!global_scope) { 6088 if (!time_to_exit) { 6089 /* 6090 * Just print a simple error message in the -1 case, 6091 * since exit_func() already handles that case, and 6092 * EOF means we are finished anyway. 6093 */ 6094 answer = ask_yesno(FALSE, 6095 gettext("Resource incomplete; really quit")); 6096 if (answer == -1) { 6097 zerr(gettext("Resource incomplete.")); 6098 return (Z_ERR); 6099 } 6100 if (answer != 1) { 6101 yyin = stdin; 6102 return (Z_REPEAT); 6103 } 6104 } else { 6105 saw_error = TRUE; 6106 } 6107 } 6108 /* 6109 * Make sure we tried something and that the handle checks 6110 * out, or we would get a false error trying to commit. 6111 */ 6112 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 6113 if ((cmd = alloc_cmd()) == NULL) { 6114 zone_perror(zone, Z_NOMEM, TRUE); 6115 return (Z_ERR); 6116 } 6117 cmd->cmd_argc = 0; 6118 cmd->cmd_argv[0] = NULL; 6119 commit_func(cmd); 6120 free_cmd(cmd); 6121 /* 6122 * need_to_commit will get set back to FALSE if the 6123 * configuration is saved successfully. 6124 */ 6125 if (need_to_commit) { 6126 if (force_exit) { 6127 zerr(gettext("Configuration not saved.")); 6128 return (Z_ERR); 6129 } 6130 answer = ask_yesno(FALSE, 6131 gettext("Configuration not saved; really quit")); 6132 if (answer == -1) { 6133 zerr(gettext("Configuration not saved.")); 6134 return (Z_ERR); 6135 } 6136 if (answer != 1) { 6137 time_to_exit = FALSE; 6138 yyin = stdin; 6139 return (Z_REPEAT); 6140 } 6141 } 6142 } 6143 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 6144 } 6145 6146 /* 6147 * read_input() is the driver of this program. It is a wrapper around 6148 * yyparse(), printing appropriate prompts when needed, checking for 6149 * exit conditions and reacting appropriately [the latter in its cleanup() 6150 * helper function]. 6151 * 6152 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 6153 * so do_interactive() knows that we are not really done (i.e, we asked 6154 * the user if we should really quit and the user said no). 6155 */ 6156 static int 6157 read_input() 6158 { 6159 bool yyin_is_a_tty = isatty(fileno(yyin)); 6160 /* 6161 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 6162 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 6163 */ 6164 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 6165 6166 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 6167 newline_terminated = TRUE; 6168 for (;;) { 6169 if (yyin_is_a_tty) { 6170 if (newline_terminated) { 6171 if (global_scope) 6172 (void) snprintf(prompt, sizeof (prompt), 6173 "%s:%s> ", execname, zone); 6174 else 6175 (void) snprintf(prompt, sizeof (prompt), 6176 "%s:%s:%s> ", execname, zone, 6177 rt_to_str(resource_scope)); 6178 } 6179 /* 6180 * If the user hits ^C then we want to catch it and 6181 * start over. If the user hits EOF then we want to 6182 * bail out. 6183 */ 6184 line = gl_get_line(gl, prompt, NULL, -1); 6185 if (gl_return_status(gl) == GLR_SIGNAL) { 6186 gl_abandon_line(gl); 6187 continue; 6188 } 6189 if (line == NULL) 6190 break; 6191 (void) string_to_yyin(line); 6192 while (!feof(yyin)) 6193 yyparse(); 6194 } else { 6195 yyparse(); 6196 } 6197 /* Bail out on an error in command file mode. */ 6198 if (saw_error && cmd_file_mode && !interactive_mode) 6199 time_to_exit = TRUE; 6200 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 6201 break; 6202 } 6203 return (cleanup()); 6204 } 6205 6206 /* 6207 * This function is used in the zonecfg-interactive-mode scenario: it just 6208 * calls read_input() until we are done. 6209 */ 6210 6211 static int 6212 do_interactive(void) 6213 { 6214 int err; 6215 6216 interactive_mode = TRUE; 6217 if (!read_only_mode) { 6218 /* 6219 * Try to set things up proactively in interactive mode, so 6220 * that if the zone in question does not exist yet, we can 6221 * provide the user with a clue. 6222 */ 6223 (void) initialize(FALSE); 6224 } 6225 do { 6226 err = read_input(); 6227 } while (err == Z_REPEAT); 6228 return (err); 6229 } 6230 6231 /* 6232 * cmd_file is slightly more complicated, as it has to open the command file 6233 * and set yyin appropriately. Once that is done, though, it just calls 6234 * read_input(), and only once, since prompting is not possible. 6235 */ 6236 6237 static int 6238 cmd_file(char *file) 6239 { 6240 FILE *infile; 6241 int err; 6242 struct stat statbuf; 6243 bool using_real_file = (strcmp(file, "-") != 0); 6244 6245 if (using_real_file) { 6246 /* 6247 * zerr() prints a line number in cmd_file_mode, which we do 6248 * not want here, so temporarily unset it. 6249 */ 6250 cmd_file_mode = FALSE; 6251 if ((infile = fopen(file, "r")) == NULL) { 6252 zerr(gettext("could not open file %s: %s"), 6253 file, strerror(errno)); 6254 return (Z_ERR); 6255 } 6256 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 6257 zerr(gettext("could not stat file %s: %s"), 6258 file, strerror(errno)); 6259 err = Z_ERR; 6260 goto done; 6261 } 6262 if (!S_ISREG(statbuf.st_mode)) { 6263 zerr(gettext("%s is not a regular file."), file); 6264 err = Z_ERR; 6265 goto done; 6266 } 6267 yyin = infile; 6268 cmd_file_mode = TRUE; 6269 ok_to_prompt = FALSE; 6270 } else { 6271 /* 6272 * "-f -" is essentially the same as interactive mode, 6273 * so treat it that way. 6274 */ 6275 interactive_mode = TRUE; 6276 } 6277 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 6278 if ((err = read_input()) == Z_REPEAT) 6279 err = Z_ERR; 6280 done: 6281 if (using_real_file) 6282 (void) fclose(infile); 6283 return (err); 6284 } 6285 6286 /* 6287 * Since yacc is based on reading from a (FILE *) whereas what we get from 6288 * the command line is in argv format, we need to convert when the user 6289 * gives us commands directly from the command line. That is done here by 6290 * concatenating the argv list into a space-separated string, writing it 6291 * to a temp file, and rewinding the file so yyin can be set to it. Then 6292 * we call read_input(), and only once, since prompting about whether to 6293 * continue or quit would make no sense in this context. 6294 */ 6295 6296 static int 6297 one_command_at_a_time(int argc, char *argv[]) 6298 { 6299 char *command; 6300 size_t len = 2; /* terminal \n\0 */ 6301 int i, err; 6302 6303 for (i = 0; i < argc; i++) 6304 len += strlen(argv[i]) + 1; 6305 if ((command = malloc(len)) == NULL) { 6306 zone_perror(execname, Z_NOMEM, TRUE); 6307 return (Z_ERR); 6308 } 6309 (void) strlcpy(command, argv[0], len); 6310 for (i = 1; i < argc; i++) { 6311 (void) strlcat(command, " ", len); 6312 (void) strlcat(command, argv[i], len); 6313 } 6314 (void) strlcat(command, "\n", len); 6315 err = string_to_yyin(command); 6316 free(command); 6317 if (err != Z_OK) 6318 return (err); 6319 while (!feof(yyin)) 6320 yyparse(); 6321 return (cleanup()); 6322 } 6323 6324 static char * 6325 get_execbasename(char *execfullname) 6326 { 6327 char *last_slash, *execbasename; 6328 6329 /* guard against '/' at end of command invocation */ 6330 for (;;) { 6331 last_slash = strrchr(execfullname, '/'); 6332 if (last_slash == NULL) { 6333 execbasename = execfullname; 6334 break; 6335 } else { 6336 execbasename = last_slash + 1; 6337 if (*execbasename == '\0') { 6338 *last_slash = '\0'; 6339 continue; 6340 } 6341 break; 6342 } 6343 } 6344 return (execbasename); 6345 } 6346 6347 int 6348 main(int argc, char *argv[]) 6349 { 6350 int err, arg; 6351 struct stat st; 6352 6353 /* This must be before anything goes to stdout. */ 6354 setbuf(stdout, NULL); 6355 6356 saw_error = FALSE; 6357 cmd_file_mode = FALSE; 6358 execname = get_execbasename(argv[0]); 6359 6360 (void) setlocale(LC_ALL, ""); 6361 (void) textdomain(TEXT_DOMAIN); 6362 6363 if (getzoneid() != GLOBAL_ZONEID) { 6364 zerr(gettext("%s can only be run from the global zone."), 6365 execname); 6366 exit(Z_ERR); 6367 } 6368 6369 if (argc < 2) { 6370 usage(FALSE, HELP_USAGE | HELP_SUBCMDS); 6371 exit(Z_USAGE); 6372 } 6373 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 6374 (void) one_command_at_a_time(argc - 1, &(argv[1])); 6375 exit(Z_OK); 6376 } 6377 6378 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 6379 switch (arg) { 6380 case '?': 6381 if (optopt == '?') 6382 usage(TRUE, HELP_USAGE | HELP_SUBCMDS); 6383 else 6384 usage(FALSE, HELP_USAGE); 6385 exit(Z_USAGE); 6386 /* NOTREACHED */ 6387 case 'f': 6388 cmd_file_name = optarg; 6389 cmd_file_mode = TRUE; 6390 break; 6391 case 'R': 6392 if (*optarg != '/') { 6393 zerr(gettext("root path must be absolute: %s"), 6394 optarg); 6395 exit(Z_USAGE); 6396 } 6397 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 6398 zerr(gettext( 6399 "root path must be a directory: %s"), 6400 optarg); 6401 exit(Z_USAGE); 6402 } 6403 zonecfg_set_root(optarg); 6404 break; 6405 case 'z': 6406 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) { 6407 global_zone = TRUE; 6408 } else if (zonecfg_validate_zonename(optarg) != Z_OK) { 6409 zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE); 6410 usage(FALSE, HELP_SYNTAX); 6411 exit(Z_USAGE); 6412 } 6413 (void) strlcpy(zone, optarg, sizeof (zone)); 6414 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 6415 break; 6416 default: 6417 usage(FALSE, HELP_USAGE); 6418 exit(Z_USAGE); 6419 } 6420 } 6421 6422 if (optind > argc || strcmp(zone, "") == 0) { 6423 usage(FALSE, HELP_USAGE); 6424 exit(Z_USAGE); 6425 } 6426 6427 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 6428 read_only_mode = FALSE; 6429 } else if (err == Z_ACCES) { 6430 read_only_mode = TRUE; 6431 /* skip this message in one-off from command line mode */ 6432 if (optind == argc) 6433 (void) fprintf(stderr, gettext("WARNING: you do not " 6434 "have write access to this zone's configuration " 6435 "file;\ngoing into read-only mode.\n")); 6436 } else { 6437 fprintf(stderr, "%s: Could not access zone configuration " 6438 "store: %s\n", execname, zonecfg_strerror(err)); 6439 exit(Z_ERR); 6440 } 6441 6442 if ((handle = zonecfg_init_handle()) == NULL) { 6443 zone_perror(execname, Z_NOMEM, TRUE); 6444 exit(Z_ERR); 6445 } 6446 6447 /* 6448 * This may get set back to FALSE again in cmd_file() if cmd_file_name 6449 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 6450 */ 6451 if (isatty(STDIN_FILENO)) 6452 ok_to_prompt = TRUE; 6453 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 6454 exit(Z_ERR); 6455 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 6456 exit(Z_ERR); 6457 (void) sigset(SIGINT, SIG_IGN); 6458 if (optind == argc) { 6459 if (!cmd_file_mode) 6460 err = do_interactive(); 6461 else 6462 err = cmd_file(cmd_file_name); 6463 } else { 6464 err = one_command_at_a_time(argc - optind, &(argv[optind])); 6465 } 6466 zonecfg_fini_handle(handle); 6467 if (brand != NULL) 6468 brand_close(brand); 6469 (void) del_GetLine(gl); 6470 return (err); 6471 } 6472