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