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