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