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