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