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