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