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