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