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