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