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