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