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