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