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