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