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 char *quote_str; 1827 1828 if (strlen(prop_id) == 0) 1829 return; 1830 quote_str = quoteit(prop_id); 1831 (void) fprintf(of, "%s %s=\"%s\"\n", cmd_to_str(CMD_SET), 1832 pt_to_str(prop_num), quote_str); 1833 free(quote_str); 1834 } 1835 1836 void 1837 export_func(cmd_t *cmd) 1838 { 1839 struct zone_nwiftab nwiftab; 1840 struct zone_fstab fstab; 1841 struct zone_devtab devtab; 1842 struct zone_attrtab attrtab; 1843 struct zone_rctltab rctltab; 1844 struct zone_dstab dstab; 1845 struct zone_psettab psettab; 1846 struct zone_mcaptab mcaptab; 1847 struct zone_rctlvaltab *valptr; 1848 struct zone_admintab admintab; 1849 struct zone_secflagstab secflagstab; 1850 int err, arg; 1851 char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN]; 1852 char bootargs[BOOTARGS_MAX]; 1853 char sched[MAXNAMELEN]; 1854 char brand[MAXNAMELEN]; 1855 char hostidp[HW_HOSTID_LEN]; 1856 char fsallowedp[ZONE_FS_ALLOWED_MAX]; 1857 char *limitpriv; 1858 FILE *of; 1859 boolean_t autoboot; 1860 zone_iptype_t iptype; 1861 boolean_t need_to_close = B_FALSE; 1862 boolean_t arg_err = B_FALSE; 1863 1864 assert(cmd != NULL); 1865 1866 outfile[0] = '\0'; 1867 optind = 0; 1868 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?f:")) != EOF) { 1869 switch (arg) { 1870 case '?': 1871 if (optopt == '?') 1872 longer_usage(CMD_EXPORT); 1873 else 1874 short_usage(CMD_EXPORT); 1875 arg_err = B_TRUE; 1876 break; 1877 case 'f': 1878 (void) strlcpy(outfile, optarg, sizeof (outfile)); 1879 break; 1880 default: 1881 short_usage(CMD_EXPORT); 1882 arg_err = B_TRUE; 1883 break; 1884 } 1885 } 1886 if (arg_err) 1887 return; 1888 1889 if (optind != cmd->cmd_argc) { 1890 short_usage(CMD_EXPORT); 1891 return; 1892 } 1893 if (strlen(outfile) == 0) { 1894 of = stdout; 1895 } else { 1896 if ((of = fopen(outfile, "w")) == NULL) { 1897 zerr(gettext("opening file %s: %s"), 1898 outfile, strerror(errno)); 1899 goto done; 1900 } 1901 setbuf(of, NULL); 1902 need_to_close = B_TRUE; 1903 } 1904 1905 if ((err = initialize(B_TRUE)) != Z_OK) 1906 goto done; 1907 1908 (void) fprintf(of, "%s -b\n", cmd_to_str(CMD_CREATE)); 1909 1910 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK && 1911 strlen(zonepath) > 0) 1912 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1913 pt_to_str(PT_ZONEPATH), zonepath); 1914 1915 if ((zone_get_brand(zone, brand, sizeof (brand)) == Z_OK) && 1916 (strcmp(brand, NATIVE_BRAND_NAME) != 0)) 1917 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1918 pt_to_str(PT_BRAND), brand); 1919 1920 if (zonecfg_get_autoboot(handle, &autoboot) == Z_OK) 1921 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1922 pt_to_str(PT_AUTOBOOT), autoboot ? "true" : "false"); 1923 1924 if (zonecfg_get_bootargs(handle, bootargs, sizeof (bootargs)) == Z_OK && 1925 strlen(bootargs) > 0) { 1926 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1927 pt_to_str(PT_BOOTARGS), bootargs); 1928 } 1929 1930 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 1931 strlen(pool) > 0) 1932 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1933 pt_to_str(PT_POOL), pool); 1934 1935 if (zonecfg_get_limitpriv(handle, &limitpriv) == Z_OK && 1936 strlen(limitpriv) > 0) { 1937 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1938 pt_to_str(PT_LIMITPRIV), limitpriv); 1939 free(limitpriv); 1940 } 1941 1942 if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK && 1943 strlen(sched) > 0) 1944 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1945 pt_to_str(PT_SCHED), sched); 1946 1947 if (zonecfg_get_iptype(handle, &iptype) == Z_OK) { 1948 switch (iptype) { 1949 case ZS_SHARED: 1950 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1951 pt_to_str(PT_IPTYPE), "shared"); 1952 break; 1953 case ZS_EXCLUSIVE: 1954 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1955 pt_to_str(PT_IPTYPE), "exclusive"); 1956 break; 1957 } 1958 } 1959 1960 if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) { 1961 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1962 pt_to_str(PT_HOSTID), hostidp); 1963 } 1964 1965 if (zonecfg_get_fs_allowed(handle, fsallowedp, 1966 sizeof (fsallowedp)) == Z_OK) { 1967 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 1968 pt_to_str(PT_FS_ALLOWED), fsallowedp); 1969 } 1970 1971 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 1972 zone_perror(zone, err, B_FALSE); 1973 goto done; 1974 } 1975 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 1976 zone_fsopt_t *optptr; 1977 1978 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 1979 rt_to_str(RT_FS)); 1980 export_prop(of, PT_DIR, fstab.zone_fs_dir); 1981 export_prop(of, PT_SPECIAL, fstab.zone_fs_special); 1982 export_prop(of, PT_RAW, fstab.zone_fs_raw); 1983 export_prop(of, PT_TYPE, fstab.zone_fs_type); 1984 for (optptr = fstab.zone_fs_options; optptr != NULL; 1985 optptr = optptr->zone_fsopt_next) { 1986 /* 1987 * Simple property values with embedded equal signs 1988 * need to be quoted to prevent the lexer from 1989 * mis-parsing them as complex name=value pairs. 1990 */ 1991 if (strchr(optptr->zone_fsopt_opt, '=')) 1992 (void) fprintf(of, "%s %s \"%s\"\n", 1993 cmd_to_str(CMD_ADD), 1994 pt_to_str(PT_OPTIONS), 1995 optptr->zone_fsopt_opt); 1996 else 1997 (void) fprintf(of, "%s %s %s\n", 1998 cmd_to_str(CMD_ADD), 1999 pt_to_str(PT_OPTIONS), 2000 optptr->zone_fsopt_opt); 2001 } 2002 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2003 zonecfg_free_fs_option_list(fstab.zone_fs_options); 2004 } 2005 (void) zonecfg_endfsent(handle); 2006 2007 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 2008 zone_perror(zone, err, B_FALSE); 2009 goto done; 2010 } 2011 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 2012 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2013 rt_to_str(RT_NET)); 2014 export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address); 2015 export_prop(of, PT_ALLOWED_ADDRESS, 2016 nwiftab.zone_nwif_allowed_address); 2017 export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical); 2018 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter); 2019 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2020 } 2021 (void) zonecfg_endnwifent(handle); 2022 2023 if ((err = zonecfg_setdevent(handle)) != Z_OK) { 2024 zone_perror(zone, err, B_FALSE); 2025 goto done; 2026 } 2027 while (zonecfg_getdevent(handle, &devtab) == Z_OK) { 2028 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2029 rt_to_str(RT_DEVICE)); 2030 export_prop(of, PT_MATCH, devtab.zone_dev_match); 2031 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2032 } 2033 (void) zonecfg_enddevent(handle); 2034 2035 if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) { 2036 char buf[128]; 2037 2038 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2039 rt_to_str(RT_MCAP)); 2040 bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf)); 2041 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 2042 pt_to_str(PT_PHYSICAL), buf); 2043 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2044 } 2045 2046 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 2047 zone_perror(zone, err, B_FALSE); 2048 goto done; 2049 } 2050 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 2051 (void) fprintf(of, "%s rctl\n", cmd_to_str(CMD_ADD)); 2052 export_prop(of, PT_NAME, rctltab.zone_rctl_name); 2053 for (valptr = rctltab.zone_rctl_valptr; valptr != NULL; 2054 valptr = valptr->zone_rctlval_next) { 2055 fprintf(of, "%s %s (%s=%s,%s=%s,%s=%s)\n", 2056 cmd_to_str(CMD_ADD), pt_to_str(PT_VALUE), 2057 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 2058 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 2059 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 2060 } 2061 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2062 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 2063 } 2064 (void) zonecfg_endrctlent(handle); 2065 2066 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 2067 zone_perror(zone, err, B_FALSE); 2068 goto done; 2069 } 2070 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 2071 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2072 rt_to_str(RT_ATTR)); 2073 export_prop(of, PT_NAME, attrtab.zone_attr_name); 2074 export_prop(of, PT_TYPE, attrtab.zone_attr_type); 2075 export_prop(of, PT_VALUE, attrtab.zone_attr_value); 2076 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2077 } 2078 (void) zonecfg_endattrent(handle); 2079 2080 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 2081 zone_perror(zone, err, B_FALSE); 2082 goto done; 2083 } 2084 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 2085 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2086 rt_to_str(RT_DATASET)); 2087 export_prop(of, PT_NAME, dstab.zone_dataset_name); 2088 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2089 } 2090 (void) zonecfg_enddsent(handle); 2091 2092 if (zonecfg_getpsetent(handle, &psettab) == Z_OK) { 2093 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2094 rt_to_str(RT_DCPU)); 2095 if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0) 2096 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 2097 pt_to_str(PT_NCPUS), psettab.zone_ncpu_max); 2098 else 2099 (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET), 2100 pt_to_str(PT_NCPUS), psettab.zone_ncpu_min, 2101 psettab.zone_ncpu_max); 2102 if (psettab.zone_importance[0] != '\0') 2103 (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), 2104 pt_to_str(PT_IMPORTANCE), psettab.zone_importance); 2105 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2106 } 2107 2108 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 2109 zone_perror(zone, err, B_FALSE); 2110 goto done; 2111 } 2112 while (zonecfg_getadminent(handle, &admintab) == Z_OK) { 2113 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2114 rt_to_str(RT_ADMIN)); 2115 export_prop(of, PT_USER, admintab.zone_admin_user); 2116 export_prop(of, PT_AUTHS, admintab.zone_admin_auths); 2117 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2118 } 2119 2120 (void) zonecfg_endadminent(handle); 2121 2122 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) { 2123 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), 2124 rt_to_str(RT_SECFLAGS)); 2125 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default); 2126 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower); 2127 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper); 2128 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); 2129 } 2130 2131 /* 2132 * There is nothing to export for pcap since this resource is just 2133 * a container for an rctl alias. 2134 */ 2135 2136 done: 2137 if (need_to_close) 2138 (void) fclose(of); 2139 } 2140 2141 void 2142 exit_func(cmd_t *cmd) 2143 { 2144 int arg, answer; 2145 boolean_t arg_err = B_FALSE; 2146 2147 optind = 0; 2148 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2149 switch (arg) { 2150 case '?': 2151 longer_usage(CMD_EXIT); 2152 arg_err = B_TRUE; 2153 break; 2154 case 'F': 2155 force_exit = B_TRUE; 2156 break; 2157 default: 2158 short_usage(CMD_EXIT); 2159 arg_err = B_TRUE; 2160 break; 2161 } 2162 } 2163 if (arg_err) 2164 return; 2165 2166 if (optind < cmd->cmd_argc) { 2167 short_usage(CMD_EXIT); 2168 return; 2169 } 2170 2171 if (global_scope || force_exit) { 2172 time_to_exit = B_TRUE; 2173 return; 2174 } 2175 2176 answer = ask_yesno(B_FALSE, "Resource incomplete; really quit"); 2177 if (answer == -1) { 2178 zerr(gettext("Resource incomplete, input " 2179 "not from terminal and -F not specified:\n%s command " 2180 "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT)); 2181 exit(Z_ERR); 2182 } else if (answer == 1) { 2183 time_to_exit = B_TRUE; 2184 } 2185 /* (answer == 0) => just return */ 2186 } 2187 2188 static int 2189 validate_zonepath_syntax(char *path) 2190 { 2191 if (path[0] != '/') { 2192 zerr(gettext("%s is not an absolute path."), path); 2193 return (Z_ERR); 2194 } 2195 /* If path is all slashes, then fail */ 2196 if (strspn(path, "/") == strlen(path)) { 2197 zerr(gettext("/ is not allowed as a %s."), 2198 pt_to_str(PT_ZONEPATH)); 2199 return (Z_ERR); 2200 } 2201 return (Z_OK); 2202 } 2203 2204 static void 2205 add_resource(cmd_t *cmd) 2206 { 2207 int type; 2208 struct zone_psettab tmp_psettab; 2209 struct zone_mcaptab tmp_mcaptab; 2210 struct zone_secflagstab tmp_secflagstab; 2211 uint64_t tmp; 2212 uint64_t tmp_mcap; 2213 char pool[MAXNAMELEN]; 2214 2215 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 2216 long_usage(CMD_ADD, B_TRUE); 2217 goto bad; 2218 } 2219 2220 switch (type) { 2221 case RT_FS: 2222 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 2223 return; 2224 case RT_NET: 2225 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 2226 return; 2227 case RT_DEVICE: 2228 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 2229 return; 2230 case RT_RCTL: 2231 if (global_zone) 2232 zerr(gettext("WARNING: Setting a global zone resource " 2233 "control too low could deny\nservice " 2234 "to even the root user; " 2235 "this could render the system impossible\n" 2236 "to administer. Please use caution.")); 2237 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 2238 return; 2239 case RT_ATTR: 2240 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 2241 return; 2242 case RT_DATASET: 2243 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 2244 return; 2245 case RT_DCPU: 2246 /* Make sure there isn't already a cpu-set or cpu-cap entry. */ 2247 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2248 zerr(gettext("The %s resource already exists."), 2249 rt_to_str(RT_DCPU)); 2250 goto bad; 2251 } 2252 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != 2253 Z_NO_ENTRY) { 2254 zerr(gettext("The %s resource already exists."), 2255 rt_to_str(RT_PCAP)); 2256 goto bad; 2257 } 2258 2259 /* Make sure the pool property isn't set. */ 2260 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && 2261 strlen(pool) > 0) { 2262 zerr(gettext("The %s property is already set. " 2263 "A persistent pool is incompatible with\nthe %s " 2264 "resource."), 2265 pt_to_str(PT_POOL), rt_to_str(RT_DCPU)); 2266 goto bad; 2267 } 2268 2269 bzero(&in_progress_psettab, sizeof (in_progress_psettab)); 2270 return; 2271 case RT_PCAP: 2272 /* 2273 * Make sure there isn't already a cpu-set or incompatible 2274 * cpu-cap rctls. 2275 */ 2276 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 2277 zerr(gettext("The %s resource already exists."), 2278 rt_to_str(RT_DCPU)); 2279 goto bad; 2280 } 2281 2282 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) { 2283 case Z_ALIAS_DISALLOW: 2284 zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW, 2285 B_FALSE); 2286 goto bad; 2287 2288 case Z_OK: 2289 zerr(gettext("The %s resource already exists."), 2290 rt_to_str(RT_PCAP)); 2291 goto bad; 2292 2293 default: 2294 break; 2295 } 2296 return; 2297 case RT_MCAP: 2298 /* 2299 * Make sure there isn't already a mem-cap entry or max-swap 2300 * or max-locked rctl. 2301 */ 2302 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK || 2303 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap) 2304 == Z_OK || 2305 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 2306 &tmp_mcap) == Z_OK) { 2307 zerr(gettext("The %s resource or a related resource " 2308 "control already exists."), rt_to_str(RT_MCAP)); 2309 goto bad; 2310 } 2311 if (global_zone) 2312 zerr(gettext("WARNING: Setting a global zone memory " 2313 "cap too low could deny\nservice " 2314 "to even the root user; " 2315 "this could render the system impossible\n" 2316 "to administer. Please use caution.")); 2317 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab)); 2318 return; 2319 case RT_ADMIN: 2320 bzero(&in_progress_admintab, sizeof (in_progress_admintab)); 2321 return; 2322 case RT_SECFLAGS: 2323 /* Make sure we haven't already set this */ 2324 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK) 2325 zerr(gettext("The %s resource already exists."), 2326 rt_to_str(RT_SECFLAGS)); 2327 bzero(&in_progress_secflagstab, 2328 sizeof (in_progress_secflagstab)); 2329 return; 2330 default: 2331 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 2332 long_usage(CMD_ADD, B_TRUE); 2333 usage(B_FALSE, HELP_RESOURCES); 2334 } 2335 bad: 2336 global_scope = B_TRUE; 2337 end_op = -1; 2338 } 2339 2340 static void 2341 do_complex_rctl_val(complex_property_ptr_t cp) 2342 { 2343 struct zone_rctlvaltab *rctlvaltab; 2344 complex_property_ptr_t cx; 2345 boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE, 2346 seen_action = B_FALSE; 2347 rctlblk_t *rctlblk; 2348 int err; 2349 2350 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 2351 zone_perror(zone, Z_NOMEM, B_TRUE); 2352 exit(Z_ERR); 2353 } 2354 for (cx = cp; cx != NULL; cx = cx->cp_next) { 2355 switch (cx->cp_type) { 2356 case PT_PRIV: 2357 if (seen_priv) { 2358 zerr(gettext("%s already specified"), 2359 pt_to_str(PT_PRIV)); 2360 goto bad; 2361 } 2362 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 2363 cx->cp_value, 2364 sizeof (rctlvaltab->zone_rctlval_priv)); 2365 seen_priv = B_TRUE; 2366 break; 2367 case PT_LIMIT: 2368 if (seen_limit) { 2369 zerr(gettext("%s already specified"), 2370 pt_to_str(PT_LIMIT)); 2371 goto bad; 2372 } 2373 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 2374 cx->cp_value, 2375 sizeof (rctlvaltab->zone_rctlval_limit)); 2376 seen_limit = B_TRUE; 2377 break; 2378 case PT_ACTION: 2379 if (seen_action) { 2380 zerr(gettext("%s already specified"), 2381 pt_to_str(PT_ACTION)); 2382 goto bad; 2383 } 2384 (void) strlcpy(rctlvaltab->zone_rctlval_action, 2385 cx->cp_value, 2386 sizeof (rctlvaltab->zone_rctlval_action)); 2387 seen_action = B_TRUE; 2388 break; 2389 default: 2390 zone_perror(pt_to_str(PT_VALUE), 2391 Z_NO_PROPERTY_TYPE, B_TRUE); 2392 long_usage(CMD_ADD, B_TRUE); 2393 usage(B_FALSE, HELP_PROPS); 2394 zonecfg_free_rctl_value_list(rctlvaltab); 2395 return; 2396 } 2397 } 2398 if (!seen_priv) 2399 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV)); 2400 if (!seen_limit) 2401 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT)); 2402 if (!seen_action) 2403 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION)); 2404 if (!seen_priv || !seen_limit || !seen_action) 2405 goto bad; 2406 rctlvaltab->zone_rctlval_next = NULL; 2407 rctlblk = alloca(rctlblk_size()); 2408 /* 2409 * Make sure the rctl value looks roughly correct; we won't know if 2410 * it's truly OK until we verify the configuration on the target 2411 * system. 2412 */ 2413 if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK || 2414 !zonecfg_valid_rctlblk(rctlblk)) { 2415 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL), 2416 pt_to_str(PT_VALUE)); 2417 goto bad; 2418 } 2419 err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab); 2420 if (err != Z_OK) 2421 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE); 2422 return; 2423 2424 bad: 2425 zonecfg_free_rctl_value_list(rctlvaltab); 2426 } 2427 2428 static void 2429 add_property(cmd_t *cmd) 2430 { 2431 char *prop_id; 2432 int err, res_type, prop_type; 2433 property_value_ptr_t pp; 2434 list_property_ptr_t l; 2435 2436 res_type = resource_scope; 2437 prop_type = cmd->cmd_prop_name[0]; 2438 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 2439 long_usage(CMD_ADD, B_TRUE); 2440 return; 2441 } 2442 2443 if (cmd->cmd_prop_nv_pairs != 1) { 2444 long_usage(CMD_ADD, B_TRUE); 2445 return; 2446 } 2447 2448 if (initialize(B_TRUE) != Z_OK) 2449 return; 2450 2451 switch (res_type) { 2452 case RT_FS: 2453 if (prop_type != PT_OPTIONS) { 2454 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2455 B_TRUE); 2456 long_usage(CMD_ADD, B_TRUE); 2457 usage(B_FALSE, HELP_PROPS); 2458 return; 2459 } 2460 pp = cmd->cmd_property_ptr[0]; 2461 if (pp->pv_type != PROP_VAL_SIMPLE && 2462 pp->pv_type != PROP_VAL_LIST) { 2463 zerr(gettext("A %s or %s value was expected here."), 2464 pvt_to_str(PROP_VAL_SIMPLE), 2465 pvt_to_str(PROP_VAL_LIST)); 2466 saw_error = B_TRUE; 2467 return; 2468 } 2469 if (pp->pv_type == PROP_VAL_SIMPLE) { 2470 if (pp->pv_simple == NULL) { 2471 long_usage(CMD_ADD, B_TRUE); 2472 return; 2473 } 2474 prop_id = pp->pv_simple; 2475 err = zonecfg_add_fs_option(&in_progress_fstab, 2476 prop_id); 2477 if (err != Z_OK) 2478 zone_perror(pt_to_str(prop_type), err, B_TRUE); 2479 } else { 2480 list_property_ptr_t list; 2481 2482 for (list = pp->pv_list; list != NULL; 2483 list = list->lp_next) { 2484 prop_id = list->lp_simple; 2485 if (prop_id == NULL) 2486 break; 2487 err = zonecfg_add_fs_option( 2488 &in_progress_fstab, prop_id); 2489 if (err != Z_OK) 2490 zone_perror(pt_to_str(prop_type), err, 2491 B_TRUE); 2492 } 2493 } 2494 return; 2495 case RT_RCTL: 2496 if (prop_type != PT_VALUE) { 2497 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 2498 B_TRUE); 2499 long_usage(CMD_ADD, B_TRUE); 2500 usage(B_FALSE, HELP_PROPS); 2501 return; 2502 } 2503 pp = cmd->cmd_property_ptr[0]; 2504 if (pp->pv_type != PROP_VAL_COMPLEX && 2505 pp->pv_type != PROP_VAL_LIST) { 2506 zerr(gettext("A %s or %s value was expected here."), 2507 pvt_to_str(PROP_VAL_COMPLEX), 2508 pvt_to_str(PROP_VAL_LIST)); 2509 saw_error = B_TRUE; 2510 return; 2511 } 2512 if (pp->pv_type == PROP_VAL_COMPLEX) { 2513 do_complex_rctl_val(pp->pv_complex); 2514 return; 2515 } 2516 for (l = pp->pv_list; l != NULL; l = l->lp_next) 2517 do_complex_rctl_val(l->lp_complex); 2518 return; 2519 default: 2520 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 2521 long_usage(CMD_ADD, B_TRUE); 2522 usage(B_FALSE, HELP_RESOURCES); 2523 return; 2524 } 2525 } 2526 2527 static boolean_t 2528 gz_invalid_resource(int type) 2529 { 2530 return (global_zone && (type == RT_FS || 2531 type == RT_NET || type == RT_DEVICE || type == RT_ATTR || 2532 type == RT_DATASET)); 2533 } 2534 2535 static boolean_t 2536 gz_invalid_rt_property(int type) 2537 { 2538 return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH || 2539 type == RT_AUTOBOOT || type == RT_LIMITPRIV || 2540 type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED || 2541 type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED)); 2542 } 2543 2544 static boolean_t 2545 gz_invalid_property(int type) 2546 { 2547 return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH || 2548 type == PT_AUTOBOOT || type == PT_LIMITPRIV || 2549 type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED || 2550 type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED)); 2551 } 2552 2553 void 2554 add_func(cmd_t *cmd) 2555 { 2556 int arg; 2557 boolean_t arg_err = B_FALSE; 2558 2559 assert(cmd != NULL); 2560 2561 optind = 0; 2562 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 2563 switch (arg) { 2564 case '?': 2565 longer_usage(CMD_ADD); 2566 arg_err = B_TRUE; 2567 break; 2568 default: 2569 short_usage(CMD_ADD); 2570 arg_err = B_TRUE; 2571 break; 2572 } 2573 } 2574 if (arg_err) 2575 return; 2576 2577 if (optind != cmd->cmd_argc) { 2578 short_usage(CMD_ADD); 2579 return; 2580 } 2581 2582 if (zone_is_read_only(CMD_ADD)) 2583 return; 2584 2585 if (initialize(B_TRUE) != Z_OK) 2586 return; 2587 if (global_scope) { 2588 if (gz_invalid_resource(cmd->cmd_res_type)) { 2589 zerr(gettext("Cannot add a %s resource to the " 2590 "global zone."), rt_to_str(cmd->cmd_res_type)); 2591 saw_error = B_TRUE; 2592 return; 2593 } 2594 2595 global_scope = B_FALSE; 2596 resource_scope = cmd->cmd_res_type; 2597 end_op = CMD_ADD; 2598 add_resource(cmd); 2599 } else 2600 add_property(cmd); 2601 } 2602 2603 /* 2604 * This routine has an unusual implementation, because it tries very 2605 * hard to succeed in the face of a variety of failure modes. 2606 * The most common and most vexing occurs when the index file and 2607 * the /etc/zones/<zonename.xml> file are not both present. In 2608 * this case, delete must eradicate as much of the zone state as is left 2609 * so that the user can later create a new zone with the same name. 2610 */ 2611 void 2612 delete_func(cmd_t *cmd) 2613 { 2614 int err, arg, answer; 2615 char line[ZONENAME_MAX + 128]; /* enough to ask a question */ 2616 boolean_t force = B_FALSE; 2617 boolean_t arg_err = B_FALSE; 2618 2619 optind = 0; 2620 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 2621 switch (arg) { 2622 case '?': 2623 longer_usage(CMD_DELETE); 2624 arg_err = B_TRUE; 2625 break; 2626 case 'F': 2627 force = B_TRUE; 2628 break; 2629 default: 2630 short_usage(CMD_DELETE); 2631 arg_err = B_TRUE; 2632 break; 2633 } 2634 } 2635 if (arg_err) 2636 return; 2637 2638 if (optind != cmd->cmd_argc) { 2639 short_usage(CMD_DELETE); 2640 return; 2641 } 2642 2643 if (zone_is_read_only(CMD_DELETE)) 2644 return; 2645 2646 if (!force) { 2647 /* 2648 * Initialize sets up the global called "handle" and warns the 2649 * user if the zone is not configured. In force mode, we don't 2650 * trust that evaluation, and hence skip it. (We don't need the 2651 * handle to be loaded anyway, since zonecfg_destroy is done by 2652 * zonename). However, we also have to take care to emulate the 2653 * messages spit out by initialize; see below. 2654 */ 2655 if (initialize(B_TRUE) != Z_OK) 2656 return; 2657 2658 (void) snprintf(line, sizeof (line), 2659 gettext("Are you sure you want to delete zone %s"), zone); 2660 if ((answer = ask_yesno(B_FALSE, line)) == -1) { 2661 zerr(gettext("Input not from terminal and -F not " 2662 "specified:\n%s command ignored, exiting."), 2663 cmd_to_str(CMD_DELETE)); 2664 exit(Z_ERR); 2665 } 2666 if (answer != 1) 2667 return; 2668 } 2669 2670 /* 2671 * This function removes the authorizations from user_attr 2672 * that correspond to those specified in the configuration 2673 */ 2674 if (initialize(B_TRUE) == Z_OK) { 2675 (void) zonecfg_deauthorize_users(handle, zone); 2676 } 2677 if ((err = zonecfg_destroy(zone, force)) != Z_OK) { 2678 if ((err == Z_BAD_ZONE_STATE) && !force) { 2679 zerr(gettext("Zone %s not in %s state; %s not " 2680 "allowed. Use -F to force %s."), 2681 zone, zone_state_str(ZONE_STATE_CONFIGURED), 2682 cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE)); 2683 } else { 2684 zone_perror(zone, err, B_TRUE); 2685 } 2686 } 2687 need_to_commit = B_FALSE; 2688 2689 /* 2690 * Emulate initialize's messaging; if there wasn't a valid handle to 2691 * begin with, then user had typed delete (or delete -F) multiple 2692 * times. So we emit a message. 2693 * 2694 * We only do this in the 'force' case because normally, initialize() 2695 * takes care of this for us. 2696 */ 2697 if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode) 2698 (void) printf(gettext("Use '%s' to begin " 2699 "configuring a new zone.\n"), cmd_to_str(CMD_CREATE)); 2700 2701 /* 2702 * Time for a new handle: finish the old one off first 2703 * then get a new one properly to avoid leaks. 2704 */ 2705 if (got_handle) { 2706 zonecfg_fini_handle(handle); 2707 if ((handle = zonecfg_init_handle()) == NULL) { 2708 zone_perror(execname, Z_NOMEM, B_TRUE); 2709 exit(Z_ERR); 2710 } 2711 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) { 2712 /* If there was no zone before, that's OK */ 2713 if (err != Z_NO_ZONE) 2714 zone_perror(zone, err, B_TRUE); 2715 got_handle = B_FALSE; 2716 } 2717 } 2718 } 2719 2720 static int 2721 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only) 2722 { 2723 int err, i; 2724 property_value_ptr_t pp; 2725 2726 if ((err = initialize(B_TRUE)) != Z_OK) 2727 return (err); 2728 2729 bzero(fstab, sizeof (*fstab)); 2730 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2731 pp = cmd->cmd_property_ptr[i]; 2732 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2733 zerr(gettext("A simple value was expected here.")); 2734 saw_error = B_TRUE; 2735 return (Z_INSUFFICIENT_SPEC); 2736 } 2737 switch (cmd->cmd_prop_name[i]) { 2738 case PT_DIR: 2739 (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple, 2740 sizeof (fstab->zone_fs_dir)); 2741 break; 2742 case PT_SPECIAL: 2743 (void) strlcpy(fstab->zone_fs_special, pp->pv_simple, 2744 sizeof (fstab->zone_fs_special)); 2745 break; 2746 case PT_RAW: 2747 (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple, 2748 sizeof (fstab->zone_fs_raw)); 2749 break; 2750 case PT_TYPE: 2751 (void) strlcpy(fstab->zone_fs_type, pp->pv_simple, 2752 sizeof (fstab->zone_fs_type)); 2753 break; 2754 default: 2755 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2756 Z_NO_PROPERTY_TYPE, B_TRUE); 2757 return (Z_INSUFFICIENT_SPEC); 2758 } 2759 } 2760 if (fill_in_only) 2761 return (Z_OK); 2762 return (zonecfg_lookup_filesystem(handle, fstab)); 2763 } 2764 2765 static int 2766 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab, 2767 boolean_t fill_in_only) 2768 { 2769 int err, i; 2770 property_value_ptr_t pp; 2771 2772 if ((err = initialize(B_TRUE)) != Z_OK) 2773 return (err); 2774 2775 bzero(nwiftab, sizeof (*nwiftab)); 2776 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2777 pp = cmd->cmd_property_ptr[i]; 2778 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2779 zerr(gettext("A simple value was expected here.")); 2780 saw_error = B_TRUE; 2781 return (Z_INSUFFICIENT_SPEC); 2782 } 2783 switch (cmd->cmd_prop_name[i]) { 2784 case PT_ADDRESS: 2785 (void) strlcpy(nwiftab->zone_nwif_address, 2786 pp->pv_simple, sizeof (nwiftab->zone_nwif_address)); 2787 break; 2788 case PT_ALLOWED_ADDRESS: 2789 (void) strlcpy(nwiftab->zone_nwif_allowed_address, 2790 pp->pv_simple, 2791 sizeof (nwiftab->zone_nwif_allowed_address)); 2792 break; 2793 case PT_PHYSICAL: 2794 (void) strlcpy(nwiftab->zone_nwif_physical, 2795 pp->pv_simple, 2796 sizeof (nwiftab->zone_nwif_physical)); 2797 break; 2798 case PT_DEFROUTER: 2799 (void) strlcpy(nwiftab->zone_nwif_defrouter, 2800 pp->pv_simple, 2801 sizeof (nwiftab->zone_nwif_defrouter)); 2802 break; 2803 default: 2804 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2805 Z_NO_PROPERTY_TYPE, B_TRUE); 2806 return (Z_INSUFFICIENT_SPEC); 2807 } 2808 } 2809 if (fill_in_only) 2810 return (Z_OK); 2811 err = zonecfg_lookup_nwif(handle, nwiftab); 2812 return (err); 2813 } 2814 2815 static int 2816 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only) 2817 { 2818 int err, i; 2819 property_value_ptr_t pp; 2820 2821 if ((err = initialize(B_TRUE)) != Z_OK) 2822 return (err); 2823 2824 bzero(devtab, sizeof (*devtab)); 2825 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2826 pp = cmd->cmd_property_ptr[i]; 2827 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2828 zerr(gettext("A simple value was expected here.")); 2829 saw_error = B_TRUE; 2830 return (Z_INSUFFICIENT_SPEC); 2831 } 2832 switch (cmd->cmd_prop_name[i]) { 2833 case PT_MATCH: 2834 (void) strlcpy(devtab->zone_dev_match, pp->pv_simple, 2835 sizeof (devtab->zone_dev_match)); 2836 break; 2837 default: 2838 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2839 Z_NO_PROPERTY_TYPE, B_TRUE); 2840 return (Z_INSUFFICIENT_SPEC); 2841 } 2842 } 2843 if (fill_in_only) 2844 return (Z_OK); 2845 err = zonecfg_lookup_dev(handle, devtab); 2846 return (err); 2847 } 2848 2849 static int 2850 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab, 2851 boolean_t fill_in_only) 2852 { 2853 int err, i; 2854 property_value_ptr_t pp; 2855 2856 if ((err = initialize(B_TRUE)) != Z_OK) 2857 return (err); 2858 2859 bzero(rctltab, sizeof (*rctltab)); 2860 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2861 pp = cmd->cmd_property_ptr[i]; 2862 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2863 zerr(gettext("A simple value was expected here.")); 2864 saw_error = B_TRUE; 2865 return (Z_INSUFFICIENT_SPEC); 2866 } 2867 switch (cmd->cmd_prop_name[i]) { 2868 case PT_NAME: 2869 (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple, 2870 sizeof (rctltab->zone_rctl_name)); 2871 break; 2872 default: 2873 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2874 Z_NO_PROPERTY_TYPE, B_TRUE); 2875 return (Z_INSUFFICIENT_SPEC); 2876 } 2877 } 2878 if (fill_in_only) 2879 return (Z_OK); 2880 err = zonecfg_lookup_rctl(handle, rctltab); 2881 return (err); 2882 } 2883 2884 static int 2885 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab, 2886 boolean_t fill_in_only) 2887 { 2888 int err, i; 2889 property_value_ptr_t pp; 2890 2891 if ((err = initialize(B_TRUE)) != Z_OK) 2892 return (err); 2893 2894 bzero(attrtab, sizeof (*attrtab)); 2895 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2896 pp = cmd->cmd_property_ptr[i]; 2897 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2898 zerr(gettext("A simple value was expected here.")); 2899 saw_error = B_TRUE; 2900 return (Z_INSUFFICIENT_SPEC); 2901 } 2902 switch (cmd->cmd_prop_name[i]) { 2903 case PT_NAME: 2904 (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple, 2905 sizeof (attrtab->zone_attr_name)); 2906 break; 2907 case PT_TYPE: 2908 (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple, 2909 sizeof (attrtab->zone_attr_type)); 2910 break; 2911 case PT_VALUE: 2912 (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple, 2913 sizeof (attrtab->zone_attr_value)); 2914 break; 2915 default: 2916 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2917 Z_NO_PROPERTY_TYPE, B_TRUE); 2918 return (Z_INSUFFICIENT_SPEC); 2919 } 2920 } 2921 if (fill_in_only) 2922 return (Z_OK); 2923 err = zonecfg_lookup_attr(handle, attrtab); 2924 return (err); 2925 } 2926 2927 static int 2928 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only) 2929 { 2930 int err, i; 2931 property_value_ptr_t pp; 2932 2933 if ((err = initialize(B_TRUE)) != Z_OK) 2934 return (err); 2935 2936 dstab->zone_dataset_name[0] = '\0'; 2937 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2938 pp = cmd->cmd_property_ptr[i]; 2939 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2940 zerr(gettext("A simple value was expected here.")); 2941 saw_error = B_TRUE; 2942 return (Z_INSUFFICIENT_SPEC); 2943 } 2944 switch (cmd->cmd_prop_name[i]) { 2945 case PT_NAME: 2946 (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple, 2947 sizeof (dstab->zone_dataset_name)); 2948 break; 2949 default: 2950 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2951 Z_NO_PROPERTY_TYPE, B_TRUE); 2952 return (Z_INSUFFICIENT_SPEC); 2953 } 2954 } 2955 if (fill_in_only) 2956 return (Z_OK); 2957 return (zonecfg_lookup_ds(handle, dstab)); 2958 } 2959 2960 static int 2961 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab, 2962 boolean_t fill_in_only) 2963 { 2964 int err, i; 2965 property_value_ptr_t pp; 2966 2967 if ((err = initialize(B_TRUE)) != Z_OK) 2968 return (err); 2969 2970 bzero(admintab, sizeof (*admintab)); 2971 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 2972 pp = cmd->cmd_property_ptr[i]; 2973 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 2974 zerr(gettext("A simple value was expected here.")); 2975 saw_error = B_TRUE; 2976 return (Z_INSUFFICIENT_SPEC); 2977 } 2978 switch (cmd->cmd_prop_name[i]) { 2979 case PT_USER: 2980 (void) strlcpy(admintab->zone_admin_user, pp->pv_simple, 2981 sizeof (admintab->zone_admin_user)); 2982 break; 2983 case PT_AUTHS: 2984 (void) strlcpy(admintab->zone_admin_auths, 2985 pp->pv_simple, sizeof (admintab->zone_admin_auths)); 2986 break; 2987 default: 2988 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 2989 Z_NO_PROPERTY_TYPE, B_TRUE); 2990 return (Z_INSUFFICIENT_SPEC); 2991 } 2992 } 2993 if (fill_in_only) 2994 return (Z_OK); 2995 err = zonecfg_lookup_admin(handle, admintab); 2996 return (err); 2997 } 2998 2999 static int 3000 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab, 3001 boolean_t fill_in_only) 3002 { 3003 int err, i; 3004 property_value_ptr_t pp; 3005 3006 if ((err = initialize(B_TRUE)) != Z_OK) 3007 return (err); 3008 3009 bzero(secflagstab, sizeof (*secflagstab)); 3010 for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) { 3011 pp = cmd->cmd_property_ptr[i]; 3012 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) { 3013 zerr(gettext("A simple value was expected here.")); 3014 saw_error = B_TRUE; 3015 return (Z_INSUFFICIENT_SPEC); 3016 } 3017 switch (cmd->cmd_prop_name[i]) { 3018 case PT_DEFAULT: 3019 (void) strlcpy(secflagstab->zone_secflags_default, 3020 pp->pv_simple, 3021 sizeof (secflagstab->zone_secflags_default)); 3022 break; 3023 case PT_LOWER: 3024 (void) strlcpy(secflagstab->zone_secflags_lower, 3025 pp->pv_simple, 3026 sizeof (secflagstab->zone_secflags_lower)); 3027 break; 3028 case PT_UPPER: 3029 (void) strlcpy(secflagstab->zone_secflags_upper, 3030 pp->pv_simple, 3031 sizeof (secflagstab->zone_secflags_upper)); 3032 break; 3033 default: 3034 zone_perror(pt_to_str(cmd->cmd_prop_name[i]), 3035 Z_NO_PROPERTY_TYPE, B_TRUE); 3036 return (Z_INSUFFICIENT_SPEC); 3037 } 3038 } 3039 if (fill_in_only) 3040 return (Z_OK); 3041 3042 err = zonecfg_lookup_secflags(handle, secflagstab); 3043 3044 return (err); 3045 } 3046 3047 static void 3048 remove_aliased_rctl(int type, char *name) 3049 { 3050 int err; 3051 uint64_t tmp; 3052 3053 if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) { 3054 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 3055 zonecfg_strerror(err)); 3056 saw_error = B_TRUE; 3057 return; 3058 } 3059 if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) { 3060 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), 3061 zonecfg_strerror(err)); 3062 saw_error = B_TRUE; 3063 } else { 3064 need_to_commit = B_TRUE; 3065 } 3066 } 3067 3068 static boolean_t 3069 prompt_remove_resource(cmd_t *cmd, char *rsrc) 3070 { 3071 int num; 3072 int answer; 3073 int arg; 3074 boolean_t force = B_FALSE; 3075 char prompt[128]; 3076 boolean_t arg_err = B_FALSE; 3077 3078 optind = 0; 3079 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 3080 switch (arg) { 3081 case 'F': 3082 force = B_TRUE; 3083 break; 3084 default: 3085 arg_err = B_TRUE; 3086 break; 3087 } 3088 } 3089 if (arg_err) 3090 return (B_FALSE); 3091 3092 3093 num = zonecfg_num_resources(handle, rsrc); 3094 3095 if (num == 0) { 3096 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY, 3097 B_TRUE); 3098 return (B_FALSE); 3099 } 3100 if (num > 1 && !force) { 3101 if (!interactive_mode) { 3102 zerr(gettext("There are multiple instances of this " 3103 "resource. Either qualify the resource to\n" 3104 "remove a single instance or use the -F option to " 3105 "remove all instances.")); 3106 saw_error = B_TRUE; 3107 return (B_FALSE); 3108 } 3109 (void) snprintf(prompt, sizeof (prompt), gettext( 3110 "Are you sure you want to remove ALL '%s' resources"), 3111 rsrc); 3112 answer = ask_yesno(B_FALSE, prompt); 3113 if (answer == -1) { 3114 zerr(gettext("Resource incomplete.")); 3115 return (B_FALSE); 3116 } 3117 if (answer != 1) 3118 return (B_FALSE); 3119 } 3120 return (B_TRUE); 3121 } 3122 3123 static void 3124 remove_fs(cmd_t *cmd) 3125 { 3126 int err; 3127 3128 /* traditional, qualified fs removal */ 3129 if (cmd->cmd_prop_nv_pairs > 0) { 3130 struct zone_fstab fstab; 3131 3132 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) { 3133 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 3134 return; 3135 } 3136 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) 3137 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 3138 else 3139 need_to_commit = B_TRUE; 3140 zonecfg_free_fs_option_list(fstab.zone_fs_options); 3141 return; 3142 } 3143 3144 /* 3145 * unqualified fs removal. remove all fs's but prompt if more 3146 * than one. 3147 */ 3148 if (!prompt_remove_resource(cmd, "fs")) 3149 return; 3150 3151 if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK) 3152 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE); 3153 else 3154 need_to_commit = B_TRUE; 3155 } 3156 3157 static void 3158 remove_net(cmd_t *cmd) 3159 { 3160 int err; 3161 3162 /* traditional, qualified net removal */ 3163 if (cmd->cmd_prop_nv_pairs > 0) { 3164 struct zone_nwiftab nwiftab; 3165 3166 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) { 3167 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3168 return; 3169 } 3170 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) 3171 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3172 else 3173 need_to_commit = B_TRUE; 3174 return; 3175 } 3176 3177 /* 3178 * unqualified net removal. remove all nets but prompt if more 3179 * than one. 3180 */ 3181 if (!prompt_remove_resource(cmd, "net")) 3182 return; 3183 3184 if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK) 3185 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE); 3186 else 3187 need_to_commit = B_TRUE; 3188 } 3189 3190 static void 3191 remove_device(cmd_t *cmd) 3192 { 3193 int err; 3194 3195 /* traditional, qualified device removal */ 3196 if (cmd->cmd_prop_nv_pairs > 0) { 3197 struct zone_devtab devtab; 3198 3199 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) { 3200 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3201 return; 3202 } 3203 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) 3204 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3205 else 3206 need_to_commit = B_TRUE; 3207 return; 3208 } 3209 3210 /* 3211 * unqualified device removal. remove all devices but prompt if more 3212 * than one. 3213 */ 3214 if (!prompt_remove_resource(cmd, "device")) 3215 return; 3216 3217 if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK) 3218 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE); 3219 else 3220 need_to_commit = B_TRUE; 3221 } 3222 3223 static void 3224 remove_attr(cmd_t *cmd) 3225 { 3226 int err; 3227 3228 /* traditional, qualified attr removal */ 3229 if (cmd->cmd_prop_nv_pairs > 0) { 3230 struct zone_attrtab attrtab; 3231 3232 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) { 3233 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3234 return; 3235 } 3236 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) 3237 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3238 else 3239 need_to_commit = B_TRUE; 3240 return; 3241 } 3242 3243 /* 3244 * unqualified attr removal. remove all attrs but prompt if more 3245 * than one. 3246 */ 3247 if (!prompt_remove_resource(cmd, "attr")) 3248 return; 3249 3250 if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK) 3251 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE); 3252 else 3253 need_to_commit = B_TRUE; 3254 } 3255 3256 static void 3257 remove_dataset(cmd_t *cmd) 3258 { 3259 int err; 3260 3261 /* traditional, qualified dataset removal */ 3262 if (cmd->cmd_prop_nv_pairs > 0) { 3263 struct zone_dstab dstab; 3264 3265 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) { 3266 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3267 return; 3268 } 3269 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) 3270 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3271 else 3272 need_to_commit = B_TRUE; 3273 return; 3274 } 3275 3276 /* 3277 * unqualified dataset removal. remove all datasets but prompt if more 3278 * than one. 3279 */ 3280 if (!prompt_remove_resource(cmd, "dataset")) 3281 return; 3282 3283 if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK) 3284 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE); 3285 else 3286 need_to_commit = B_TRUE; 3287 } 3288 3289 static void 3290 remove_rctl(cmd_t *cmd) 3291 { 3292 int err; 3293 3294 /* traditional, qualified rctl removal */ 3295 if (cmd->cmd_prop_nv_pairs > 0) { 3296 struct zone_rctltab rctltab; 3297 3298 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) { 3299 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3300 return; 3301 } 3302 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) 3303 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3304 else 3305 need_to_commit = B_TRUE; 3306 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 3307 return; 3308 } 3309 3310 /* 3311 * unqualified rctl removal. remove all rctls but prompt if more 3312 * than one. 3313 */ 3314 if (!prompt_remove_resource(cmd, "rctl")) 3315 return; 3316 3317 if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK) 3318 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE); 3319 else 3320 need_to_commit = B_TRUE; 3321 } 3322 3323 static void 3324 remove_pset() 3325 { 3326 int err; 3327 struct zone_psettab psettab; 3328 3329 if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) { 3330 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE); 3331 return; 3332 } 3333 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 3334 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE); 3335 else 3336 need_to_commit = B_TRUE; 3337 } 3338 3339 static void 3340 remove_pcap() 3341 { 3342 int err; 3343 uint64_t tmp; 3344 3345 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) { 3346 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP), 3347 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 3348 saw_error = B_TRUE; 3349 return; 3350 } 3351 3352 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK) 3353 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE); 3354 else 3355 need_to_commit = B_TRUE; 3356 } 3357 3358 static void 3359 remove_mcap() 3360 { 3361 int err, res1, res2, res3; 3362 uint64_t tmp; 3363 struct zone_mcaptab mcaptab; 3364 boolean_t revert = B_FALSE; 3365 3366 res1 = zonecfg_lookup_mcap(handle, &mcaptab); 3367 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp); 3368 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp); 3369 3370 /* if none of these exist, there is no resource to remove */ 3371 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 3372 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP), 3373 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 3374 saw_error = B_TRUE; 3375 return; 3376 } 3377 if (res1 == Z_OK) { 3378 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) { 3379 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3380 revert = B_TRUE; 3381 } else { 3382 need_to_commit = B_TRUE; 3383 } 3384 } 3385 if (res2 == Z_OK) { 3386 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP)) 3387 != Z_OK) { 3388 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3389 revert = B_TRUE; 3390 } else { 3391 need_to_commit = B_TRUE; 3392 } 3393 } 3394 if (res3 == Z_OK) { 3395 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM)) 3396 != Z_OK) { 3397 z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE); 3398 revert = B_TRUE; 3399 } else { 3400 need_to_commit = B_TRUE; 3401 } 3402 } 3403 3404 if (revert) 3405 need_to_commit = B_FALSE; 3406 } 3407 3408 static void 3409 remove_admin(cmd_t *cmd) 3410 { 3411 int err; 3412 3413 /* traditional, qualified attr removal */ 3414 if (cmd->cmd_prop_nv_pairs > 0) { 3415 struct zone_admintab admintab; 3416 3417 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) { 3418 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3419 err, B_TRUE); 3420 return; 3421 } 3422 if ((err = zonecfg_delete_admin(handle, &admintab, 3423 zone)) 3424 != Z_OK) 3425 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3426 err, B_TRUE); 3427 else 3428 need_to_commit = B_TRUE; 3429 return; 3430 } else { 3431 /* 3432 * unqualified admin removal. 3433 * remove all admins but prompt if more 3434 * than one. 3435 */ 3436 if (!prompt_remove_resource(cmd, "admin")) 3437 return; 3438 3439 if ((err = zonecfg_delete_admins(handle, zone)) 3440 != Z_OK) 3441 z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, 3442 err, B_TRUE); 3443 else 3444 need_to_commit = B_TRUE; 3445 } 3446 } 3447 3448 static void 3449 remove_secflags() 3450 { 3451 int err; 3452 struct zone_secflagstab sectab = { 0 }; 3453 3454 if (zonecfg_lookup_secflags(handle, §ab) != Z_OK) { 3455 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), 3456 rt_to_str(RT_SECFLAGS), 3457 zonecfg_strerror(Z_NO_RESOURCE_TYPE)); 3458 return; 3459 } 3460 3461 if ((err = zonecfg_delete_secflags(handle, §ab)) != Z_OK) { 3462 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE); 3463 return; 3464 } 3465 3466 need_to_commit = B_TRUE; 3467 } 3468 3469 static void 3470 remove_resource(cmd_t *cmd) 3471 { 3472 int type; 3473 int arg; 3474 boolean_t arg_err = B_FALSE; 3475 3476 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3477 long_usage(CMD_REMOVE, B_TRUE); 3478 return; 3479 } 3480 3481 optind = 0; 3482 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 3483 switch (arg) { 3484 case '?': 3485 longer_usage(CMD_REMOVE); 3486 arg_err = B_TRUE; 3487 break; 3488 case 'F': 3489 break; 3490 default: 3491 short_usage(CMD_REMOVE); 3492 arg_err = B_TRUE; 3493 break; 3494 } 3495 } 3496 if (arg_err) 3497 return; 3498 3499 if (initialize(B_TRUE) != Z_OK) 3500 return; 3501 3502 switch (type) { 3503 case RT_FS: 3504 remove_fs(cmd); 3505 return; 3506 case RT_NET: 3507 remove_net(cmd); 3508 return; 3509 case RT_DEVICE: 3510 remove_device(cmd); 3511 return; 3512 case RT_RCTL: 3513 remove_rctl(cmd); 3514 return; 3515 case RT_ATTR: 3516 remove_attr(cmd); 3517 return; 3518 case RT_DATASET: 3519 remove_dataset(cmd); 3520 return; 3521 case RT_DCPU: 3522 remove_pset(); 3523 return; 3524 case RT_PCAP: 3525 remove_pcap(); 3526 return; 3527 case RT_MCAP: 3528 remove_mcap(); 3529 return; 3530 case RT_ADMIN: 3531 remove_admin(cmd); 3532 return; 3533 case RT_SECFLAGS: 3534 remove_secflags(); 3535 return; 3536 default: 3537 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 3538 long_usage(CMD_REMOVE, B_TRUE); 3539 usage(B_FALSE, HELP_RESOURCES); 3540 return; 3541 } 3542 } 3543 3544 static void 3545 remove_property(cmd_t *cmd) 3546 { 3547 char *prop_id; 3548 int err, res_type, prop_type; 3549 property_value_ptr_t pp; 3550 struct zone_rctlvaltab *rctlvaltab; 3551 complex_property_ptr_t cx; 3552 3553 res_type = resource_scope; 3554 prop_type = cmd->cmd_prop_name[0]; 3555 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3556 long_usage(CMD_REMOVE, B_TRUE); 3557 return; 3558 } 3559 3560 if (cmd->cmd_prop_nv_pairs != 1) { 3561 long_usage(CMD_ADD, B_TRUE); 3562 return; 3563 } 3564 3565 if (initialize(B_TRUE) != Z_OK) 3566 return; 3567 3568 switch (res_type) { 3569 case RT_FS: 3570 if (prop_type != PT_OPTIONS) { 3571 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3572 B_TRUE); 3573 long_usage(CMD_REMOVE, B_TRUE); 3574 usage(B_FALSE, HELP_PROPS); 3575 return; 3576 } 3577 pp = cmd->cmd_property_ptr[0]; 3578 if (pp->pv_type == PROP_VAL_COMPLEX) { 3579 zerr(gettext("A %s or %s value was expected here."), 3580 pvt_to_str(PROP_VAL_SIMPLE), 3581 pvt_to_str(PROP_VAL_LIST)); 3582 saw_error = B_TRUE; 3583 return; 3584 } 3585 if (pp->pv_type == PROP_VAL_SIMPLE) { 3586 if (pp->pv_simple == NULL) { 3587 long_usage(CMD_ADD, B_TRUE); 3588 return; 3589 } 3590 prop_id = pp->pv_simple; 3591 err = zonecfg_remove_fs_option(&in_progress_fstab, 3592 prop_id); 3593 if (err != Z_OK) 3594 zone_perror(pt_to_str(prop_type), err, B_TRUE); 3595 } else { 3596 list_property_ptr_t list; 3597 3598 for (list = pp->pv_list; list != NULL; 3599 list = list->lp_next) { 3600 prop_id = list->lp_simple; 3601 if (prop_id == NULL) 3602 break; 3603 err = zonecfg_remove_fs_option( 3604 &in_progress_fstab, prop_id); 3605 if (err != Z_OK) 3606 zone_perror(pt_to_str(prop_type), err, 3607 B_TRUE); 3608 } 3609 } 3610 return; 3611 case RT_RCTL: 3612 if (prop_type != PT_VALUE) { 3613 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3614 B_TRUE); 3615 long_usage(CMD_REMOVE, B_TRUE); 3616 usage(B_FALSE, HELP_PROPS); 3617 return; 3618 } 3619 pp = cmd->cmd_property_ptr[0]; 3620 if (pp->pv_type != PROP_VAL_COMPLEX) { 3621 zerr(gettext("A %s value was expected here."), 3622 pvt_to_str(PROP_VAL_COMPLEX)); 3623 saw_error = B_TRUE; 3624 return; 3625 } 3626 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) { 3627 zone_perror(zone, Z_NOMEM, B_TRUE); 3628 exit(Z_ERR); 3629 } 3630 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) { 3631 switch (cx->cp_type) { 3632 case PT_PRIV: 3633 (void) strlcpy(rctlvaltab->zone_rctlval_priv, 3634 cx->cp_value, 3635 sizeof (rctlvaltab->zone_rctlval_priv)); 3636 break; 3637 case PT_LIMIT: 3638 (void) strlcpy(rctlvaltab->zone_rctlval_limit, 3639 cx->cp_value, 3640 sizeof (rctlvaltab->zone_rctlval_limit)); 3641 break; 3642 case PT_ACTION: 3643 (void) strlcpy(rctlvaltab->zone_rctlval_action, 3644 cx->cp_value, 3645 sizeof (rctlvaltab->zone_rctlval_action)); 3646 break; 3647 default: 3648 zone_perror(pt_to_str(prop_type), 3649 Z_NO_PROPERTY_TYPE, B_TRUE); 3650 long_usage(CMD_ADD, B_TRUE); 3651 usage(B_FALSE, HELP_PROPS); 3652 zonecfg_free_rctl_value_list(rctlvaltab); 3653 return; 3654 } 3655 } 3656 rctlvaltab->zone_rctlval_next = NULL; 3657 err = zonecfg_remove_rctl_value(&in_progress_rctltab, 3658 rctlvaltab); 3659 if (err != Z_OK) 3660 zone_perror(pt_to_str(prop_type), err, B_TRUE); 3661 zonecfg_free_rctl_value_list(rctlvaltab); 3662 return; 3663 case RT_NET: 3664 if (prop_type != PT_DEFROUTER) { 3665 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 3666 B_TRUE); 3667 long_usage(CMD_REMOVE, B_TRUE); 3668 usage(B_FALSE, HELP_PROPS); 3669 return; 3670 } else { 3671 bzero(&in_progress_nwiftab.zone_nwif_defrouter, 3672 sizeof (in_progress_nwiftab.zone_nwif_defrouter)); 3673 return; 3674 } 3675 default: 3676 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 3677 long_usage(CMD_REMOVE, B_TRUE); 3678 usage(B_FALSE, HELP_RESOURCES); 3679 return; 3680 } 3681 } 3682 3683 void 3684 remove_func(cmd_t *cmd) 3685 { 3686 if (zone_is_read_only(CMD_REMOVE)) 3687 return; 3688 3689 assert(cmd != NULL); 3690 3691 if (global_scope) { 3692 if (gz_invalid_resource(cmd->cmd_res_type)) { 3693 zerr(gettext("%s is not a valid resource for the " 3694 "global zone."), rt_to_str(cmd->cmd_res_type)); 3695 saw_error = B_TRUE; 3696 return; 3697 } 3698 remove_resource(cmd); 3699 } else { 3700 remove_property(cmd); 3701 } 3702 } 3703 3704 static void 3705 clear_property(cmd_t *cmd) 3706 { 3707 int res_type, prop_type; 3708 3709 res_type = resource_scope; 3710 prop_type = cmd->cmd_res_type; 3711 if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { 3712 long_usage(CMD_CLEAR, B_TRUE); 3713 return; 3714 } 3715 3716 if (initialize(B_TRUE) != Z_OK) 3717 return; 3718 3719 switch (res_type) { 3720 case RT_FS: 3721 if (prop_type == PT_RAW) { 3722 in_progress_fstab.zone_fs_raw[0] = '\0'; 3723 need_to_commit = B_TRUE; 3724 return; 3725 } 3726 break; 3727 case RT_DCPU: 3728 if (prop_type == PT_IMPORTANCE) { 3729 in_progress_psettab.zone_importance[0] = '\0'; 3730 need_to_commit = B_TRUE; 3731 return; 3732 } 3733 break; 3734 case RT_MCAP: 3735 switch (prop_type) { 3736 case PT_PHYSICAL: 3737 in_progress_mcaptab.zone_physmem_cap[0] = '\0'; 3738 need_to_commit = B_TRUE; 3739 return; 3740 case PT_SWAP: 3741 remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP); 3742 return; 3743 case PT_LOCKED: 3744 remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM); 3745 return; 3746 } 3747 break; 3748 case RT_SECFLAGS: 3749 switch (prop_type) { 3750 case PT_LOWER: 3751 in_progress_secflagstab.zone_secflags_lower[0] = '\0'; 3752 need_to_commit = B_TRUE; 3753 return; 3754 case PT_DEFAULT: 3755 in_progress_secflagstab.zone_secflags_default[0] = '\0'; 3756 need_to_commit = B_TRUE; 3757 return; 3758 case PT_UPPER: 3759 in_progress_secflagstab.zone_secflags_upper[0] = '\0'; 3760 need_to_commit = B_TRUE; 3761 return; 3762 } 3763 break; 3764 default: 3765 break; 3766 } 3767 3768 zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE); 3769 } 3770 3771 static void 3772 clear_global(cmd_t *cmd) 3773 { 3774 int err, type; 3775 3776 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3777 long_usage(CMD_CLEAR, B_TRUE); 3778 return; 3779 } 3780 3781 if (initialize(B_TRUE) != Z_OK) 3782 return; 3783 3784 switch (type) { 3785 case PT_ZONENAME: 3786 /* FALLTHRU */ 3787 case PT_ZONEPATH: 3788 /* FALLTHRU */ 3789 case PT_BRAND: 3790 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE); 3791 return; 3792 case PT_AUTOBOOT: 3793 /* false is default; we'll treat as equivalent to clearing */ 3794 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK) 3795 z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE); 3796 else 3797 need_to_commit = B_TRUE; 3798 return; 3799 case PT_POOL: 3800 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK) 3801 z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE); 3802 else 3803 need_to_commit = B_TRUE; 3804 return; 3805 case PT_LIMITPRIV: 3806 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK) 3807 z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE); 3808 else 3809 need_to_commit = B_TRUE; 3810 return; 3811 case PT_BOOTARGS: 3812 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK) 3813 z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE); 3814 else 3815 need_to_commit = B_TRUE; 3816 return; 3817 case PT_SCHED: 3818 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK) 3819 z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE); 3820 else 3821 need_to_commit = B_TRUE; 3822 return; 3823 case PT_IPTYPE: 3824 /* shared is default; we'll treat as equivalent to clearing */ 3825 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK) 3826 z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE); 3827 else 3828 need_to_commit = B_TRUE; 3829 return; 3830 case PT_MAXLWPS: 3831 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS); 3832 return; 3833 case PT_MAXPROCS: 3834 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS); 3835 return; 3836 case PT_MAXSHMMEM: 3837 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM); 3838 return; 3839 case PT_MAXSHMIDS: 3840 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS); 3841 return; 3842 case PT_MAXMSGIDS: 3843 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS); 3844 return; 3845 case PT_MAXSEMIDS: 3846 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS); 3847 return; 3848 case PT_SHARES: 3849 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES); 3850 return; 3851 case PT_HOSTID: 3852 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK) 3853 z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE); 3854 else 3855 need_to_commit = B_TRUE; 3856 return; 3857 case PT_FS_ALLOWED: 3858 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK) 3859 z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE); 3860 else 3861 need_to_commit = B_TRUE; 3862 return; 3863 default: 3864 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE); 3865 long_usage(CMD_CLEAR, B_TRUE); 3866 usage(B_FALSE, HELP_PROPS); 3867 return; 3868 } 3869 } 3870 3871 void 3872 clear_func(cmd_t *cmd) 3873 { 3874 if (zone_is_read_only(CMD_CLEAR)) 3875 return; 3876 3877 assert(cmd != NULL); 3878 3879 if (global_scope) { 3880 if (gz_invalid_property(cmd->cmd_res_type)) { 3881 zerr(gettext("%s is not a valid property for the " 3882 "global zone."), pt_to_str(cmd->cmd_res_type)); 3883 saw_error = B_TRUE; 3884 return; 3885 } 3886 3887 clear_global(cmd); 3888 } else { 3889 clear_property(cmd); 3890 } 3891 } 3892 3893 void 3894 select_func(cmd_t *cmd) 3895 { 3896 int type, err, res; 3897 uint64_t limit; 3898 uint64_t tmp; 3899 3900 if (zone_is_read_only(CMD_SELECT)) 3901 return; 3902 3903 assert(cmd != NULL); 3904 3905 if (global_scope) { 3906 global_scope = B_FALSE; 3907 resource_scope = cmd->cmd_res_type; 3908 end_op = CMD_SELECT; 3909 } else { 3910 scope_usage(CMD_SELECT); 3911 return; 3912 } 3913 3914 if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { 3915 long_usage(CMD_SELECT, B_TRUE); 3916 return; 3917 } 3918 3919 if (initialize(B_TRUE) != Z_OK) 3920 return; 3921 3922 switch (type) { 3923 case RT_FS: 3924 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) { 3925 z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE); 3926 global_scope = B_TRUE; 3927 } 3928 bcopy(&old_fstab, &in_progress_fstab, 3929 sizeof (struct zone_fstab)); 3930 return; 3931 case RT_NET: 3932 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE)) 3933 != Z_OK) { 3934 z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE); 3935 global_scope = B_TRUE; 3936 } 3937 bcopy(&old_nwiftab, &in_progress_nwiftab, 3938 sizeof (struct zone_nwiftab)); 3939 return; 3940 case RT_DEVICE: 3941 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) { 3942 z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE); 3943 global_scope = B_TRUE; 3944 } 3945 bcopy(&old_devtab, &in_progress_devtab, 3946 sizeof (struct zone_devtab)); 3947 return; 3948 case RT_RCTL: 3949 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE)) 3950 != Z_OK) { 3951 z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE); 3952 global_scope = B_TRUE; 3953 } 3954 bcopy(&old_rctltab, &in_progress_rctltab, 3955 sizeof (struct zone_rctltab)); 3956 return; 3957 case RT_ATTR: 3958 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE)) 3959 != Z_OK) { 3960 z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE); 3961 global_scope = B_TRUE; 3962 } 3963 bcopy(&old_attrtab, &in_progress_attrtab, 3964 sizeof (struct zone_attrtab)); 3965 return; 3966 case RT_DATASET: 3967 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) { 3968 z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE); 3969 global_scope = B_TRUE; 3970 } 3971 bcopy(&old_dstab, &in_progress_dstab, 3972 sizeof (struct zone_dstab)); 3973 return; 3974 case RT_DCPU: 3975 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) { 3976 z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE); 3977 global_scope = B_TRUE; 3978 } 3979 bcopy(&old_psettab, &in_progress_psettab, 3980 sizeof (struct zone_psettab)); 3981 return; 3982 case RT_PCAP: 3983 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) 3984 != Z_OK) { 3985 z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE); 3986 global_scope = B_TRUE; 3987 } 3988 return; 3989 case RT_MCAP: 3990 /* if none of these exist, there is no resource to select */ 3991 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK && 3992 zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit) 3993 != Z_OK && 3994 zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit) 3995 != Z_OK) { 3996 z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE, 3997 B_TRUE); 3998 global_scope = B_TRUE; 3999 } 4000 if (res == Z_OK) 4001 bcopy(&old_mcaptab, &in_progress_mcaptab, 4002 sizeof (struct zone_mcaptab)); 4003 else 4004 bzero(&in_progress_mcaptab, 4005 sizeof (in_progress_mcaptab)); 4006 return; 4007 case RT_ADMIN: 4008 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE)) 4009 != Z_OK) { 4010 z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err, 4011 B_TRUE); 4012 global_scope = B_TRUE; 4013 } 4014 bcopy(&old_admintab, &in_progress_admintab, 4015 sizeof (struct zone_admintab)); 4016 return; 4017 case RT_SECFLAGS: 4018 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE)) 4019 != Z_OK) { 4020 z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err, 4021 B_TRUE); 4022 global_scope = B_TRUE; 4023 } 4024 bcopy(&old_secflagstab, &in_progress_secflagstab, 4025 sizeof (struct zone_secflagstab)); 4026 return; 4027 default: 4028 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE); 4029 long_usage(CMD_SELECT, B_TRUE); 4030 usage(B_FALSE, HELP_RESOURCES); 4031 return; 4032 } 4033 } 4034 4035 /* 4036 * Network "addresses" can be one of the following forms: 4037 * <IPv4 address> 4038 * <IPv4 address>/<prefix length> 4039 * <IPv6 address>/<prefix length> 4040 * <host name> 4041 * <host name>/<prefix length> 4042 * In other words, the "/" followed by a prefix length is allowed but not 4043 * required for IPv4 addresses and host names, and required for IPv6 addresses. 4044 * If a prefix length is given, it must be in the allowable range: 0 to 32 for 4045 * IPv4 addresses and host names, 0 to 128 for IPv6 addresses. 4046 * Host names must start with an alpha-numeric character, and all subsequent 4047 * characters must be either alpha-numeric or "-". 4048 * 4049 * In some cases, e.g., the nexthop for the defrouter, the context indicates 4050 * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't 4051 * require the /<prefix length> (and should ignore it if provided). 4052 */ 4053 4054 static int 4055 validate_net_address_syntax(char *address, boolean_t ishost) 4056 { 4057 char *slashp, part1[MAXHOSTNAMELEN]; 4058 struct in6_addr in6; 4059 struct in_addr in4; 4060 int prefixlen, i; 4061 4062 /* 4063 * Copy the part before any '/' into part1 or copy the whole 4064 * thing if there is no '/'. 4065 */ 4066 if ((slashp = strchr(address, '/')) != NULL) { 4067 *slashp = '\0'; 4068 (void) strlcpy(part1, address, sizeof (part1)); 4069 *slashp = '/'; 4070 prefixlen = atoi(++slashp); 4071 } else { 4072 (void) strlcpy(part1, address, sizeof (part1)); 4073 } 4074 4075 if (ishost && slashp != NULL) { 4076 zerr(gettext("Warning: prefix length in %s is not required and " 4077 "will be ignored. The default host-prefix length " 4078 "will be used"), address); 4079 } 4080 4081 4082 if (inet_pton(AF_INET6, part1, &in6) == 1) { 4083 if (ishost) { 4084 prefixlen = IPV6_ABITS; 4085 } else if (slashp == NULL) { 4086 zerr(gettext("%s: IPv6 addresses " 4087 "require /prefix-length suffix."), address); 4088 return (Z_ERR); 4089 } 4090 if (prefixlen < 0 || prefixlen > 128) { 4091 zerr(gettext("%s: IPv6 address " 4092 "prefix lengths must be 0 - 128."), address); 4093 return (Z_ERR); 4094 } 4095 return (Z_OK); 4096 } 4097 4098 /* At this point, any /prefix must be for IPv4. */ 4099 if (ishost) 4100 prefixlen = IPV4_ABITS; 4101 else if (slashp != NULL) { 4102 if (prefixlen < 0 || prefixlen > 32) { 4103 zerr(gettext("%s: IPv4 address " 4104 "prefix lengths must be 0 - 32."), address); 4105 return (Z_ERR); 4106 } 4107 } 4108 4109 if (inet_pton(AF_INET, part1, &in4) == 1) 4110 return (Z_OK); 4111 4112 /* address may also be a host name */ 4113 if (!isalnum(part1[0])) { 4114 zerr(gettext("%s: bogus host name or network address syntax"), 4115 part1); 4116 saw_error = B_TRUE; 4117 usage(B_FALSE, HELP_NETADDR); 4118 return (Z_ERR); 4119 } 4120 for (i = 1; part1[i]; i++) 4121 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') { 4122 zerr(gettext("%s: bogus host name or " 4123 "network address syntax"), part1); 4124 saw_error = B_TRUE; 4125 usage(B_FALSE, HELP_NETADDR); 4126 return (Z_ERR); 4127 } 4128 return (Z_OK); 4129 } 4130 4131 static int 4132 validate_net_physical_syntax(const char *ifname) 4133 { 4134 ifspec_t ifnameprop; 4135 zone_iptype_t iptype; 4136 4137 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 4138 zerr(gettext("zone configuration has an invalid or nonexistent " 4139 "ip-type property")); 4140 return (Z_ERR); 4141 } 4142 switch (iptype) { 4143 case ZS_SHARED: 4144 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) { 4145 zerr(gettext("%s: invalid physical interface name"), 4146 ifname); 4147 return (Z_ERR); 4148 } 4149 if (ifnameprop.ifsp_lunvalid) { 4150 zerr(gettext("%s: LUNs not allowed in physical " 4151 "interface names"), ifname); 4152 return (Z_ERR); 4153 } 4154 break; 4155 case ZS_EXCLUSIVE: 4156 if (dladm_valid_linkname(ifname) == B_FALSE) { 4157 if (strchr(ifname, ':') != NULL) 4158 zerr(gettext("%s: physical interface name " 4159 "required; logical interface name not " 4160 "allowed"), ifname); 4161 else 4162 zerr(gettext("%s: invalid physical interface " 4163 "name"), ifname); 4164 return (Z_ERR); 4165 } 4166 break; 4167 } 4168 return (Z_OK); 4169 } 4170 4171 static boolean_t 4172 valid_fs_type(const char *type) 4173 { 4174 /* 4175 * Is this a valid path component? 4176 */ 4177 if (strlen(type) + 1 > MAXNAMELEN) 4178 return (B_FALSE); 4179 /* 4180 * Make sure a bad value for "type" doesn't make 4181 * /usr/lib/fs/<type>/mount turn into something else. 4182 */ 4183 if (strchr(type, '/') != NULL || type[0] == '\0' || 4184 strcmp(type, ".") == 0 || strcmp(type, "..") == 0) 4185 return (B_FALSE); 4186 /* 4187 * More detailed verification happens later by zoneadm(1m). 4188 */ 4189 return (B_TRUE); 4190 } 4191 4192 static boolean_t 4193 allow_exclusive() 4194 { 4195 brand_handle_t bh; 4196 char brand[MAXNAMELEN]; 4197 boolean_t ret; 4198 4199 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 4200 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 4201 return (B_FALSE); 4202 } 4203 if ((bh = brand_open(brand)) == NULL) { 4204 zerr("%s: %s\n", zone, gettext("unknown brand.")); 4205 return (B_FALSE); 4206 } 4207 ret = brand_allow_exclusive_ip(bh); 4208 brand_close(bh); 4209 if (!ret) 4210 zerr(gettext("%s cannot be '%s' when %s is '%s'."), 4211 pt_to_str(PT_IPTYPE), "exclusive", 4212 pt_to_str(PT_BRAND), brand); 4213 return (ret); 4214 } 4215 4216 static void 4217 set_aliased_rctl(char *alias, int prop_type, char *s) 4218 { 4219 uint64_t limit; 4220 int err; 4221 char tmp[128]; 4222 4223 if (global_zone && strcmp(alias, ALIAS_SHARES) != 0) 4224 zerr(gettext("WARNING: Setting a global zone resource " 4225 "control too low could deny\nservice " 4226 "to even the root user; " 4227 "this could render the system impossible\n" 4228 "to administer. Please use caution.")); 4229 4230 /* convert memory based properties */ 4231 if (prop_type == PT_MAXSHMMEM) { 4232 if (!zonecfg_valid_memlimit(s, &limit)) { 4233 zerr(gettext("A non-negative number with a required " 4234 "scale suffix (K, M, G or T) was expected\nhere.")); 4235 saw_error = B_TRUE; 4236 return; 4237 } 4238 4239 (void) snprintf(tmp, sizeof (tmp), "%llu", limit); 4240 s = tmp; 4241 } 4242 4243 if (!zonecfg_aliased_rctl_ok(handle, alias)) { 4244 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE); 4245 saw_error = B_TRUE; 4246 } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) { 4247 zerr(gettext("%s property is out of range."), 4248 pt_to_str(prop_type)); 4249 saw_error = B_TRUE; 4250 } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit)) 4251 != Z_OK) { 4252 zone_perror(zone, err, B_TRUE); 4253 saw_error = B_TRUE; 4254 } else { 4255 need_to_commit = B_TRUE; 4256 } 4257 } 4258 4259 static void 4260 set_in_progress_nwiftab_address(char *prop_id, int prop_type) 4261 { 4262 if (prop_type == PT_ADDRESS) { 4263 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id, 4264 sizeof (in_progress_nwiftab.zone_nwif_address)); 4265 } else { 4266 assert(prop_type == PT_ALLOWED_ADDRESS); 4267 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address, 4268 prop_id, 4269 sizeof (in_progress_nwiftab.zone_nwif_allowed_address)); 4270 } 4271 } 4272 4273 void 4274 set_func(cmd_t *cmd) 4275 { 4276 char *prop_id; 4277 int arg, err, res_type, prop_type; 4278 property_value_ptr_t pp; 4279 boolean_t autoboot; 4280 zone_iptype_t iptype; 4281 boolean_t force_set = B_FALSE; 4282 size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap); 4283 uint64_t mem_cap, mem_limit; 4284 float cap; 4285 char *unitp; 4286 struct zone_psettab tmp_psettab; 4287 boolean_t arg_err = B_FALSE; 4288 4289 if (zone_is_read_only(CMD_SET)) 4290 return; 4291 4292 assert(cmd != NULL); 4293 4294 optind = opterr = 0; 4295 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { 4296 switch (arg) { 4297 case 'F': 4298 force_set = B_TRUE; 4299 break; 4300 default: 4301 if (optopt == '?') 4302 longer_usage(CMD_SET); 4303 else 4304 short_usage(CMD_SET); 4305 arg_err = B_TRUE; 4306 break; 4307 } 4308 } 4309 if (arg_err) 4310 return; 4311 4312 prop_type = cmd->cmd_prop_name[0]; 4313 if (global_scope) { 4314 if (gz_invalid_property(prop_type)) { 4315 zerr(gettext("%s is not a valid property for the " 4316 "global zone."), pt_to_str(prop_type)); 4317 saw_error = B_TRUE; 4318 return; 4319 } 4320 4321 if (prop_type == PT_ZONENAME) { 4322 res_type = RT_ZONENAME; 4323 } else if (prop_type == PT_ZONEPATH) { 4324 res_type = RT_ZONEPATH; 4325 } else if (prop_type == PT_AUTOBOOT) { 4326 res_type = RT_AUTOBOOT; 4327 } else if (prop_type == PT_BRAND) { 4328 res_type = RT_BRAND; 4329 } else if (prop_type == PT_POOL) { 4330 res_type = RT_POOL; 4331 } else if (prop_type == PT_LIMITPRIV) { 4332 res_type = RT_LIMITPRIV; 4333 } else if (prop_type == PT_BOOTARGS) { 4334 res_type = RT_BOOTARGS; 4335 } else if (prop_type == PT_SCHED) { 4336 res_type = RT_SCHED; 4337 } else if (prop_type == PT_IPTYPE) { 4338 res_type = RT_IPTYPE; 4339 } else if (prop_type == PT_MAXLWPS) { 4340 res_type = RT_MAXLWPS; 4341 } else if (prop_type == PT_MAXPROCS) { 4342 res_type = RT_MAXPROCS; 4343 } else if (prop_type == PT_MAXSHMMEM) { 4344 res_type = RT_MAXSHMMEM; 4345 } else if (prop_type == PT_MAXSHMIDS) { 4346 res_type = RT_MAXSHMIDS; 4347 } else if (prop_type == PT_MAXMSGIDS) { 4348 res_type = RT_MAXMSGIDS; 4349 } else if (prop_type == PT_MAXSEMIDS) { 4350 res_type = RT_MAXSEMIDS; 4351 } else if (prop_type == PT_SHARES) { 4352 res_type = RT_SHARES; 4353 } else if (prop_type == PT_HOSTID) { 4354 res_type = RT_HOSTID; 4355 } else if (prop_type == PT_FS_ALLOWED) { 4356 res_type = RT_FS_ALLOWED; 4357 } else { 4358 zerr(gettext("Cannot set a resource-specific property " 4359 "from the global scope.")); 4360 saw_error = B_TRUE; 4361 return; 4362 } 4363 } else { 4364 res_type = resource_scope; 4365 } 4366 4367 if (force_set) { 4368 if (res_type != RT_ZONEPATH) { 4369 zerr(gettext("Only zonepath setting can be forced.")); 4370 saw_error = B_TRUE; 4371 return; 4372 } 4373 if (!zonecfg_in_alt_root()) { 4374 zerr(gettext("Zonepath is changeable only in an " 4375 "alternate root.")); 4376 saw_error = B_TRUE; 4377 return; 4378 } 4379 } 4380 4381 pp = cmd->cmd_property_ptr[0]; 4382 /* 4383 * A nasty expression but not that complicated: 4384 * 1. fs options are simple or list (tested below) 4385 * 2. rctl value's are complex or list (tested below) 4386 * Anything else should be simple. 4387 */ 4388 if (!(res_type == RT_FS && prop_type == PT_OPTIONS) && 4389 !(res_type == RT_RCTL && prop_type == PT_VALUE) && 4390 (pp->pv_type != PROP_VAL_SIMPLE || 4391 (prop_id = pp->pv_simple) == NULL)) { 4392 zerr(gettext("A %s value was expected here."), 4393 pvt_to_str(PROP_VAL_SIMPLE)); 4394 saw_error = B_TRUE; 4395 return; 4396 } 4397 if (prop_type == PT_UNKNOWN) { 4398 long_usage(CMD_SET, B_TRUE); 4399 return; 4400 } 4401 4402 /* 4403 * Special case: the user can change the zone name prior to 'create'; 4404 * if the zone already exists, we fall through letting initialize() 4405 * and the rest of the logic run. 4406 */ 4407 if (res_type == RT_ZONENAME && got_handle == B_FALSE && 4408 !state_atleast(ZONE_STATE_CONFIGURED)) { 4409 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) { 4410 zone_perror(prop_id, err, B_TRUE); 4411 usage(B_FALSE, HELP_SYNTAX); 4412 return; 4413 } 4414 (void) strlcpy(zone, prop_id, sizeof (zone)); 4415 return; 4416 } 4417 4418 if (initialize(B_TRUE) != Z_OK) 4419 return; 4420 4421 switch (res_type) { 4422 case RT_ZONENAME: 4423 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) { 4424 /* 4425 * Use prop_id instead of 'zone' here, since we're 4426 * reporting a problem about the *new* zonename. 4427 */ 4428 zone_perror(prop_id, err, B_TRUE); 4429 usage(B_FALSE, HELP_SYNTAX); 4430 } else { 4431 need_to_commit = B_TRUE; 4432 (void) strlcpy(zone, prop_id, sizeof (zone)); 4433 } 4434 return; 4435 case RT_ZONEPATH: 4436 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) { 4437 zerr(gettext("Zone %s already installed; %s %s not " 4438 "allowed."), zone, cmd_to_str(CMD_SET), 4439 rt_to_str(RT_ZONEPATH)); 4440 return; 4441 } 4442 if (validate_zonepath_syntax(prop_id) != Z_OK) { 4443 saw_error = B_TRUE; 4444 return; 4445 } 4446 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK) 4447 zone_perror(zone, err, B_TRUE); 4448 else 4449 need_to_commit = B_TRUE; 4450 return; 4451 case RT_BRAND: 4452 if (state_atleast(ZONE_STATE_INSTALLED)) { 4453 zerr(gettext("Zone %s already installed; %s %s not " 4454 "allowed."), zone, cmd_to_str(CMD_SET), 4455 rt_to_str(RT_BRAND)); 4456 return; 4457 } 4458 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK) 4459 zone_perror(zone, err, B_TRUE); 4460 else 4461 need_to_commit = B_TRUE; 4462 return; 4463 case RT_AUTOBOOT: 4464 if (strcmp(prop_id, "true") == 0) { 4465 autoboot = B_TRUE; 4466 } else if (strcmp(prop_id, "false") == 0) { 4467 autoboot = B_FALSE; 4468 } else { 4469 zerr(gettext("%s value must be '%s' or '%s'."), 4470 pt_to_str(PT_AUTOBOOT), "true", "false"); 4471 saw_error = B_TRUE; 4472 return; 4473 } 4474 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK) 4475 zone_perror(zone, err, B_TRUE); 4476 else 4477 need_to_commit = B_TRUE; 4478 return; 4479 case RT_POOL: 4480 /* don't allow use of the reserved temporary pool names */ 4481 if (strncmp("SUNW", prop_id, 4) == 0) { 4482 zerr(gettext("pool names starting with SUNW are " 4483 "reserved.")); 4484 saw_error = B_TRUE; 4485 return; 4486 } 4487 4488 /* can't set pool if dedicated-cpu exists */ 4489 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { 4490 zerr(gettext("The %s resource already exists. " 4491 "A persistent pool is incompatible\nwith the %s " 4492 "resource."), rt_to_str(RT_DCPU), 4493 rt_to_str(RT_DCPU)); 4494 saw_error = B_TRUE; 4495 return; 4496 } 4497 4498 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) 4499 zone_perror(zone, err, B_TRUE); 4500 else 4501 need_to_commit = B_TRUE; 4502 return; 4503 case RT_LIMITPRIV: 4504 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK) 4505 zone_perror(zone, err, B_TRUE); 4506 else 4507 need_to_commit = B_TRUE; 4508 return; 4509 case RT_BOOTARGS: 4510 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK) 4511 zone_perror(zone, err, B_TRUE); 4512 else 4513 need_to_commit = B_TRUE; 4514 return; 4515 case RT_SCHED: 4516 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK) 4517 zone_perror(zone, err, B_TRUE); 4518 else 4519 need_to_commit = B_TRUE; 4520 return; 4521 case RT_IPTYPE: 4522 if (strcmp(prop_id, "shared") == 0) { 4523 iptype = ZS_SHARED; 4524 } else if (strcmp(prop_id, "exclusive") == 0) { 4525 iptype = ZS_EXCLUSIVE; 4526 } else { 4527 zerr(gettext("%s value must be '%s' or '%s'."), 4528 pt_to_str(PT_IPTYPE), "shared", "exclusive"); 4529 saw_error = B_TRUE; 4530 return; 4531 } 4532 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) { 4533 saw_error = B_TRUE; 4534 return; 4535 } 4536 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK) 4537 zone_perror(zone, err, B_TRUE); 4538 else 4539 need_to_commit = B_TRUE; 4540 return; 4541 case RT_MAXLWPS: 4542 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id); 4543 return; 4544 case RT_MAXPROCS: 4545 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id); 4546 return; 4547 case RT_MAXSHMMEM: 4548 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id); 4549 return; 4550 case RT_MAXSHMIDS: 4551 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id); 4552 return; 4553 case RT_MAXMSGIDS: 4554 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id); 4555 return; 4556 case RT_MAXSEMIDS: 4557 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id); 4558 return; 4559 case RT_SHARES: 4560 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id); 4561 return; 4562 case RT_HOSTID: 4563 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) { 4564 if (err == Z_TOO_BIG) { 4565 zerr(gettext("hostid string is too large: %s"), 4566 prop_id); 4567 saw_error = B_TRUE; 4568 } else { 4569 zone_perror(pt_to_str(prop_type), err, B_TRUE); 4570 } 4571 return; 4572 } 4573 need_to_commit = B_TRUE; 4574 return; 4575 case RT_FS_ALLOWED: 4576 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK) 4577 zone_perror(zone, err, B_TRUE); 4578 else 4579 need_to_commit = B_TRUE; 4580 return; 4581 case RT_FS: 4582 switch (prop_type) { 4583 case PT_DIR: 4584 (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id, 4585 sizeof (in_progress_fstab.zone_fs_dir)); 4586 return; 4587 case PT_SPECIAL: 4588 (void) strlcpy(in_progress_fstab.zone_fs_special, 4589 prop_id, 4590 sizeof (in_progress_fstab.zone_fs_special)); 4591 return; 4592 case PT_RAW: 4593 (void) strlcpy(in_progress_fstab.zone_fs_raw, 4594 prop_id, sizeof (in_progress_fstab.zone_fs_raw)); 4595 return; 4596 case PT_TYPE: 4597 if (!valid_fs_type(prop_id)) { 4598 zerr(gettext("\"%s\" is not a valid %s."), 4599 prop_id, pt_to_str(PT_TYPE)); 4600 saw_error = B_TRUE; 4601 return; 4602 } 4603 (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id, 4604 sizeof (in_progress_fstab.zone_fs_type)); 4605 return; 4606 case PT_OPTIONS: 4607 if (pp->pv_type != PROP_VAL_SIMPLE && 4608 pp->pv_type != PROP_VAL_LIST) { 4609 zerr(gettext("A %s or %s value was expected " 4610 "here."), pvt_to_str(PROP_VAL_SIMPLE), 4611 pvt_to_str(PROP_VAL_LIST)); 4612 saw_error = B_TRUE; 4613 return; 4614 } 4615 zonecfg_free_fs_option_list( 4616 in_progress_fstab.zone_fs_options); 4617 in_progress_fstab.zone_fs_options = NULL; 4618 if (!(pp->pv_type == PROP_VAL_LIST && 4619 pp->pv_list == NULL)) 4620 add_property(cmd); 4621 return; 4622 default: 4623 break; 4624 } 4625 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4626 long_usage(CMD_SET, B_TRUE); 4627 usage(B_FALSE, HELP_PROPS); 4628 return; 4629 case RT_NET: 4630 switch (prop_type) { 4631 case PT_ADDRESS: 4632 case PT_ALLOWED_ADDRESS: 4633 if (validate_net_address_syntax(prop_id, B_FALSE) 4634 != Z_OK) { 4635 saw_error = B_TRUE; 4636 return; 4637 } 4638 set_in_progress_nwiftab_address(prop_id, prop_type); 4639 break; 4640 case PT_PHYSICAL: 4641 if (validate_net_physical_syntax(prop_id) != Z_OK) { 4642 saw_error = B_TRUE; 4643 return; 4644 } 4645 (void) strlcpy(in_progress_nwiftab.zone_nwif_physical, 4646 prop_id, 4647 sizeof (in_progress_nwiftab.zone_nwif_physical)); 4648 break; 4649 case PT_DEFROUTER: 4650 if (validate_net_address_syntax(prop_id, B_TRUE) 4651 != Z_OK) { 4652 saw_error = B_TRUE; 4653 return; 4654 } 4655 (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter, 4656 prop_id, 4657 sizeof (in_progress_nwiftab.zone_nwif_defrouter)); 4658 break; 4659 default: 4660 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4661 B_TRUE); 4662 long_usage(CMD_SET, B_TRUE); 4663 usage(B_FALSE, HELP_PROPS); 4664 return; 4665 } 4666 return; 4667 case RT_DEVICE: 4668 switch (prop_type) { 4669 case PT_MATCH: 4670 (void) strlcpy(in_progress_devtab.zone_dev_match, 4671 prop_id, 4672 sizeof (in_progress_devtab.zone_dev_match)); 4673 break; 4674 default: 4675 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4676 B_TRUE); 4677 long_usage(CMD_SET, B_TRUE); 4678 usage(B_FALSE, HELP_PROPS); 4679 return; 4680 } 4681 return; 4682 case RT_RCTL: 4683 switch (prop_type) { 4684 case PT_NAME: 4685 if (!zonecfg_valid_rctlname(prop_id)) { 4686 zerr(gettext("'%s' is not a valid zone %s " 4687 "name."), prop_id, rt_to_str(RT_RCTL)); 4688 return; 4689 } 4690 (void) strlcpy(in_progress_rctltab.zone_rctl_name, 4691 prop_id, 4692 sizeof (in_progress_rctltab.zone_rctl_name)); 4693 break; 4694 case PT_VALUE: 4695 if (pp->pv_type != PROP_VAL_COMPLEX && 4696 pp->pv_type != PROP_VAL_LIST) { 4697 zerr(gettext("A %s or %s value was expected " 4698 "here."), pvt_to_str(PROP_VAL_COMPLEX), 4699 pvt_to_str(PROP_VAL_LIST)); 4700 saw_error = B_TRUE; 4701 return; 4702 } 4703 zonecfg_free_rctl_value_list( 4704 in_progress_rctltab.zone_rctl_valptr); 4705 in_progress_rctltab.zone_rctl_valptr = NULL; 4706 if (!(pp->pv_type == PROP_VAL_LIST && 4707 pp->pv_list == NULL)) 4708 add_property(cmd); 4709 break; 4710 default: 4711 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4712 B_TRUE); 4713 long_usage(CMD_SET, B_TRUE); 4714 usage(B_FALSE, HELP_PROPS); 4715 return; 4716 } 4717 return; 4718 case RT_ATTR: 4719 switch (prop_type) { 4720 case PT_NAME: 4721 (void) strlcpy(in_progress_attrtab.zone_attr_name, 4722 prop_id, 4723 sizeof (in_progress_attrtab.zone_attr_name)); 4724 break; 4725 case PT_TYPE: 4726 (void) strlcpy(in_progress_attrtab.zone_attr_type, 4727 prop_id, 4728 sizeof (in_progress_attrtab.zone_attr_type)); 4729 break; 4730 case PT_VALUE: 4731 (void) strlcpy(in_progress_attrtab.zone_attr_value, 4732 prop_id, 4733 sizeof (in_progress_attrtab.zone_attr_value)); 4734 break; 4735 default: 4736 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4737 B_TRUE); 4738 long_usage(CMD_SET, B_TRUE); 4739 usage(B_FALSE, HELP_PROPS); 4740 return; 4741 } 4742 return; 4743 case RT_DATASET: 4744 switch (prop_type) { 4745 case PT_NAME: 4746 (void) strlcpy(in_progress_dstab.zone_dataset_name, 4747 prop_id, 4748 sizeof (in_progress_dstab.zone_dataset_name)); 4749 return; 4750 default: 4751 break; 4752 } 4753 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4754 long_usage(CMD_SET, B_TRUE); 4755 usage(B_FALSE, HELP_PROPS); 4756 return; 4757 case RT_DCPU: 4758 switch (prop_type) { 4759 char *lowp, *highp; 4760 4761 case PT_NCPUS: 4762 lowp = prop_id; 4763 if ((highp = strchr(prop_id, '-')) != NULL) 4764 *highp++ = '\0'; 4765 else 4766 highp = lowp; 4767 4768 /* Make sure the input makes sense. */ 4769 if (!zonecfg_valid_ncpus(lowp, highp)) { 4770 zerr(gettext("%s property is out of range."), 4771 pt_to_str(PT_NCPUS)); 4772 saw_error = B_TRUE; 4773 return; 4774 } 4775 4776 (void) strlcpy( 4777 in_progress_psettab.zone_ncpu_min, lowp, 4778 sizeof (in_progress_psettab.zone_ncpu_min)); 4779 (void) strlcpy( 4780 in_progress_psettab.zone_ncpu_max, highp, 4781 sizeof (in_progress_psettab.zone_ncpu_max)); 4782 return; 4783 case PT_IMPORTANCE: 4784 /* Make sure the value makes sense. */ 4785 if (!zonecfg_valid_importance(prop_id)) { 4786 zerr(gettext("%s property is out of range."), 4787 pt_to_str(PT_IMPORTANCE)); 4788 saw_error = B_TRUE; 4789 return; 4790 } 4791 4792 (void) strlcpy(in_progress_psettab.zone_importance, 4793 prop_id, 4794 sizeof (in_progress_psettab.zone_importance)); 4795 return; 4796 default: 4797 break; 4798 } 4799 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE); 4800 long_usage(CMD_SET, B_TRUE); 4801 usage(B_FALSE, HELP_PROPS); 4802 return; 4803 case RT_PCAP: 4804 if (prop_type != PT_NCPUS) { 4805 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4806 B_TRUE); 4807 long_usage(CMD_SET, B_TRUE); 4808 usage(B_FALSE, HELP_PROPS); 4809 return; 4810 } 4811 4812 /* 4813 * We already checked that an rctl alias is allowed in 4814 * the add_resource() function. 4815 */ 4816 4817 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' || 4818 (int)(cap * 100) < 1) { 4819 zerr(gettext("%s property is out of range."), 4820 pt_to_str(PT_NCPUS)); 4821 saw_error = B_TRUE; 4822 return; 4823 } 4824 4825 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP, 4826 (int)(cap * 100))) != Z_OK) 4827 zone_perror(zone, err, B_TRUE); 4828 else 4829 need_to_commit = B_TRUE; 4830 return; 4831 case RT_MCAP: 4832 switch (prop_type) { 4833 case PT_PHYSICAL: 4834 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4835 zerr(gettext("A positive number with a " 4836 "required scale suffix (K, M, G or T) was " 4837 "expected here.")); 4838 saw_error = B_TRUE; 4839 } else if (mem_cap < ONE_MB) { 4840 zerr(gettext("%s value is too small. It must " 4841 "be at least 1M."), pt_to_str(PT_PHYSICAL)); 4842 saw_error = B_TRUE; 4843 } else { 4844 snprintf(in_progress_mcaptab.zone_physmem_cap, 4845 physmem_size, "%llu", mem_cap); 4846 } 4847 break; 4848 case PT_SWAP: 4849 /* 4850 * We have to check if an rctl is allowed here since 4851 * there might already be a rctl defined that blocks 4852 * the alias. 4853 */ 4854 if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) { 4855 zone_perror(pt_to_str(PT_MAXSWAP), 4856 Z_ALIAS_DISALLOW, B_FALSE); 4857 saw_error = B_TRUE; 4858 return; 4859 } 4860 4861 if (global_zone) 4862 mem_limit = ONE_MB * 100; 4863 else 4864 mem_limit = ONE_MB * 50; 4865 4866 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4867 zerr(gettext("A positive number with a " 4868 "required scale suffix (K, M, G or T) was " 4869 "expected here.")); 4870 saw_error = B_TRUE; 4871 } else if (mem_cap < mem_limit) { 4872 char buf[128]; 4873 4874 (void) snprintf(buf, sizeof (buf), "%llu", 4875 mem_limit); 4876 bytes_to_units(buf, buf, sizeof (buf)); 4877 zerr(gettext("%s value is too small. It must " 4878 "be at least %s."), pt_to_str(PT_SWAP), 4879 buf); 4880 saw_error = B_TRUE; 4881 } else { 4882 if ((err = zonecfg_set_aliased_rctl(handle, 4883 ALIAS_MAXSWAP, mem_cap)) != Z_OK) 4884 zone_perror(zone, err, B_TRUE); 4885 else 4886 need_to_commit = B_TRUE; 4887 } 4888 break; 4889 case PT_LOCKED: 4890 /* 4891 * We have to check if an rctl is allowed here since 4892 * there might already be a rctl defined that blocks 4893 * the alias. 4894 */ 4895 if (!zonecfg_aliased_rctl_ok(handle, 4896 ALIAS_MAXLOCKEDMEM)) { 4897 zone_perror(pt_to_str(PT_LOCKED), 4898 Z_ALIAS_DISALLOW, B_FALSE); 4899 saw_error = B_TRUE; 4900 return; 4901 } 4902 4903 if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { 4904 zerr(gettext("A non-negative number with a " 4905 "required scale suffix (K, M, G or T) was " 4906 "expected\nhere.")); 4907 saw_error = B_TRUE; 4908 } else { 4909 if ((err = zonecfg_set_aliased_rctl(handle, 4910 ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK) 4911 zone_perror(zone, err, B_TRUE); 4912 else 4913 need_to_commit = B_TRUE; 4914 } 4915 break; 4916 default: 4917 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4918 B_TRUE); 4919 long_usage(CMD_SET, B_TRUE); 4920 usage(B_FALSE, HELP_PROPS); 4921 return; 4922 } 4923 return; 4924 case RT_ADMIN: 4925 switch (prop_type) { 4926 case PT_USER: 4927 (void) strlcpy(in_progress_admintab.zone_admin_user, 4928 prop_id, 4929 sizeof (in_progress_admintab.zone_admin_user)); 4930 return; 4931 case PT_AUTHS: 4932 (void) strlcpy(in_progress_admintab.zone_admin_auths, 4933 prop_id, 4934 sizeof (in_progress_admintab.zone_admin_auths)); 4935 return; 4936 default: 4937 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4938 B_TRUE); 4939 long_usage(CMD_SET, B_TRUE); 4940 usage(B_FALSE, HELP_PROPS); 4941 return; 4942 } 4943 case RT_SECFLAGS: { 4944 char *propstr; 4945 4946 switch (prop_type) { 4947 case PT_DEFAULT: 4948 propstr = in_progress_secflagstab.zone_secflags_default; 4949 break; 4950 case PT_UPPER: 4951 propstr = in_progress_secflagstab.zone_secflags_upper; 4952 break; 4953 case PT_LOWER: 4954 propstr = in_progress_secflagstab.zone_secflags_lower; 4955 break; 4956 default: 4957 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, 4958 B_TRUE); 4959 long_usage(CMD_SET, B_TRUE); 4960 usage(B_FALSE, HELP_PROPS); 4961 return; 4962 } 4963 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX); 4964 return; 4965 } 4966 default: 4967 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE); 4968 long_usage(CMD_SET, B_TRUE); 4969 usage(B_FALSE, HELP_RESOURCES); 4970 return; 4971 } 4972 } 4973 4974 static void 4975 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec) 4976 { 4977 char *qstr; 4978 4979 if (*pval != '\0') { 4980 qstr = quoteit(pval); 4981 if (pnum == PT_SWAP || pnum == PT_LOCKED) 4982 (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum), 4983 qstr); 4984 else 4985 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); 4986 free(qstr); 4987 } else if (print_notspec) 4988 (void) fprintf(fp, gettext("\t%s not specified\n"), 4989 pt_to_str(pnum)); 4990 } 4991 4992 static void 4993 info_zonename(zone_dochandle_t handle, FILE *fp) 4994 { 4995 char zonename[ZONENAME_MAX]; 4996 4997 if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK) 4998 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME), 4999 zonename); 5000 else 5001 (void) fprintf(fp, gettext("%s not specified\n"), 5002 pt_to_str(PT_ZONENAME)); 5003 } 5004 5005 static void 5006 info_zonepath(zone_dochandle_t handle, FILE *fp) 5007 { 5008 char zonepath[MAXPATHLEN]; 5009 5010 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK) 5011 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH), 5012 zonepath); 5013 else { 5014 (void) fprintf(fp, gettext("%s not specified\n"), 5015 pt_to_str(PT_ZONEPATH)); 5016 } 5017 } 5018 5019 static void 5020 info_brand(zone_dochandle_t handle, FILE *fp) 5021 { 5022 char brand[MAXNAMELEN]; 5023 5024 if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK) 5025 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND), 5026 brand); 5027 else 5028 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND), 5029 gettext("not specified")); 5030 } 5031 5032 static void 5033 info_autoboot(zone_dochandle_t handle, FILE *fp) 5034 { 5035 boolean_t autoboot; 5036 int err; 5037 5038 if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK) 5039 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT), 5040 autoboot ? "true" : "false"); 5041 else 5042 zone_perror(zone, err, B_TRUE); 5043 } 5044 5045 static void 5046 info_pool(zone_dochandle_t handle, FILE *fp) 5047 { 5048 char pool[MAXNAMELEN]; 5049 int err; 5050 5051 if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK) 5052 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool); 5053 else 5054 zone_perror(zone, err, B_TRUE); 5055 } 5056 5057 static void 5058 info_limitpriv(zone_dochandle_t handle, FILE *fp) 5059 { 5060 char *limitpriv; 5061 int err; 5062 5063 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) { 5064 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV), 5065 limitpriv); 5066 free(limitpriv); 5067 } else { 5068 zone_perror(zone, err, B_TRUE); 5069 } 5070 } 5071 5072 static void 5073 info_bootargs(zone_dochandle_t handle, FILE *fp) 5074 { 5075 char bootargs[BOOTARGS_MAX]; 5076 int err; 5077 5078 if ((err = zonecfg_get_bootargs(handle, bootargs, 5079 sizeof (bootargs))) == Z_OK) { 5080 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS), 5081 bootargs); 5082 } else { 5083 zone_perror(zone, err, B_TRUE); 5084 } 5085 } 5086 5087 static void 5088 info_sched(zone_dochandle_t handle, FILE *fp) 5089 { 5090 char sched[MAXNAMELEN]; 5091 int err; 5092 5093 if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched))) 5094 == Z_OK) { 5095 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched); 5096 } else { 5097 zone_perror(zone, err, B_TRUE); 5098 } 5099 } 5100 5101 static void 5102 info_iptype(zone_dochandle_t handle, FILE *fp) 5103 { 5104 zone_iptype_t iptype; 5105 int err; 5106 5107 if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) { 5108 switch (iptype) { 5109 case ZS_SHARED: 5110 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 5111 "shared"); 5112 break; 5113 case ZS_EXCLUSIVE: 5114 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE), 5115 "exclusive"); 5116 break; 5117 } 5118 } else { 5119 zone_perror(zone, err, B_TRUE); 5120 } 5121 } 5122 5123 static void 5124 info_hostid(zone_dochandle_t handle, FILE *fp) 5125 { 5126 char hostidp[HW_HOSTID_LEN]; 5127 int err; 5128 5129 if ((err = zonecfg_get_hostid(handle, hostidp, 5130 sizeof (hostidp))) == Z_OK) { 5131 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp); 5132 } else if (err == Z_BAD_PROPERTY) { 5133 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID)); 5134 } else { 5135 zone_perror(zone, err, B_TRUE); 5136 } 5137 } 5138 5139 static void 5140 info_fs_allowed(zone_dochandle_t handle, FILE *fp) 5141 { 5142 char fsallowedp[ZONE_FS_ALLOWED_MAX]; 5143 int err; 5144 5145 if ((err = zonecfg_get_fs_allowed(handle, fsallowedp, 5146 sizeof (fsallowedp))) == Z_OK) { 5147 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED), 5148 fsallowedp); 5149 } else if (err == Z_BAD_PROPERTY) { 5150 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED)); 5151 } else { 5152 zone_perror(zone, err, B_TRUE); 5153 } 5154 } 5155 5156 static void 5157 output_fs(FILE *fp, struct zone_fstab *fstab) 5158 { 5159 zone_fsopt_t *this; 5160 5161 (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS)); 5162 output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE); 5163 output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE); 5164 output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE); 5165 output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE); 5166 (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS)); 5167 for (this = fstab->zone_fs_options; this != NULL; 5168 this = this->zone_fsopt_next) { 5169 if (strchr(this->zone_fsopt_opt, '=')) 5170 (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt); 5171 else 5172 (void) fprintf(fp, "%s", this->zone_fsopt_opt); 5173 if (this->zone_fsopt_next != NULL) 5174 (void) fprintf(fp, ","); 5175 } 5176 (void) fprintf(fp, "]\n"); 5177 } 5178 5179 static void 5180 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5181 { 5182 struct zone_fstab lookup, user; 5183 boolean_t output = B_FALSE; 5184 5185 if (zonecfg_setfsent(handle) != Z_OK) 5186 return; 5187 while (zonecfg_getfsent(handle, &lookup) == Z_OK) { 5188 if (cmd->cmd_prop_nv_pairs == 0) { 5189 output_fs(fp, &lookup); 5190 goto loopend; 5191 } 5192 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK) 5193 goto loopend; 5194 if (strlen(user.zone_fs_dir) > 0 && 5195 strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0) 5196 goto loopend; /* no match */ 5197 if (strlen(user.zone_fs_special) > 0 && 5198 strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0) 5199 goto loopend; /* no match */ 5200 if (strlen(user.zone_fs_type) > 0 && 5201 strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0) 5202 goto loopend; /* no match */ 5203 output_fs(fp, &lookup); 5204 output = B_TRUE; 5205 loopend: 5206 zonecfg_free_fs_option_list(lookup.zone_fs_options); 5207 } 5208 (void) zonecfg_endfsent(handle); 5209 /* 5210 * If a property n/v pair was specified, warn the user if there was 5211 * nothing to output. 5212 */ 5213 if (!output && cmd->cmd_prop_nv_pairs > 0) 5214 (void) printf(gettext("No such %s resource.\n"), 5215 rt_to_str(RT_FS)); 5216 } 5217 5218 static void 5219 output_net(FILE *fp, struct zone_nwiftab *nwiftab) 5220 { 5221 (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET)); 5222 output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE); 5223 output_prop(fp, PT_ALLOWED_ADDRESS, 5224 nwiftab->zone_nwif_allowed_address, B_TRUE); 5225 output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE); 5226 output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE); 5227 } 5228 5229 static void 5230 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5231 { 5232 struct zone_nwiftab lookup, user; 5233 boolean_t output = B_FALSE; 5234 5235 if (zonecfg_setnwifent(handle) != Z_OK) 5236 return; 5237 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) { 5238 if (cmd->cmd_prop_nv_pairs == 0) { 5239 output_net(fp, &lookup); 5240 continue; 5241 } 5242 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK) 5243 continue; 5244 if (strlen(user.zone_nwif_physical) > 0 && 5245 strcmp(user.zone_nwif_physical, 5246 lookup.zone_nwif_physical) != 0) 5247 continue; /* no match */ 5248 /* If present make sure it matches */ 5249 if (strlen(user.zone_nwif_address) > 0 && 5250 !zonecfg_same_net_address(user.zone_nwif_address, 5251 lookup.zone_nwif_address)) 5252 continue; /* no match */ 5253 output_net(fp, &lookup); 5254 output = B_TRUE; 5255 } 5256 (void) zonecfg_endnwifent(handle); 5257 /* 5258 * If a property n/v pair was specified, warn the user if there was 5259 * nothing to output. 5260 */ 5261 if (!output && cmd->cmd_prop_nv_pairs > 0) 5262 (void) printf(gettext("No such %s resource.\n"), 5263 rt_to_str(RT_NET)); 5264 } 5265 5266 static void 5267 output_dev(FILE *fp, struct zone_devtab *devtab) 5268 { 5269 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE)); 5270 output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE); 5271 } 5272 5273 static void 5274 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5275 { 5276 struct zone_devtab lookup, user; 5277 boolean_t output = B_FALSE; 5278 5279 if (zonecfg_setdevent(handle) != Z_OK) 5280 return; 5281 while (zonecfg_getdevent(handle, &lookup) == Z_OK) { 5282 if (cmd->cmd_prop_nv_pairs == 0) { 5283 output_dev(fp, &lookup); 5284 continue; 5285 } 5286 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK) 5287 continue; 5288 if (strlen(user.zone_dev_match) > 0 && 5289 strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0) 5290 continue; /* no match */ 5291 output_dev(fp, &lookup); 5292 output = B_TRUE; 5293 } 5294 (void) zonecfg_enddevent(handle); 5295 /* 5296 * If a property n/v pair was specified, warn the user if there was 5297 * nothing to output. 5298 */ 5299 if (!output && cmd->cmd_prop_nv_pairs > 0) 5300 (void) printf(gettext("No such %s resource.\n"), 5301 rt_to_str(RT_DEVICE)); 5302 } 5303 5304 static void 5305 output_rctl(FILE *fp, struct zone_rctltab *rctltab) 5306 { 5307 struct zone_rctlvaltab *valptr; 5308 5309 (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL)); 5310 output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE); 5311 for (valptr = rctltab->zone_rctl_valptr; valptr != NULL; 5312 valptr = valptr->zone_rctlval_next) { 5313 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n", 5314 pt_to_str(PT_VALUE), 5315 pt_to_str(PT_PRIV), valptr->zone_rctlval_priv, 5316 pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit, 5317 pt_to_str(PT_ACTION), valptr->zone_rctlval_action); 5318 } 5319 } 5320 5321 static void 5322 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5323 { 5324 struct zone_rctltab lookup, user; 5325 boolean_t output = B_FALSE; 5326 5327 if (zonecfg_setrctlent(handle) != Z_OK) 5328 return; 5329 while (zonecfg_getrctlent(handle, &lookup) == Z_OK) { 5330 if (cmd->cmd_prop_nv_pairs == 0) { 5331 output_rctl(fp, &lookup); 5332 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK && 5333 (strlen(user.zone_rctl_name) == 0 || 5334 strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) { 5335 output_rctl(fp, &lookup); 5336 output = B_TRUE; 5337 } 5338 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr); 5339 } 5340 (void) zonecfg_endrctlent(handle); 5341 /* 5342 * If a property n/v pair was specified, warn the user if there was 5343 * nothing to output. 5344 */ 5345 if (!output && cmd->cmd_prop_nv_pairs > 0) 5346 (void) printf(gettext("No such %s resource.\n"), 5347 rt_to_str(RT_RCTL)); 5348 } 5349 5350 static void 5351 output_attr(FILE *fp, struct zone_attrtab *attrtab) 5352 { 5353 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR)); 5354 output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE); 5355 output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE); 5356 output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE); 5357 } 5358 5359 static void 5360 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5361 { 5362 struct zone_attrtab lookup, user; 5363 boolean_t output = B_FALSE; 5364 5365 if (zonecfg_setattrent(handle) != Z_OK) 5366 return; 5367 while (zonecfg_getattrent(handle, &lookup) == Z_OK) { 5368 if (cmd->cmd_prop_nv_pairs == 0) { 5369 output_attr(fp, &lookup); 5370 continue; 5371 } 5372 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK) 5373 continue; 5374 if (strlen(user.zone_attr_name) > 0 && 5375 strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0) 5376 continue; /* no match */ 5377 if (strlen(user.zone_attr_type) > 0 && 5378 strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0) 5379 continue; /* no match */ 5380 if (strlen(user.zone_attr_value) > 0 && 5381 strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0) 5382 continue; /* no match */ 5383 output_attr(fp, &lookup); 5384 output = B_TRUE; 5385 } 5386 (void) zonecfg_endattrent(handle); 5387 /* 5388 * If a property n/v pair was specified, warn the user if there was 5389 * nothing to output. 5390 */ 5391 if (!output && cmd->cmd_prop_nv_pairs > 0) 5392 (void) printf(gettext("No such %s resource.\n"), 5393 rt_to_str(RT_ATTR)); 5394 } 5395 5396 static void 5397 output_ds(FILE *fp, struct zone_dstab *dstab) 5398 { 5399 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET)); 5400 output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE); 5401 } 5402 5403 static void 5404 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5405 { 5406 struct zone_dstab lookup, user; 5407 boolean_t output = B_FALSE; 5408 5409 if (zonecfg_setdsent(handle) != Z_OK) 5410 return; 5411 while (zonecfg_getdsent(handle, &lookup) == Z_OK) { 5412 if (cmd->cmd_prop_nv_pairs == 0) { 5413 output_ds(fp, &lookup); 5414 continue; 5415 } 5416 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK) 5417 continue; 5418 if (strlen(user.zone_dataset_name) > 0 && 5419 strcmp(user.zone_dataset_name, 5420 lookup.zone_dataset_name) != 0) 5421 continue; /* no match */ 5422 output_ds(fp, &lookup); 5423 output = B_TRUE; 5424 } 5425 (void) zonecfg_enddsent(handle); 5426 /* 5427 * If a property n/v pair was specified, warn the user if there was 5428 * nothing to output. 5429 */ 5430 if (!output && cmd->cmd_prop_nv_pairs > 0) 5431 (void) printf(gettext("No such %s resource.\n"), 5432 rt_to_str(RT_DATASET)); 5433 } 5434 5435 static void 5436 output_pset(FILE *fp, struct zone_psettab *psettab) 5437 { 5438 (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU)); 5439 if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0) 5440 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS), 5441 psettab->zone_ncpu_max); 5442 else 5443 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS), 5444 psettab->zone_ncpu_min, psettab->zone_ncpu_max); 5445 if (psettab->zone_importance[0] != '\0') 5446 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE), 5447 psettab->zone_importance); 5448 } 5449 5450 static void 5451 info_pset(zone_dochandle_t handle, FILE *fp) 5452 { 5453 struct zone_psettab lookup; 5454 5455 if (zonecfg_getpsetent(handle, &lookup) == Z_OK) 5456 output_pset(fp, &lookup); 5457 } 5458 5459 static void 5460 output_pcap(FILE *fp) 5461 { 5462 uint64_t cap; 5463 5464 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) { 5465 float scaled = (float)cap / 100; 5466 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP)); 5467 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS), 5468 scaled); 5469 } 5470 } 5471 5472 static void 5473 info_pcap(FILE *fp) 5474 { 5475 output_pcap(fp); 5476 } 5477 5478 5479 static void 5480 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias) 5481 { 5482 uint64_t limit; 5483 5484 if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) { 5485 /* convert memory based properties */ 5486 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) { 5487 char buf[128]; 5488 5489 (void) snprintf(buf, sizeof (buf), "%llu", limit); 5490 bytes_to_units(buf, buf, sizeof (buf)); 5491 (void) fprintf(fp, "[%s: %s]\n", alias, buf); 5492 return; 5493 } 5494 5495 (void) fprintf(fp, "[%s: %llu]\n", alias, limit); 5496 } 5497 } 5498 5499 static void 5500 bytes_to_units(char *str, char *buf, int bufsize) 5501 { 5502 unsigned long long num; 5503 unsigned long long save = 0; 5504 char *units = "BKMGT"; 5505 char *up = units; 5506 5507 num = strtoll(str, NULL, 10); 5508 5509 if (num < 1024) { 5510 (void) snprintf(buf, bufsize, "%llu", num); 5511 return; 5512 } 5513 5514 while ((num >= 1024) && (*up != 'T')) { 5515 up++; /* next unit of measurement */ 5516 save = num; 5517 num = (num + 512) >> 10; 5518 } 5519 5520 /* check if we should output a fraction. snprintf will round for us */ 5521 if (save % 1024 != 0 && ((save >> 10) < 10)) 5522 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024), 5523 *up); 5524 else 5525 (void) snprintf(buf, bufsize, "%llu%c", num, *up); 5526 } 5527 5528 static void 5529 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap, 5530 uint64_t maxswap, int showlocked, uint64_t maxlocked) 5531 { 5532 char buf[128]; 5533 5534 (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP)); 5535 if (mcaptab->zone_physmem_cap[0] != '\0') { 5536 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf)); 5537 output_prop(fp, PT_PHYSICAL, buf, B_TRUE); 5538 } 5539 5540 if (showswap == Z_OK) { 5541 (void) snprintf(buf, sizeof (buf), "%llu", maxswap); 5542 bytes_to_units(buf, buf, sizeof (buf)); 5543 output_prop(fp, PT_SWAP, buf, B_TRUE); 5544 } 5545 5546 if (showlocked == Z_OK) { 5547 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked); 5548 bytes_to_units(buf, buf, sizeof (buf)); 5549 output_prop(fp, PT_LOCKED, buf, B_TRUE); 5550 } 5551 } 5552 5553 static void 5554 info_mcap(zone_dochandle_t handle, FILE *fp) 5555 { 5556 int res1, res2, res3; 5557 uint64_t swap_limit; 5558 uint64_t locked_limit; 5559 struct zone_mcaptab lookup; 5560 5561 bzero(&lookup, sizeof (lookup)); 5562 res1 = zonecfg_getmcapent(handle, &lookup); 5563 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit); 5564 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 5565 &locked_limit); 5566 5567 if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK) 5568 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit); 5569 } 5570 5571 static void 5572 output_auth(FILE *fp, struct zone_admintab *admintab) 5573 { 5574 (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN)); 5575 output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE); 5576 output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE); 5577 } 5578 5579 static void 5580 output_secflags(FILE *fp, struct zone_secflagstab *sftab) 5581 { 5582 (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS)); 5583 output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE); 5584 output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE); 5585 output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE); 5586 } 5587 5588 static void 5589 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) 5590 { 5591 struct zone_admintab lookup, user; 5592 boolean_t output = B_FALSE; 5593 int err; 5594 5595 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 5596 zone_perror(zone, err, B_TRUE); 5597 return; 5598 } 5599 while (zonecfg_getadminent(handle, &lookup) == Z_OK) { 5600 if (cmd->cmd_prop_nv_pairs == 0) { 5601 output_auth(fp, &lookup); 5602 continue; 5603 } 5604 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK) 5605 continue; 5606 if (strlen(user.zone_admin_user) > 0 && 5607 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0) 5608 continue; /* no match */ 5609 output_auth(fp, &lookup); 5610 output = B_TRUE; 5611 } 5612 (void) zonecfg_endadminent(handle); 5613 /* 5614 * If a property n/v pair was specified, warn the user if there was 5615 * nothing to output. 5616 */ 5617 if (!output && cmd->cmd_prop_nv_pairs > 0) 5618 (void) printf(gettext("No such %s resource.\n"), 5619 rt_to_str(RT_ADMIN)); 5620 } 5621 5622 static void 5623 info_secflags(zone_dochandle_t handle, FILE *fp) 5624 { 5625 struct zone_secflagstab sftab; 5626 5627 if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) { 5628 output_secflags(fp, &sftab); 5629 } 5630 } 5631 5632 void 5633 info_func(cmd_t *cmd) 5634 { 5635 FILE *fp = stdout; 5636 boolean_t need_to_close = B_FALSE; 5637 int type; 5638 int res1, res2; 5639 uint64_t swap_limit; 5640 uint64_t locked_limit; 5641 5642 assert(cmd != NULL); 5643 5644 if (initialize(B_TRUE) != Z_OK) 5645 return; 5646 5647 /* don't page error output */ 5648 if (interactive_mode) { 5649 if ((fp = pager_open()) != NULL) 5650 need_to_close = B_TRUE; 5651 else 5652 fp = stdout; 5653 5654 setbuf(fp, NULL); 5655 } 5656 5657 if (!global_scope) { 5658 switch (resource_scope) { 5659 case RT_FS: 5660 output_fs(fp, &in_progress_fstab); 5661 break; 5662 case RT_NET: 5663 output_net(fp, &in_progress_nwiftab); 5664 break; 5665 case RT_DEVICE: 5666 output_dev(fp, &in_progress_devtab); 5667 break; 5668 case RT_RCTL: 5669 output_rctl(fp, &in_progress_rctltab); 5670 break; 5671 case RT_ATTR: 5672 output_attr(fp, &in_progress_attrtab); 5673 break; 5674 case RT_DATASET: 5675 output_ds(fp, &in_progress_dstab); 5676 break; 5677 case RT_DCPU: 5678 output_pset(fp, &in_progress_psettab); 5679 break; 5680 case RT_PCAP: 5681 output_pcap(fp); 5682 break; 5683 case RT_MCAP: 5684 res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 5685 &swap_limit); 5686 res2 = zonecfg_get_aliased_rctl(handle, 5687 ALIAS_MAXLOCKEDMEM, &locked_limit); 5688 output_mcap(fp, &in_progress_mcaptab, res1, swap_limit, 5689 res2, locked_limit); 5690 break; 5691 case RT_ADMIN: 5692 output_auth(fp, &in_progress_admintab); 5693 break; 5694 case RT_SECFLAGS: 5695 output_secflags(fp, &in_progress_secflagstab); 5696 break; 5697 } 5698 goto cleanup; 5699 } 5700 5701 type = cmd->cmd_res_type; 5702 5703 if (gz_invalid_rt_property(type)) { 5704 zerr(gettext("%s is not a valid property for the global zone."), 5705 rt_to_str(type)); 5706 goto cleanup; 5707 } 5708 5709 if (gz_invalid_resource(type)) { 5710 zerr(gettext("%s is not a valid resource for the global zone."), 5711 rt_to_str(type)); 5712 goto cleanup; 5713 } 5714 5715 switch (cmd->cmd_res_type) { 5716 case RT_UNKNOWN: 5717 info_zonename(handle, fp); 5718 if (!global_zone) { 5719 info_zonepath(handle, fp); 5720 info_brand(handle, fp); 5721 info_autoboot(handle, fp); 5722 info_bootargs(handle, fp); 5723 } 5724 info_pool(handle, fp); 5725 if (!global_zone) { 5726 info_limitpriv(handle, fp); 5727 info_sched(handle, fp); 5728 info_iptype(handle, fp); 5729 info_hostid(handle, fp); 5730 info_fs_allowed(handle, fp); 5731 } 5732 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5733 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS); 5734 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5735 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5736 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5737 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5738 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5739 if (!global_zone) { 5740 info_fs(handle, fp, cmd); 5741 info_net(handle, fp, cmd); 5742 info_dev(handle, fp, cmd); 5743 } 5744 info_pset(handle, fp); 5745 info_pcap(fp); 5746 info_mcap(handle, fp); 5747 if (!global_zone) { 5748 info_attr(handle, fp, cmd); 5749 info_ds(handle, fp, cmd); 5750 info_auth(handle, fp, cmd); 5751 } 5752 info_rctl(handle, fp, cmd); 5753 info_secflags(handle, fp); 5754 break; 5755 case RT_ZONENAME: 5756 info_zonename(handle, fp); 5757 break; 5758 case RT_ZONEPATH: 5759 info_zonepath(handle, fp); 5760 break; 5761 case RT_BRAND: 5762 info_brand(handle, fp); 5763 break; 5764 case RT_AUTOBOOT: 5765 info_autoboot(handle, fp); 5766 break; 5767 case RT_POOL: 5768 info_pool(handle, fp); 5769 break; 5770 case RT_LIMITPRIV: 5771 info_limitpriv(handle, fp); 5772 break; 5773 case RT_BOOTARGS: 5774 info_bootargs(handle, fp); 5775 break; 5776 case RT_SCHED: 5777 info_sched(handle, fp); 5778 break; 5779 case RT_IPTYPE: 5780 info_iptype(handle, fp); 5781 break; 5782 case RT_MAXLWPS: 5783 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); 5784 break; 5785 case RT_MAXPROCS: 5786 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS); 5787 break; 5788 case RT_MAXSHMMEM: 5789 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); 5790 break; 5791 case RT_MAXSHMIDS: 5792 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); 5793 break; 5794 case RT_MAXMSGIDS: 5795 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); 5796 break; 5797 case RT_MAXSEMIDS: 5798 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); 5799 break; 5800 case RT_SHARES: 5801 info_aliased_rctl(handle, fp, ALIAS_SHARES); 5802 break; 5803 case RT_FS: 5804 info_fs(handle, fp, cmd); 5805 break; 5806 case RT_NET: 5807 info_net(handle, fp, cmd); 5808 break; 5809 case RT_DEVICE: 5810 info_dev(handle, fp, cmd); 5811 break; 5812 case RT_RCTL: 5813 info_rctl(handle, fp, cmd); 5814 break; 5815 case RT_ATTR: 5816 info_attr(handle, fp, cmd); 5817 break; 5818 case RT_DATASET: 5819 info_ds(handle, fp, cmd); 5820 break; 5821 case RT_DCPU: 5822 info_pset(handle, fp); 5823 break; 5824 case RT_PCAP: 5825 info_pcap(fp); 5826 break; 5827 case RT_MCAP: 5828 info_mcap(handle, fp); 5829 break; 5830 case RT_HOSTID: 5831 info_hostid(handle, fp); 5832 break; 5833 case RT_ADMIN: 5834 info_auth(handle, fp, cmd); 5835 break; 5836 case RT_FS_ALLOWED: 5837 info_fs_allowed(handle, fp); 5838 break; 5839 case RT_SECFLAGS: 5840 info_secflags(handle, fp); 5841 break; 5842 default: 5843 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, 5844 B_TRUE); 5845 } 5846 5847 cleanup: 5848 if (need_to_close) 5849 (void) pager_close(fp); 5850 } 5851 5852 /* 5853 * Helper function for verify-- checks that a required string property 5854 * exists. 5855 */ 5856 static void 5857 check_reqd_prop(char *attr, int rt, int pt, int *ret_val) 5858 { 5859 if (strlen(attr) == 0) { 5860 zerr(gettext("%s: %s not specified"), rt_to_str(rt), 5861 pt_to_str(pt)); 5862 saw_error = B_TRUE; 5863 if (*ret_val == Z_OK) 5864 *ret_val = Z_REQD_PROPERTY_MISSING; 5865 } 5866 } 5867 5868 static int 5869 do_subproc(char *cmdbuf) 5870 { 5871 char inbuf[MAX_CMD_LEN]; 5872 FILE *file; 5873 int status; 5874 5875 file = popen(cmdbuf, "r"); 5876 if (file == NULL) { 5877 zerr(gettext("Could not launch: %s"), cmdbuf); 5878 return (-1); 5879 } 5880 5881 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 5882 fprintf(stderr, "%s", inbuf); 5883 status = pclose(file); 5884 5885 if (WIFSIGNALED(status)) { 5886 zerr(gettext("%s unexpectedly terminated due to signal %d"), 5887 cmdbuf, WTERMSIG(status)); 5888 return (-1); 5889 } 5890 assert(WIFEXITED(status)); 5891 return (WEXITSTATUS(status)); 5892 } 5893 5894 static int 5895 brand_verify(zone_dochandle_t handle) 5896 { 5897 char xml_file[32]; 5898 char cmdbuf[MAX_CMD_LEN]; 5899 brand_handle_t bh; 5900 char brand[MAXNAMELEN]; 5901 int err; 5902 5903 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) { 5904 zerr("%s: %s\n", zone, gettext("could not get zone brand")); 5905 return (Z_INVALID_DOCUMENT); 5906 } 5907 if ((bh = brand_open(brand)) == NULL) { 5908 zerr("%s: %s\n", zone, gettext("unknown brand.")); 5909 return (Z_INVALID_DOCUMENT); 5910 } 5911 5912 /* 5913 * Fetch the verify command, if any, from the brand configuration 5914 * and build the command line to execute it. 5915 */ 5916 strcpy(cmdbuf, EXEC_PREFIX); 5917 err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN, 5918 sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1))); 5919 brand_close(bh); 5920 if (err != Z_OK) { 5921 zerr("%s: %s\n", zone, 5922 gettext("could not get brand verification command")); 5923 return (Z_INVALID_DOCUMENT); 5924 } 5925 5926 /* 5927 * If the brand doesn't provide a verification routine, we just 5928 * return success. 5929 */ 5930 if (strlen(cmdbuf) == EXEC_LEN) 5931 return (Z_OK); 5932 5933 /* 5934 * Dump the current config information for this zone to a file. 5935 */ 5936 strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX"); 5937 if (mkstemp(xml_file) == -1) 5938 return (Z_TEMP_FILE); 5939 if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) { 5940 (void) unlink(xml_file); 5941 return (err); 5942 } 5943 5944 /* 5945 * Execute the verification command. 5946 */ 5947 if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) || 5948 (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) { 5949 err = Z_BRAND_ERROR; 5950 } else { 5951 err = do_subproc(cmdbuf); 5952 } 5953 5954 (void) unlink(xml_file); 5955 return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR); 5956 } 5957 5958 /* 5959 * Track the network interfaces listed in zonecfg(1m) in a linked list 5960 * so that we can later check that defrouter is specified for an exclusive IP 5961 * zone if and only if at least one allowed-address has been specified. 5962 */ 5963 static boolean_t 5964 add_nwif(struct zone_nwiftab *nwif) 5965 { 5966 struct xif *tmp; 5967 5968 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) { 5969 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) { 5970 if (strlen(nwif->zone_nwif_allowed_address) > 0) 5971 tmp->xif_has_address = B_TRUE; 5972 if (strlen(nwif->zone_nwif_defrouter) > 0) 5973 tmp->xif_has_defrouter = B_TRUE; 5974 return (B_TRUE); 5975 } 5976 } 5977 5978 tmp = malloc(sizeof (*tmp)); 5979 if (tmp == NULL) { 5980 zerr(gettext("memory allocation failed for %s"), 5981 nwif->zone_nwif_physical); 5982 return (B_FALSE); 5983 } 5984 strlcpy(tmp->xif_name, nwif->zone_nwif_physical, 5985 sizeof (tmp->xif_name)); 5986 tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0); 5987 tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0); 5988 tmp->xif_next = xif; 5989 xif = tmp; 5990 return (B_TRUE); 5991 } 5992 5993 boolean_t 5994 verify_secflags(struct zone_secflagstab *tab) 5995 { 5996 secflagdelta_t def = {0}; 5997 secflagdelta_t upper = {0}; 5998 secflagdelta_t lower = {0}; 5999 boolean_t def_set = B_FALSE; 6000 boolean_t upper_set = B_FALSE; 6001 boolean_t lower_set = B_FALSE; 6002 boolean_t ret = B_TRUE; 6003 6004 if (strlen(tab->zone_secflags_default) > 0) { 6005 def_set = B_TRUE; 6006 if (secflags_parse(NULL, tab->zone_secflags_default, 6007 &def) == -1) { 6008 zerr(gettext("default security flags '%s' are invalid"), 6009 tab->zone_secflags_default); 6010 ret = B_FALSE; 6011 } 6012 } else { 6013 secflags_zero(&def.psd_assign); 6014 def.psd_ass_active = B_TRUE; 6015 } 6016 6017 if (strlen(tab->zone_secflags_upper) > 0) { 6018 upper_set = B_TRUE; 6019 if (secflags_parse(NULL, tab->zone_secflags_upper, 6020 &upper) == -1) { 6021 zerr(gettext("upper security flags '%s' are invalid"), 6022 tab->zone_secflags_upper); 6023 ret = B_FALSE; 6024 } 6025 } else { 6026 secflags_fullset(&upper.psd_assign); 6027 upper.psd_ass_active = B_TRUE; 6028 } 6029 6030 if (strlen(tab->zone_secflags_lower) > 0) { 6031 lower_set = B_TRUE; 6032 if (secflags_parse(NULL, tab->zone_secflags_lower, 6033 &lower) == -1) { 6034 zerr(gettext("lower security flags '%s' are invalid"), 6035 tab->zone_secflags_lower); 6036 ret = B_FALSE; 6037 } 6038 } else { 6039 secflags_zero(&lower.psd_assign); 6040 lower.psd_ass_active = B_TRUE; 6041 } 6042 6043 if (def_set && !def.psd_ass_active) { 6044 zerr(gettext("only assignment of security flags is " 6045 "allowed (default: %s)"), tab->zone_secflags_default); 6046 } 6047 6048 if (lower_set && !lower.psd_ass_active) { 6049 zerr(gettext("only assignment of security flags is " 6050 "allowed (lower: %s)"), tab->zone_secflags_lower); 6051 } 6052 6053 if (upper_set && !upper.psd_ass_active) { 6054 zerr(gettext("only assignment of security flags is " 6055 "allowed (upper: %s)"), tab->zone_secflags_upper); 6056 } 6057 6058 if (def.psd_assign & ~upper.psd_assign) { /* In default but not upper */ 6059 zerr(gettext("default secflags must be within the " 6060 "upper limit")); 6061 ret = B_FALSE; 6062 } 6063 if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */ 6064 zerr(gettext("default secflags must be above the lower limit")); 6065 ret = B_FALSE; 6066 } 6067 if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */ 6068 zerr(gettext("lower secflags must be within the upper limit")); 6069 ret = B_FALSE; 6070 } 6071 6072 return (ret); 6073 } 6074 6075 /* 6076 * See the DTD for which attributes are required for which resources. 6077 * 6078 * This function can be called by commit_func(), which needs to save things, 6079 * in addition to the general call from parse_and_run(), which doesn't need 6080 * things saved. Since the parameters are standardized, we distinguish by 6081 * having commit_func() call here with cmd->cmd_arg set to "save" to indicate 6082 * that a save is needed. 6083 */ 6084 void 6085 verify_func(cmd_t *cmd) 6086 { 6087 struct zone_nwiftab nwiftab; 6088 struct zone_fstab fstab; 6089 struct zone_attrtab attrtab; 6090 struct zone_rctltab rctltab; 6091 struct zone_dstab dstab; 6092 struct zone_psettab psettab; 6093 struct zone_admintab admintab; 6094 struct zone_secflagstab secflagstab; 6095 char zonepath[MAXPATHLEN]; 6096 char sched[MAXNAMELEN]; 6097 char brand[MAXNAMELEN]; 6098 char hostidp[HW_HOSTID_LEN]; 6099 char fsallowedp[ZONE_FS_ALLOWED_MAX]; 6100 priv_set_t *privs; 6101 char *privname = NULL; 6102 int err, ret_val = Z_OK, arg; 6103 int pset_res; 6104 boolean_t save = B_FALSE; 6105 boolean_t arg_err = B_FALSE; 6106 zone_iptype_t iptype; 6107 boolean_t has_cpu_shares = B_FALSE; 6108 boolean_t has_cpu_cap = B_FALSE; 6109 struct xif *tmp; 6110 6111 optind = 0; 6112 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6113 switch (arg) { 6114 case '?': 6115 longer_usage(CMD_VERIFY); 6116 arg_err = B_TRUE; 6117 break; 6118 default: 6119 short_usage(CMD_VERIFY); 6120 arg_err = B_TRUE; 6121 break; 6122 } 6123 } 6124 if (arg_err) 6125 return; 6126 6127 if (optind > cmd->cmd_argc) { 6128 short_usage(CMD_VERIFY); 6129 return; 6130 } 6131 6132 if (zone_is_read_only(CMD_VERIFY)) 6133 return; 6134 6135 assert(cmd != NULL); 6136 6137 if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0)) 6138 save = B_TRUE; 6139 if (initialize(B_TRUE) != Z_OK) 6140 return; 6141 6142 if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK && 6143 !global_zone) { 6144 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); 6145 ret_val = Z_REQD_RESOURCE_MISSING; 6146 saw_error = B_TRUE; 6147 } 6148 if (strlen(zonepath) == 0 && !global_zone) { 6149 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); 6150 ret_val = Z_REQD_RESOURCE_MISSING; 6151 saw_error = B_TRUE; 6152 } 6153 6154 if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) { 6155 zone_perror(zone, err, B_TRUE); 6156 return; 6157 } 6158 if ((err = brand_verify(handle)) != Z_OK) { 6159 zone_perror(zone, err, B_TRUE); 6160 return; 6161 } 6162 6163 if (zonecfg_get_iptype(handle, &iptype) != Z_OK) { 6164 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE)); 6165 ret_val = Z_REQD_RESOURCE_MISSING; 6166 saw_error = B_TRUE; 6167 } 6168 6169 if ((privs = priv_allocset()) == NULL) { 6170 zerr(gettext("%s: priv_allocset failed"), zone); 6171 return; 6172 } 6173 if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) { 6174 zerr(gettext("%s: invalid privilege: %s"), zone, privname); 6175 priv_freeset(privs); 6176 free(privname); 6177 return; 6178 } 6179 priv_freeset(privs); 6180 6181 if (zonecfg_get_hostid(handle, hostidp, 6182 sizeof (hostidp)) == Z_INVALID_PROPERTY) { 6183 zerr(gettext("%s: invalid hostid: %s"), 6184 zone, hostidp); 6185 return; 6186 } 6187 6188 if (zonecfg_get_fs_allowed(handle, fsallowedp, 6189 sizeof (fsallowedp)) == Z_INVALID_PROPERTY) { 6190 zerr(gettext("%s: invalid fs-allowed: %s"), 6191 zone, fsallowedp); 6192 return; 6193 } 6194 6195 if ((err = zonecfg_setfsent(handle)) != Z_OK) { 6196 zone_perror(zone, err, B_TRUE); 6197 return; 6198 } 6199 while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 6200 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val); 6201 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL, 6202 &ret_val); 6203 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val); 6204 6205 zonecfg_free_fs_option_list(fstab.zone_fs_options); 6206 } 6207 (void) zonecfg_endfsent(handle); 6208 6209 if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 6210 zone_perror(zone, err, B_TRUE); 6211 return; 6212 } 6213 while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 6214 /* 6215 * physical is required in all cases. 6216 * A shared IP requires an address, 6217 * and may include a default router, while 6218 * an exclusive IP must have neither an address 6219 * nor a default router. 6220 * The physical interface name must be valid in all cases. 6221 */ 6222 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET, 6223 PT_PHYSICAL, &ret_val); 6224 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) != 6225 Z_OK) { 6226 saw_error = B_TRUE; 6227 if (ret_val == Z_OK) 6228 ret_val = Z_INVAL; 6229 } 6230 6231 switch (iptype) { 6232 case ZS_SHARED: 6233 check_reqd_prop(nwiftab.zone_nwif_address, RT_NET, 6234 PT_ADDRESS, &ret_val); 6235 if (strlen(nwiftab.zone_nwif_allowed_address) > 0) { 6236 zerr(gettext("%s: %s cannot be specified " 6237 "for a shared IP type"), 6238 rt_to_str(RT_NET), 6239 pt_to_str(PT_ALLOWED_ADDRESS)); 6240 saw_error = B_TRUE; 6241 if (ret_val == Z_OK) 6242 ret_val = Z_INVAL; 6243 } 6244 break; 6245 case ZS_EXCLUSIVE: 6246 if (strlen(nwiftab.zone_nwif_address) > 0) { 6247 zerr(gettext("%s: %s cannot be specified " 6248 "for an exclusive IP type"), 6249 rt_to_str(RT_NET), pt_to_str(PT_ADDRESS)); 6250 saw_error = B_TRUE; 6251 if (ret_val == Z_OK) 6252 ret_val = Z_INVAL; 6253 } else { 6254 if (!add_nwif(&nwiftab)) { 6255 saw_error = B_TRUE; 6256 if (ret_val == Z_OK) 6257 ret_val = Z_INVAL; 6258 } 6259 } 6260 break; 6261 } 6262 } 6263 for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) { 6264 if (!tmp->xif_has_address && tmp->xif_has_defrouter) { 6265 zerr(gettext("%s: %s for %s cannot be specified " 6266 "without %s for an exclusive IP type"), 6267 rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER), 6268 tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS)); 6269 saw_error = B_TRUE; 6270 ret_val = Z_INVAL; 6271 } 6272 } 6273 free(xif); 6274 xif = NULL; 6275 (void) zonecfg_endnwifent(handle); 6276 6277 if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 6278 zone_perror(zone, err, B_TRUE); 6279 return; 6280 } 6281 while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 6282 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, 6283 &ret_val); 6284 6285 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0) 6286 has_cpu_shares = B_TRUE; 6287 6288 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0) 6289 has_cpu_cap = B_TRUE; 6290 6291 if (rctltab.zone_rctl_valptr == NULL) { 6292 zerr(gettext("%s: no %s specified"), 6293 rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); 6294 saw_error = B_TRUE; 6295 if (ret_val == Z_OK) 6296 ret_val = Z_REQD_PROPERTY_MISSING; 6297 } else { 6298 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 6299 } 6300 } 6301 (void) zonecfg_endrctlent(handle); 6302 6303 if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK && 6304 has_cpu_shares) { 6305 zerr(gettext("%s zone.cpu-shares and %s are incompatible."), 6306 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 6307 saw_error = B_TRUE; 6308 if (ret_val == Z_OK) 6309 ret_val = Z_INCOMPATIBLE; 6310 } 6311 6312 if (has_cpu_shares && zonecfg_get_sched_class(handle, sched, 6313 sizeof (sched)) == Z_OK && strlen(sched) > 0 && 6314 strcmp(sched, "FSS") != 0) { 6315 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are " 6316 "incompatible"), 6317 rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched); 6318 saw_error = B_TRUE; 6319 if (ret_val == Z_OK) 6320 ret_val = Z_INCOMPATIBLE; 6321 } 6322 6323 if (pset_res == Z_OK && has_cpu_cap) { 6324 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."), 6325 rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); 6326 saw_error = B_TRUE; 6327 if (ret_val == Z_OK) 6328 ret_val = Z_INCOMPATIBLE; 6329 } 6330 6331 if ((err = zonecfg_setattrent(handle)) != Z_OK) { 6332 zone_perror(zone, err, B_TRUE); 6333 return; 6334 } 6335 while (zonecfg_getattrent(handle, &attrtab) == Z_OK) { 6336 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME, 6337 &ret_val); 6338 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE, 6339 &ret_val); 6340 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE, 6341 &ret_val); 6342 } 6343 (void) zonecfg_endattrent(handle); 6344 6345 if ((err = zonecfg_setdsent(handle)) != Z_OK) { 6346 zone_perror(zone, err, B_TRUE); 6347 return; 6348 } 6349 while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 6350 if (strlen(dstab.zone_dataset_name) == 0) { 6351 zerr("%s: %s %s", rt_to_str(RT_DATASET), 6352 pt_to_str(PT_NAME), gettext("not specified")); 6353 saw_error = B_TRUE; 6354 if (ret_val == Z_OK) 6355 ret_val = Z_REQD_PROPERTY_MISSING; 6356 } else if (!zfs_name_valid(dstab.zone_dataset_name, 6357 ZFS_TYPE_FILESYSTEM)) { 6358 zerr("%s: %s %s", rt_to_str(RT_DATASET), 6359 pt_to_str(PT_NAME), gettext("invalid")); 6360 saw_error = B_TRUE; 6361 if (ret_val == Z_OK) 6362 ret_val = Z_BAD_PROPERTY; 6363 } 6364 6365 } 6366 (void) zonecfg_enddsent(handle); 6367 6368 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 6369 zone_perror(zone, err, B_TRUE); 6370 return; 6371 } 6372 while (zonecfg_getadminent(handle, &admintab) == Z_OK) { 6373 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN, 6374 PT_USER, &ret_val); 6375 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN, 6376 PT_AUTHS, &ret_val); 6377 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user) 6378 == NULL)) { 6379 zerr(gettext("%s %s is not a valid username"), 6380 pt_to_str(PT_USER), 6381 admintab.zone_admin_user); 6382 ret_val = Z_BAD_PROPERTY; 6383 } 6384 if ((ret_val == Z_OK) && (!zonecfg_valid_auths( 6385 admintab.zone_admin_auths, zone))) { 6386 ret_val = Z_BAD_PROPERTY; 6387 } 6388 } 6389 (void) zonecfg_endadminent(handle); 6390 6391 if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) { 6392 /* 6393 * No properties are required, but any specified should be 6394 * valid 6395 */ 6396 if (verify_secflags(&secflagstab) != B_TRUE) { 6397 /* Error is reported from verify_secflags */ 6398 ret_val = Z_BAD_PROPERTY; 6399 } 6400 } 6401 6402 if (!global_scope) { 6403 zerr(gettext("resource specification incomplete")); 6404 saw_error = B_TRUE; 6405 if (ret_val == Z_OK) 6406 ret_val = Z_INSUFFICIENT_SPEC; 6407 } 6408 6409 if (save) { 6410 if (ret_val == Z_OK) { 6411 if ((ret_val = zonecfg_save(handle)) == Z_OK) { 6412 need_to_commit = B_FALSE; 6413 (void) strlcpy(revert_zone, zone, 6414 sizeof (revert_zone)); 6415 } 6416 } else { 6417 zerr(gettext("Zone %s failed to verify"), zone); 6418 } 6419 } 6420 if (ret_val != Z_OK) 6421 zone_perror(zone, ret_val, B_TRUE); 6422 } 6423 6424 void 6425 cancel_func(cmd_t *cmd) 6426 { 6427 int arg; 6428 boolean_t arg_err = B_FALSE; 6429 6430 assert(cmd != NULL); 6431 6432 optind = 0; 6433 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6434 switch (arg) { 6435 case '?': 6436 longer_usage(CMD_CANCEL); 6437 arg_err = B_TRUE; 6438 break; 6439 default: 6440 short_usage(CMD_CANCEL); 6441 arg_err = B_TRUE; 6442 break; 6443 } 6444 } 6445 if (arg_err) 6446 return; 6447 6448 if (optind != cmd->cmd_argc) { 6449 short_usage(CMD_CANCEL); 6450 return; 6451 } 6452 6453 if (global_scope) 6454 scope_usage(CMD_CANCEL); 6455 global_scope = B_TRUE; 6456 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 6457 bzero(&in_progress_fstab, sizeof (in_progress_fstab)); 6458 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab)); 6459 bzero(&in_progress_devtab, sizeof (in_progress_devtab)); 6460 zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr); 6461 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); 6462 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab)); 6463 bzero(&in_progress_dstab, sizeof (in_progress_dstab)); 6464 } 6465 6466 static int 6467 validate_attr_name(char *name) 6468 { 6469 int i; 6470 6471 if (!isalnum(name[0])) { 6472 zerr(gettext("Invalid %s %s %s: must start with an alpha-" 6473 "numeric character."), rt_to_str(RT_ATTR), 6474 pt_to_str(PT_NAME), name); 6475 return (Z_INVAL); 6476 } 6477 for (i = 1; name[i]; i++) 6478 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') { 6479 zerr(gettext("Invalid %s %s %s: can only contain " 6480 "alpha-numeric characters, plus '-' and '.'."), 6481 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name); 6482 return (Z_INVAL); 6483 } 6484 return (Z_OK); 6485 } 6486 6487 static int 6488 validate_attr_type_val(struct zone_attrtab *attrtab) 6489 { 6490 boolean_t boolval; 6491 int64_t intval; 6492 char strval[MAXNAMELEN]; 6493 uint64_t uintval; 6494 6495 if (strcmp(attrtab->zone_attr_type, "boolean") == 0) { 6496 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK) 6497 return (Z_OK); 6498 zerr(gettext("invalid %s value for %s=%s"), 6499 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean"); 6500 return (Z_ERR); 6501 } 6502 6503 if (strcmp(attrtab->zone_attr_type, "int") == 0) { 6504 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK) 6505 return (Z_OK); 6506 zerr(gettext("invalid %s value for %s=%s"), 6507 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int"); 6508 return (Z_ERR); 6509 } 6510 6511 if (strcmp(attrtab->zone_attr_type, "string") == 0) { 6512 if (zonecfg_get_attr_string(attrtab, strval, 6513 sizeof (strval)) == Z_OK) 6514 return (Z_OK); 6515 zerr(gettext("invalid %s value for %s=%s"), 6516 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string"); 6517 return (Z_ERR); 6518 } 6519 6520 if (strcmp(attrtab->zone_attr_type, "uint") == 0) { 6521 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK) 6522 return (Z_OK); 6523 zerr(gettext("invalid %s value for %s=%s"), 6524 rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint"); 6525 return (Z_ERR); 6526 } 6527 6528 zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR), 6529 pt_to_str(PT_TYPE), attrtab->zone_attr_type); 6530 return (Z_ERR); 6531 } 6532 6533 /* 6534 * Helper function for end_func-- checks the existence of a given property 6535 * and emits a message if not specified. 6536 */ 6537 static int 6538 end_check_reqd(char *attr, int pt, boolean_t *validation_failed) 6539 { 6540 if (strlen(attr) == 0) { 6541 *validation_failed = B_TRUE; 6542 zerr(gettext("%s not specified"), pt_to_str(pt)); 6543 return (Z_ERR); 6544 } 6545 return (Z_OK); 6546 } 6547 6548 static void 6549 net_exists_error(struct zone_nwiftab nwif) 6550 { 6551 if (strlen(nwif.zone_nwif_address) > 0) { 6552 zerr(gettext("A %s resource with the %s '%s', " 6553 "and %s '%s' already exists."), 6554 rt_to_str(RT_NET), 6555 pt_to_str(PT_PHYSICAL), 6556 nwif.zone_nwif_physical, 6557 pt_to_str(PT_ADDRESS), 6558 in_progress_nwiftab.zone_nwif_address); 6559 } else { 6560 zerr(gettext("A %s resource with the %s '%s', " 6561 "and %s '%s' already exists."), 6562 rt_to_str(RT_NET), 6563 pt_to_str(PT_PHYSICAL), 6564 nwif.zone_nwif_physical, 6565 pt_to_str(PT_ALLOWED_ADDRESS), 6566 nwif.zone_nwif_allowed_address); 6567 } 6568 } 6569 6570 void 6571 end_func(cmd_t *cmd) 6572 { 6573 boolean_t validation_failed = B_FALSE; 6574 boolean_t arg_err = B_FALSE; 6575 struct zone_fstab tmp_fstab; 6576 struct zone_nwiftab tmp_nwiftab; 6577 struct zone_devtab tmp_devtab; 6578 struct zone_rctltab tmp_rctltab; 6579 struct zone_attrtab tmp_attrtab; 6580 struct zone_dstab tmp_dstab; 6581 struct zone_admintab tmp_admintab; 6582 int err, arg, res1, res2, res3; 6583 uint64_t swap_limit; 6584 uint64_t locked_limit; 6585 uint64_t proc_cap; 6586 6587 assert(cmd != NULL); 6588 6589 optind = 0; 6590 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 6591 switch (arg) { 6592 case '?': 6593 longer_usage(CMD_END); 6594 arg_err = B_TRUE; 6595 break; 6596 default: 6597 short_usage(CMD_END); 6598 arg_err = B_TRUE; 6599 break; 6600 } 6601 } 6602 if (arg_err) 6603 return; 6604 6605 if (optind != cmd->cmd_argc) { 6606 short_usage(CMD_END); 6607 return; 6608 } 6609 6610 if (global_scope) { 6611 scope_usage(CMD_END); 6612 return; 6613 } 6614 6615 assert(end_op == CMD_ADD || end_op == CMD_SELECT); 6616 6617 switch (resource_scope) { 6618 case RT_FS: 6619 /* First make sure everything was filled in. */ 6620 if (end_check_reqd(in_progress_fstab.zone_fs_dir, 6621 PT_DIR, &validation_failed) == Z_OK) { 6622 if (in_progress_fstab.zone_fs_dir[0] != '/') { 6623 zerr(gettext("%s %s is not an absolute path."), 6624 pt_to_str(PT_DIR), 6625 in_progress_fstab.zone_fs_dir); 6626 validation_failed = B_TRUE; 6627 } 6628 } 6629 6630 (void) end_check_reqd(in_progress_fstab.zone_fs_special, 6631 PT_SPECIAL, &validation_failed); 6632 6633 if (in_progress_fstab.zone_fs_raw[0] != '\0' && 6634 in_progress_fstab.zone_fs_raw[0] != '/') { 6635 zerr(gettext("%s %s is not an absolute path."), 6636 pt_to_str(PT_RAW), 6637 in_progress_fstab.zone_fs_raw); 6638 validation_failed = B_TRUE; 6639 } 6640 6641 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE, 6642 &validation_failed); 6643 6644 if (validation_failed) { 6645 saw_error = B_TRUE; 6646 return; 6647 } 6648 6649 if (end_op == CMD_ADD) { 6650 /* Make sure there isn't already one like this. */ 6651 bzero(&tmp_fstab, sizeof (tmp_fstab)); 6652 (void) strlcpy(tmp_fstab.zone_fs_dir, 6653 in_progress_fstab.zone_fs_dir, 6654 sizeof (tmp_fstab.zone_fs_dir)); 6655 err = zonecfg_lookup_filesystem(handle, &tmp_fstab); 6656 zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options); 6657 if (err == Z_OK) { 6658 zerr(gettext("A %s resource " 6659 "with the %s '%s' already exists."), 6660 rt_to_str(RT_FS), pt_to_str(PT_DIR), 6661 in_progress_fstab.zone_fs_dir); 6662 saw_error = B_TRUE; 6663 return; 6664 } 6665 err = zonecfg_add_filesystem(handle, 6666 &in_progress_fstab); 6667 } else { 6668 err = zonecfg_modify_filesystem(handle, &old_fstab, 6669 &in_progress_fstab); 6670 } 6671 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options); 6672 in_progress_fstab.zone_fs_options = NULL; 6673 break; 6674 6675 case RT_NET: 6676 /* 6677 * First make sure everything was filled in. 6678 * Since we don't know whether IP will be shared 6679 * or exclusive here, some checks are deferred until 6680 * the verify command. 6681 */ 6682 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical, 6683 PT_PHYSICAL, &validation_failed); 6684 6685 if (validation_failed) { 6686 saw_error = B_TRUE; 6687 return; 6688 } 6689 if (end_op == CMD_ADD) { 6690 /* Make sure there isn't already one like this. */ 6691 bzero(&tmp_nwiftab, sizeof (tmp_nwiftab)); 6692 (void) strlcpy(tmp_nwiftab.zone_nwif_physical, 6693 in_progress_nwiftab.zone_nwif_physical, 6694 sizeof (tmp_nwiftab.zone_nwif_physical)); 6695 (void) strlcpy(tmp_nwiftab.zone_nwif_address, 6696 in_progress_nwiftab.zone_nwif_address, 6697 sizeof (tmp_nwiftab.zone_nwif_address)); 6698 (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address, 6699 in_progress_nwiftab.zone_nwif_allowed_address, 6700 sizeof (tmp_nwiftab.zone_nwif_allowed_address)); 6701 (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter, 6702 in_progress_nwiftab.zone_nwif_defrouter, 6703 sizeof (tmp_nwiftab.zone_nwif_defrouter)); 6704 if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) { 6705 net_exists_error(in_progress_nwiftab); 6706 saw_error = B_TRUE; 6707 return; 6708 } 6709 err = zonecfg_add_nwif(handle, &in_progress_nwiftab); 6710 } else { 6711 err = zonecfg_modify_nwif(handle, &old_nwiftab, 6712 &in_progress_nwiftab); 6713 } 6714 break; 6715 6716 case RT_DEVICE: 6717 /* First make sure everything was filled in. */ 6718 (void) end_check_reqd(in_progress_devtab.zone_dev_match, 6719 PT_MATCH, &validation_failed); 6720 6721 if (validation_failed) { 6722 saw_error = B_TRUE; 6723 return; 6724 } 6725 6726 if (end_op == CMD_ADD) { 6727 /* Make sure there isn't already one like this. */ 6728 (void) strlcpy(tmp_devtab.zone_dev_match, 6729 in_progress_devtab.zone_dev_match, 6730 sizeof (tmp_devtab.zone_dev_match)); 6731 if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) { 6732 zerr(gettext("A %s resource with the %s '%s' " 6733 "already exists."), rt_to_str(RT_DEVICE), 6734 pt_to_str(PT_MATCH), 6735 in_progress_devtab.zone_dev_match); 6736 saw_error = B_TRUE; 6737 return; 6738 } 6739 err = zonecfg_add_dev(handle, &in_progress_devtab); 6740 } else { 6741 err = zonecfg_modify_dev(handle, &old_devtab, 6742 &in_progress_devtab); 6743 } 6744 break; 6745 6746 case RT_RCTL: 6747 /* First make sure everything was filled in. */ 6748 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name, 6749 PT_NAME, &validation_failed); 6750 6751 if (in_progress_rctltab.zone_rctl_valptr == NULL) { 6752 zerr(gettext("no %s specified"), pt_to_str(PT_VALUE)); 6753 validation_failed = B_TRUE; 6754 } 6755 6756 if (validation_failed) { 6757 saw_error = B_TRUE; 6758 return; 6759 } 6760 6761 if (end_op == CMD_ADD) { 6762 /* Make sure there isn't already one like this. */ 6763 (void) strlcpy(tmp_rctltab.zone_rctl_name, 6764 in_progress_rctltab.zone_rctl_name, 6765 sizeof (tmp_rctltab.zone_rctl_name)); 6766 tmp_rctltab.zone_rctl_valptr = NULL; 6767 err = zonecfg_lookup_rctl(handle, &tmp_rctltab); 6768 zonecfg_free_rctl_value_list( 6769 tmp_rctltab.zone_rctl_valptr); 6770 if (err == Z_OK) { 6771 zerr(gettext("A %s resource " 6772 "with the %s '%s' already exists."), 6773 rt_to_str(RT_RCTL), pt_to_str(PT_NAME), 6774 in_progress_rctltab.zone_rctl_name); 6775 saw_error = B_TRUE; 6776 return; 6777 } 6778 err = zonecfg_add_rctl(handle, &in_progress_rctltab); 6779 } else { 6780 err = zonecfg_modify_rctl(handle, &old_rctltab, 6781 &in_progress_rctltab); 6782 } 6783 if (err == Z_OK) { 6784 zonecfg_free_rctl_value_list( 6785 in_progress_rctltab.zone_rctl_valptr); 6786 in_progress_rctltab.zone_rctl_valptr = NULL; 6787 } 6788 break; 6789 6790 case RT_ATTR: 6791 /* First make sure everything was filled in. */ 6792 (void) end_check_reqd(in_progress_attrtab.zone_attr_name, 6793 PT_NAME, &validation_failed); 6794 (void) end_check_reqd(in_progress_attrtab.zone_attr_type, 6795 PT_TYPE, &validation_failed); 6796 (void) end_check_reqd(in_progress_attrtab.zone_attr_value, 6797 PT_VALUE, &validation_failed); 6798 6799 if (validate_attr_name(in_progress_attrtab.zone_attr_name) != 6800 Z_OK) 6801 validation_failed = B_TRUE; 6802 6803 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK) 6804 validation_failed = B_TRUE; 6805 6806 if (validation_failed) { 6807 saw_error = B_TRUE; 6808 return; 6809 } 6810 if (end_op == CMD_ADD) { 6811 /* Make sure there isn't already one like this. */ 6812 bzero(&tmp_attrtab, sizeof (tmp_attrtab)); 6813 (void) strlcpy(tmp_attrtab.zone_attr_name, 6814 in_progress_attrtab.zone_attr_name, 6815 sizeof (tmp_attrtab.zone_attr_name)); 6816 if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) { 6817 zerr(gettext("An %s resource " 6818 "with the %s '%s' already exists."), 6819 rt_to_str(RT_ATTR), pt_to_str(PT_NAME), 6820 in_progress_attrtab.zone_attr_name); 6821 saw_error = B_TRUE; 6822 return; 6823 } 6824 err = zonecfg_add_attr(handle, &in_progress_attrtab); 6825 } else { 6826 err = zonecfg_modify_attr(handle, &old_attrtab, 6827 &in_progress_attrtab); 6828 } 6829 break; 6830 case RT_DATASET: 6831 /* First make sure everything was filled in. */ 6832 if (strlen(in_progress_dstab.zone_dataset_name) == 0) { 6833 zerr("%s %s", pt_to_str(PT_NAME), 6834 gettext("not specified")); 6835 saw_error = B_TRUE; 6836 validation_failed = B_TRUE; 6837 } 6838 if (validation_failed) 6839 return; 6840 if (end_op == CMD_ADD) { 6841 /* Make sure there isn't already one like this. */ 6842 bzero(&tmp_dstab, sizeof (tmp_dstab)); 6843 (void) strlcpy(tmp_dstab.zone_dataset_name, 6844 in_progress_dstab.zone_dataset_name, 6845 sizeof (tmp_dstab.zone_dataset_name)); 6846 err = zonecfg_lookup_ds(handle, &tmp_dstab); 6847 if (err == Z_OK) { 6848 zerr(gettext("A %s resource " 6849 "with the %s '%s' already exists."), 6850 rt_to_str(RT_DATASET), pt_to_str(PT_NAME), 6851 in_progress_dstab.zone_dataset_name); 6852 saw_error = B_TRUE; 6853 return; 6854 } 6855 err = zonecfg_add_ds(handle, &in_progress_dstab); 6856 } else { 6857 err = zonecfg_modify_ds(handle, &old_dstab, 6858 &in_progress_dstab); 6859 } 6860 break; 6861 case RT_DCPU: 6862 /* Make sure everything was filled in. */ 6863 if (end_check_reqd(in_progress_psettab.zone_ncpu_min, 6864 PT_NCPUS, &validation_failed) != Z_OK) { 6865 saw_error = B_TRUE; 6866 return; 6867 } 6868 6869 if (end_op == CMD_ADD) { 6870 err = zonecfg_add_pset(handle, &in_progress_psettab); 6871 } else { 6872 err = zonecfg_modify_pset(handle, &in_progress_psettab); 6873 } 6874 break; 6875 case RT_PCAP: 6876 /* Make sure everything was filled in. */ 6877 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap) 6878 != Z_OK) { 6879 zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS)); 6880 saw_error = B_TRUE; 6881 validation_failed = B_TRUE; 6882 return; 6883 } 6884 err = Z_OK; 6885 break; 6886 case RT_MCAP: 6887 /* Make sure everything was filled in. */ 6888 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ? 6889 Z_ERR : Z_OK; 6890 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, 6891 &swap_limit); 6892 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, 6893 &locked_limit); 6894 6895 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { 6896 zerr(gettext("No property was specified. One of %s, " 6897 "%s or %s is required."), pt_to_str(PT_PHYSICAL), 6898 pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED)); 6899 saw_error = B_TRUE; 6900 return; 6901 } 6902 6903 /* if phys & locked are both set, verify locked <= phys */ 6904 if (res1 == Z_OK && res3 == Z_OK) { 6905 uint64_t phys_limit; 6906 char *endp; 6907 6908 phys_limit = strtoull( 6909 in_progress_mcaptab.zone_physmem_cap, &endp, 10); 6910 if (phys_limit < locked_limit) { 6911 zerr(gettext("The %s cap must be less than or " 6912 "equal to the %s cap."), 6913 pt_to_str(PT_LOCKED), 6914 pt_to_str(PT_PHYSICAL)); 6915 saw_error = B_TRUE; 6916 return; 6917 } 6918 } 6919 6920 err = Z_OK; 6921 if (res1 == Z_OK) { 6922 /* 6923 * We could be ending from either an add operation 6924 * or a select operation. Since all of the properties 6925 * within this resource are optional, we always use 6926 * modify on the mcap entry. zonecfg_modify_mcap() 6927 * will handle both adding and modifying a memory cap. 6928 */ 6929 err = zonecfg_modify_mcap(handle, &in_progress_mcaptab); 6930 } else if (end_op == CMD_SELECT) { 6931 /* 6932 * If we're ending from a select and the physical 6933 * memory cap is empty then the user could have cleared 6934 * the physical cap value, so try to delete the entry. 6935 */ 6936 (void) zonecfg_delete_mcap(handle); 6937 } 6938 break; 6939 case RT_ADMIN: 6940 /* First make sure everything was filled in. */ 6941 if (end_check_reqd(in_progress_admintab.zone_admin_user, 6942 PT_USER, &validation_failed) == Z_OK) { 6943 if (getpwnam(in_progress_admintab.zone_admin_user) 6944 == NULL) { 6945 zerr(gettext("%s %s is not a valid username"), 6946 pt_to_str(PT_USER), 6947 in_progress_admintab.zone_admin_user); 6948 validation_failed = B_TRUE; 6949 } 6950 } 6951 6952 if (end_check_reqd(in_progress_admintab.zone_admin_auths, 6953 PT_AUTHS, &validation_failed) == Z_OK) { 6954 if (!zonecfg_valid_auths( 6955 in_progress_admintab.zone_admin_auths, 6956 zone)) { 6957 validation_failed = B_TRUE; 6958 } 6959 } 6960 6961 if (validation_failed) { 6962 saw_error = B_TRUE; 6963 return; 6964 } 6965 6966 if (end_op == CMD_ADD) { 6967 /* Make sure there isn't already one like this. */ 6968 bzero(&tmp_admintab, sizeof (tmp_admintab)); 6969 (void) strlcpy(tmp_admintab.zone_admin_user, 6970 in_progress_admintab.zone_admin_user, 6971 sizeof (tmp_admintab.zone_admin_user)); 6972 err = zonecfg_lookup_admin( 6973 handle, &tmp_admintab); 6974 if (err == Z_OK) { 6975 zerr(gettext("A %s resource " 6976 "with the %s '%s' already exists."), 6977 rt_to_str(RT_ADMIN), 6978 pt_to_str(PT_USER), 6979 in_progress_admintab.zone_admin_user); 6980 saw_error = B_TRUE; 6981 return; 6982 } 6983 err = zonecfg_add_admin(handle, 6984 &in_progress_admintab, zone); 6985 } else { 6986 err = zonecfg_modify_admin(handle, 6987 &old_admintab, &in_progress_admintab, 6988 zone); 6989 } 6990 break; 6991 case RT_SECFLAGS: 6992 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) { 6993 saw_error = B_TRUE; 6994 return; 6995 } 6996 6997 if (end_op == CMD_ADD) { 6998 err = zonecfg_add_secflags(handle, 6999 &in_progress_secflagstab); 7000 } else { 7001 err = zonecfg_modify_secflags(handle, 7002 &old_secflagstab, &in_progress_secflagstab); 7003 } 7004 break; 7005 default: 7006 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, 7007 B_TRUE); 7008 saw_error = B_TRUE; 7009 return; 7010 } 7011 7012 if (err != Z_OK) { 7013 zone_perror(zone, err, B_TRUE); 7014 } else { 7015 need_to_commit = B_TRUE; 7016 global_scope = B_TRUE; 7017 end_op = -1; 7018 } 7019 } 7020 7021 void 7022 commit_func(cmd_t *cmd) 7023 { 7024 int arg; 7025 boolean_t arg_err = B_FALSE; 7026 7027 optind = 0; 7028 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { 7029 switch (arg) { 7030 case '?': 7031 longer_usage(CMD_COMMIT); 7032 arg_err = B_TRUE; 7033 break; 7034 default: 7035 short_usage(CMD_COMMIT); 7036 arg_err = B_TRUE; 7037 break; 7038 } 7039 } 7040 if (arg_err) 7041 return; 7042 7043 if (optind != cmd->cmd_argc) { 7044 short_usage(CMD_COMMIT); 7045 return; 7046 } 7047 7048 if (zone_is_read_only(CMD_COMMIT)) 7049 return; 7050 7051 assert(cmd != NULL); 7052 7053 cmd->cmd_argc = 1; 7054 /* 7055 * cmd_arg normally comes from a strdup() in the lexer, and the 7056 * whole cmd structure and its (char *) attributes are freed at 7057 * the completion of each command, so the strdup() below is needed 7058 * to match this and prevent a core dump from trying to free() 7059 * something that can't be. 7060 */ 7061 if ((cmd->cmd_argv[0] = strdup("save")) == NULL) { 7062 zone_perror(zone, Z_NOMEM, B_TRUE); 7063 exit(Z_ERR); 7064 } 7065 cmd->cmd_argv[1] = NULL; 7066 verify_func(cmd); 7067 } 7068 7069 void 7070 revert_func(cmd_t *cmd) 7071 { 7072 char line[128]; /* enough to ask a question */ 7073 boolean_t force = B_FALSE; 7074 boolean_t arg_err = B_FALSE; 7075 int err, arg, answer; 7076 7077 optind = 0; 7078 while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { 7079 switch (arg) { 7080 case '?': 7081 longer_usage(CMD_REVERT); 7082 arg_err = B_TRUE; 7083 break; 7084 case 'F': 7085 force = B_TRUE; 7086 break; 7087 default: 7088 short_usage(CMD_REVERT); 7089 arg_err = B_TRUE; 7090 break; 7091 } 7092 } 7093 if (arg_err) 7094 return; 7095 7096 if (optind != cmd->cmd_argc) { 7097 short_usage(CMD_REVERT); 7098 return; 7099 } 7100 7101 if (zone_is_read_only(CMD_REVERT)) 7102 return; 7103 7104 if (!global_scope) { 7105 zerr(gettext("You can only use %s in the global scope.\nUse" 7106 " '%s' to cancel changes to a resource specification."), 7107 cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL)); 7108 saw_error = B_TRUE; 7109 return; 7110 } 7111 7112 if (zonecfg_check_handle(handle) != Z_OK) { 7113 zerr(gettext("No changes to revert.")); 7114 saw_error = B_TRUE; 7115 return; 7116 } 7117 7118 if (!force) { 7119 (void) snprintf(line, sizeof (line), 7120 gettext("Are you sure you want to revert")); 7121 if ((answer = ask_yesno(B_FALSE, line)) == -1) { 7122 zerr(gettext("Input not from terminal and -F not " 7123 "specified:\n%s command ignored, exiting."), 7124 cmd_to_str(CMD_REVERT)); 7125 exit(Z_ERR); 7126 } 7127 if (answer != 1) 7128 return; 7129 } 7130 7131 /* 7132 * Reset any pending admins that were 7133 * removed from the previous zone 7134 */ 7135 zonecfg_remove_userauths(handle, "", zone, B_FALSE); 7136 7137 /* 7138 * Time for a new handle: finish the old one off first 7139 * then get a new one properly to avoid leaks. 7140 */ 7141 zonecfg_fini_handle(handle); 7142 if ((handle = zonecfg_init_handle()) == NULL) { 7143 zone_perror(execname, Z_NOMEM, B_TRUE); 7144 exit(Z_ERR); 7145 } 7146 7147 if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) { 7148 saw_error = B_TRUE; 7149 got_handle = B_FALSE; 7150 if (err == Z_NO_ZONE) 7151 zerr(gettext("%s: no such saved zone to revert to."), 7152 revert_zone); 7153 else 7154 zone_perror(zone, err, B_TRUE); 7155 } 7156 (void) strlcpy(zone, revert_zone, sizeof (zone)); 7157 } 7158 7159 void 7160 help_func(cmd_t *cmd) 7161 { 7162 int i; 7163 7164 assert(cmd != NULL); 7165 7166 if (cmd->cmd_argc == 0) { 7167 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE); 7168 return; 7169 } 7170 if (strcmp(cmd->cmd_argv[0], "usage") == 0) { 7171 usage(B_TRUE, HELP_USAGE); 7172 return; 7173 } 7174 if (strcmp(cmd->cmd_argv[0], "commands") == 0) { 7175 usage(B_TRUE, HELP_SUBCMDS); 7176 return; 7177 } 7178 if (strcmp(cmd->cmd_argv[0], "syntax") == 0) { 7179 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS); 7180 return; 7181 } 7182 if (strcmp(cmd->cmd_argv[0], "-?") == 0) { 7183 longer_usage(CMD_HELP); 7184 return; 7185 } 7186 7187 for (i = 0; i <= CMD_MAX; i++) { 7188 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { 7189 longer_usage(i); 7190 return; 7191 } 7192 } 7193 /* We do not use zerr() here because we do not want its extra \n. */ 7194 (void) fprintf(stderr, gettext("Unknown help subject %s. "), 7195 cmd->cmd_argv[0]); 7196 usage(B_FALSE, HELP_META); 7197 } 7198 7199 static int 7200 string_to_yyin(char *string) 7201 { 7202 if ((yyin = tmpfile()) == NULL) { 7203 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 7204 return (Z_ERR); 7205 } 7206 if (fwrite(string, strlen(string), 1, yyin) != 1) { 7207 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 7208 return (Z_ERR); 7209 } 7210 if (fseek(yyin, 0, SEEK_SET) != 0) { 7211 zone_perror(execname, Z_TEMP_FILE, B_TRUE); 7212 return (Z_ERR); 7213 } 7214 return (Z_OK); 7215 } 7216 7217 /* This is the back-end helper function for read_input() below. */ 7218 7219 static int 7220 cleanup() 7221 { 7222 int answer; 7223 cmd_t *cmd; 7224 7225 if (!interactive_mode && !cmd_file_mode) { 7226 /* 7227 * If we're not in interactive mode, and we're not in command 7228 * file mode, then we must be in commands-from-the-command-line 7229 * mode. As such, we can't loop back and ask for more input. 7230 * It was OK to prompt for such things as whether or not to 7231 * really delete a zone in the command handler called from 7232 * yyparse() above, but "really quit?" makes no sense in this 7233 * context. So disable prompting. 7234 */ 7235 ok_to_prompt = B_FALSE; 7236 } 7237 if (!global_scope) { 7238 if (!time_to_exit) { 7239 /* 7240 * Just print a simple error message in the -1 case, 7241 * since exit_func() already handles that case, and 7242 * EOF means we are finished anyway. 7243 */ 7244 answer = ask_yesno(B_FALSE, 7245 gettext("Resource incomplete; really quit")); 7246 if (answer == -1) { 7247 zerr(gettext("Resource incomplete.")); 7248 return (Z_ERR); 7249 } 7250 if (answer != 1) { 7251 yyin = stdin; 7252 return (Z_REPEAT); 7253 } 7254 } else { 7255 saw_error = B_TRUE; 7256 } 7257 } 7258 /* 7259 * Make sure we tried something and that the handle checks 7260 * out, or we would get a false error trying to commit. 7261 */ 7262 if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) { 7263 if ((cmd = alloc_cmd()) == NULL) { 7264 zone_perror(zone, Z_NOMEM, B_TRUE); 7265 return (Z_ERR); 7266 } 7267 cmd->cmd_argc = 0; 7268 cmd->cmd_argv[0] = NULL; 7269 commit_func(cmd); 7270 free_cmd(cmd); 7271 /* 7272 * need_to_commit will get set back to FALSE if the 7273 * configuration is saved successfully. 7274 */ 7275 if (need_to_commit) { 7276 if (force_exit) { 7277 zerr(gettext("Configuration not saved.")); 7278 return (Z_ERR); 7279 } 7280 answer = ask_yesno(B_FALSE, 7281 gettext("Configuration not saved; really quit")); 7282 if (answer == -1) { 7283 zerr(gettext("Configuration not saved.")); 7284 return (Z_ERR); 7285 } 7286 if (answer != 1) { 7287 time_to_exit = B_FALSE; 7288 yyin = stdin; 7289 return (Z_REPEAT); 7290 } 7291 } 7292 } 7293 return ((need_to_commit || saw_error) ? Z_ERR : Z_OK); 7294 } 7295 7296 /* 7297 * read_input() is the driver of this program. It is a wrapper around 7298 * yyparse(), printing appropriate prompts when needed, checking for 7299 * exit conditions and reacting appropriately [the latter in its cleanup() 7300 * helper function]. 7301 * 7302 * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT 7303 * so do_interactive() knows that we are not really done (i.e, we asked 7304 * the user if we should really quit and the user said no). 7305 */ 7306 static int 7307 read_input() 7308 { 7309 boolean_t yyin_is_a_tty = isatty(fileno(yyin)); 7310 /* 7311 * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone 7312 * and r is resource_scope: 5 is for the two ":"s + "> " + terminator. 7313 */ 7314 char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line; 7315 7316 /* yyin should have been set to the appropriate (FILE *) if not stdin */ 7317 newline_terminated = B_TRUE; 7318 for (;;) { 7319 if (yyin_is_a_tty) { 7320 if (newline_terminated) { 7321 if (global_scope) 7322 (void) snprintf(prompt, sizeof (prompt), 7323 "%s:%s> ", execname, zone); 7324 else 7325 (void) snprintf(prompt, sizeof (prompt), 7326 "%s:%s:%s> ", execname, zone, 7327 rt_to_str(resource_scope)); 7328 } 7329 /* 7330 * If the user hits ^C then we want to catch it and 7331 * start over. If the user hits EOF then we want to 7332 * bail out. 7333 */ 7334 line = gl_get_line(gl, prompt, NULL, -1); 7335 if (gl_return_status(gl) == GLR_SIGNAL) { 7336 gl_abandon_line(gl); 7337 continue; 7338 } 7339 if (line == NULL) 7340 break; 7341 (void) string_to_yyin(line); 7342 while (!feof(yyin)) 7343 yyparse(); 7344 } else { 7345 yyparse(); 7346 } 7347 /* Bail out on an error in command file mode. */ 7348 if (saw_error && cmd_file_mode && !interactive_mode) 7349 time_to_exit = B_TRUE; 7350 if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) 7351 break; 7352 } 7353 return (cleanup()); 7354 } 7355 7356 /* 7357 * This function is used in the zonecfg-interactive-mode scenario: it just 7358 * calls read_input() until we are done. 7359 */ 7360 7361 static int 7362 do_interactive(void) 7363 { 7364 int err; 7365 7366 interactive_mode = B_TRUE; 7367 if (!read_only_mode) { 7368 /* 7369 * Try to set things up proactively in interactive mode, so 7370 * that if the zone in question does not exist yet, we can 7371 * provide the user with a clue. 7372 */ 7373 (void) initialize(B_FALSE); 7374 } 7375 do { 7376 err = read_input(); 7377 } while (err == Z_REPEAT); 7378 return (err); 7379 } 7380 7381 /* 7382 * cmd_file is slightly more complicated, as it has to open the command file 7383 * and set yyin appropriately. Once that is done, though, it just calls 7384 * read_input(), and only once, since prompting is not possible. 7385 */ 7386 7387 static int 7388 cmd_file(char *file) 7389 { 7390 FILE *infile; 7391 int err; 7392 struct stat statbuf; 7393 boolean_t using_real_file = (strcmp(file, "-") != 0); 7394 7395 if (using_real_file) { 7396 /* 7397 * zerr() prints a line number in cmd_file_mode, which we do 7398 * not want here, so temporarily unset it. 7399 */ 7400 cmd_file_mode = B_FALSE; 7401 if ((infile = fopen(file, "r")) == NULL) { 7402 zerr(gettext("could not open file %s: %s"), 7403 file, strerror(errno)); 7404 return (Z_ERR); 7405 } 7406 if ((err = fstat(fileno(infile), &statbuf)) != 0) { 7407 zerr(gettext("could not stat file %s: %s"), 7408 file, strerror(errno)); 7409 err = Z_ERR; 7410 goto done; 7411 } 7412 if (!S_ISREG(statbuf.st_mode)) { 7413 zerr(gettext("%s is not a regular file."), file); 7414 err = Z_ERR; 7415 goto done; 7416 } 7417 yyin = infile; 7418 cmd_file_mode = B_TRUE; 7419 ok_to_prompt = B_FALSE; 7420 } else { 7421 /* 7422 * "-f -" is essentially the same as interactive mode, 7423 * so treat it that way. 7424 */ 7425 interactive_mode = B_TRUE; 7426 } 7427 /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */ 7428 if ((err = read_input()) == Z_REPEAT) 7429 err = Z_ERR; 7430 done: 7431 if (using_real_file) 7432 (void) fclose(infile); 7433 return (err); 7434 } 7435 7436 /* 7437 * Since yacc is based on reading from a (FILE *) whereas what we get from 7438 * the command line is in argv format, we need to convert when the user 7439 * gives us commands directly from the command line. That is done here by 7440 * concatenating the argv list into a space-separated string, writing it 7441 * to a temp file, and rewinding the file so yyin can be set to it. Then 7442 * we call read_input(), and only once, since prompting about whether to 7443 * continue or quit would make no sense in this context. 7444 */ 7445 7446 static int 7447 one_command_at_a_time(int argc, char *argv[]) 7448 { 7449 char *command; 7450 size_t len = 2; /* terminal \n\0 */ 7451 int i, err; 7452 7453 for (i = 0; i < argc; i++) 7454 len += strlen(argv[i]) + 1; 7455 if ((command = malloc(len)) == NULL) { 7456 zone_perror(execname, Z_NOMEM, B_TRUE); 7457 return (Z_ERR); 7458 } 7459 (void) strlcpy(command, argv[0], len); 7460 for (i = 1; i < argc; i++) { 7461 (void) strlcat(command, " ", len); 7462 (void) strlcat(command, argv[i], len); 7463 } 7464 (void) strlcat(command, "\n", len); 7465 err = string_to_yyin(command); 7466 free(command); 7467 if (err != Z_OK) 7468 return (err); 7469 while (!feof(yyin)) 7470 yyparse(); 7471 return (cleanup()); 7472 } 7473 7474 static char * 7475 get_execbasename(char *execfullname) 7476 { 7477 char *last_slash, *execbasename; 7478 7479 /* guard against '/' at end of command invocation */ 7480 for (;;) { 7481 last_slash = strrchr(execfullname, '/'); 7482 if (last_slash == NULL) { 7483 execbasename = execfullname; 7484 break; 7485 } else { 7486 execbasename = last_slash + 1; 7487 if (*execbasename == '\0') { 7488 *last_slash = '\0'; 7489 continue; 7490 } 7491 break; 7492 } 7493 } 7494 return (execbasename); 7495 } 7496 7497 int 7498 main(int argc, char *argv[]) 7499 { 7500 int err, arg; 7501 struct stat st; 7502 7503 /* This must be before anything goes to stdout. */ 7504 setbuf(stdout, NULL); 7505 7506 saw_error = B_FALSE; 7507 cmd_file_mode = B_FALSE; 7508 execname = get_execbasename(argv[0]); 7509 7510 (void) setlocale(LC_ALL, ""); 7511 (void) textdomain(TEXT_DOMAIN); 7512 7513 if (getzoneid() != GLOBAL_ZONEID) { 7514 zerr(gettext("%s can only be run from the global zone."), 7515 execname); 7516 exit(Z_ERR); 7517 } 7518 7519 if (argc < 2) { 7520 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS); 7521 exit(Z_USAGE); 7522 } 7523 if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) { 7524 (void) one_command_at_a_time(argc - 1, &(argv[1])); 7525 exit(Z_OK); 7526 } 7527 7528 while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) { 7529 switch (arg) { 7530 case '?': 7531 if (optopt == '?') 7532 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS); 7533 else 7534 usage(B_FALSE, HELP_USAGE); 7535 exit(Z_USAGE); 7536 /* NOTREACHED */ 7537 case 'f': 7538 cmd_file_name = optarg; 7539 cmd_file_mode = B_TRUE; 7540 break; 7541 case 'R': 7542 if (*optarg != '/') { 7543 zerr(gettext("root path must be absolute: %s"), 7544 optarg); 7545 exit(Z_USAGE); 7546 } 7547 if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 7548 zerr(gettext( 7549 "root path must be a directory: %s"), 7550 optarg); 7551 exit(Z_USAGE); 7552 } 7553 zonecfg_set_root(optarg); 7554 break; 7555 case 'z': 7556 if (strcmp(optarg, GLOBAL_ZONENAME) == 0) { 7557 global_zone = B_TRUE; 7558 } else if (zonecfg_validate_zonename(optarg) != Z_OK) { 7559 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE); 7560 usage(B_FALSE, HELP_SYNTAX); 7561 exit(Z_USAGE); 7562 } 7563 (void) strlcpy(zone, optarg, sizeof (zone)); 7564 (void) strlcpy(revert_zone, optarg, sizeof (zone)); 7565 break; 7566 default: 7567 usage(B_FALSE, HELP_USAGE); 7568 exit(Z_USAGE); 7569 } 7570 } 7571 7572 if (optind > argc || strcmp(zone, "") == 0) { 7573 usage(B_FALSE, HELP_USAGE); 7574 exit(Z_USAGE); 7575 } 7576 7577 if ((err = zonecfg_access(zone, W_OK)) == Z_OK) { 7578 read_only_mode = B_FALSE; 7579 } else if (err == Z_ACCES) { 7580 read_only_mode = B_TRUE; 7581 /* skip this message in one-off from command line mode */ 7582 if (optind == argc) 7583 (void) fprintf(stderr, gettext("WARNING: you do not " 7584 "have write access to this zone's configuration " 7585 "file;\ngoing into read-only mode.\n")); 7586 } else { 7587 fprintf(stderr, "%s: Could not access zone configuration " 7588 "store: %s\n", execname, zonecfg_strerror(err)); 7589 exit(Z_ERR); 7590 } 7591 7592 if ((handle = zonecfg_init_handle()) == NULL) { 7593 zone_perror(execname, Z_NOMEM, B_TRUE); 7594 exit(Z_ERR); 7595 } 7596 7597 /* 7598 * This may get set back to FALSE again in cmd_file() if cmd_file_name 7599 * is a "real" file as opposed to "-" (i.e. meaning use stdin). 7600 */ 7601 if (isatty(STDIN_FILENO)) 7602 ok_to_prompt = B_TRUE; 7603 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) 7604 exit(Z_ERR); 7605 if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) 7606 exit(Z_ERR); 7607 (void) sigset(SIGINT, SIG_IGN); 7608 if (optind == argc) { 7609 if (!cmd_file_mode) 7610 err = do_interactive(); 7611 else 7612 err = cmd_file(cmd_file_name); 7613 } else { 7614 err = one_command_at_a_time(argc - optind, &(argv[optind])); 7615 } 7616 zonecfg_fini_handle(handle); 7617 if (brand != NULL) 7618 brand_close(brand); 7619 (void) del_GetLine(gl); 7620 return (err); 7621 }