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