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