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