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         int err, ret_val = Z_OK, arg;
5733         int pset_res;
5734         boolean_t save = B_FALSE;
5735         boolean_t arg_err = B_FALSE;
5736         zone_iptype_t iptype;
5737         boolean_t has_cpu_shares = B_FALSE;
5738         boolean_t has_cpu_cap = B_FALSE;
5739         struct xif *tmp;
5740 
5741         optind = 0;
5742         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
5743                 switch (arg) {
5744                 case '?':
5745                         longer_usage(CMD_VERIFY);
5746                         arg_err = B_TRUE;
5747                         break;
5748                 default:
5749                         short_usage(CMD_VERIFY);
5750                         arg_err = B_TRUE;
5751                         break;
5752                 }
5753         }
5754         if (arg_err)
5755                 return;
5756 
5757         if (optind > cmd->cmd_argc) {
5758                 short_usage(CMD_VERIFY);
5759                 return;
5760         }
5761 
5762         if (zone_is_read_only(CMD_VERIFY))
5763                 return;
5764 
5765         assert(cmd != NULL);
5766 
5767         if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
5768                 save = B_TRUE;
5769         if (initialize(B_TRUE) != Z_OK)
5770                 return;
5771 
5772         if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
5773             !global_zone) {
5774                 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
5775                 ret_val = Z_REQD_RESOURCE_MISSING;
5776                 saw_error = B_TRUE;
5777         }
5778         if (strlen(zonepath) == 0 && !global_zone) {
5779                 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
5780                 ret_val = Z_REQD_RESOURCE_MISSING;
5781                 saw_error = B_TRUE;
5782         }
5783 
5784         if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
5785                 zone_perror(zone, err, B_TRUE);
5786                 return;
5787         }
5788         if ((err = brand_verify(handle)) != Z_OK) {
5789                 zone_perror(zone, err, B_TRUE);
5790                 return;
5791         }
5792 
5793         if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
5794                 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
5795                 ret_val = Z_REQD_RESOURCE_MISSING;
5796                 saw_error = B_TRUE;
5797         }
5798 
5799         if (zonecfg_get_hostid(handle, hostidp,
5800             sizeof (hostidp)) == Z_INVALID_PROPERTY) {
5801                 zerr(gettext("%s: invalid hostid: %s"),
5802                     zone, hostidp);
5803                 return;
5804         }
5805 
5806         if (zonecfg_get_fs_allowed(handle, fsallowedp,
5807             sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
5808                 zerr(gettext("%s: invalid fs-allowed: %s"),
5809                     zone, fsallowedp);
5810                 return;
5811         }
5812 
5813         if ((err = zonecfg_setfsent(handle)) != Z_OK) {
5814                 zone_perror(zone, err, B_TRUE);
5815                 return;
5816         }
5817         while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
5818                 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
5819                 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
5820                     &ret_val);
5821                 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
5822 
5823                 zonecfg_free_fs_option_list(fstab.zone_fs_options);
5824         }
5825         (void) zonecfg_endfsent(handle);
5826 
5827         if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
5828                 zone_perror(zone, err, B_TRUE);
5829                 return;
5830         }
5831         while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
5832                 /*
5833                  * physical is required in all cases.
5834                  * A shared IP requires an address,
5835                  * and may include a default router, while
5836                  * an exclusive IP must have neither an address
5837                  * nor a default router.
5838                  * The physical interface name must be valid in all cases.
5839                  */
5840                 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
5841                     PT_PHYSICAL, &ret_val);
5842                 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
5843                     Z_OK) {
5844                         saw_error = B_TRUE;
5845                         if (ret_val == Z_OK)
5846                                 ret_val = Z_INVAL;
5847                 }
5848 
5849                 switch (iptype) {
5850                 case ZS_SHARED:
5851                         check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
5852                             PT_ADDRESS, &ret_val);
5853                         if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
5854                                 zerr(gettext("%s: %s cannot be specified "
5855                                     "for a shared IP type"),
5856                                     rt_to_str(RT_NET),
5857                                     pt_to_str(PT_ALLOWED_ADDRESS));
5858                                 saw_error = B_TRUE;
5859                                 if (ret_val == Z_OK)
5860                                         ret_val = Z_INVAL;
5861                         }
5862                         break;
5863                 case ZS_EXCLUSIVE:
5864                         if (strlen(nwiftab.zone_nwif_address) > 0) {
5865                                 zerr(gettext("%s: %s cannot be specified "
5866                                     "for an exclusive IP type"),
5867                                     rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
5868                                 saw_error = B_TRUE;
5869                                 if (ret_val == Z_OK)
5870                                         ret_val = Z_INVAL;
5871                         } else {
5872                                 if (!add_nwif(&nwiftab)) {
5873                                         saw_error = B_TRUE;
5874                                         if (ret_val == Z_OK)
5875                                                 ret_val = Z_INVAL;
5876                                 }
5877                         }
5878                         break;
5879                 }
5880         }
5881         for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5882                 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
5883                         zerr(gettext("%s: %s for %s cannot be specified "
5884                             "without %s for an exclusive IP type"),
5885                             rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
5886                             tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
5887                         saw_error = B_TRUE;
5888                         ret_val = Z_INVAL;
5889                 }
5890         }
5891         free(xif);
5892         xif = NULL;
5893         (void) zonecfg_endnwifent(handle);
5894 
5895         if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
5896                 zone_perror(zone, err, B_TRUE);
5897                 return;
5898         }
5899         while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
5900                 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
5901                     &ret_val);
5902 
5903                 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
5904                         has_cpu_shares = B_TRUE;
5905 
5906                 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
5907                         has_cpu_cap = B_TRUE;
5908 
5909                 if (rctltab.zone_rctl_valptr == NULL) {
5910                         zerr(gettext("%s: no %s specified"),
5911                             rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
5912                         saw_error = B_TRUE;
5913                         if (ret_val == Z_OK)
5914                                 ret_val = Z_REQD_PROPERTY_MISSING;
5915                 } else {
5916                         zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
5917                 }
5918         }
5919         (void) zonecfg_endrctlent(handle);
5920 
5921         if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
5922             has_cpu_shares) {
5923                 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
5924                     rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
5925                 saw_error = B_TRUE;
5926                 if (ret_val == Z_OK)
5927                         ret_val = Z_INCOMPATIBLE;
5928         }
5929 
5930         if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
5931             sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
5932             strcmp(sched, "FSS") != 0) {
5933                 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
5934                     "incompatible"),
5935                     rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
5936                 saw_error = B_TRUE;
5937                 if (ret_val == Z_OK)
5938                         ret_val = Z_INCOMPATIBLE;
5939         }
5940 
5941         if (pset_res == Z_OK && has_cpu_cap) {
5942                 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
5943                     rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
5944                 saw_error = B_TRUE;
5945                 if (ret_val == Z_OK)
5946                         ret_val = Z_INCOMPATIBLE;
5947         }
5948 
5949         if ((err = zonecfg_setattrent(handle)) != Z_OK) {
5950                 zone_perror(zone, err, B_TRUE);
5951                 return;
5952         }
5953         while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
5954                 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
5955                     &ret_val);
5956                 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
5957                     &ret_val);
5958                 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
5959                     &ret_val);
5960         }
5961         (void) zonecfg_endattrent(handle);
5962 
5963         if ((err = zonecfg_setdsent(handle)) != Z_OK) {
5964                 zone_perror(zone, err, B_TRUE);
5965                 return;
5966         }
5967         while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
5968                 if (strlen(dstab.zone_dataset_name) == 0) {
5969                         zerr("%s: %s %s", rt_to_str(RT_DATASET),
5970                             pt_to_str(PT_NAME), gettext("not specified"));
5971                         saw_error = B_TRUE;
5972                         if (ret_val == Z_OK)
5973                                 ret_val = Z_REQD_PROPERTY_MISSING;
5974                 } else if (!zfs_name_valid(dstab.zone_dataset_name,
5975                     ZFS_TYPE_FILESYSTEM)) {
5976                         zerr("%s: %s %s", rt_to_str(RT_DATASET),
5977                             pt_to_str(PT_NAME), gettext("invalid"));
5978                         saw_error = B_TRUE;
5979                         if (ret_val == Z_OK)
5980                                 ret_val = Z_BAD_PROPERTY;
5981                 }
5982 
5983         }
5984         (void) zonecfg_enddsent(handle);
5985 
5986         if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5987                 zone_perror(zone, err, B_TRUE);
5988                 return;
5989         }
5990         while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
5991                 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
5992                     PT_USER, &ret_val);
5993                 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
5994                     PT_AUTHS, &ret_val);
5995                 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
5996                     == NULL)) {
5997                         zerr(gettext("%s %s is not a valid username"),
5998                             pt_to_str(PT_USER),
5999                             admintab.zone_admin_user);
6000                         ret_val = Z_BAD_PROPERTY;
6001                 }
6002                 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6003                     admintab.zone_admin_auths, zone))) {
6004                         ret_val = Z_BAD_PROPERTY;
6005                 }
6006         }
6007         (void) zonecfg_endadminent(handle);
6008 
6009         if (!global_scope) {
6010                 zerr(gettext("resource specification incomplete"));
6011                 saw_error = B_TRUE;
6012                 if (ret_val == Z_OK)
6013                         ret_val = Z_INSUFFICIENT_SPEC;
6014         }
6015 
6016         if (save) {
6017                 if (ret_val == Z_OK) {
6018                         if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6019                                 need_to_commit = B_FALSE;
6020                                 (void) strlcpy(revert_zone, zone,
6021                                     sizeof (revert_zone));
6022                         }
6023                 } else {
6024                         zerr(gettext("Zone %s failed to verify"), zone);
6025                 }
6026         }
6027         if (ret_val != Z_OK)
6028                 zone_perror(zone, ret_val, B_TRUE);
6029 }
6030 
6031 void
6032 cancel_func(cmd_t *cmd)
6033 {
6034         int arg;
6035         boolean_t arg_err = B_FALSE;
6036 
6037         assert(cmd != NULL);
6038 
6039         optind = 0;
6040         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6041                 switch (arg) {
6042                 case '?':
6043                         longer_usage(CMD_CANCEL);
6044                         arg_err = B_TRUE;
6045                         break;
6046                 default:
6047                         short_usage(CMD_CANCEL);
6048                         arg_err = B_TRUE;
6049                         break;
6050                 }
6051         }
6052         if (arg_err)
6053                 return;
6054 
6055         if (optind != cmd->cmd_argc) {
6056                 short_usage(CMD_CANCEL);
6057                 return;
6058         }
6059 
6060         if (global_scope)
6061                 scope_usage(CMD_CANCEL);
6062         global_scope = B_TRUE;
6063         zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6064         bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6065         bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6066         bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6067         zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6068         bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6069         bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6070         bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6071 }
6072 
6073 static int
6074 validate_attr_name(char *name)
6075 {
6076         int i;
6077 
6078         if (!isalnum(name[0])) {
6079                 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6080                     "numeric character."), rt_to_str(RT_ATTR),
6081                     pt_to_str(PT_NAME), name);
6082                 return (Z_INVAL);
6083         }
6084         for (i = 1; name[i]; i++)
6085                 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6086                         zerr(gettext("Invalid %s %s %s: can only contain "
6087                             "alpha-numeric characters, plus '-' and '.'."),
6088                             rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6089                         return (Z_INVAL);
6090                 }
6091         return (Z_OK);
6092 }
6093 
6094 static int
6095 validate_attr_type_val(struct zone_attrtab *attrtab)
6096 {
6097         boolean_t boolval;
6098         int64_t intval;
6099         char strval[MAXNAMELEN];
6100         uint64_t uintval;
6101 
6102         if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6103                 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6104                         return (Z_OK);
6105                 zerr(gettext("invalid %s value for %s=%s"),
6106                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6107                 return (Z_ERR);
6108         }
6109 
6110         if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6111                 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6112                         return (Z_OK);
6113                 zerr(gettext("invalid %s value for %s=%s"),
6114                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6115                 return (Z_ERR);
6116         }
6117 
6118         if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6119                 if (zonecfg_get_attr_string(attrtab, strval,
6120                     sizeof (strval)) == Z_OK)
6121                         return (Z_OK);
6122                 zerr(gettext("invalid %s value for %s=%s"),
6123                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6124                 return (Z_ERR);
6125         }
6126 
6127         if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6128                 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6129                         return (Z_OK);
6130                 zerr(gettext("invalid %s value for %s=%s"),
6131                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6132                 return (Z_ERR);
6133         }
6134 
6135         zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6136             pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6137         return (Z_ERR);
6138 }
6139 
6140 /*
6141  * Helper function for end_func-- checks the existence of a given property
6142  * and emits a message if not specified.
6143  */
6144 static int
6145 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6146 {
6147         if (strlen(attr) == 0) {
6148                 *validation_failed = B_TRUE;
6149                 zerr(gettext("%s not specified"), pt_to_str(pt));
6150                 return (Z_ERR);
6151         }
6152         return (Z_OK);
6153 }
6154 
6155 static void
6156 net_exists_error(struct zone_nwiftab nwif)
6157 {
6158         if (strlen(nwif.zone_nwif_address) > 0) {
6159                 zerr(gettext("A %s resource with the %s '%s', "
6160                     "and %s '%s' already exists."),
6161                     rt_to_str(RT_NET),
6162                     pt_to_str(PT_PHYSICAL),
6163                     nwif.zone_nwif_physical,
6164                     pt_to_str(PT_ADDRESS),
6165                     in_progress_nwiftab.zone_nwif_address);
6166         } else {
6167                 zerr(gettext("A %s resource with the %s '%s', "
6168                     "and %s '%s' already exists."),
6169                     rt_to_str(RT_NET),
6170                     pt_to_str(PT_PHYSICAL),
6171                     nwif.zone_nwif_physical,
6172                     pt_to_str(PT_ALLOWED_ADDRESS),
6173                     nwif.zone_nwif_allowed_address);
6174         }
6175 }
6176 
6177 void
6178 end_func(cmd_t *cmd)
6179 {
6180         boolean_t validation_failed = B_FALSE;
6181         boolean_t arg_err = B_FALSE;
6182         struct zone_fstab tmp_fstab;
6183         struct zone_nwiftab tmp_nwiftab;
6184         struct zone_devtab tmp_devtab;
6185         struct zone_rctltab tmp_rctltab;
6186         struct zone_attrtab tmp_attrtab;
6187         struct zone_dstab tmp_dstab;
6188         struct zone_admintab tmp_admintab;
6189         int err, arg, res1, res2, res3;
6190         uint64_t swap_limit;
6191         uint64_t locked_limit;
6192         uint64_t proc_cap;
6193 
6194         assert(cmd != NULL);
6195 
6196         optind = 0;
6197         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6198                 switch (arg) {
6199                 case '?':
6200                         longer_usage(CMD_END);
6201                         arg_err = B_TRUE;
6202                         break;
6203                 default:
6204                         short_usage(CMD_END);
6205                         arg_err = B_TRUE;
6206                         break;
6207                 }
6208         }
6209         if (arg_err)
6210                 return;
6211 
6212         if (optind != cmd->cmd_argc) {
6213                 short_usage(CMD_END);
6214                 return;
6215         }
6216 
6217         if (global_scope) {
6218                 scope_usage(CMD_END);
6219                 return;
6220         }
6221 
6222         assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6223 
6224         switch (resource_scope) {
6225         case RT_FS:
6226                 /* First make sure everything was filled in. */
6227                 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6228                     PT_DIR, &validation_failed) == Z_OK) {
6229                         if (in_progress_fstab.zone_fs_dir[0] != '/') {
6230                                 zerr(gettext("%s %s is not an absolute path."),
6231                                     pt_to_str(PT_DIR),
6232                                     in_progress_fstab.zone_fs_dir);
6233                                 validation_failed = B_TRUE;
6234                         }
6235                 }
6236 
6237                 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6238                     PT_SPECIAL, &validation_failed);
6239 
6240                 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6241                     in_progress_fstab.zone_fs_raw[0] != '/') {
6242                         zerr(gettext("%s %s is not an absolute path."),
6243                             pt_to_str(PT_RAW),
6244                             in_progress_fstab.zone_fs_raw);
6245                         validation_failed = B_TRUE;
6246                 }
6247 
6248                 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6249                     &validation_failed);
6250 
6251                 if (validation_failed) {
6252                         saw_error = B_TRUE;
6253                         return;
6254                 }
6255 
6256                 if (end_op == CMD_ADD) {
6257                         /* Make sure there isn't already one like this. */
6258                         bzero(&tmp_fstab, sizeof (tmp_fstab));
6259                         (void) strlcpy(tmp_fstab.zone_fs_dir,
6260                             in_progress_fstab.zone_fs_dir,
6261                             sizeof (tmp_fstab.zone_fs_dir));
6262                         err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6263                         zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6264                         if (err == Z_OK) {
6265                                 zerr(gettext("A %s resource "
6266                                     "with the %s '%s' already exists."),
6267                                     rt_to_str(RT_FS), pt_to_str(PT_DIR),
6268                                     in_progress_fstab.zone_fs_dir);
6269                                 saw_error = B_TRUE;
6270                                 return;
6271                         }
6272                         err = zonecfg_add_filesystem(handle,
6273                             &in_progress_fstab);
6274                 } else {
6275                         err = zonecfg_modify_filesystem(handle, &old_fstab,
6276                             &in_progress_fstab);
6277                 }
6278                 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6279                 in_progress_fstab.zone_fs_options = NULL;
6280                 break;
6281 
6282         case RT_NET:
6283                 /*
6284                  * First make sure everything was filled in.
6285                  * Since we don't know whether IP will be shared
6286                  * or exclusive here, some checks are deferred until
6287                  * the verify command.
6288                  */
6289                 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6290                     PT_PHYSICAL, &validation_failed);
6291 
6292                 if (validation_failed) {
6293                         saw_error = B_TRUE;
6294                         return;
6295                 }
6296                 if (end_op == CMD_ADD) {
6297                         /* Make sure there isn't already one like this. */
6298                         bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6299                         (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6300                             in_progress_nwiftab.zone_nwif_physical,
6301                             sizeof (tmp_nwiftab.zone_nwif_physical));
6302                         (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6303                             in_progress_nwiftab.zone_nwif_address,
6304                             sizeof (tmp_nwiftab.zone_nwif_address));
6305                         (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6306                             in_progress_nwiftab.zone_nwif_allowed_address,
6307                             sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6308                         (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6309                             in_progress_nwiftab.zone_nwif_defrouter,
6310                             sizeof (tmp_nwiftab.zone_nwif_defrouter));
6311                         if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6312                                 net_exists_error(in_progress_nwiftab);
6313                                 saw_error = B_TRUE;
6314                                 return;
6315                         }
6316                         err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6317                 } else {
6318                         err = zonecfg_modify_nwif(handle, &old_nwiftab,
6319                             &in_progress_nwiftab);
6320                 }
6321                 break;
6322 
6323         case RT_DEVICE:
6324                 /* First make sure everything was filled in. */
6325                 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6326                     PT_MATCH, &validation_failed);
6327 
6328                 if (validation_failed) {
6329                         saw_error = B_TRUE;
6330                         return;
6331                 }
6332 
6333                 if (end_op == CMD_ADD) {
6334                         /* Make sure there isn't already one like this. */
6335                         (void) strlcpy(tmp_devtab.zone_dev_match,
6336                             in_progress_devtab.zone_dev_match,
6337                             sizeof (tmp_devtab.zone_dev_match));
6338                         if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6339                                 zerr(gettext("A %s resource with the %s '%s' "
6340                                     "already exists."), rt_to_str(RT_DEVICE),
6341                                     pt_to_str(PT_MATCH),
6342                                     in_progress_devtab.zone_dev_match);
6343                                 saw_error = B_TRUE;
6344                                 return;
6345                         }
6346                         err = zonecfg_add_dev(handle, &in_progress_devtab);
6347                 } else {
6348                         err = zonecfg_modify_dev(handle, &old_devtab,
6349                             &in_progress_devtab);
6350                 }
6351                 break;
6352 
6353         case RT_RCTL:
6354                 /* First make sure everything was filled in. */
6355                 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6356                     PT_NAME, &validation_failed);
6357 
6358                 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6359                         zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6360                         validation_failed = B_TRUE;
6361                 }
6362 
6363                 if (validation_failed) {
6364                         saw_error = B_TRUE;
6365                         return;
6366                 }
6367 
6368                 if (end_op == CMD_ADD) {
6369                         /* Make sure there isn't already one like this. */
6370                         (void) strlcpy(tmp_rctltab.zone_rctl_name,
6371                             in_progress_rctltab.zone_rctl_name,
6372                             sizeof (tmp_rctltab.zone_rctl_name));
6373                         tmp_rctltab.zone_rctl_valptr = NULL;
6374                         err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6375                         zonecfg_free_rctl_value_list(
6376                             tmp_rctltab.zone_rctl_valptr);
6377                         if (err == Z_OK) {
6378                                 zerr(gettext("A %s resource "
6379                                     "with the %s '%s' already exists."),
6380                                     rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6381                                     in_progress_rctltab.zone_rctl_name);
6382                                 saw_error = B_TRUE;
6383                                 return;
6384                         }
6385                         err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6386                 } else {
6387                         err = zonecfg_modify_rctl(handle, &old_rctltab,
6388                             &in_progress_rctltab);
6389                 }
6390                 if (err == Z_OK) {
6391                         zonecfg_free_rctl_value_list(
6392                             in_progress_rctltab.zone_rctl_valptr);
6393                         in_progress_rctltab.zone_rctl_valptr = NULL;
6394                 }
6395                 break;
6396 
6397         case RT_ATTR:
6398                 /* First make sure everything was filled in. */
6399                 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6400                     PT_NAME, &validation_failed);
6401                 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6402                     PT_TYPE, &validation_failed);
6403                 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6404                     PT_VALUE, &validation_failed);
6405 
6406                 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6407                     Z_OK)
6408                         validation_failed = B_TRUE;
6409 
6410                 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6411                         validation_failed = B_TRUE;
6412 
6413                 if (validation_failed) {
6414                         saw_error = B_TRUE;
6415                         return;
6416                 }
6417                 if (end_op == CMD_ADD) {
6418                         /* Make sure there isn't already one like this. */
6419                         bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6420                         (void) strlcpy(tmp_attrtab.zone_attr_name,
6421                             in_progress_attrtab.zone_attr_name,
6422                             sizeof (tmp_attrtab.zone_attr_name));
6423                         if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6424                                 zerr(gettext("An %s resource "
6425                                     "with the %s '%s' already exists."),
6426                                     rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6427                                     in_progress_attrtab.zone_attr_name);
6428                                 saw_error = B_TRUE;
6429                                 return;
6430                         }
6431                         err = zonecfg_add_attr(handle, &in_progress_attrtab);
6432                 } else {
6433                         err = zonecfg_modify_attr(handle, &old_attrtab,
6434                             &in_progress_attrtab);
6435                 }
6436                 break;
6437         case RT_DATASET:
6438                 /* First make sure everything was filled in. */
6439                 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6440                         zerr("%s %s", pt_to_str(PT_NAME),
6441                             gettext("not specified"));
6442                         saw_error = B_TRUE;
6443                         validation_failed = B_TRUE;
6444                 }
6445                 if (validation_failed)
6446                         return;
6447                 if (end_op == CMD_ADD) {
6448                         /* Make sure there isn't already one like this. */
6449                         bzero(&tmp_dstab, sizeof (tmp_dstab));
6450                         (void) strlcpy(tmp_dstab.zone_dataset_name,
6451                             in_progress_dstab.zone_dataset_name,
6452                             sizeof (tmp_dstab.zone_dataset_name));
6453                         err = zonecfg_lookup_ds(handle, &tmp_dstab);
6454                         if (err == Z_OK) {
6455                                 zerr(gettext("A %s resource "
6456                                     "with the %s '%s' already exists."),
6457                                     rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6458                                     in_progress_dstab.zone_dataset_name);
6459                                 saw_error = B_TRUE;
6460                                 return;
6461                         }
6462                         err = zonecfg_add_ds(handle, &in_progress_dstab);
6463                 } else {
6464                         err = zonecfg_modify_ds(handle, &old_dstab,
6465                             &in_progress_dstab);
6466                 }
6467                 break;
6468         case RT_DCPU:
6469                 /* Make sure everything was filled in. */
6470                 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6471                     PT_NCPUS, &validation_failed) != Z_OK) {
6472                         saw_error = B_TRUE;
6473                         return;
6474                 }
6475 
6476                 if (end_op == CMD_ADD) {
6477                         err = zonecfg_add_pset(handle, &in_progress_psettab);
6478                 } else {
6479                         err = zonecfg_modify_pset(handle, &in_progress_psettab);
6480                 }
6481                 break;
6482         case RT_PCAP:
6483                 /* Make sure everything was filled in. */
6484                 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6485                     != Z_OK) {
6486                         zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6487                         saw_error = B_TRUE;
6488                         validation_failed = B_TRUE;
6489                         return;
6490                 }
6491                 err = Z_OK;
6492                 break;
6493         case RT_MCAP:
6494                 /* Make sure everything was filled in. */
6495                 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6496                     Z_ERR : Z_OK;
6497                 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6498                     &swap_limit);
6499                 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6500                     &locked_limit);
6501 
6502                 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6503                         zerr(gettext("No property was specified.  One of %s, "
6504                             "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6505                             pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6506                         saw_error = B_TRUE;
6507                         return;
6508                 }
6509 
6510                 /* if phys & locked are both set, verify locked <= phys */
6511                 if (res1 == Z_OK && res3 == Z_OK) {
6512                         uint64_t phys_limit;
6513                         char *endp;
6514 
6515                         phys_limit = strtoull(
6516                             in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6517                         if (phys_limit < locked_limit) {
6518                                 zerr(gettext("The %s cap must be less than or "
6519                                     "equal to the %s cap."),
6520                                     pt_to_str(PT_LOCKED),
6521                                     pt_to_str(PT_PHYSICAL));
6522                                 saw_error = B_TRUE;
6523                                 return;
6524                         }
6525                 }
6526 
6527                 err = Z_OK;
6528                 if (res1 == Z_OK) {
6529                         /*
6530                          * We could be ending from either an add operation
6531                          * or a select operation.  Since all of the properties
6532                          * within this resource are optional, we always use
6533                          * modify on the mcap entry.  zonecfg_modify_mcap()
6534                          * will handle both adding and modifying a memory cap.
6535                          */
6536                         err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6537                 } else if (end_op == CMD_SELECT) {
6538                         /*
6539                          * If we're ending from a select and the physical
6540                          * memory cap is empty then the user could have cleared
6541                          * the physical cap value, so try to delete the entry.
6542                          */
6543                         (void) zonecfg_delete_mcap(handle);
6544                 }
6545                 break;
6546         case RT_ADMIN:
6547                 /* First make sure everything was filled in. */
6548                 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6549                     PT_USER, &validation_failed) == Z_OK) {
6550                         if (getpwnam(in_progress_admintab.zone_admin_user)
6551                             == NULL) {
6552                                 zerr(gettext("%s %s is not a valid username"),
6553                                     pt_to_str(PT_USER),
6554                                     in_progress_admintab.zone_admin_user);
6555                                 validation_failed = B_TRUE;
6556                         }
6557                 }
6558 
6559                 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6560                     PT_AUTHS, &validation_failed) == Z_OK) {
6561                         if (!zonecfg_valid_auths(
6562                             in_progress_admintab.zone_admin_auths,
6563                             zone)) {
6564                                 validation_failed = B_TRUE;
6565                         }
6566                 }
6567 
6568                 if (validation_failed) {
6569                         saw_error = B_TRUE;
6570                         return;
6571                 }
6572 
6573                 if (end_op == CMD_ADD) {
6574                         /* Make sure there isn't already one like this. */
6575                         bzero(&tmp_admintab, sizeof (tmp_admintab));
6576                         (void) strlcpy(tmp_admintab.zone_admin_user,
6577                             in_progress_admintab.zone_admin_user,
6578                             sizeof (tmp_admintab.zone_admin_user));
6579                         err = zonecfg_lookup_admin(
6580                             handle, &tmp_admintab);
6581                         if (err == Z_OK) {
6582                                 zerr(gettext("A %s resource "
6583                                     "with the %s '%s' already exists."),
6584                                     rt_to_str(RT_ADMIN),
6585                                     pt_to_str(PT_USER),
6586                                     in_progress_admintab.zone_admin_user);
6587                                 saw_error = B_TRUE;
6588                                 return;
6589                         }
6590                         err = zonecfg_add_admin(handle,
6591                             &in_progress_admintab, zone);
6592                 } else {
6593                         err = zonecfg_modify_admin(handle,
6594                             &old_admintab, &in_progress_admintab,
6595                             zone);
6596                 }
6597                 break;
6598         default:
6599                 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
6600                     B_TRUE);
6601                 saw_error = B_TRUE;
6602                 return;
6603         }
6604 
6605         if (err != Z_OK) {
6606                 zone_perror(zone, err, B_TRUE);
6607         } else {
6608                 need_to_commit = B_TRUE;
6609                 global_scope = B_TRUE;
6610                 end_op = -1;
6611         }
6612 }
6613 
6614 void
6615 commit_func(cmd_t *cmd)
6616 {
6617         int arg;
6618         boolean_t arg_err = B_FALSE;
6619 
6620         optind = 0;
6621         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6622                 switch (arg) {
6623                 case '?':
6624                         longer_usage(CMD_COMMIT);
6625                         arg_err = B_TRUE;
6626                         break;
6627                 default:
6628                         short_usage(CMD_COMMIT);
6629                         arg_err = B_TRUE;
6630                         break;
6631                 }
6632         }
6633         if (arg_err)
6634                 return;
6635 
6636         if (optind != cmd->cmd_argc) {
6637                 short_usage(CMD_COMMIT);
6638                 return;
6639         }
6640 
6641         if (zone_is_read_only(CMD_COMMIT))
6642                 return;
6643 
6644         assert(cmd != NULL);
6645 
6646         cmd->cmd_argc = 1;
6647         /*
6648          * cmd_arg normally comes from a strdup() in the lexer, and the
6649          * whole cmd structure and its (char *) attributes are freed at
6650          * the completion of each command, so the strdup() below is needed
6651          * to match this and prevent a core dump from trying to free()
6652          * something that can't be.
6653          */
6654         if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
6655                 zone_perror(zone, Z_NOMEM, B_TRUE);
6656                 exit(Z_ERR);
6657         }
6658         cmd->cmd_argv[1] = NULL;
6659         verify_func(cmd);
6660 }
6661 
6662 void
6663 revert_func(cmd_t *cmd)
6664 {
6665         char line[128]; /* enough to ask a question */
6666         boolean_t force = B_FALSE;
6667         boolean_t arg_err = B_FALSE;
6668         int err, arg, answer;
6669 
6670         optind = 0;
6671         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
6672                 switch (arg) {
6673                 case '?':
6674                         longer_usage(CMD_REVERT);
6675                         arg_err = B_TRUE;
6676                         break;
6677                 case 'F':
6678                         force = B_TRUE;
6679                         break;
6680                 default:
6681                         short_usage(CMD_REVERT);
6682                         arg_err = B_TRUE;
6683                         break;
6684                 }
6685         }
6686         if (arg_err)
6687                 return;
6688 
6689         if (optind != cmd->cmd_argc) {
6690                 short_usage(CMD_REVERT);
6691                 return;
6692         }
6693 
6694         if (zone_is_read_only(CMD_REVERT))
6695                 return;
6696 
6697         if (!global_scope) {
6698                 zerr(gettext("You can only use %s in the global scope.\nUse"
6699                     " '%s' to cancel changes to a resource specification."),
6700                     cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
6701                 saw_error = B_TRUE;
6702                 return;
6703         }
6704 
6705         if (zonecfg_check_handle(handle) != Z_OK) {
6706                 zerr(gettext("No changes to revert."));
6707                 saw_error = B_TRUE;
6708                 return;
6709         }
6710 
6711         if (!force) {
6712                 (void) snprintf(line, sizeof (line),
6713                     gettext("Are you sure you want to revert"));
6714                 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
6715                         zerr(gettext("Input not from terminal and -F not "
6716                             "specified:\n%s command ignored, exiting."),
6717                             cmd_to_str(CMD_REVERT));
6718                         exit(Z_ERR);
6719                 }
6720                 if (answer != 1)
6721                         return;
6722         }
6723 
6724         /*
6725          * Reset any pending admins that were
6726          * removed from the previous zone
6727          */
6728         zonecfg_remove_userauths(handle, "", zone, B_FALSE);
6729 
6730         /*
6731          * Time for a new handle: finish the old one off first
6732          * then get a new one properly to avoid leaks.
6733          */
6734         zonecfg_fini_handle(handle);
6735         if ((handle = zonecfg_init_handle()) == NULL) {
6736                 zone_perror(execname, Z_NOMEM, B_TRUE);
6737                 exit(Z_ERR);
6738         }
6739 
6740         if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
6741                 saw_error = B_TRUE;
6742                 got_handle = B_FALSE;
6743                 if (err == Z_NO_ZONE)
6744                         zerr(gettext("%s: no such saved zone to revert to."),
6745                             revert_zone);
6746                 else
6747                         zone_perror(zone, err, B_TRUE);
6748         }
6749         (void) strlcpy(zone, revert_zone, sizeof (zone));
6750 }
6751 
6752 void
6753 help_func(cmd_t *cmd)
6754 {
6755         int i;
6756 
6757         assert(cmd != NULL);
6758 
6759         if (cmd->cmd_argc == 0) {
6760                 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
6761                 return;
6762         }
6763         if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
6764                 usage(B_TRUE, HELP_USAGE);
6765                 return;
6766         }
6767         if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
6768                 usage(B_TRUE, HELP_SUBCMDS);
6769                 return;
6770         }
6771         if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
6772                 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
6773                 return;
6774         }
6775         if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
6776                 longer_usage(CMD_HELP);
6777                 return;
6778         }
6779 
6780         for (i = 0; i <= CMD_MAX; i++) {
6781                 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
6782                         longer_usage(i);
6783                         return;
6784                 }
6785         }
6786         /* We do not use zerr() here because we do not want its extra \n. */
6787         (void) fprintf(stderr, gettext("Unknown help subject %s.  "),
6788             cmd->cmd_argv[0]);
6789         usage(B_FALSE, HELP_META);
6790 }
6791 
6792 static int
6793 string_to_yyin(char *string)
6794 {
6795         if ((yyin = tmpfile()) == NULL) {
6796                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6797                 return (Z_ERR);
6798         }
6799         if (fwrite(string, strlen(string), 1, yyin) != 1) {
6800                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6801                 return (Z_ERR);
6802         }
6803         if (fseek(yyin, 0, SEEK_SET) != 0) {
6804                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
6805                 return (Z_ERR);
6806         }
6807         return (Z_OK);
6808 }
6809 
6810 /* This is the back-end helper function for read_input() below. */
6811 
6812 static int
6813 cleanup()
6814 {
6815         int answer;
6816         cmd_t *cmd;
6817 
6818         if (!interactive_mode && !cmd_file_mode) {
6819                 /*
6820                  * If we're not in interactive mode, and we're not in command
6821                  * file mode, then we must be in commands-from-the-command-line
6822                  * mode.  As such, we can't loop back and ask for more input.
6823                  * It was OK to prompt for such things as whether or not to
6824                  * really delete a zone in the command handler called from
6825                  * yyparse() above, but "really quit?" makes no sense in this
6826                  * context.  So disable prompting.
6827                  */
6828                 ok_to_prompt = B_FALSE;
6829         }
6830         if (!global_scope) {
6831                 if (!time_to_exit) {
6832                         /*
6833                          * Just print a simple error message in the -1 case,
6834                          * since exit_func() already handles that case, and
6835                          * EOF means we are finished anyway.
6836                          */
6837                         answer = ask_yesno(B_FALSE,
6838                             gettext("Resource incomplete; really quit"));
6839                         if (answer == -1) {
6840                                 zerr(gettext("Resource incomplete."));
6841                                 return (Z_ERR);
6842                         }
6843                         if (answer != 1) {
6844                                 yyin = stdin;
6845                                 return (Z_REPEAT);
6846                         }
6847                 } else {
6848                         saw_error = B_TRUE;
6849                 }
6850         }
6851         /*
6852          * Make sure we tried something and that the handle checks
6853          * out, or we would get a false error trying to commit.
6854          */
6855         if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
6856                 if ((cmd = alloc_cmd()) == NULL) {
6857                         zone_perror(zone, Z_NOMEM, B_TRUE);
6858                         return (Z_ERR);
6859                 }
6860                 cmd->cmd_argc = 0;
6861                 cmd->cmd_argv[0] = NULL;
6862                 commit_func(cmd);
6863                 free_cmd(cmd);
6864                 /*
6865                  * need_to_commit will get set back to FALSE if the
6866                  * configuration is saved successfully.
6867                  */
6868                 if (need_to_commit) {
6869                         if (force_exit) {
6870                                 zerr(gettext("Configuration not saved."));
6871                                 return (Z_ERR);
6872                         }
6873                         answer = ask_yesno(B_FALSE,
6874                             gettext("Configuration not saved; really quit"));
6875                         if (answer == -1) {
6876                                 zerr(gettext("Configuration not saved."));
6877                                 return (Z_ERR);
6878                         }
6879                         if (answer != 1) {
6880                                 time_to_exit = B_FALSE;
6881                                 yyin = stdin;
6882                                 return (Z_REPEAT);
6883                         }
6884                 }
6885         }
6886         return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
6887 }
6888 
6889 /*
6890  * read_input() is the driver of this program.  It is a wrapper around
6891  * yyparse(), printing appropriate prompts when needed, checking for
6892  * exit conditions and reacting appropriately [the latter in its cleanup()
6893  * helper function].
6894  *
6895  * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
6896  * so do_interactive() knows that we are not really done (i.e, we asked
6897  * the user if we should really quit and the user said no).
6898  */
6899 static int
6900 read_input()
6901 {
6902         boolean_t yyin_is_a_tty = isatty(fileno(yyin));
6903         /*
6904          * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
6905          * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
6906          */
6907         char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
6908 
6909         /* yyin should have been set to the appropriate (FILE *) if not stdin */
6910         newline_terminated = B_TRUE;
6911         for (;;) {
6912                 if (yyin_is_a_tty) {
6913                         if (newline_terminated) {
6914                                 if (global_scope)
6915                                         (void) snprintf(prompt, sizeof (prompt),
6916                                             "%s:%s> ", execname, zone);
6917                                 else
6918                                         (void) snprintf(prompt, sizeof (prompt),
6919                                             "%s:%s:%s> ", execname, zone,
6920                                             rt_to_str(resource_scope));
6921                         }
6922                         /*
6923                          * If the user hits ^C then we want to catch it and
6924                          * start over.  If the user hits EOF then we want to
6925                          * bail out.
6926                          */
6927                         line = gl_get_line(gl, prompt, NULL, -1);
6928                         if (gl_return_status(gl) == GLR_SIGNAL) {
6929                                 gl_abandon_line(gl);
6930                                 continue;
6931                         }
6932                         if (line == NULL)
6933                                 break;
6934                         (void) string_to_yyin(line);
6935                         while (!feof(yyin))
6936                                 yyparse();
6937                 } else {
6938                         yyparse();
6939                 }
6940                 /* Bail out on an error in command file mode. */
6941                 if (saw_error && cmd_file_mode && !interactive_mode)
6942                         time_to_exit = B_TRUE;
6943                 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
6944                         break;
6945         }
6946         return (cleanup());
6947 }
6948 
6949 /*
6950  * This function is used in the zonecfg-interactive-mode scenario: it just
6951  * calls read_input() until we are done.
6952  */
6953 
6954 static int
6955 do_interactive(void)
6956 {
6957         int err;
6958 
6959         interactive_mode = B_TRUE;
6960         if (!read_only_mode) {
6961                 /*
6962                  * Try to set things up proactively in interactive mode, so
6963                  * that if the zone in question does not exist yet, we can
6964                  * provide the user with a clue.
6965                  */
6966                 (void) initialize(B_FALSE);
6967         }
6968         do {
6969                 err = read_input();
6970         } while (err == Z_REPEAT);
6971         return (err);
6972 }
6973 
6974 /*
6975  * cmd_file is slightly more complicated, as it has to open the command file
6976  * and set yyin appropriately.  Once that is done, though, it just calls
6977  * read_input(), and only once, since prompting is not possible.
6978  */
6979 
6980 static int
6981 cmd_file(char *file)
6982 {
6983         FILE *infile;
6984         int err;
6985         struct stat statbuf;
6986         boolean_t using_real_file = (strcmp(file, "-") != 0);
6987 
6988         if (using_real_file) {
6989                 /*
6990                  * zerr() prints a line number in cmd_file_mode, which we do
6991                  * not want here, so temporarily unset it.
6992                  */
6993                 cmd_file_mode = B_FALSE;
6994                 if ((infile = fopen(file, "r")) == NULL) {
6995                         zerr(gettext("could not open file %s: %s"),
6996                             file, strerror(errno));
6997                         return (Z_ERR);
6998                 }
6999                 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7000                         zerr(gettext("could not stat file %s: %s"),
7001                             file, strerror(errno));
7002                         err = Z_ERR;
7003                         goto done;
7004                 }
7005                 if (!S_ISREG(statbuf.st_mode)) {
7006                         zerr(gettext("%s is not a regular file."), file);
7007                         err = Z_ERR;
7008                         goto done;
7009                 }
7010                 yyin = infile;
7011                 cmd_file_mode = B_TRUE;
7012                 ok_to_prompt = B_FALSE;
7013         } else {
7014                 /*
7015                  * "-f -" is essentially the same as interactive mode,
7016                  * so treat it that way.
7017                  */
7018                 interactive_mode = B_TRUE;
7019         }
7020         /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7021         if ((err = read_input()) == Z_REPEAT)
7022                 err = Z_ERR;
7023 done:
7024         if (using_real_file)
7025                 (void) fclose(infile);
7026         return (err);
7027 }
7028 
7029 /*
7030  * Since yacc is based on reading from a (FILE *) whereas what we get from
7031  * the command line is in argv format, we need to convert when the user
7032  * gives us commands directly from the command line.  That is done here by
7033  * concatenating the argv list into a space-separated string, writing it
7034  * to a temp file, and rewinding the file so yyin can be set to it.  Then
7035  * we call read_input(), and only once, since prompting about whether to
7036  * continue or quit would make no sense in this context.
7037  */
7038 
7039 static int
7040 one_command_at_a_time(int argc, char *argv[])
7041 {
7042         char *command;
7043         size_t len = 2; /* terminal \n\0 */
7044         int i, err;
7045 
7046         for (i = 0; i < argc; i++)
7047                 len += strlen(argv[i]) + 1;
7048         if ((command = malloc(len)) == NULL) {
7049                 zone_perror(execname, Z_NOMEM, B_TRUE);
7050                 return (Z_ERR);
7051         }
7052         (void) strlcpy(command, argv[0], len);
7053         for (i = 1; i < argc; i++) {
7054                 (void) strlcat(command, " ", len);
7055                 (void) strlcat(command, argv[i], len);
7056         }
7057         (void) strlcat(command, "\n", len);
7058         err = string_to_yyin(command);
7059         free(command);
7060         if (err != Z_OK)
7061                 return (err);
7062         while (!feof(yyin))
7063                 yyparse();
7064         return (cleanup());
7065 }
7066 
7067 static char *
7068 get_execbasename(char *execfullname)
7069 {
7070         char *last_slash, *execbasename;
7071 
7072         /* guard against '/' at end of command invocation */
7073         for (;;) {
7074                 last_slash = strrchr(execfullname, '/');
7075                 if (last_slash == NULL) {
7076                         execbasename = execfullname;
7077                         break;
7078                 } else {
7079                         execbasename = last_slash + 1;
7080                         if (*execbasename == '\0') {
7081                                 *last_slash = '\0';
7082                                 continue;
7083                         }
7084                         break;
7085                 }
7086         }
7087         return (execbasename);
7088 }
7089 
7090 int
7091 main(int argc, char *argv[])
7092 {
7093         int err, arg;
7094         struct stat st;
7095 
7096         /* This must be before anything goes to stdout. */
7097         setbuf(stdout, NULL);
7098 
7099         saw_error = B_FALSE;
7100         cmd_file_mode = B_FALSE;
7101         execname = get_execbasename(argv[0]);
7102 
7103         (void) setlocale(LC_ALL, "");
7104         (void) textdomain(TEXT_DOMAIN);
7105 
7106         if (getzoneid() != GLOBAL_ZONEID) {
7107                 zerr(gettext("%s can only be run from the global zone."),
7108                     execname);
7109                 exit(Z_ERR);
7110         }
7111 
7112         if (argc < 2) {
7113                 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7114                 exit(Z_USAGE);
7115         }
7116         if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7117                 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7118                 exit(Z_OK);
7119         }
7120 
7121         while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7122                 switch (arg) {
7123                 case '?':
7124                         if (optopt == '?')
7125                                 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7126                         else
7127                                 usage(B_FALSE, HELP_USAGE);
7128                         exit(Z_USAGE);
7129                         /* NOTREACHED */
7130                 case 'f':
7131                         cmd_file_name = optarg;
7132                         cmd_file_mode = B_TRUE;
7133                         break;
7134                 case 'R':
7135                         if (*optarg != '/') {
7136                                 zerr(gettext("root path must be absolute: %s"),
7137                                     optarg);
7138                                 exit(Z_USAGE);
7139                         }
7140                         if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7141                                 zerr(gettext(
7142                                     "root path must be a directory: %s"),
7143                                     optarg);
7144                                 exit(Z_USAGE);
7145                         }
7146                         zonecfg_set_root(optarg);
7147                         break;
7148                 case 'z':
7149                         if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7150                                 global_zone = B_TRUE;
7151                         } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7152                                 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7153                                 usage(B_FALSE, HELP_SYNTAX);
7154                                 exit(Z_USAGE);
7155                         }
7156                         (void) strlcpy(zone, optarg, sizeof (zone));
7157                         (void) strlcpy(revert_zone, optarg, sizeof (zone));
7158                         break;
7159                 default:
7160                         usage(B_FALSE, HELP_USAGE);
7161                         exit(Z_USAGE);
7162                 }
7163         }
7164 
7165         if (optind > argc || strcmp(zone, "") == 0) {
7166                 usage(B_FALSE, HELP_USAGE);
7167                 exit(Z_USAGE);
7168         }
7169 
7170         if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7171                 read_only_mode = B_FALSE;
7172         } else if (err == Z_ACCES) {
7173                 read_only_mode = B_TRUE;
7174                 /* skip this message in one-off from command line mode */
7175                 if (optind == argc)
7176                         (void) fprintf(stderr, gettext("WARNING: you do not "
7177                             "have write access to this zone's configuration "
7178                             "file;\ngoing into read-only mode.\n"));
7179         } else {
7180                 fprintf(stderr, "%s: Could not access zone configuration "
7181                     "store: %s\n", execname, zonecfg_strerror(err));
7182                 exit(Z_ERR);
7183         }
7184 
7185         if ((handle = zonecfg_init_handle()) == NULL) {
7186                 zone_perror(execname, Z_NOMEM, B_TRUE);
7187                 exit(Z_ERR);
7188         }
7189 
7190         /*
7191          * This may get set back to FALSE again in cmd_file() if cmd_file_name
7192          * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7193          */
7194         if (isatty(STDIN_FILENO))
7195                 ok_to_prompt = B_TRUE;
7196         if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7197                 exit(Z_ERR);
7198         if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7199                 exit(Z_ERR);
7200         (void) sigset(SIGINT, SIG_IGN);
7201         if (optind == argc) {
7202                 if (!cmd_file_mode)
7203                         err = do_interactive();
7204                 else
7205                         err = cmd_file(cmd_file_name);
7206         } else {
7207                 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7208         }
7209         zonecfg_fini_handle(handle);
7210         if (brand != NULL)
7211                 brand_close(brand);
7212         (void) del_GetLine(gl);
7213         return (err);
7214 }